Cairo and Shoes in Ruby - ruby

How do I use Cairo ta draw on a shoes window?
I am trying to start a school project for Computer Graphics. Can anybody post a simple code that draws a circle on a shoes window? I'd be very grateful. I have been searching for quite a while now... I've reached nowhere yet. so, please help me!! :)

I'm not sure how you would use Cairo in Ruby. It's not my area of expertise; however drawing circles in Shoes is not difficult at all. The following example allows circles to be created from mouse clicking and dragging.
Shoes.app do
ox,oy = nil,nil
click{|button, x, y| # on click, set the original x and y position
if button == 1
ox = x
oy = y
end
}
release{|button, x, y| #on mouse release, draw the circle
if button == 1
oval(
:left => [ox, x].min, # furthest left point
:top => [oy, y].min, # furthest top point
:radius => ((ox-x).abs + (oy-y).abs) / 2 # the average of the positive difference between original and final x and y points
)
end
}
end
Obviously, depending on your specific requirements, you will need to decide whether it is good enough.
In my experience, Shoes is a decent platform for making a broad range of low to medium power apps. However, if you're trying to build something substantial, like a graphics package, there are probably better solutions.

Related

How to Plot Several 3D Trajectories in Julia (using a for-loop, presumably?) -- also, how to animate over time?

I am trying to plot a set of 3D trajectories in a single plot in Julia. By 3-D trajectories I mean: different sets of 3-D coordinates over time. These trajectories are stored in a multidimensional array called positions, where the dimensions respectively correspond to the Trajectory ID, X-Y-Z coordinate and Time. For example, positions[75,2,1:100] refers to the Y (2nd) coordinate of the 75th Trajectory, across the first 100 timesteps of the trajectory.
I am trying to figure out why the following code doesn't work:
using Plots
plotlyjs()
time_indices = 1:100
ax= scatter3d(positions[1,1,time_indices],positions[1,2,time_indices],positions[1,3,time_indices],label="Trajectory 1 for times 1 to 100")
for n in 2:size(positions,1)
scatter3d!(ax, positions[n,1,time_indices], positions[n,2,time_indices],positions[n,3,time_indices],label="Trajectory $n for times 1 to 100")
end
When I run that code, I don't see anything in the Plots window (I'm using Atom), although I don't get any errors / it appears to run successfully. Any thoughts on what I'm doing wrong? Should I use a different backend? It doesn't work on either gr() or plotlyjs() (those are the only ones I know of, based on tutorials I've completed).
Follow up question: once I can successfully plot such 3-D trajectories in a single static plot, I am wondering how you would go about animating them over time (using #gif or #animate macros, presumably)? I am asking this here, because I wasn't able to understand the documentation / tutorial on 3D animations, unfortunately. Googling / other sources have also not helped :(
It looks like you're just missing a display(ax) at the end, after the loop.
Edit: to animate, try
anim = #animate for n in 1:size(positions,1)
scatter3d(positions[n,1,time_indices], positions[n,2,time_indices],positions[n,3,time_indices],label="Trajectory $n for times 1 to 100")
end
gif(anim, "some_file_name.gif", fps=15)
(or if you want the prior trajectories to show up as well in later frames of the gif, then replace the scatter3d with scatter3d!)
I can't test the above without having your positions, but here is another example that I have just tested on Julia 1.5.0beta with Plots and the GR backend:
using Plots; gr();
anim = #animate for i=1:100
plot(sin.(range(0,i/10*pi,length=1000)), label="", ylims=(-1,1))
end
gif(anim, "anim_fps15.gif", fps=15)
How to do the second bit (the animation - see details in comments on the accepted answer):
gr()
anim = #animate for t in time_indices
all_positions_t = positions[:,:,t] # positions of all trajectories at time t
scatter3d(all_positions_t[:,1], all_positions_t[:,2],all_positions_t[:,3],label="")
end
gif(anim, "some_file_name.gif", fps=15)

MATLAB, algorithm for free surface detection in bubbly flow

I am trying to figure out an algorithm for detecting the free surface from a PIV image (see attached). The major problem is that in the flow under consideration gas bubbles are injected into the fluid, these rise up due to buoyancy and tend to sit on top of the surface. I don't want these to be mistaken for the free surface (actually want the '2nd' edge underneath them) - I'm struggling to figure out how to include that in the algorithm.
Ideally, I want an array of x and y values representing coordinates of the free surface (like a continuous, smooth curve).
My initial approach was to scan the picture left to right, one column at a time, find an edge, move to the next column etc... That works somewhat ok, but fails as soon as the bubbles appear and my 'edge' splits in two. So I am wondering if there is some more sophisticated way of going about it.
If anybody have any expertise in the area of image processing/edge detection, any advice would be greatly appreciated.
Typical PIV image
Desired outcome
I think you can actually solve the problem by using morphologic methods.
A = imread('./MATLAB/ZBhAM.jpg');
figure;
subplot 131;
imshow(A)
subplot 132;
B = double(A(:,:,1));
B = B/255;
B = im2bw(B, 0.1);
imshow(B);
subplot 133;
st = strel('diamond', 5);
B = imerode(B, st);
B = imdilate(B, st);
B = imshow(B);
This gives the following result:
As you can see this approach is not perfect mostly because I picked a random value for the threshold in im2bw, if you use an adaptive threshold for the different column of your images you should have something better.
Try to work on your lighting otherwise.

How to make my playing field as a grid in Ruby (Gosu)?

So I'm attempting to make a simple Snake game. However, there's one major problem with that - I don't know how to make my playing field as a grid.
So far I've split my snake into segemnts, which are drawn every time it eats an apple. My turn method looks like that (it's analogical for every direction pretty much):
if #direction == :right
x = #head.x + #speed
y = #head.y
new_segment = Segment.new(#window, self, [x, y])
end
with new_segment being immediately pushed into the array segments.
The problem with that is that the snake is too independant. I'd like to make it move in predetermined rows and columns a.k.a make myself a grid. Could somoene help me with that? Thank you!

Proper OO 2D Animation Logic

I'm doing some animation script in RPG Maker XP (made with ruby) that allow you to display moving images. My question here is not strictly about RPG Maker, but in general term. This is the code I found out so far and it works, but with problem :
class Poser
attr_accessor :images
def initialize
#images = Sprite.new
#images.bitmap = RPG::Cache.picture('Character.png') #display picture
#images.x = 540 #place it on the bottom right corner of the screen
#images.y = 180
end
def move(x,y)
#images.x += x
#images.y += y
end
def animate(x,y,step,delay) #Animate moving the picture up and down with delay
forward = true
2.times { #the first loop, do code 2 times of :
step.times {
wait(delay) #wait x frame
if forward
move(x/step,y/step) #move the picture down
else
move(-x/step,-y/step) #move the picture up
end
}
wait(delay*3)
forward = false
}
end
def wait(time)
while time > 0
time -= 1
Graphics.update
end
end
end
Then I create an instance of it and called the method :
$test = Poser.new
$test.animate(0,10,10,10)
What the above code do is to move the picture up and down (just like breathing animation, your head bob up and down)
As you can see, Im using loop functions to move the picture with delay. What I got is, I cannot do anything else until the animation finished. What I meant by "anything else" is such as walking around with my character, talk to NPC, I want to do those things while there is animation being played in the background. In the end, the game "paused" in the loop block.
Is there is another way to do animation without looping, or, anything that doesn't "pause" the screen until animation is finished ? Thanks in advance.
Usually, games use a system called a game loop. A game loop is a loop in the main function of the program that executes as fast as it can. Each time it executes, it executes two functions (or these can be the body of the loop, that's a design choice that you can make): draw and update (update, then draw).
update's job is to change the positions of characters, usually by a formula of position=(x+pixelsPerSecond*secondsSinceLastTick,y+pixelsPerSecond*secondsSinceLastTick) (in game terminology, a tick is an iteration of the game loop). The system of a game loop is optimized for games, because every tick you can execute one tiny piece of each animation, fast enough together that they give an illusion of concurrency (game loops run many times per second).
After update has changed the position of entire objects (eg. a fast NPC is now 5 pixels further to the left), draw is used to draw the scene. draw can do a couple of things. It can draw sprites at the locations indicated by update, and it can also maintain it's own animations (small things like the animation of legs walking -- update shouldn't set the position of the legs in the walking animation, just the new position of the character for this tick).
I'm not sure if I am exactly answering your question, as I know nothing about RPG Maker (so maybe you have to do something else completely), but because you said in general, this is what it is.

Writing a paint program à la MS Paint - how to interpolate between mouse move events?

I want to write a paint program in the style of MS Paint.
For painting things on screen when the user moves the mouse, I have to wait for mouse move events and draw on the screen whenever I receive one. Apparently, mose move events are not sent very often, so I have to interpolate the mouse movement by drawing a line between the current mouse position and the previous one. In pseudocode, this looks something like this:
var positionOld = null
def handleMouseMove(positionNew):
if mouse.button.down:
if positionOld == null:
positionOld = positionNew
screen.draw.line(positionOld,positionNew)
positionOld = positionNew
Now my question: interpolating with straight line segments looks too jagged for my taste, can you recommend a better interpolation method? What method do GIMP or Adobe Photoshop implement?
Alternatively, is there a way to increase the frequency of the mouse move events that I receive? The GUI framework I'm using is wxWidgets.
GUI framework: wxWidgets.
(Programming language: Haskell, but that's irrelevant here)
EDIT: Clarification: I want something that looks smoother than straight line segments, see the picture (original size):
EDIT2: The code I'm using looks like this:
-- create bitmap and derive drawing context
im <- imageCreateSized (sy 800 600)
bitmap <- bitmapCreateFromImage im (-1) -- wxBitmap
dc <- memoryDCCreate -- wxMemoryDC
memoryDCSelectObject dc bitmap
...
-- handle mouse move
onMouse ... sw (MouseLeftDrag posNew _) = do
...
line dc posOld posNew [color := white
, penJoin := JoinRound
, penWidth := 2]
repaint sw -- a wxScrolledWindow
-- handle paint event
onPaint ... = do
...
-- draw bitmap on the wxScrolledWindow
drawBitmap dc_sw bitmap pointZero False []
which might make a difference. Maybe my choices of wx-classes is why I'm getting a rather low frequency of mouse move events.
Live demos
version 1 - more smooth, but more changing while you draw: http://jsfiddle.net/Ub7RV/1/
version 2 - less smooth but more stable: http://jsfiddle.net/Ub7RV/2/
The way to go is
Spline interpolation of the points
The solution is to store coordinates of the points and then perform spline interpolation.
I took the solution demonstrated here and modified it. They computed the spline after you stop drawing. I modified the code so that it draws immediately. You might see though that the spline is changing during the drawing. For real application, you probably will need two canvases - one with the old drawings and the other with just the current drawing, that will change constantly until your mouse stops.
Version 1 uses spline simplification - deletes points that are close to the line - which results in smoother splines but produce less "stable" result. Version 2 uses all points on the line and produces much more stable solution though (and computationally less expensive).
You can make them really smooth using splines:
http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm
But you'll have to delay the drawing of each line segment until one frame later, so that you have the start and end points, plus the next and previous points available for the calculation.
so, as I see the problem of jagged edge of freehand made curve, when the mouse are moved very fast, is not solved !!! In my opinion there are need to work around with the polling frequency of mousemove event in the system i.e. using different mouse driver or smf.. And the second way is the math.. using some kind of algorithm, to accuratly bend the straight line between two points when the mouse event is polled out.. For clear view you can compare how is drawed free hand line in photoshop and how in mspaint.. thanks folks.. ;)
I think you need to look into the Device Context documentation for wxWidgets.
I have some code that draws like this:
//screenArea is a wxStaticBitmap
int startx, starty;
void OnMouseDown(wxMouseEvent& event)
{
screenArea->CaptureMouse();
xstart = event.GetX();
ystart = event.GetY();
event.Skip();
}
void OnMouseMove(wxMouseEvent& event)
{
if(event.Dragging() && event.LeftIsDown())
{
wxClientDC dc(screenArea);
dc.SetPen(*wxBLACK_PEN);
dc.DrawLine(startx, starty, event.GetX(), event.GetY());
}
startx = event.GetX();
starty = event.GetY();
event.Skip();
}
I know it's C++ but you said the language was irrelevant, so I hope it helps anyway.
This lets me do this:
which seems significantly smoother than your example.
Interpolating mouse movements with line segments is fine, GIMP does it that way, too, as the following screenshot from a very fast mouse movement shows:
So, smoothness comes from a high frequency of mouse move events. WxWidgets can do that, as the example code for a related question demonstrates.
The problem is in your code, Heinrich. Namely, drawing into a large bitmap first and then copying the whole bitmap to the screen is not cheap! To estimate how efficient you need to be, compare your problem to video games: a smooth rate of 30 mouse move events per second correspond to 30fps. Copying a double buffer is no problem for modern machines, but WxHaskell is likely not optimized for video games, so it's not surprising that you experience some jitter.
The solution is to draw only as much as necessary, i.e. just the lines, directly on the screen, for example as shown in the link above.
I agree with harviz - the problem isn't solved. It should be solved on the operating system level by recording mouse movements in a priority thread, but no operating system I know of does that. However, the app developer can also work around this operating system limitation by interpolating better than linear.
Since mouse movement events don't always come fast enough, linear interpolation isn't always enough.
I experimented a little bit with the spline idea brought up by Rocketmagnet.
Instead of putting a line between two points A and D, look at the point P preceding A and use a cubic spline with the following control points B = A + v' and C = D - w', where
v = A - P,
w = D - A,
w' = w / 4 and
v' = v * |w| / |v| / 4.
This means we fall into the second point with the same angle as the line interpolation would, but go out a starting point in the same angle the previous segment came in, making the edge smooth. We use the length of the segment for both control point distances to make the size of the bend fit its proportion.
The following picture shows the result with very few data points (indicated in grey).
The sequence starts at the top left and ends in the middle.
There is still some level of uneasiness here which may be alleviated if one uses both the previous and the next point to adjust for both angles, but that would also mean to draw one point less than what one has got. I find this result already satisfactory, so I didn't try.

Resources