I am developing a simple diagram tool with shapes on a plan using flex.
First i was using a simple 20*20 grid.
But the real cool stuff out their is auto axe magnet effect, that's how i call it at least to see why i mean by that i made a small video of balsamiq.
http://screenr.com/clB
http://www.balsamiq.com/
As you can see it aligns on the vertical horizontal border and center axes.
Borders: gray axes
Horizontal align (height/2) Center: blue axe
No Vertical align (width/2) axe
Some intermediary padding space of 25px: green axes
How do you think such algorithms work:
For now i will do with no rotation.
Given a shape S1 selected at position top left x,y of width w and height h.
Look at all shapes intersecting two zone:
from xmin = x, xmax= x+w for y > 0.
from yming = y , ymax= y+h for x > 0.
Once i have the list of shape concerned i check if any conditions matches:
When i use '=' its an approximation + or - 2 pixels will give the wanted 'magnet' effect
S1 x = S'x => Gray line at x
S1 x+w = S'x => Gray line at x+w
S1 y = S'y => Gray line at y
S1 y+h = S'y => Gray line at y+h
S1 x = S'x and S1 x+w = S'x+w => Blue line at x + w/2
And Given a padding magnet of 20 px
S1 x = S'x + PADD => greenline at S1 x
S1 x = S'x - PADD => greenline at S1 x
S1 y = S'y + PADD => greenline at S1 y
S1 y = S'y - PADD => greenline at S1 y
Whats your thought about this ?
I wrote Balsamiq's snapping algorithm. You're pretty close. The one "clever" thing we do (if I may say so myself), is to pre-populate two sparse arrays with snapping coordinates onMouseDown, so that they are easy/fast/cheap to look up onMouseMove. What I do onMouseDown is this:
let's talk about x coordinates (then repeat the same thing for y):
say GRAVITY is 5
look at all the shapes
for each shape, look at the left edge, say it's at 100. Populate the xSnappingPositions object from 100-GRAVITY (95) to 100+GRAVITY (105) with the number 100. Repeat for right edge
Then when you do an onMouseMove, you look at the control you're dragging's x and y. Is there something in xSnappingPositions and ySnappingPosition that matches the left edge now? if so, go to the value saved in the array instead of using the position detected by the mouse (i.e. snap to it). Repeat the check for right edge, center, etc.
I hope this helps!
Related
So to give further context lets say I have an image that is 200px by 200px with a rectangle on it, its red below:
I know the height and width of the image, the coordinates of the rectangle and also the height and width of the red rectangle.
So what I need to know is if I flip this whole image (including the rectangle) is there a way to work out what the new coordinates are of the red rectangle? I'd imagine there must be some kind of formula or algorithm I can apply to get these new coordinates.
This was already answered over here. The below is the function that worked best for my use case which is very similar to yours.
def rotate(point, origin, degrees):
radians = np.deg2rad(degrees)
x,y = point
offset_x, offset_y = origin
adjusted_x = (x - offset_x)
adjusted_y = (y - offset_y)
cos_rad = np.cos(radians)
sin_rad = np.sin(radians)
qx = offset_x + cos_rad * adjusted_x + sin_rad * adjusted_y
qy = offset_y + -sin_rad * adjusted_x + cos_rad * adjusted_y
return int(qx), int(qy)
In addition to this sometimes when you rotate the points you get negative values(depending on degrees of rotation), in cases like these you need to add the height and or width of the image you are rotating to the value. In my case below the images were of fixed size (416x416)
def cord_checker(pt1):
for item in pt1:
if item<0:
pt1[pt1.index(item)]=416+item
else: pass
return pt1
finally to get the coordinates of the rotated point
pt1=tuple(cord_checker(list(rotate((xmi,ymi),origin=(0,0),degrees*=))))
*degrees can be 90,180 etc
If the image is centered around the origin (0,0), you can just flip the signs of the x-coordinates to do a horizontal flip or the y-coordinates to do a vertical flip while preserving the origin as your center.
You can also flip an arbitrary image by flipping the signs:
# Horizontal flip
new_x = -x
new_y = y
# Vertical flip
new_x = x
new_y = -y
but the center coordinates will not be the same. If you want the same center coordinates, you'd have to shift it back.
I am trying to create a game using one-point perspective. Everything works fine for points within the view but goes wrong with the negative depth. I understand the perspective as shown on the following picture (source).
In general, I took a point at some distance from the left of the right vertical edge of the frame along the lower horizontal line (5 points in this case), join it with the O' point (line H'O') and where the line intersects the vertical line (at point H') is the depth line (of 5 in this case). This works well even for negative depth (as the line H'O' intersect the vertical line below the viewpoint). However, if the depth is more then is the distance of O' (that mean the point would be on the right from the O') the line flip and the H' end on top of the viewpoint (although it should end up below).
How should I correct it, so the point with negative depth is transformed correctly (mean from 3D space to 2D space)?
EDIT
This image is probably better.
My question is how to handle points with negative depth (should end up below the screen) higher then is a distance of transversal.
The points to the right of the point O', along the line determined by the lower edge of the frame, correspond to points that are behind the observer, so technically, the observer cannot see them. To see the points behind you, means that you have to turn around, so you need to change the position of the screen. Draw a copy of the black square frame to the right of the point O', so that the new square is the mirror symmetric image of the original frame square with respect to the line orthogonal to the horizon line and passing trough the point O'.
Edit: The points with negative depth to the right of point O' (i.e. a point behind the observer) is supposed to be mapped above the horizontal blue line. This is the right way to go.
I assume your coordinate system in three dimensions has its origin at the lower right corner of the square frame on your picture. The x axis (I think how you measure width) runs along the lower horizontl edge of the frame, while the y axis (what you call height) is along the right vertical edge of the frame. The depth axis is in three dimensions and it's perpendicular to the plane of the square frame (so it is parallel to the ground). It starts from the lower right corner of the frame square. Assume that the distance of point O' from the right vertical edge of the square is S and the coordinates of the point C are {C1, C2} (C1 is the distance of point C from the right vertical edge and C2 is the distance of C from the lower horizontal edge of the square).
Given the coordinates {w, h, d} (w - width, h - height, d - depth) of a point in three dimensions, its representation on the two dimesnional square screen is gievn by the formulas:
x = (S*w + C1*d)/(S+d)
y = (S*h + C2*d)/(S+d)
So the points you gave as an example in the comments are
P1 = {h = 5, w = 5, d = 5} and P2 = {h = 5, w = 5, d = -10}
Their representation on the screen is
P1_screen = {(S*5 + C1*5)/(S+5), (S*5 + C2*5)/(S+5)}
P2_screen = {(S*5 - C1*10)/(S-10), (S*5 - C2*10)/(S-10)}
whatever your parameters S, C1 and C2 are. The representation of the (infinte) line connecting points P1 and P2 is represented on the screen as the (infinite) line connecting the points P1_screen and P2_screen. However, if you want the 2D representation of the visible part of the segment that connects P1 and P2, then you have to draw the (infinite) line between P1_screen and P2_screen and exclude the following two segment: segment [P1_screen, P2_screen] and the segment from P2_screen along the line up towards the upper top edge. You have to draw on the screen only the segment from the infinite line connecting P1_screen and P2_screen which starts from P1_Screen and goes down towards the lower horizontal edge of the screen.
I want to determine if a point from another point on a circle in the left section or in the right section. (left & right just a matter of sign interpretaton). For that I have calculated the cross product of those two points for creating the normal vector.
So the problem which I am facing is how I can interpret the normal as an scalar which has a sign which indicates whether its in the right or in the left half of the circle.
I have created a gif as for illustration (C' is just the animated point C):
My idea was to add all values within the vector v. For instance:
v = (0.16, 0.1, -0.2)
vSum = v.x + v.y + v.z = 0.06
result = sign(vSum) = 1
o = (-0.16, -0.1, 0.2)
oSum = o.x + o.y + o.z = -0.06
result = sign(oSum) = -1
unfortunately this does only work if the circle is static and does not rotate. If its rotating the sign changes so my result is flipped which leads to reversed left and right sites. And the dot product results positive values only, but this is a value which doesnt changes while rotating the circle. Maybe this is something which can help me ?
I assume, your cross product is the following:
c = cross(p - circle center, reference - circle center)
Then you can take the dot product with the circle normal to get the sign:
sign(dot(c, circle normal))
I've always wondered the easiest way to figure out whether or not a point lies within a triangle, or in this instance, a rectangle cut into half diagonally.
Let's say I have a rectangle that is 64x64 pixels. With this rectangle, I want to return a TRUE value if a passed point is within the upper-left corner of the rectangle, and FALSE if it isn't.
-----
| /|
| / |
|<__|
Horray for bad ASCII art.
Anyway, the hypothetical points for this triangle that would return TRUE would be (0,0) and (63,0) and (0, 63). If a point lands on a line (e.g., 50,0) it would return TRUE as well.
Assuming 0,0 is in the upper-left corner and increases downwards...
I've had a possible solution in my head, but it seems more complicated than it should be - taking the passed Y value, determining where it would be in the rectangle, and figuring out manually where the line would cut at that Y value. E.g, a passed Y value of 16 would be quarter height of the rectangle. And thus, depending on what side you were checking (left or right), the line would either be at 16px or 48px, depending on the direction of the line. In the example above, since we're testing the upper-left corner, at 16px height, the line would be at 48px width
There has to be a better way.
EDIT:
The rectangle could also look like this as well
-----
|\ |
| \ |
|__>|
But I'm figuring in most cases the current answers already provided should still hold up...
Top-left/bottom-right triangles: For all points in the top-left triangle, x+y<=64. Points in the bottom-right triangle have x+y>64.
(for a rectangle of size (w,h) use w*y+h*x-w*h<0)
Top-right/bottom-left triangles: For all points in the bottom-left triangle, x<=y. Points in the top-right triangle have x>y.
(for a rectangle of size (w,h) use h*x-w*y<0)
How did we get there?
For a rectangle of dimensions (w,h) and TL/BR triangles, the equation of the diagonal is (try it out! assign x=0 and check that you get y==h, and assign y=0 and check that x==w)
h*x + w*y - w*h = 0
Points on one side of that line will have
h*x + w*y - w*h > 0
While points on the other will have
h*x + w*y - w*h < 0
Inserting 64 for both w and h, we get:
64x + 64y - 64*64 < 0
Dividing by 64 gets us:
x+y < 64
For TR/BL triangles, the line equation and the resulting inequalities are:
h*x - w*y = 0
h*x - w*y < 0
h*x - w*y > 0
Inserting 64 for w and h, we get
64x-64y < 0
=> x<y
you can represent the triangle with three affine functions
take the unit triangle with corners at (0, 0), (1, 0) and (1, 1). the sides are represented by the three lines
y = 0
x = 1
y = x
So the interior and boundry of the triangle are given as the intersection of the sets
x >= 1
y >= 0
y <= x
so given a point, (x, y), you just need to verify that it satisfies those three inequalities.
You can of course generalize this to any triangle using the fact that any affine function (representing a line) can be written in the form y = mx + b.
The equation for the line looks like this :
y = mx + b
So, if you insert your x and y-Values into that equation, it will probably not hold anymore. Let's reformulate it:
mx + b - y = 0
Same thing, different look. Again, the result is probably not zero. But, the result will now tell you whether it's on the one side of the line or the other.
Now you just have to find out whether the point is inside your rectangle.
Lets assume your right angled triangle has one corner at 0,0 and the diagonal corner at a,b.
So y=mx+c c=0 as we start at the origin.
m=b/a
So y=bx/a
To know which half of the triangle your point (c,d) falls in
if (d<=(bc/a)) {//point is in bottom half}
if (d>(bc/a)) {//point is in top half}
I think...
A simple option is to use a ray casting algorithm. Whilst perhaps a little overkill for what you need, it does have the advantage that it will work with more complex triangles and polygons.
Loosely, the algorithm takes an imaginary point in a direction (infinitely off to the left, for example) and casts a ray to your test point; you then calculate whether each line of your triangle crosses that infinitely long line. If you get an odd number of crossings, your point is inside your triangle; even and you're out of your triangle
Hey there guys, I'm learning processing.js, and I've come across a mathematical problem, which I can't seem to solve with my limited geometry and trigonometry knowledge or by help of Wikipedia.
I need to draw a rectangle. To draw this rectangle, I need to know the coordinate points of each corner. All I know is x and y for the midpoints of the top and bottom of the box, and the length of all four sides.
There is no guarantee on the orientation of the box.
Any help? This seems like it should be easy, but it is really stumping me.
If this quadrilateral is a rectangle (all four angles are 90 degrees), then it can be solved. (if it could be any quadrilateral, then it is not solvable)
if the points are (x1,y1), and (x2, y2), and if the two points are not perfectly vertical (x1 = x2) or horizontal (y1 = y2), then the slope of one edge of the rectangle is
m1 = (y2-y1) / (x2-x1)
and the slope of the other edge is:
m2 = - 1 / m1
If you know the lengths of the sides, and the midpoints of two opposite sides, then the corrner points are easily determined by adding dx, dy to the midpoints: (if L is length of the sides that the midpoints are on)
dx = Sqrt( L^2 / (1 + m2^2) ) / 2
and
dy = m2 * dx
NOTE: if the points are vertically or horizontally aligned, this technique will not work, although the obvious solution for those degenerative cases is much simpler.
If you know your quadrilateral is a rectangle, then you can use some simple vector maths to find the coordinates of the corners. The knowns are:
(x1,y1) - the coordinate of the midpoint on the top line
(x2,y2) - the coordinate of the midpoint on the bottom line
l1 - the length of the top and bottom lines
l2 - the length of the other two lines
First, we find the vector between the two known points. This vector is parallel to the side lines:
(vx, vy) = (x2 - x1, y2 - y1)
We need to normalize this vector (i.e. make it length 1) so we can use it later as a basis to find our coordinates.
vlen = sqrt(vx*vx + vy*vy)
(v1x, v1y) = (vx / vlen, vy / vlen)
Next, we rotate this vector anticlockwise by 90 degrees. The rotated vector will be parallel to the top and bottom lines. 90 degree rotation turns out to just be swapping the coordinates and negating one of them. You can see this just by trying it out on paper. Or take at look at the equations for 2D rotations and substitute in 90 degrees.
(u1x, u1y) = (-v1y, v1x)
Now we have enough information to find the 'top-left' corner. We simply start at our point (x1, y1) and move back along that side by half the side length:
(p1x, p1y) = (x1 - u1x * l1 / 2, y1 - u1y * l1 / 2)
From here we can find the remaining points just by adding the appropriate multiples of our basis vectors. When implementing this you can obviously speed it up by only calculating each unique multiplication a single time:
(p2x, p2y) = (p1x + u1x * l1, p1y + u1y * l1)
(p3x, p3y) = (p1x + v1x * l2, p1y + v1y * l2)
(p4x, p4y) = (p3x + u1x * l1, p3y + u1y * l1)
function getFirstPoint(x1,y1,x2,y2,l1,l2)
distanceV = {x2 - x1, y2 - y1}
vlen = math.sqrt(distanceV[1]^2 + distanceV[2]^2)
normalized = {distanceV[1] / vlen, distanceV[2] / vlen}
rotated = {-normalized[2], normalized[1]}
p1 = {x1 - rotated[1] * l1 / 2, y1 - rotated[2] * l1 / 2}
p2 = {p1[1] + rotated[1] * l1, p1[2] + rotated[2] * l1}
p3 = {p1[1] + normalized[1] * l2, p1[2] + normalized[2] * l2}
p4 = {p3[1] + rotated[1] * l1, p3[2] + rotated[2] * l1}
points = { p1 , p2 , p3 , p4}
return p1
end
It's definitely a rectangle? Then you know the orientation of the short sides (they're parallel to the line between your points), and hence the orientation of the long sides.
You know the orientation and length of the long sides, and you know their midpoints, so it's straightforward to find the corners from there.
Implementation is left as an exercise to the reader.
This means that there will be two lines parallel to the line between the two points you have. Get the corners by translating the line you have 1/2 the length of the top side in each direction perpendicular to the line you have.
If you know the midpoint for the top, and the length of the top, then you know that the y will stay the same for both top corners, and the x will be the midpoint plus/minus the width of the rectangle. This will also be true for the bottom.
Once you have the four corners, there is no need to worry about the side lengths, as their points are the same as those used for the top and bottom.
midpoint
x,10 10,10 x,10
*--------------------------------------------*
width = 30
mx = midpoint x.
top left corner = (w/2) - mx or 15 - 10
top left corner coords = -5,10
mx = midpoint x.
top right corner = (w/2) + mx or 15 + 10
top left corner coords = 25,10
There's a difference between a "quadrilateral" and a "rectangle".
If you have the midpoint of the top and bottom, and the sides lengths, the rest is simple.
Given:
(x1, y1) -- (top_middle_x, top_middle_y) -- (x2, y1)
(x1, y2) -- (btm_middle_x, btm_middle_y) -- (x2, y2)
and top/bottom length along with right/left length.
x1 = top_middle_x - top/bottom_length / 2;
x2 = x1 + top/bottom_length;
y1 = top_middle_y
y2 = bottom_middle_y
Obviously, that's the simplest case and assuming that the line of (tmx, tmy) (bmx, bmy) is solely along the Y axis.
We'll call that line the "mid line".
The next trick is to take the mid line, and calculate it's rotational offset off the Y axis.
Now, my trig is super rusty.
dx = tmx - bmx, dy = tmy - bmy.
So, the tangent of the angle is dy / dx. The arctangent(dy / dx) is the angle of the line.
From that you can get your orientation.
(mind, there's some games with quadrants, and signs, and stuff to get this right -- but this is the gist of it.)
Once you have the orientation, you can "rotate" the line back to the Y axis. Look up 2D graphics for the math, it's straight forward.
That gets you your normal orientation. Then calculate the rectangles points, in this new normal form, and finally, rotate them back.
Viola. Rectangle.
Other things you can do is "rotate" a line that's half the length of the "top" line to where it's 90 deg of the mid line. So, say you have a mid line that's 45 degrees. You would start this line at tmx, tmy, and rotate this line 135 degrees (90 + 45). That point would be your "top left" corner. Rotate it -45 (45 - 90) to get the "top right" point. Then do something similar with the lower points.
Calculate the angle of the line joining the two midpoints using an arc-tangent function applied to the vector you get between them.
Subtract 90 degrees from that angle to get the direction of the top edge
Starting from the top-center point, move relative (1/2 top width x sin(angle), 1/2 top width x cos(angle)) - that gets the top right corner point.
Continue around the rectangle using the sin and cos of the angles and widths as appropriate
As a test: Check you made it back to the starting point
/* rcx = center x rectangle, rcy = center y rectangle, rw = width rectangle, rh = height rectangle, rr = rotation in radian from the rectangle (around it's center point) */
function toRectObjectFromCenter(rcx, rcy, rw, rh, rr){
var a = {
x: rcx+(Math.sin((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2)),
y: rcy-(Math.cos((rr-degToRad(90))+Math.asin(rh/(Math.sqrt(rh*rh+rw*rw)))) * (Math.sqrt(rh*rh+rw*rw)/2))
};
var b = {
x: a.x+Math.cos(rr)*rw,
y: a.y+Math.sin(rr)*rw
};
var c = {
x: b.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
y: b.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
};
var d = {
x: a.x+Math.cos(degToRad(radToDeg(rr)+90))*rh,
y: a.y+Math.sin(degToRad(radToDeg(rr)+90))*rh
};
return {a:a,b:b,c:c,d:d};
}