Understanding anchoring in Hype Processing - processing

I am trying understand how anchoring works in HYPE library for Processing 3.
I built a very small example to illustrate my question. In the following code, I expected the triangles not to intercept each other:
HPath d1,d2;
void setup(){
size(600,600);
H.init(this).background(#202020);
smooth();
float u=100;
d1 = new HPath();
d1
.triangle( H.EQUILATERAL, H.TOP )
.noStroke()
.fill(#FF0000,100)
.size( 1*u )
.loc( 0, 0 )
.anchorAt(H.TOP)
;
H.add(d1);
d2 = new HPath();
d2
.triangle( H.EQUILATERAL, H.BOTTOM )
.noStroke()
.fill(#00FF00,100)
.size( 1*u )
.loc( u/2,0 )
.anchorAt(H.TOP)
;
H.add(d2);
H.drawStage();
}
Isn't size() the side of the triangle? If so, if I am setting the size to u and start drawing a new triangle at position (u/2,0), why are they overlapping?

It seems all down what you consider to be the size of triangle (ie circumscribed circle in HYPE library methinks).
HPath d1, d2;
void setup() {
size(600, 600);
H.init(this).background(#202020);
smooth();
float u = 100 * sqrt(3);
d1 = new HPath();
d1
.triangle( H.EQUILATERAL, H.TOP )
.noStroke()
.fill(#FF0000, 100)
.size( u / sqrt(3))
.anchorAt(H.TOP)
.loc( 0, 0 )
;
H.add(d1);
d2 = new HPath();
d2
.triangle( H.EQUILATERAL, H.BOTTOM )
.noStroke()
.fill(#00FF00, 100)
.size( u / sqrt(3))
.anchorAt(H.TOP)
.loc( u * 1 / 3, 0 )
;
H.add(d2);
H.drawStage();
}

Related

Incorrect behavior of image undistortion algorithm

I'm trying to create a program that receives a photograph of a surface from a certain angle and position, and generates an image of what an isometric projection of the plane would look like. For example, given a photo of a checkerboard
and information about the positioning and properties of the camera, it could reconstruct a section of the undistorted pattern
My approach has been divided into two parts. The first part is to create four rays, coming from the camera, following the four corners of its field of view. I compute where these rays intersect with the plane, to form the quadrangle of the area of the plane that the camera can see, like this:
The second part is to render an isomorphic projection of the plane with the textured quadrangle. I divide the quadrangle into two triangles, then for each pixel on the rendering, I convert the cartesian coordinates into barymetric coordinates relative to each triangle, then convert it back into cartesian coordinates relative to a corresponding triangle that consumes half of the photograph, so that I can sample a color.
(I am aware that this could be done more efficiently with OpenGL, but I would like to not use it for logistical reasons. I am also aware that the quality will be affected by lack of interpolation, that does not matter for this task.)
I am testing the program with some data, but the rendering does not occur as intended. Here is the photograph:
And here is the program output:
I believe that the problem is occurring in the quadrangle rendering, because I have graphed the projected vertices, and they appear to be correct:
I am by no means an expert in computer graphics, so I would very much appreciate if someone had any idea what would cause this problem. Here is the relevant code:
public class ImageProjector {
private static final EquationSystem ground = new EquationSystem(0, 1, 0, 0);
private double fov;
private double aspectRatio;
private vec3d position;
private double xAngle;
private double yAngle;
private double zAngle;
public ImageProjector(double fov, double aspectRatio, vec3d position, double xAngle, double yAngle, double zAngle) {
this.fov = fov;
this.aspectRatio = aspectRatio;
this.position = position;
this.xAngle = xAngle;
this.yAngle = yAngle;
this.zAngle = zAngle;
}
public vec3d[] computeVertices() {
return new vec3d[] {
computeVertex(1, 1),
computeVertex(1, -1),
computeVertex(-1, -1),
computeVertex(-1, 1)
};
}
private vec3d computeVertex(int horizCoef, int vertCoef) {
vec3d p2 = new vec3d(tan(fov / 2) * horizCoef, tan((fov / 2) / aspectRatio) * vertCoef, 1);
p2 = p2.rotateXAxis(xAngle);
p2 = p2.rotateYAxis(yAngle);
p2 = p2.rotateZAxis(zAngle);
if (p2.y > 0) {
throw new RuntimeException("sky is visible to camera: " + p2);
}
p2 = p2.plus(position);
//System.out.println("passing through " + p2);
EquationSystem line = new LineBuilder(position, p2).build();
return new vec3d(line.add(ground).solveVariables());
}
}
public class barypoint {
public barypoint(double u, double v, double w) {
this.u = u;
this.v = v;
this.w = w;
}
public final double u;
public final double v;
public final double w;
public barypoint(vec2d p, vec2d a, vec2d b, vec2d c) {
vec2d v0 = b.minus(a);
vec2d v1 = c.minus(a);
vec2d v2 = p.minus(a);
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d11 = v1.dotProduct(v1);
double d20 = v2.dotProduct(v0);
double d21 = v2.dotProduct(v1);
double denom = d00 * d11 - d01 * d01;
v = (d11 * d20 - d01 * d21) / denom;
w = (d00 * d21 - d01 * d20) / denom;
u = 1.0 - v - w;
}
public barypoint(vec2d p, Triangle triangle) {
this(p, triangle.a, triangle.b, triangle.c);
}
public vec2d toCartesian(vec2d a, vec2d b, vec2d c) {
return new vec2d(
u * a.x + v * b.x + w * c.x,
u * a.y + v * b.y + w * c.y
);
}
public vec2d toCartesian(Triangle triangle) {
return toCartesian(triangle.a, triangle.b, triangle.c);
}
}
public class ImageTransposer {
private BufferedImage source;
private BufferedImage receiver;
public ImageTransposer(BufferedImage source, BufferedImage receiver) {
this.source = source;
this.receiver = receiver;
}
public void transpose(Triangle sourceCoords, Triangle receiverCoords) {
int xMin = (int) Double.min(Double.min(receiverCoords.a.x, receiverCoords.b.x), receiverCoords.c.x);
int xMax = (int) Double.max(Double.max(receiverCoords.a.x, receiverCoords.b.x), receiverCoords.c.x);
int yMin = (int) Double.min(Double.min(receiverCoords.a.y, receiverCoords.b.y), receiverCoords.c.y);
int yMax = (int) Double.max(Double.max(receiverCoords.a.y, receiverCoords.b.y), receiverCoords.c.y);
for (int x = xMin; x <= xMax; x++) {
for (int y = yMin; y <= yMax; y++) {
vec2d p = new vec2d(x, y);
if (receiverCoords.contains(p) && p.x >= 0 && p.y >= 0 && p.x < receiver.getWidth() && y < receiver.getHeight()) {
barypoint bary = new barypoint(p, receiverCoords);
vec2d sp = bary.toCartesian(sourceCoords);
if (sp.x >= 0 && sp.y >= 0 && sp.x < source.getWidth() && sp.y < source.getHeight()) {
receiver.setRGB(x, y, source.getRGB((int) sp.x, (int) sp.y));
}
}
}
}
}
}
public class ProjectionRenderer {
private String imagePath;
private BufferedImage mat;
private vec3d[] vertices;
private vec2d pos;
private double scale;
private int width;
private int height;
public boolean error = false;
public ProjectionRenderer(String image, BufferedImage mat, vec3d[] vertices, vec3d pos, double scale, int width, int height) {
this.imagePath = image;
this.mat = mat;
this.vertices = vertices;
this.pos = new vec2d(pos.x, pos.z);
this.scale = scale;
this.width = width;
this.height = height;
}
public void run() {
try {
BufferedImage image = ImageIO.read(new File(imagePath));
vec2d[] transVerts = Arrays.stream(vertices)
.map(v -> new vec2d(v.x, v.z))
.map(v -> v.minus(pos))
.map(v -> v.multiply(scale))
.map(v -> v.plus(new vec2d(mat.getWidth() / 2, mat.getHeight() / 2)))
// this fixes the image being upside down
.map(v -> new vec2d(v.x, mat.getHeight() / 2 + (mat.getHeight() / 2 - v.y)))
.toArray(vec2d[]::new);
System.out.println(Arrays.toString(transVerts));
Triangle sourceTri1 = new Triangle(
new vec2d(0, 0),
new vec2d(image.getWidth(), 0),
new vec2d(0, image.getHeight())
);
Triangle sourceTri2 = new Triangle(
new vec2d(image.getWidth(), image.getHeight()),
new vec2d(0, image.getHeight()),
new vec2d(image.getWidth(), 0)
);
Triangle destTri1 = new Triangle(
transVerts[3],
transVerts[0],
transVerts[2]
);
Triangle destTri2 = new Triangle(
transVerts[1],
transVerts[2],
transVerts[0]
);
ImageTransposer transposer = new ImageTransposer(image, mat);
System.out.println("transposing " + sourceTri1 + " -> " + destTri1);
transposer.transpose(sourceTri1, destTri1);
System.out.println("transposing " + sourceTri2 + " -> " + destTri2);
transposer.transpose(sourceTri2, destTri2);
} catch (IOException e) {
e.printStackTrace();
error = true;
}
}
}
The reason it's not working is because your transpose function works entirely with 2D co-ordinates, therefore it cannot compensate for the image distortion resulting from 3D perspective. You have effectively implemented a 2D affine transformation. Parallel lines remain parallel, which they do not under a 3D perspective transform. If you draw a straight line between two points on your triangle, you can linearly interpolate between them by linearly interpolating the barycentric co-ordinates, and vice versa.
To take Z into account, you can keep the barycentric co-ordinate approach, but provide a Z co-ordinate for each point in sourceCoords. The trick is to interpolate between 1/Z values (which can be linearly interpolated in a perspective image) instead of interpolating Z itself. So instead of interpolating what are effectively the texture co-ordinates for each point, interpolate the texture co-ordinate divided by Z, along with inverse Z, and interpolate all of those using your barycentric system. Then divide by inverse Z before doing your texture lookup to get texture co-ordinates back.
You could do that like this (assume a b c contain an extra z co-ordinate giving distance from camera):
public vec3d toCartesianInvZ(vec3d a, vec3d b, vec3d c) {
// put some asserts in to check for z = 0 to avoid div by zero
return new vec3d(
u * a.x/a.z + v * b.x/b.z + w * c.x/c.z,
u * a.y/a.z + v * b.y/b.z + w * c.y/c.z,
u * 1/a.z + v * 1/b.z + w * 1/c.z
);
}
(You could obviously speed up/simplify this by pre-computing all those divides and storing in sourceCoords, and just doing regular barycentric interpolation in 3D)
Then after you call it in transpose, divide by inv Z to get the texture co-ords back:
vec3d spInvZ = bary.toCartesianInvZ(sourceCoords);
vec2d sp = new vec2d(spInvZ.x / spInvZ.z, spInvZ.y / spInvZ.z);
etc. The Z co-ordinate that you need is the distance of the point in 3D space from the camera position, in the direction the camera is pointing. You can compute it with a dot product if you aren't getting it some other way:
float z = point.subtract(camera_pos).dot(camera_direction);
etc

Reflect vector in 3D space

A vector should be reflected when intersecting a mesh. When applying the following formula to reflect a vector, the result is set off. I am using toxiclibs in Processing.
// Get the normal of the face that is intersected.
ReadonlyVec3D n = isect.normal;
// calculate the reflected vector b
// a is the green point in the screenshot
b = a.sub(n.scale(2 * a.dot(n)));
b = b.add(b.getNormalized());
EDIT: When taking into account to create a directional vector by subtracting the last point before the intersection with the intersection, still the reflection is off.
Vec3D id = b.sub(isect.pos);
id.normalize();
b = n.scale(2 * id.dot(n)).sub(id);
I had the question a while back and found a few helpful resources:
Paul Bourke's solution for Line-Plane intersection
Vector reflection on 3D Kingdoms
Here's the snippet I used then:
import toxi.geom.Vec3D;
Vec3D[] face = new Vec3D[3];
float ai = TWO_PI/3;//angle increment
float r = 300;//overall radius
float ro = 150;//random offset
Vec3D n;//normal
Ray r1;
void setup() {
size(500, 500, P3D);
for (int i = 0 ; i < 3; i++) face[i] = new Vec3D(cos(ai * i) * r + random(ro), random(-50, 50), sin(ai * i) * r + random(ro));
r1 = new Ray(new Vec3D(-100, -200, -300), new Vec3D(100, 200, 300));
}
void draw() {
background(255);
lights();
translate(width/2, height/2, -500);
rotateX(map(mouseY, 0, height, -PI, PI));
rotateY(map(mouseX, 0, width, -PI, PI));
//draw plane
beginShape(TRIANGLES);
for (Vec3D p : face) vertex(p.x, p.y, p.z);
endShape();
//normals
Vec3D c = new Vec3D();//centroid
for (Vec3D p : face) c.addSelf(p);
c.scaleSelf(1.0/3.0);
Vec3D cb = face[2].sub(face[1]);
Vec3D ab = face[0].sub(face[1]);
n = cb.cross(ab);//compute normal
n.normalize();
line(c.x, c.y, c.z, n.x, n.y, n.z);//draw normal
pushStyle();
//http://paulbourke.net/geometry/planeline/
//line to plane intersection u = N dot ( P3 - P1 ) / N dot (P2 - P1), P = P1 + u (P2-P1), where P1,P2 are on the line and P3 is a point on the plane
Vec3D P2SubP1 = r1.end.sub(r1.start);
Vec3D P3SubP1 = face[0].sub(r1.start);
float u = n.dot(P3SubP1) / n.dot(P2SubP1);
Vec3D P = r1.start.add(P2SubP1.scaleSelf(u));
strokeWeight(5);
point(P.x, P.y, P.z);//point of ray-plane intersection
//vector reflecting http://www.3dkingdoms.com/weekly/weekly.php?a=2
//R = 2*(V dot N)*N - V
//Vnew = -2*(V dot N)*N + V
//PVector V = PVector.sub(r1.start,r1.end);
Vec3D V = r1.start.sub(P);
Vec3D R = n.scaleSelf(2 * (V.dot(n))).sub(V);
strokeWeight(1);
stroke(0, 192, 0);
line(P.x, P.y, P.z, R.x, R.y, R.z);
stroke(192, 0, 0);
line(r1.start.x, r1.start.y, r1.start.z, P.x, P.y, P.z);
stroke(0, 0, 192);
line(P.x, P.y, P.z, r1.end.x, r1.end.y, r1.end.z);
popStyle();
}
void keyPressed() {
setup();
}//reset
class Ray {
Vec3D start = new Vec3D(), end = new Vec3D();
Ray(Vec3D s, Vec3D e) {
start = s ;
end = e;
}
}
Note that this is a basic proof of concept.
Toxiclibs may already provide Ray/Face classes.
Assuming you have the incident direction id and the normal at the point of intersection n, then the reflection rd is
rd = 2 * dot(n,id) * n - id
where all the vectors are normalized.
In your case, if b is the green point, and isect is the point of intersection then id = b - isect normalized.
So the reflection ray r (assuming it has an origin and a direction) is
r.direction = rd
r.origin = isect
You can also look at this Wikipedia article. https://en.wikipedia.org/wiki/Specular_reflection.

How to calculate the coordinates of a arrowhead based on the arrow?

I have a line that is based on two (x,y) coordinates I know. This line has a starting and an end point. Now I want to add an arrowhead at the end point of the line.
I know that the arrow is an equilateral triangle, and therefore each angle has 60 degrees. Additionally, I know the length of one side, which will be 20. I also no one edge of the triangle (that is the end point of the line).
How can I calculate the other two points of the triangle? I know I should use some trigonometry but how?
P.s. The endpoint of the line should be the arrowhead's tip.
You don't need trig., just some vector arithmetic...
Say the line goes from A to B, with the front vertex of the arrowhead at B. The length of the arrowhead is h = 10(√3) and its half-width is w = 10. We'll denote the unit vector from A to B as U = (B - A)/|B - A| (i.e., the difference divided by the length of the difference), and the unit vector perpendicular to this as V = [-Uy, Ux].
From these quantities, you can calculate the two rear vertices of the arrowhead as B - hU ± wV.
In C++:
struct vec { float x, y; /* … */ };
void arrowhead(vec A, vec B, vec& v1, vec& v2) {
float h = 10*sqrtf(3), w = 10;
vec U = (B - A)/(B - A).length();
vec V = vec(-U.y, U.x);
v1 = B - h*U + w*V;
v2 = B - h*U - w*V;
}
If you want to specify different angles, then you will need some trig. to calculate different values of h and w. Assuming you want an arrowhead of length h and tip-angle θ, then w = h tan(θ/2). In practice, however, it's simplest to specify h and w directly.
Here's a sample LINQPad program that shows how to do that:
void Main()
{
const int imageWidth = 512;
Bitmap b = new Bitmap(imageWidth , imageWidth , PixelFormat.Format24bppRgb);
Random r = new Random();
for (int index = 0; index < 10; index++)
{
Point fromPoint = new Point(0, 0);
Point toPoint = new Point(0, 0);
// Ensure we actually have a line
while (fromPoint == toPoint)
{
fromPoint = new Point(r.Next(imageWidth ), r.Next(imageWidth ));
toPoint = new Point(r.Next(imageWidth ), r.Next(imageWidth ));
}
// dx,dy = arrow line vector
var dx = toPoint.X - fromPoint.X;
var dy = toPoint.Y - fromPoint.Y;
// normalize
var length = Math.Sqrt(dx * dx + dy * dy);
var unitDx = dx / length;
var unitDy = dy / length;
// increase this to get a larger arrow head
const int arrowHeadBoxSize = 10;
var arrowPoint1 = new Point(
Convert.ToInt32(toPoint.X - unitDx * arrowHeadBoxSize - unitDy * arrowHeadBoxSize),
Convert.ToInt32(toPoint.Y - unitDy * arrowHeadBoxSize + unitDx * arrowHeadBoxSize));
var arrowPoint2 = new Point(
Convert.ToInt32(toPoint.X - unitDx * arrowHeadBoxSize + unitDy * arrowHeadBoxSize),
Convert.ToInt32(toPoint.Y - unitDy * arrowHeadBoxSize - unitDx * arrowHeadBoxSize));
using (Graphics g = Graphics.FromImage(b))
{
if (index == 0)
g.Clear(Color.White);
g.DrawLine(Pens.Black, fromPoint, toPoint);
g.DrawLine(Pens.Black, toPoint, arrowPoint1);
g.DrawLine(Pens.Black, toPoint, arrowPoint2);
}
}
using (var stream = new MemoryStream())
{
b.Save(stream, ImageFormat.Png);
Util.Image(stream.ToArray()).Dump();
}
}
Basically, you:
Calculate the vector of the arrow line
Normalize the vector, ie. making its length 1
Calculate the ends of the arrow heads by going:
First back from the head a certain distance
Then perpendicular out from the line a certain distance
Note that if you want the arrow head lines to have a different angle than 45 degrees, you'll have to use a different method.
The program above will draw 10 random arrows each time, here's an example:
Let's your line is (x0,y0)-(x1,y1)
Backward direction vector (dx, dy) = (x0-x1, y0-y1)
It's norm Norm = Sqrt(dx*dx+dy*dy)
Normalize it: (udx, udy) = (dx/Norm, dy/Norm)
Rotate by angles Pi/6 and -Pi/6
ax = udx * Sqrt(3)/2 - udy * 1/2
ay = udx * 1/2 + udy * Sqrt(3)/2
bx = udx * Sqrt(3)/2 + udy * 1/2
by = - udx * 1/2 + udy * Sqrt(3)/2
Your points: (x1 + 20 * ax, y1 + 20 * ay) and (x1 + 20 * bx, y1 + 20 * by)
I want to contribute my answer in C# based on Marcelo Cantos' answer since the algorithm works really well. I wrote a program to calculate the centroid of a laser beam projected on the CCD array. After the centroid is found, the direction angle line is drawn and I need the arrow head pointing at that direction. Since the angle is calculated, the arrow head would have to follow the angle in any of the direction.
This code gives you the flexibility of changing the arrow head size as shown in the pictures.
First you need the vector struct with all the necessary operators overloading.
private struct vec
{
public float x;
public float y;
public vec(float x, float y)
{
this.x = x;
this.y = y;
}
public static vec operator -(vec v1, vec v2)
{
return new vec(v1.x - v2.x, v1.y - v2.y);
}
public static vec operator +(vec v1, vec v2)
{
return new vec(v1.x + v2.x, v1.y + v2.y);
}
public static vec operator /(vec v1, float number)
{
return new vec(v1.x / number, v1.y / number);
}
public static vec operator *(vec v1, float number)
{
return new vec(v1.x * number, v1.y * number);
}
public static vec operator *(float number, vec v1)
{
return new vec(v1.x * number, v1.y * number);
}
public float length()
{
double distance;
distance = (this.x * this.x) + (this.y * this.y);
return (float)Math.Sqrt(distance);
}
}
Then you can use the same code given by Marcelo Cantos, but I made the length and half_width of the arrow head variables so that you can define that when calling the function.
private void arrowhead(float length, float half_width,
vec A, vec B, ref vec v1, ref vec v2)
{
float h = length * (float)Math.Sqrt(3);
float w = half_width;
vec U = (B - A) / (B - A).length();
vec V = new vec(-U.y, U.x);
v1 = B - h * U + w * V;
v2 = B - h * U - w * V;
}
Now you can call the function like this:
vec leftArrowHead = new vec();
vec rightArrowHead = new vec();
arrowhead(20, 10, new vec(circle_center_x, circle_center_y),
new vec(x_centroid_pixel, y_centroid_pixel),
ref leftArrowHead, ref rightArrowHead);
In my code, the circle center is the first vector location (arrow butt), and the centroid_pixel is the second vector location (arrow head).
I draw the arrow head by storing the vector values in the points for graphics.DrawPolygon() function in the System.Drawings. Code is shown below:
Point[] ppts = new Point[3];
ppts[0] = new Point((int)leftArrowHead.x, (int)leftArrowHead.y);
ppts[1] = new Point(x_cm_pixel,y_cm_pixel);
ppts[2] = new Point((int)rightArrowHead.x, (int)rightArrowHead.y);
g2.DrawPolygon(p, ppts);
You can find angle of line.
Vector ox = Vector(1,0);
Vector line_direction = Vector(line_begin.x - line_end.x, line_begin.y - line_end.y);
line_direction.normalize();
float angle = acos(ox.x * line_direction.x + line_direction.y * ox.y);
Then use this function to all 3 points using found angle.
Point rotate(Point point, float angle)
{
Point rotated_point;
rotated_point.x = point.x * cos(angle) - point.y * sin(angle);
rotated_point.y = point.x * sin(angle) + point.y * cos(angle);
return rotated_point;
}
Assuming that upper point of arrow's head is line's end it will perfectly rotated and fit to line.
Didn't test it =(
For anyone that is interested, #TomP was wondering about a js version, so here is a javascript version that I made. It is based off of #Patratacus and #Marcelo Cantos answers. Javascript doesn't support operator overloading, so it isn't as clean looking as C++ or other languages. Feel free to offer improvements.
I am using Class.js to create classes.
Vector = Class.extend({
NAME: "Vector",
init: function(x, y)
{
this.x = x;
this.y = y;
},
subtract: function(v1)
{
return new Vector(this.x - v1.x, this.y - v1.y);
},
add: function(v1)
{
return new Vector(this.x + v1.x, this.y + v1.y);
},
divide: function(number)
{
return new Vector(this.x / number, this.y / number);
},
multiply: function(number)
{
return new Vector(this.x * number, this.y * number);
},
length: function()
{
var distance;
distance = (this.x * this.x) + (this.y * this.y);
return Math.sqrt(distance);
}
});
And then a function to do the logic:
var getArrowhead = function(A, B)
{
var h = 10 * Math.sqrt(3);
var w = 5;
var v1 = B.subtract(A);
var length = v1.length();
var U = v1.divide(length);
var V = new Vector(-U.y, U.x);
var r1 = B.subtract(U.multiply(h)).add(V.multiply(w));
var r2 = B.subtract(U.multiply(h)).subtract(V.multiply(w));
return [r1,r2];
}
And call the function like this:
var A = new Vector(start.x,start.y);
var B = new Vector(end.x,end.y);
var vec = getArrowhead(A,B);
console.log(vec[0]);
console.log(vec[1]);
I know the OP didn't ask for any specific language, but I came across this looking for a JS implementation, so I thought I would post the result.

Rotate some elements in an ellipse path

I am trying to make some objects, say 12, to rotate in an ellipse path continuously in Processing. I got a sketch which does rotation in a circle and I want to make it to rotate in a ellipse. I have some pointer from processing forum but the code from the pointer is different from the code that I posted and I couldn't understand yet (weak in trigonometry).
I googled a bit and found a post trying to achieve this with this algorithm:
You need to define your ellipse with a few parameters:
x, y: center of the ellipse
a, b: semimajor and semiminor axes
If you want to move on the elipses this means that you change the
angle between the major axes and your position on the ellipse. Lets
call this angle alpha.
Your position (X,Y) is:
X = x + (a * Math.cos(alpha));
Y = y + (b * Math.sin(alpha));
In order to move left or right you need to increase/decrease alpha and
then recalculate your position. Source:
http://answers.unity3d.com/questions/27620/move-object-allong-an-ellipsoid-path.html
How do I integrate it into my sketch? Thank you.
Here's my sketch:
void setup()
{
size(1024, 768);
textFont(createFont("Arial", 30));
}
void draw()
{
background(0);
stroke(255);
int cx = 500;
int cy = 350;
int r = 300; //radius of the circle
float t = millis()/4000.0f; //increase to slow down the movement
ellipse(cx, cy, 5, 5);
for (int i = 1 ; i <= 12; i++) {
t = t + 100;
int x = (int)(cx + r * cos(t));
int y = (int)(cy + r * sin(t));
line(cx, cy, x, y);
textSize(30);
text(i, x, y);
if (i == 10) {
textSize(15);
text("x: " + x + " y: " + y, x - 50, y - 20);
}
}
}
Replace
int r = 300; //radius of the circle
with
int a = 350; // major axis of ellipse
int b = 250; // minor axis of ellipse
and replace
int x = (int)(cx + r * cos(t));
int y = (int)(cy + r * sin(t));
with
int x = (int)(cx + a * cos(t));
int y = (int)(cy + b * sin(t));

Circle-circle intersection points

How do I calculate the intersection points of two circles. I would expect there to be either two, one or no intersection points in all cases.
I have the x and y coordinates of the centre-point, and the radius for each circle.
An answer in python would be preferred, but any working algorithm would be acceptable.
Intersection of two circles
Written by Paul Bourke
The following note describes how to find the intersection point(s)
between two circles on a plane, the following notation is used. The
aim is to find the two points P3 = (x3,
y3) if they exist.
First calculate the distance d between the center
of the circles. d = ||P1 - P0||.
If d > r0 + r1 then there are no solutions,
the circles are separate. If d < |r0 -
r1| then there are no solutions because one circle is
contained within the other. If d = 0 and r0 =
r1 then the circles are coincident and there are an
infinite number of solutions.
Considering the two triangles P0P2P3
and P1P2P3 we can write
a2 + h2 = r02 and
b2 + h2 = r12
Using d = a + b we can solve for a, a =
(r02 - r12 +
d2 ) / (2 d)
It can be readily shown that this reduces to
r0 when the two circles touch at one point, ie: d =
r0 + r1
Solve for h by substituting a into the first
equation, h2 = r02 - a2
So P2 = P0 + a ( P1 -
P0 ) / d And finally, P3 =
(x3,y3) in terms of P0 =
(x0,y0), P1 =
(x1,y1) and P2 =
(x2,y2), is x3 =
x2 +- h ( y1 - y0 ) / d
y3 = y2 -+ h ( x1 - x0 ) /
d
Source: http://paulbourke.net/geometry/circlesphere/
Here is my C++ implementation based on Paul Bourke's article. It only works if there are two intersections, otherwise it probably returns NaN NAN NAN NAN.
class Point{
public:
float x, y;
Point(float px, float py) {
x = px;
y = py;
}
Point sub(Point p2) {
return Point(x - p2.x, y - p2.y);
}
Point add(Point p2) {
return Point(x + p2.x, y + p2.y);
}
float distance(Point p2) {
return sqrt((x - p2.x)*(x - p2.x) + (y - p2.y)*(y - p2.y));
}
Point normal() {
float length = sqrt(x*x + y*y);
return Point(x/length, y/length);
}
Point scale(float s) {
return Point(x*s, y*s);
}
};
class Circle {
public:
float x, y, r, left;
Circle(float cx, float cy, float cr) {
x = cx;
y = cy;
r = cr;
left = x - r;
}
pair<Point, Point> intersections(Circle c) {
Point P0(x, y);
Point P1(c.x, c.y);
float d, a, h;
d = P0.distance(P1);
a = (r*r - c.r*c.r + d*d)/(2*d);
h = sqrt(r*r - a*a);
Point P2 = P1.sub(P0).scale(a/d).add(P0);
float x3, y3, x4, y4;
x3 = P2.x + h*(P1.y - P0.y)/d;
y3 = P2.y - h*(P1.x - P0.x)/d;
x4 = P2.x - h*(P1.y - P0.y)/d;
y4 = P2.y + h*(P1.x - P0.x)/d;
return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
}
};
Why not just use 7 lines of your favorite procedural language (or programmable calculator!) as below.
Assuming you are given P0 coords (x0,y0), P1 coords (x1,y1), r0 and r1 and you want to find P3 coords (x3,y3):
d=sqr((x1-x0)^2 + (y1-y0)^2)
a=(r0^2-r1^2+d^2)/(2*d)
h=sqr(r0^2-a^2)
x2=x0+a*(x1-x0)/d
y2=y0+a*(y1-y0)/d
x3=x2+h*(y1-y0)/d // also x3=x2-h*(y1-y0)/d
y3=y2-h*(x1-x0)/d // also y3=y2+h*(x1-x0)/d
Here's an implementation in Javascript using vectors. The code is well documented, you should be able to follow it. Here's the original source
See live demo here:
// Let EPS (epsilon) be a small value
var EPS = 0.0000001;
// Let a point be a pair: (x, y)
function Point(x, y) {
this.x = x;
this.y = y;
}
// Define a circle centered at (x,y) with radius r
function Circle(x,y,r) {
this.x = x;
this.y = y;
this.r = r;
}
// Due to double rounding precision the value passed into the Math.acos
// function may be outside its domain of [-1, +1] which would return
// the value NaN which we do not want.
function acossafe(x) {
if (x >= +1.0) return 0;
if (x <= -1.0) return Math.PI;
return Math.acos(x);
}
// Rotates a point about a fixed point at some angle 'a'
function rotatePoint(fp, pt, a) {
var x = pt.x - fp.x;
var y = pt.y - fp.y;
var xRot = x * Math.cos(a) + y * Math.sin(a);
var yRot = y * Math.cos(a) - x * Math.sin(a);
return new Point(fp.x+xRot,fp.y+yRot);
}
// Given two circles this method finds the intersection
// point(s) of the two circles (if any exists)
function circleCircleIntersectionPoints(c1, c2) {
var r, R, d, dx, dy, cx, cy, Cx, Cy;
if (c1.r < c2.r) {
r = c1.r; R = c2.r;
cx = c1.x; cy = c1.y;
Cx = c2.x; Cy = c2.y;
} else {
r = c2.r; R = c1.r;
Cx = c1.x; Cy = c1.y;
cx = c2.x; cy = c2.y;
}
// Compute the vector <dx, dy>
dx = cx - Cx;
dy = cy - Cy;
// Find the distance between two points.
d = Math.sqrt( dx*dx + dy*dy );
// There are an infinite number of solutions
// Seems appropriate to also return null
if (d < EPS && Math.abs(R-r) < EPS) return [];
// No intersection (circles centered at the
// same place with different size)
else if (d < EPS) return [];
var x = (dx / d) * R + Cx;
var y = (dy / d) * R + Cy;
var P = new Point(x, y);
// Single intersection (kissing circles)
if (Math.abs((R+r)-d) < EPS || Math.abs(R-(r+d)) < EPS) return [P];
// No intersection. Either the small circle contained within
// big circle or circles are simply disjoint.
if ( (d+r) < R || (R+r < d) ) return [];
var C = new Point(Cx, Cy);
var angle = acossafe((r*r-d*d-R*R)/(-2.0*d*R));
var pt1 = rotatePoint(C, P, +angle);
var pt2 = rotatePoint(C, P, -angle);
return [pt1, pt2];
}
Try this;
def ri(cr1,cr2,cp1,cp2):
int1=[]
int2=[]
ori=0
if cp1[0]<cp2[0] and cp1[1]!=cp2[1]:
p1=cp1
p2=cp2
r1=cr1
r2=cr2
if cp1[1]<cp2[1]:
ori+=1
elif cp1[1]>cp2[1]:
ori+=2
elif cp1[0]>cp2[0] and cp1[1]!=cp2[1]:
p1=cp2
p2=cp1
r1=cr2
r2=cr1
if p1[1]<p2[1]:
ori+=1
elif p1[1]>p2[1]:
ori+=2
elif cp1[0]==cp2[0]:
ori+=4
if cp1[1]>cp2[1]:
p1=cp1
p2=cp2
r1=cr1
r2=cr2
elif cp1[1]<cp2[1]:
p1=cp2
p2=cp1
r1=cr2
r2=cr1
elif cp1[1]==cp2[1]:
ori+=3
if cp1[0]>cp2[0]:
p1=cp2
p2=cp1
r1=cr2
r2=cr1
elif cp1[0]<cp2[0]:
p1=cp1
p2=cp2
r1=cr1
r2=cr2
if ori==1:#+
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
thta=math.degrees(math.acos(A/r1))
rs=p2[1]-p1[1]
rn=p2[0]-p1[0]
gd=rs/rn
yint=p1[1]-((gd)*p1[0])
dty=calc_dist(p1,[0,yint])
aa=p1[1]-yint
bb=math.degrees(math.asin(aa/dty))
d=90-bb
e=180-d-thta
g=(dty/math.sin(math.radians(e)))*math.sin(math.radians(thta))
f=(g/math.sin(math.radians(thta)))*math.sin(math.radians(d))
oty=yint+g
h=f+r1
i=90-e
j=180-90-i
l=math.sin(math.radians(i))*h
k=math.cos(math.radians(i))*h
iy2=oty-l
ix2=k
int2.append(ix2)
int2.append(iy2)
m=90+bb
n=180-m-thta
p=(dty/math.sin(math.radians(n)))*math.sin(math.radians(m))
o=(p/math.sin(math.radians(m)))*math.sin(math.radians(thta))
q=p+r1
r=90-n
s=math.sin(math.radians(r))*q
t=math.cos(math.radians(r))*q
otty=yint-o
iy1=otty+s
ix1=t
int1.append(ix1)
int1.append(iy1)
elif ori==2:#-
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
thta=math.degrees(math.acos(A/r1))
rs=p2[1]-p1[1]
rn=p2[0]-p1[0]
gd=rs/rn
yint=p1[1]-((gd)*p1[0])
dty=calc_dist(p1,[0,yint])
aa=yint-p1[1]
bb=math.degrees(math.asin(aa/dty))
c=180-90-bb
d=180-c-thta
e=180-90-d
f=math.tan(math.radians(e))*p1[0]
g=math.sqrt(p1[0]**2+f**2)
h=g+r1
i=180-90-e
j=math.sin(math.radians(e))*h
jj=math.cos(math.radians(i))*h
k=math.cos(math.radians(e))*h
kk=math.sin(math.radians(i))*h
l=90-bb
m=90-e
tt=l+m+thta
n=(dty/math.sin(math.radians(m)))*math.sin(math.radians(thta))
nn=(g/math.sin(math.radians(l)))*math.sin(math.radians(thta))
oty=yint-n
iy1=oty+j
ix1=k
int1.append(ix1)
int1.append(iy1)
o=bb+90
p=180-o-thta
q=90-p
r=180-90-q
s=(dty/math.sin(math.radians(p)))*math.sin(math.radians(o))
t=(s/math.sin(math.radians(o)))*math.sin(math.radians(thta))
u=s+r1
v=math.sin(math.radians(r))*u
vv=math.cos(math.radians(q))*u
w=math.cos(math.radians(r))*u
ww=math.sin(math.radians(q))*u
ix2=v
otty=yint+t
iy2=otty-w
int2.append(ix2)
int2.append(iy2)
elif ori==3:#y
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
b=math.sqrt(r1**2-A**2)
int1.append(p1[0]+A)
int1.append(p1[1]+b)
int2.append(p1[0]+A)
int2.append(p1[1]-b)
elif ori==4:#x
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
b=math.sqrt(r1**2-A**2)
int1.append(p1[0]+b)
int1.append(p1[1]-A)
int2.append(p1[0]-b)
int2.append(p1[1]-A)
return [int1,int2]
def calc_dist(p1,p2):
return math.sqrt((p2[0] - p1[0]) ** 2 +
(p2[1] - p1[1]) ** 2)

Resources