hello all,
I am writing a code with a bunch of circles and lines intersecting and I would like to draw the arcs based on the points of intersection.
I isolated some parts of the code to illustrate my problem. (this is why the code may look overcomplicated for my exemple)
all I am lookin for is a predictable way to draw the arcs from a point A to B clockwise.
for my exemple , I have to add TWO_PI when one an angle the line is under the circle center aka the angle<PI in this case. but this is not working of every situation I have, and I can not study every situation. what am I missing ?
if ( d<0) {
arc(Circle2.center.x, Circle2.center.y, 500, 500, Angle1, TAU+Angle2);
}
this should be easy but it is driving me crazy!
any suggestion ?
the code is a circle class and line class and a bunch of intersection detection function, between two circles and between a line and a circle.
import java.util.Arrays;
import java.util.Comparator;
import processing.pdf.*;
Line Line;
Circle Circle1, Circle2;
boolean show= true;
void setup() {
size(800, 800);
smooth();
strokeWeight(1);
}
void draw() {
background(#2D4D83);
/// one line and two circles
Line = new Line(0, mouseY, width, mouseY);
Circle1 = new Circle(300, 400, 500);
Circle2 = new Circle(500, 400, 500);
Line.show();
/// intersection points
PVector C1L=intersectLC(Circle1, Line, 0, 1);
PVector C2L=intersectLC(Circle2, Line, 0, 0);
PVector C1C2=intersectCC(Circle1.center, Circle2.center, 500, 500, 1, 0);
//////////////////////////////////////////
///// drawing the arcs
//////////////////////////////////////////
if (C1L!=null && C2L !=null && C1C2 != null) {
float Angle1 = atan2(C2L.y-Circle2.center.y, C2L.x-Circle2.center.x);
float Angle2 = atan2(C1C2.y-Circle2.center.y, C1C2.x-Circle2.center.x);
//println(Angle1+" "+Angle2);
pushStyle();
strokeWeight(4);
stroke(#FFA805);
noFill();
arc(Circle2.center.x, Circle2.center.y, 500, 500, Angle1, Angle2);
// is the line above or under the circles center
float d= Circle1.center.y - C2L.y ;
//// uncomment to make it work correctly
// if ( d<0) {
//arc(Circle2.center.x, Circle2.center.y, 500, 500, Angle1, TAU+Angle2);
//}
float Angle3 = atan2(C1C2.y-Circle1.center.y, C1C2.x-Circle1.center.x);
float Angle4 = atan2(C1L.y-Circle1.center.y, C1L.x-Circle1.center.x);
arc(Circle1.center.x, Circle1.center.y, 500, 500, Angle3, Angle4);
popStyle();
pushStyle();
noStroke();
fill(255, 0, 0);
circle(C1L.x, C1L.y, 10);
circle(C2L.x, C2L.y, 10);
circle(C1C2.x, C1C2.y, 10);
circle(Circle1.center.x, Circle1.center.y, 10);
circle(Circle2.center.x, Circle2.center.y, 10);
popStyle();
pushStyle();
noStroke();
fill(255);
text("C1L",C1L.x-10, C1L.y-10);
text("C2L",C2L.x-10, C2L.y-10);
text("C1C2",C1C2.x, C1C2.y-10);
text("Circle1 center",Circle1.center.x, Circle1.center.y+20);
text("Circle2 center",Circle2.center.x, Circle2.center.y+20);
popStyle();
}
}
//// coparators to sort an array of PVectors by x or y
static final Comparator<PVector> VEC_CMPX = new Comparator<PVector>() {
@ Override final int compare(final PVector a, final PVector b) {
int cmp;
return
(cmp = Float.compare(a.y, b.y)) != 0? cmp :
Float.compare(a.x, b.x);
}
};
static final Comparator<PVector> VEC_CMPY = new Comparator<PVector>() {
@ Override final int compare(final PVector a, final PVector b) {
int cmp;
return
(cmp = Float.compare(a.x, b.x)) != 0? cmp :
Float.compare(a.y, b.y);
}
};
//// class Circle
class Circle {
PVector center;
float radius; // diametre
float x, y;
Circle(float _x, float _y, float _radius) {
center = new PVector(_x, _y);
radius = _radius;
}
PVector circleCenter() {
return center;
}
float radius() {
return radius/2;
}
}
//// class Line
class Line {
float x1;
float y1;
float x2;
float y2;
public Line(float _x1, float _y1, float _x2, float _y2) {
x1 = _x1;
y1 = _y1;
x2 = _x2;
y2 = _y2;
}
PVector Start() {
PVector start = new PVector(x1, y1);
return start;
}
PVector End() {
PVector end = new PVector(x2, y2);
return end;
}
void show() {
line(x1, y1, x2, y2);
}
}
PVector intersectCC(PVector CC1, PVector CC2, float r1, float r2, int direction, int mode) {
//horizontal =0 vertical 1 min=0 max 1
PVector inter= new PVector();
pushStyle();
stroke(255);
noFill();
//if (show) {
// ellipse(CC1.x, CC1.y, r1, r1);
// ellipse(CC2.x, CC2.y, r2, r2);
//}
popStyle();
PVector[] sh1sh2 = CCinter(CC1, CC2, r1, r2);
if (sh1sh2 != null) {
PVector[] Points=new PVector[sh1sh2.length];
for (int i=0; i<sh1sh2.length; i++) {
pushStyle();
fill(255, 0, 0);
Points[i]=new PVector(sh1sh2[i].x, sh1sh2[i].y);
popStyle();
}
if (direction == 1 && mode==0) {
Arrays.sort(Points, VEC_CMPY);
inter = new PVector(Points[0].x, Points[0].y);
}
if (direction == 1 && mode==1) {
Arrays.sort(Points, VEC_CMPY.reversed());
inter = new PVector(Points[0].x, Points[0].y);
}
if (direction == 0 && mode==0) {
Arrays.sort(Points, VEC_CMPX);
inter = new PVector(Points[0].x, Points[0].y);
}
if (direction == 0 && mode==1) {
Arrays.sort(Points, VEC_CMPX.reversed());
inter = new PVector(Points[0].x, Points[0].y);
}
}
return inter;
}
void lineV(PVector A, PVector B) {
if (A != null && B!= null) {
line(A.x, A.y, B.x, B.y);
}
}
PVector[] CCinter(PVector CC1, PVector CC2, float R1, float R2) {
float x1, x2, y1, y2;
float r1=R1/2;
float r2=R2/2;
x1=CC1.x;
x2=CC2.x;
y1=CC1.y;
y2=CC2.y;
float a = x2 - x1;
float b = y2 - y1;
float ds = a*a + b*b;
float d = sqrt( ds );
if (r1 + r2 <= d)
return null;
if (d <= Math.abs( r1 - r2 ))
return null;
float t = sqrt( (d + r1 + r2) * (d + r1 - r2) * (d - r1 + r2) * (-d + r1 + r2) );
float sx1 = 0.5 * (a + (a*(r1*r1 - r2*r2) + b*t)/ds);
float sx2 = 0.5 * (a + (a*(r1*r1 - r2*r2) - b*t)/ds);
float sy1 = 0.5 * (b + (b*(r1*r1 - r2*r2) - a*t)/ds);
float sy2 = 0.5 * (b + (b*(r1*r1 - r2*r2) + a*t)/ds);
sx1 += x1;
sy1 += y1;
sx2 += x1;
sy2 += y1;
PVector Sx1= new PVector(sx1, sy1);
PVector Sx2= new PVector(sx2, sy2);
PVector[] intersect=new PVector[2];
intersect[0]=Sx1;
intersect[1]=Sx2;
if (show) {
pushStyle();
noStroke();
fill(255, 0, 0);
// ellipse(Sx1.x, Sx1.y, 10, 10);
popStyle();
}
return intersect;
}
ArrayList<PVector> intersectionsLC(Circle C, Line L) {
PVector start, end, circleCenter;
float radius;
start = new PVector(L.Start().x, L.Start().y);
end= new PVector(L.End().x, L.End().y);
circleCenter = new PVector(C.circleCenter().x, C.circleCenter().y);
radius = C.radius();
PVector d = PVector.sub(end, start);
PVector f = PVector.sub(start, circleCenter);
ArrayList<PVector> result = new ArrayList<PVector>();
float a = d.dot(d);
float b = 2 * f.dot( d );
float c = f.dot(f) - radius * radius;
float discriminant = b * b - 4 * a * c;
if ( discriminant < 0 ) {
return result;
}
discriminant = sqrt(discriminant);
float t1 = (-b - discriminant) / (2 * a);
float t2 = (-b + discriminant) / (2 * a);
if (t1 >= 0 && t1 <= 1) {
result.add(PVector.lerp(start, end, t1));
}
if (t2 >= 0 && t2 <= 1) {
result.add(PVector.lerp(start, end, t2));
}
return result;
}
PVector intersectLC(Circle C, Line L, int direction, int mode) {
//horizontal =0 vertical 1 min=0 max 1
PVector CC1=new PVector();
CC1=C.circleCenter();
float radius=C.radius();
//intersectionsLC
PVector inter= new PVector();
pushStyle();
stroke(255);
noFill();
if (show) {
ellipse(CC1.x, CC1.y, radius*2, radius*2);
}
popStyle();
ArrayList<PVector> sh1sh2 = intersectionsLC(C, L);
if (sh1sh2 != null) {
int Len = sh1sh2.size();
PVector[] Points=new PVector[Len];
if (Len == 1) {
Points[0]= new PVector(sh1sh2.get(0).x, sh1sh2.get(0).y);
inter = new PVector(Points[0].x, Points[0].y);
return inter;
}
if (Len==2) {
for (int i=0; i<Len; i++) {
pushStyle();
fill(255, 0, 0);
if (show) {
}
Points[i]=new PVector(sh1sh2.get(i).x, sh1sh2.get(i).y);
popStyle();
}
if (direction == 1 && mode==0) {
Arrays.sort(Points, VEC_CMPY);
inter = new PVector(Points[0].x, Points[0].y);
}
if (direction == 1 && mode==1) {
Arrays.sort(Points, VEC_CMPY.reversed());
inter = new PVector(Points[0].x, Points[0].y);
}
if (direction == 0 && mode==0) {
Arrays.sort(Points, VEC_CMPX);
inter = new PVector(Points[0].x, Points[0].y);
}
if (direction == 0 && mode==1) {
Arrays.sort(Points, VEC_CMPX.reversed());
inter = new PVector(Points[0].x, Points[0].y);
}
}
}
return inter;
}