i've quite noob geometry question.
I have first rect, for example R1(0,0,320, 240), a point P1(20,40), and second rect R2(0,0,640,480), with point P2(40,80) i would like to calculate the position of 2nd rect, that makes two points share one position. In this case it's ofc R2(-20,-40,600, 440), but i need universal formula. I know it's silly, but i've spend 3 hours and can't find answer.
Thanks!
r1.left + p1.x = r2.left + p2.x + x_shift
so
x_shift = r1.left + p1.x - r2.left - p2.x
the same logic for y-coordinate
Related
So I was wondering how does a circle() function work, and how can I draw to circle without using it (wanted to do something related to it). Does anyone know this stuff?
A classic way of rasterizing a circle is using the Midpoint Circle Algorithm.
It works by tracking the pixels which are as close to the x2 + y2 = r2 isoline as possible. This can even be done with purely integer calculations, which is particularly suitable for low-computation power devices.
A circle is the set of points located at a constant distance from another point, called the center.
If you can draw lines defined by two points, you can draw the representation of a circle on a canvas, knowing its center, and its radius.
The approach is to determine a set of consecutive points located on the circumference, then join them with lines.
for instance, in python (which reads like pseudocode):
import math
def make_circle(center, radius, num_points=40):
"""returns a sequence of points on the circumference
"""
points = [center]
d_theta = 2 * math.pi / num_points
cx, cy = center
for idx in range(num_points + 1):
theta = idx * d_theta
points.append((cx + math.cos(theta) * radius, cy + math.sin(theta) * radius))
return points
And if you want to try it, here it is: circles codeskulptor.
You will see that for display purposes, 40 points on the circumference is enough to give an acceptable rendition.
I am trying to reconstruct original graphics primitives from Postscript/SVG paths. Thus an original circle is rendered (in SVG markup) as:
<path stroke-width="0.5" d="M159.679 141.309
C159.679 141.793 159.286 142.186 158.801 142.186
C158.318 142.186 157.925 141.793 157.925 141.309
C157.925 140.825 158.318 140.432 158.801 140.432
C159.286 140.432 159.679 140.825 159.679 141.309" />
This is an approximation using 4 Beziers curves to create a circle.In other places circular arcs are approximated by linked Bezier curves.
My question is whether there is an algorithm I can use to recognize this construct and reconstruct the "best" circle. I don't mind small errors - they will be second-order at worst.
UPDATE: Note that I don't know a priori that this is a circle or an arc - it could be anything. And there could be 2, 3 4 or possibly even more points on the curve. So I'd really like a function of the sort:
error = getCircleFromPath(path)
where error will give an early indication of whether this is likely to be a circle.
[I agree that if I know it's a circle it's an easier problem.]
UPDATE: #george goes some way towards answering my problem but I don't think it's the whole story.
After translation to the origin and normalization I appear to have the following four points on the curve:
point [0, 1] with control point at [+-d,1] // horizontal tangent
point [1, 0] with control point at [1,+-d] // vertical tangent
point [0, -1] with control point at [+-d,-1] // horizontal tangent
point [-1, 0] with control point at [-1,+-d] // vertical tangent
This guarantees that the tangent at each point is "parallel" to the path direction at the point. It also guarantees the symmetry (4-fold axis with reflection. But it does not guarantee a circle. For example a large value of d will give a rounded box and a small value a rounded diamond.
My value of d appears to be about 0.57. This might be 1/sqrt(3.) or it might be something else.It is this sort of relationship I am asking for.
#george gives midpoint of arc as;
{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}
so in my example (for 1,0 to 0,1) this would be:
[[1,0]+3[1,d]+3[d,1]+[0,1]] / 8
i.e.
[0.5+3d/8, 3d/8+0.5]
and if d =0.57, this gives 0.71, so maybe d is
(sqrt(0.5)-0.5)*8./3.
This holds for a square diamond, but for circular arcs the formula must be more general and I'd be grateful if anyone has it. For example, I am not familiar with Bezier math, so #george's formula was new to me
enter code here
Without doing all the math for you.. this may help:
there are always 4 control points on a bezier.
Your curve is 4 beziers linked together with points 1-4 , 4-7 , 7-10 , and 10-13 the control points
for each part. Points 1 , 4 , 7 and 10 (&13==1) lie exactly on the curve. To see if you have a nice circle calculate:
center = ( p1+p7 )/2 =( {159.679, 141.309} + {157.925, 141.309} ) / 2
= {158.802, 141.309}
verify you get the same result using points 4+10 -> {158.801, 141.309}
Once you know the center you can sample points along the curve and see if you have a constant distance.
If you only have a single bezier arc with 4 points a useful formula is that the midpoint is at
(p1 + 3 (p2 + p3) + p4)/8. So you can find the circle passing through three points:
{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}
and again sample other points on the curve to decide if you indeed have a near circular arc.
Edit
the bezier formula is this:
x=(1-t)^3 p1 + 3 (1-t)^2 t p2 + 3 (1-t) t^2 p3 + t^3 p4 with parameter 0 < t < 1
so for example at t=1/4 you have
x=( 27 p1 + 27 p2 + 9 p3 + 1 p4 ) / 64
so once you find the center you can readily check a few points and calculate their distance.
I suspect if you only want to detect nearly exact circular arcs then checking two extra points with a tight tolerance will do the job. If you want to detect things that are approximately circular I would compute a bunch of points and use the average error as a criteria.
If all your elements are circle-like then you can just get the dimensions through path.getBBox() and generate a circle from there. In this case I'm considering ellipses, but you can easily translate it to actual circle elements:
var path = document.getElementById("circle_path");
var bbox = path.getBBox();
var rx = bbox.width/2;
var ry = bbox.height/2;
var cx = bbox.x + rx;
var cy = bbox.y + ry;
var ellipse = document.createElementNS(xmlns, "ellipse");
ellipse.setAttribute("fill", "none");
ellipse.setAttribute("stroke", "red");
ellipse.setAttribute("stroke-width", 0.1);
ellipse.setAttribute("cx", cx);
ellipse.setAttribute("cy", cy);
ellipse.setAttribute("rx", rx);
ellipse.setAttribute("ry", ry);
svg.appendChild(ellipse);
You can see a demo here:
http://jsfiddle.net/nwHm6/
The endpoints of the Bézier curves are probably on the circle. If so, it's easy to reconstruct the original circle.
Another possibility is to take the barycenter of the control points as the center of the circle because the control points are probably laid out symmetrically around the center. From the center, you get the radius as the average distance of the four control points closest to the center.
One can define an ellipse as a unit circle centred on (0,0), translated (2 params), scaled (2 params), and rotated (1 param). So on each arc take five points (t=0 ¼ ½ ¾ 1) and solve for these five parameters. Next take the in-between four points (t=⅛ ⅜ ⅝ ⅞), and test whether these lie on the same transformed circle. If yes, whoopee!, this is (part of) a transformed circle.
Immediately before and after might be another arc or arcn. Are these the same ellipse? If yes, and the subtended angles touch, then join together your descriptions of the pieces.
I'm making a SHMUP game that has a space ship. That space ship currently fires a main cannon from its center point. The sprite that represents the ship has a center based registration point. 0,0 is center of the ship.
When I fire the main cannon i make a bullet and assign make its x & y coordinates match the avatar and add it to the display list. This works fine.
I then made two new functions called fireLeftCannon, fireRightCannon. These create a bullet and add it to the display list but the x, y values are this.y + 15 and this.y +(-) 10. This creates a sort of triangle of bullet entry points.
Similar to this:
▲
▲ ▲
the game tick function will adjust the avatar's rotation to always point at the cursor. This is my aiming method. When I shoot straight up all 3 bullets fire up in the expected pattern. However when i rotate and face the right the entry points do not rotate. This is not an issue for the center point main cannon.
My question is how do i use the current center position ( this.x, this.y ) and adjust them based on my current rotation to place a new bullet so that it is angled correctly.
Thanks a lot in advance.
Tyler
EDIT
OK i tried your solution and it didn't work. Here is my bullet move code:
var pi:Number = Math.PI
var _xSpeed:Number = Math.cos((_rotation - 90) * (pi/180) );
var _ySpeed:Number = Math.sin((_rotation - 90) * (pi / 180) );
this.x += (_xSpeed * _bulletSpeed );
this.y += (_ySpeed * _bulletSpeed );
And i tried adding your code to the left shoulder cannon:
_bullet.x = this.x + Math.cos( StaticMath.ToRad(this.rotation) ) * ( this.x - 10 ) - Math.sin( StaticMath.ToRad(this.rotation)) * ( this.x - 10 );
_bullet.y = this.y + Math.sin( StaticMath.ToRad(this.rotation)) * ( this.y + 15 ) + Math.cos( StaticMath.ToRad(this.rotation)) * ( this.y + 15 );
This is placing the shots a good deal away from the ship and sometimes off screen.
How am i messing up the translation code?
What you need to start with is, to be precise, the coordinates of your cannons in the ship's coordinate system (or “frame of reference”). This is like what you have now but starting from 0, not the ship's position, so they would be something like:
(0, 0) -- center
(10, 15) -- left shoulder
(-10, 15) -- right shoulder
Then what you need to do is transform those coordinates into the coordinate system of the world/scene; this is the same kind of thing your graphics library is doing to draw the sprite.
In your particular case, the intervening transformations are
world ←translation→ ship position ←rotation→ ship positioned and rotated
So given that you have coordinates in the third frame (how the ship's sprite is drawn), you need to apply the rotation, and then apply the translation, at which point you're in the first frame. There are two approaches to this: one is matrix arithmetic, and the other is performing the transformations individually.
For this case, it is simpler to skip the matrices unless you already have a matrix library handy already, in which case you should use it — calculate "ship's coordinate transformation matrix" once per frame and then use it for all bullets etc.
I'll now explain doing it directly.
The general method of applying a rotation to coordinates (in two dimensions) is this (where (x1,y1) is the original point and (x2,y2) is the new point):
x2 = cos(angle)*x1 - sin(angle)*y1
y2 = sin(angle)*x1 + cos(angle)*y1
Whether this is a clockwise or counterclockwise rotation will depend on the “handedness” of your coordinate system; just try it both ways (+angle and -angle) until you have the right result. Don't forget to use the appropriate units (radians or degrees, but most likely radians) for your angles given the trig functions you have.
Now, you need to apply the translation. I'll continue using the same names, so (x3,y3) is the rotated-and-translated point. (dx,dy) is what we're translating by.
x3 = dx + x2
y3 = dy + x2
As you can see, that's very simple; you could easily combine it with the rotation formulas.
I have described transformations in general. In the particular case of the ship bullets, it works out to this in particular:
bulletX = shipPosX + cos(shipAngle)*gunX - sin(shipAngle)*gunY
bulletY = shipPosY + sin(shipAngle)*gunX + cos(shipAngle)*gunY
If your bullets are turning the wrong direction, negate the angle.
If you want to establish a direction-dependent initial velocity for your bullets (e.g. always-firing-forward guns) then you just apply the rotation but not the translation to the velocity (gunVelX, gunVelY).
bulletVelX = cos(shipAngle)*gunVelX - sin(shipAngle)*gunVelY
bulletVelY = sin(shipAngle)*gunVelX + cos(shipAngle)*gunVelY
If you were to use vector and matrix math, you would be doing all the same calculations as here, but they would be bundled up in single objects rather than pairs of x's and y's and four trig functions. It can greatly simplify your code:
shipTransform = translate(shipX, shipY)*rotate(shipAngle)
bulletPos = shipTransform*gunPos
I've given the explicit formulas because knowing how the bare arithmetic works is useful to the conceptual understanding.
Response to edit:
In the code you edited into your question, you are adding what I assume is the ship position into the coordinates you multiply by sin/cos. Don't do that — just multiply the offset of the gun position from the ship center by sin/cos and only then add that to the ship position. Also, you are using x x; y y on the two lines, where you should be using x y; x y. Here is your code edited to fix those two things:
_bullet.x = this.x + Math.cos( StaticMath.ToRad(this.rotation)) * (-10) - Math.sin( StaticMath.ToRad(this.rotation)) * (+15);
_bullet.y = this.y + Math.sin( StaticMath.ToRad(this.rotation)) * (-10) + Math.cos( StaticMath.ToRad(this.rotation)) * (+15);
This is the code for a gun at offset (-10, 15).
is there some good and better way to find centroid of contour in opencv, without using built in functions?
While Sonaten's answer is perfectly correct, there is a simple way to do it: Use the dedicated opencv function for that: moments()
http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=moments#moments
It does not only returns the centroid, but some more statistics about your shape. And you can send it a contour or a raster shape (binary image), whatever best fits your need.
EDIT
example (modified) from "Learning OpenCV", by gary bradsky
CvMoments moments;
double M00, M01, M10;
cvMoments(contour,&moments);
M00 = cvGetSpatialMoment(&moments,0,0);
M10 = cvGetSpatialMoment(&moments,1,0);
M01 = cvGetSpatialMoment(&moments,0,1);
centers[i].x = (int)(M10/M00);
centers[i].y = (int)(M01/M00);
What you get in your current piece of code is of course the centroid of your bounding box.
"If you have a bunch of points(2d vectors), you should be able to get the centroid by averaging those points: create a point to add all the other points' positions into and then divide the components of that point with accumulated positions by the total number of points." - George Profenza mentions
This is indeed the right approach for the exact centroid of any given object in two-dimentionalspace.
On wikipedia we have some general forms for finding the centroid of an object.
http://en.wikipedia.org/wiki/Centroid
Personally, I would ask myself what I needed from this program. Do I want a thorough but performance heavy operation, or do I want to make some approximations? I might even be able to find an OpenCV function that deals with this correct and efficiently.
Don't have a working example, so I'm writing this in pseudocode on a simple 5 pixel example on a thorough method.
x_centroid = (pixel1_x + pixel2_x + pixel3_x + pixel4_x +pixel5_x)/5
y_centroid = (pixel1_y + pixel2_y + pixel3_y + pixel4_y +pixel5_y)/5
centroidPoint(x_centroid, y_centroid)
Looped for x pixels
Loop j times *sample (for (int i=0, i < j, i++))*
{
x_centroid = pixel[j]_x + x_centroid
y_centroid = pixel[j]_x + x_centroid
}
x_centroid = x_centroid/j
y_centroid = y_centroid/j
centroidPoint(x_centroid, y_centroid)
Essentially, you have the vector contours of the type
vector<vector<point>>
in OpenCV 2.3. I believe you have something similar in earlier versions, and you should be able to go through each blob on your picture with the first index of this "double vector", and go through each pixel in the inner vector.
Here is a link to documentation on the contour function
http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contours#cv.DrawContours
note: you've tagged your question as c++ visual. I'd suggest that you use the c++ syntax in OpenCV 2.3 instead of c. The first and good reason to use 2.3 is that it is more class based, which in this case means that the class Mat (instead of IplImage) does leak memory. One does not have to write destroy commands all the live long day :)
I hope this shed some light on your problem. Enjoy.
I've used Joseph O'Rourke excellent polygon centroid algorithm to great success.
See http://maven.smith.edu/~orourke/Code/centroid.c
Essentially:
For each point in the contour, find the triangle area from the current index polygon xy to the next 2 polygon xy points e.g.: Math.Abs(((X1 - X0) * (Y2 - Y0) - (X2 - X0) * (Y1 - Y0)) / 2)
Add this triangle area to a list TriAreas
Sum the triangle area, and store in SumT
Find the centroid CTx and CTy from this current triangle: CTx = (X0 + X1 + X2) / 3 and CTy = (Y0 + Y1 + Y2) / 3;
Store these 2 centroid values in 2 other lists CTxs CTys.
Finally after performing this with all points in the contour, find the contours centroid x and y using the 2 triangle x and y lists in 5 which is a weighted sum of signed triangle areas, weighted by the centroid of each triangle:
for (Int32 Index = 0; Index < CTxs.Count; Index++)
{
CentroidPointRet.X += CTxs[Index] * (TriAreas[Index] / SumT);
}
// now find centroid Y value
for (Int32 Index = 0; Index < CTys.Count; Index++)
{
CentroidPointRet.Y += CTys[Index] * (TriAreas[Index] / SumT);
}
I am trying to figure out the correct trig. eq./function to determine the following:
The Angle-change (in DEGREES) between two DIRECTION VECTORS(already determined), that represent two line-segment.
This is used in the context of SHAPE RECOGTNITION (hand drawn by user on screen).
SO basically,
a) if the user draws a (rough) shape, such as a circle, or oval, or rectangle etc - the lines that makes up that shape are broken down in to say.. 20 points(x-y pairs).
b) I have the DirectionVector for each of these LINE SEGMENTS.
c) So the BEGINNING of a LINE SEGMENT(x0,y0), will the END points of the previous line(so as to form a closed shape like a rectangle, let's say).
SO, my question is , given the context(i.e. determinign the type of a polygon), how does one find the angle-change between two DIRECTION VECTORS(available as two floating point values for x and y) ???
I have seen so many different trig. equations and I'm seeking clarity on this.
Thanks so much in advance folks!
If (x1,y1) is the first direction vector and (x2,y2) is the second one, it holds:
cos( alpha ) = (x1 * x2 + y1 * y2) / ( sqrt(x1*x1 + y1*y1) * sqrt(x2*x2 + y2*y2) )
sqrt means the square root.
Look up http://en.wikipedia.org/wiki/Dot_product
Especially the section "Geometric Representation".
You could try atan2:
float angle = atan2(previousY-currentY, previousX-currentY);
but also, as the previous answers mentioned, the
angle between two verctors = acos(first.dotProduct(second))
I guess you have the vector as three points (x_1, y_1), (x_2, y_2) and (x_3, y_3).
Then you can move the points so that (x_1, y_1) == (0, 0) by
(x_1, y_1) = (x_2, y_2) - (x_1, y_1)
(x_2, y_2) = (x_3, y_3) - (x_1, y_1)
Now you have this situation:
Think of this triangle as two right-angled triangles. The first one has the angle alpha and a part of beta, the second right-angled triangle has the other part of beta.
Then you can apply:
You can calculate alpha like this:
If I understand you correctly, you may just evaluate the dot product between two vectors and take the appropriate arccos to retrieve the angle between these vectors.