/**
@file geo2d.pde
@brief This is the soul of this program, you might laugh, but it's true.\n
This file contains all of the basis functions and classes for action.pde.\n
We added one important class to this file. The triangle class.
*/
//!************************************************************************
//!**** 2D GEOMETRY CLASSES AND UTILITIES, Jarek Rossignac, REVISED MARCH 2007
//!**** ADD TRIANGLE CLASS, Sungbae Kim, Jeonggyu Lee, AUGUST 2007
//!************************************************************************
//!************************************************************************
//!**** POINTS
//!************************************************************************
/**
@brief \class pt
This class represent a point on 2 dimensional space.
*/
public class pt
{
float x=0,y=0; //!!< The default value of x and y is both 0.
pt () {}
/**
@brief A constructer with two specific parameters.
@see pt ()
@see pt (pt P)
@param px float value of x-coordinate.
@param px float value of y-coordinate.
@return pt
*/
//!! Basic constructure without any parameter.
pt (float px, float py)
{
x = px;
y = py;
};
/**
@brief A constructer with two specific parameters.
@see pt ()
@see pt (float px, float py)
@param P pt of any point.
@return pt
*/
pt (pt P)
{
x = P.x;
y = P.y;
};
// MODIFY
void setTo(float px, float py) {x = px; y = py;};
void setTo(pt P) {x = P.x; y = P.y;};
void setTo(pt P, vec v, float t) { x = P.x + v.x * t; y = P.y + v.y * t; }
void setToMouse() { x = mouseX; y = mouseY; };
void scaleBy(float f) {x*=f; y*=f;};
void scaleBy(float u, float v) {x*=u; y*=v;};
void translateBy(vec V) {x += V.x; y += V.y;};
void translateBy(float s, vec V) {x += s*V.x; y += s*V.y;};
void addScaledPt(float s, pt V) {x += s*V.x; y += s*V.y;};
void translateBy(float u, float v) {x += u; y += v;};
void translateTowards(float s, pt P) {x=s*(x-P.x)+P.x; y=s*(y-P.y)+P.y; };
void rotateBy(float a, pt P) {float dx=x-P.x, dy=y-P.y, c=cos(a), s=sin(a); x=P.x+c*dx+s*dy; y=P.y-s*dx+c*dy; };
void rotateBy(float a) {float dx=x, dy=y, c=cos(a), s=sin(a); x=c*dx+s*dy; y=-s*dx+c*dy; };
// OUTPUT POINT
pt makeClone() {return(new pt(x,y));};
pt makeTranslatedBy(vec V) {return(new pt(x + V.x, y + V.y));};
pt makeTranslatedBy(float s, vec V) {return(new pt(x + s*V.x, y + s*V.y));};
pt makeTransaltedTowards(float s, pt P) {return(new pt(x + s*(P.x-x), y + s*(P.y-y)));};
pt makeTranslatedBy(float u, float v) {return(new pt(x + u, y + v));};
pt makeRotatedBy(float a, pt P) {float dx=x-P.x, dy=y-P.y, c=cos(a), s=sin(a); return(new pt(P.x+c*dx+s*dy, P.y-s*dx+c*dy)); };
pt makeRotatedBy(float a) {float dx=x, dy=y, c=cos(a), s=sin(a); return(new pt(c*dx+s*dy, -s*dx+c*dy)); };
pt projectOnEdge(pt P, pt Q) {float a=dot(P.makeVecTo(this),P.makeVecTo(Q)), b=dot(P.makeVecTo(Q),P.makeVecTo(Q)); return(P.makeTransaltedTowards(a/b,Q)); };
// OUTPUT VEC
vec makeVecTo(pt P) {return(new vec(P.x-x,P.y-y)); };
vec makeVecToCenter () {return(new vec(x-height/2.,y-height/2.)); };
vec makeVecToCenter (pt P, pt Q) {return(new vec((P.x+Q.x)/2.0-x,(P.y+Q.y)/2.0-y)); };
vec makeVecToCenter (pt P, pt Q, pt R) {return(new vec((P.x+Q.x+R.x)/3.0-x,(P.y+Q.y+R.x)/3.0-y)); };
vec makeVecToMouse () {return(new vec(mouseX-x,mouseY-y)); };
vec makeVecToBisectProjection (pt P, pt Q) {float a=this.disTo(P), b=this.disTo(Q); return(this.makeVecTo(interpolate(P,a/(a+b),Q))); };
vec makeVecToNormalProjection (pt P, pt Q) {float a=dot(P.makeVecTo(this),P.makeVecTo(Q)), b=dot(P.makeVecTo(Q),P.makeVecTo(Q)); return(this.makeVecTo(interpolate(P,a/b,Q))); };
// OUTPUT TEST MEASURE
float disTo(pt P) {return(sqrt(sq(P.x-x)+sq(P.y-y))); };
float disToMouse() {return(sqrt(sq(x-mouseX)+sq(y-mouseY))); };
boolean isInWindow() {return(((x>0)&&(x0)&&(y0; return(l); };
boolean isInTriangle(pt A, pt B, pt C) { boolean a = this.isLeftOf(B,C); boolean b = this.isLeftOf(C,A); boolean c = this.isLeftOf(A,B); return((a&&b&&c)||(!a&&!b&&!c) );};
// DRAW , PRINT
void show() {ellipse(x, y, height/200, height/200); };
void show(float r) {ellipse(x, y, 2*r, 2*r); };
void v() {vertex(x,y);};
void write() {println("("+x+","+y+")");};
void showLabel(String s, vec D) {text(s, x+D.x,y+D.y); };
void showLabel(String s) {text(s, x+5,y+4); };
void showLabel(int i) {text(str(i), x+5,y+4); };
void showLabel(String s, float u, float v) {text(s, x+u, y+v); };
void showSegmentTo (pt P) {line(x,y,P.x,P.y); };
void showDashTo(pt P, float len)
{
vec v = new vec();
v.setTo(this, P);
float norm = v.norm();
float lenSum = 0;
v.normalize();
pt S = new pt();
pt E = new pt();
S.setTo(this);
while ( lenSum < norm )
{
E.setTo(S);
E.translateBy(len, v);
line(S.x, S.y, E.x, E.y);
E.translateBy(len*2, v);
S.setTo(E);
lenSum = lenSum + 3*len;
}
}
} // end of pt class
pt average(pt A, pt B) {return(new pt((A.x+B.x)/2.0,(A.y+B.y)/2.0)); };
/**
@brief This function calculate the average of three points A, B and C by add them then divide by 3.
@param A point A
@param B point B
@param C point C
@return pt
*/
pt average(pt A, pt B, pt C) {return(new pt((A.x+B.x+C.x)/3.0,(A.y+B.y+C.y)/3.0)); };
pt scaledAverage(pt A, pt B, pt C, float s) {return(new pt((A.x+B.x+C.x)/s,(A.y+B.y+C.y)/s)); };
pt interpolate(pt A, float s, pt B) {return(new pt(A.x+s*(B.x-A.x),A.y+s*(B.y-A.y))); };
pt mouse() {return(new pt(mouseX,mouseY));};
pt pmouse() {return(new pt(pmouseX,pmouseY));};
pt mouseInWindow() {float x=mouseX, y=mouseY; x=max(x,0); y=max(y,0); x=min(x,height); y=min(y,height); return(new pt(x,y));};
/**
@brief This is the Professor Jarek's function to calculate the center of the screen.
@return pt of center position.
*/
pt screenCenter() {return(new pt(width/2,height/2));}
/**
@brief This is the Professor Jarek's notorious function, isLeftTurn.
First we make a vector AB. Then we turn it left and dot-product vector BC.
By inspecting result of it, we know it's left-turn or not(Remember there's cosine in dot-product).
@param A point A
@param B point B
@param C point C
@see dot(vec U, vec V)
@return true if it's left-turn, false otherwise.
*/
boolean isLeftTurn(pt A, pt B, pt C) {return(dot(A.makeVecTo(B).makeTurnedLeft() , B.makeVecTo(C) )>0); };
pt s(pt A, float s, pt B) {return(new pt(A.x+s*(B.x-A.x),A.y+s*(B.y-A.y))); };
pt b(pt A, pt B, pt C, float s) {return( s(s(B,s/4.,A),0.5,s(B,s/4.,C))); }; // tucks in a vertex towards its neighbors
pt f(pt A, pt B, pt C, pt D, float s) {return( s(s(A,1.+(1.-s)/8.,B) ,0.5, s(D,1.+(1.-s)/8.,C))); }; // bulges out a mid-edge point
pt weightedSum(float a, pt A, float b, pt B) {pt P = A.makeClone(); P.scaleBy(a); P.addScaledPt(b,B); return(P);}
pt weightedSum(float a, pt A, float b, pt B, float c, pt C) {pt P = A.makeClone(); P.scaleBy(a); P.addScaledPt(b,B); P.addScaledPt(c,C); return(P);}
pt weightedSum(float a, pt A, float b, pt B, float c, pt C, float d, pt D)
{pt P = A.makeClone(); P.scaleBy(a); P.addScaledPt(b,B); P.addScaledPt(c,C); P.addScaledPt(d,D); return(P);}
boolean leftTurn(pt A, pt B, pt C) {return(C.isLeftOf(A,B));}
float trapezeArea(pt A, pt B) {return((B.x-A.x)*(B.y+A.y)/2.);}
//************************************************************************
//**** VECTORS
//************************************************************************
/**
@brief \class vec
This class represent a vector.
*/
class vec { float x=0,y=0;
vec () {};
vec (vec V) {x = V.x; y = V.y;};
vec (float px, float py) {x = px; y = py;};
// MODIFY
void setTo(float px, float py) {x = px; y = py;};
void setTo(pt P, pt Q) {x = Q.x-P.x; y = Q.y-P.y;};
void setTo(vec V) {x = V.x; y = V.y;};
void scaleBy(float f) {x*=f; y*=f;};
void scaleBy(float u, float v) {x*=u; y*=v;};
void normalize() {float n=sqrt(sq(x)+sq(y)); if (n>0.000001) {x/=n; y/=n;};};
void add(vec V) {x += V.x; y += V.y;};
void add(float s, vec V) {x += s*V.x; y += s*V.y;};
void add(float u, float v) {x += u; y += v;};
void turnLeft() {float w=x; x=-y; y=w;};
void rotateBy (float a) {float xx=x, yy=y; x=xx*cos(a)-yy*sin(a); y=xx*sin(a)+yy*cos(a); };
// OUTPUT VEC
vec makeClone() {return(new vec(x,y));};
vec makeUnit() {float n=sqrt(sq(x)+sq(y)); if (n<0.000001) n=1; return(new vec(x/n,y/n));};
vec makeScaledBy(float s) {return(new vec(x*s, y*s));};
vec makeTurnedLeft() {return(new vec(-y,x));};
vec makeOffsetVec(float s, vec V) {return(new vec(x + s*V.x, y + s*V.y));};
vec makeOffsetVec(float u, float v) {return(new vec(x + u, y + v));};
vec makeRotatedBy(float a) {return(new vec(x*cos(a)-y*sin(a),x*sin(a)+y*cos(a))); };
// OUTPUT TEST MEASURE
float norm() {return(sqrt(sq(x)+sq(y)));}
boolean isNull() {return((abs(x)+abs(y)<0.000001));}
float angle() {return(atan2(y,x)); }
// DRAW, PRINT
void write() {println("("+x+","+y+")");};
void showAt (pt P) {line(P.x,P.y,P.x+x,P.y+y); };
void showArrowAt (pt P) {line(P.x,P.y,P.x+x,P.y+y);
float n=min(this.norm()/10.,height/50.);
pt Q=P.makeTranslatedBy(this);
vec U = this.makeUnit().makeScaledBy(-n);
vec W = U.makeTurnedLeft().makeScaledBy(0.3);
beginShape(); Q.makeTranslatedBy(U).makeTranslatedBy(W).v(); Q.v(); W.scaleBy(-1); Q.makeTranslatedBy(U).makeTranslatedBy(W).v(); endShape(CLOSE); };
} // end vec class
vec average(vec A, vec B) {return(new vec((A.x+B.x)/2.0,(A.y+B.y)/2.0)); };
/**
@brief This is the Professor Jarek's dot-product function..
As we all know, in a given two vector U(x,y) and V(x,y) dot-product
can be calculate by following equation.\n
U dot V = Ux*Vx + Uy*Vy
@param U vector U
@param V vector V
@return float
*/
float dot(vec U, vec V) {return(U.x*V.x+U.y*V.y); };
vec interpolate(vec A, float s, vec B) {return(new vec(A.x+s*(B.x-A.x),A.y+s*(B.y-A.y))); };
float angle(vec U, vec V) {return(atan2(dot(U.makeTurnedLeft(),V),dot(U,V))); };
float angle(vec V) {return(atan2(V.y,V.x)); };
float mPItoPIangle(float a) { if(a>PI) return(mPItoPIangle(a-2*PI)); if(a<-PI) return(mPItoPIangle(a+2*PI)); return(a);};
float toDeg(float a) {return(a*180/PI);}
float toRad(float a) {return(a*PI/180);}
//************************************************************************
//**** FRAMES
//************************************************************************
/**
@brief \class frame
This class represent a frame.
*/
class frame {
pt O = new pt();
vec I = new vec(1,0);
vec J = new vec(0,1);
frame() {}
frame(pt pO, vec pI, vec pJ) {O.setTo(pO); I.setTo(pI); J.setTo(pJ); }
frame(pt A, pt B, pt C) {O.setTo(B); I=A.makeVecTo(C); I.normalize(); J=I.makeTurnedLeft();}
frame(pt A, pt B) {O.setTo(A); I=A.makeVecTo(B).makeUnit(); J=I.makeTurnedLeft();}
frame(pt A, vec V) {O.setTo(A); I=V.makeUnit(); J=I.makeTurnedLeft();}
frame(float x, float y) {O.setTo(x,y);}
frame(float x, float y, float a) {O.setTo(x,y); this.rotateBy(a);}
frame(float a) {this.rotateBy(a);}
frame makeClone() {return(new frame(O,I,J));}
void reset() {O.setTo(0,0); I.setTo(1,0); J.setTo(0,1); }
void setTo(frame F) {O.setTo(F.O); I.setTo(F.I); J.setTo(F.J); }
void setTo(pt pO, vec pI, vec pJ) {O.setTo(pO); I.setTo(pI); J.setTo(pJ); }
void show() {float d=height/20; O.show(); I.makeScaledBy(d).showArrowAt(O); J.makeScaledBy(d).showArrowAt(O);
}
void showLabels() {float d=height/20;
O.makeTranslatedBy(average(I,J).makeScaledBy(-d/4)).showLabel("O",-3,5);
O.makeTranslatedBy(d,I).makeTranslatedBy(-d/5.,J).showLabel("I",-3,5);
O.makeTranslatedBy(d,J).makeTranslatedBy(-d/5.,I).showLabel("J",-3,5);
}
void translateBy(vec V) {O.translateBy(V);}
void translateBy(float x, float y) {O.translateBy(x,y);}
void rotateBy(float a) {I.rotateBy(a); J.rotateBy(a); }
frame makeTranslatedBy(vec V) {frame F = this.makeClone(); F.translateBy(V); return(F);}
frame makeTranslatedBy(float x, float y) {frame F = this.makeClone(); F.translateBy(x,y); return(F); }
frame makeRotatedBy(float a) {frame F = this.makeClone(); F.rotateBy(a); return(F); }
float angle() {return(I.angle());}
} // end frame class
frame makeMidEdgeFrame(pt A, pt B) {return(new frame(average(A,B),A.makeVecTo(B)));}
frame interpolate(frame A, float s, frame B) {
frame F = A.makeClone(); F.O.translateTowards(s,B.O); F.rotateBy(s*(B.angle()-A.angle()));
return(F);
}
frame twist(frame A, float s, frame B) {
float d=A.O.disTo(B.O);
float b=mPItoPIangle(angle(A.I,B.I));
frame F = A.makeClone(); F.rotateBy(s*b);
pt M = average(A.O,B.O);
if ((abs(b)<0.000001) || (abs(b-PI)<0.000001)) F.O.translateTowards(s,B.O);
else {
float h=d/2/tan(b/2); //else print("/b");
vec W = A.O.makeVecTo(B.O); W.normalize();
vec L = W.makeTurnedLeft(); L.scaleBy(h);
M.translateBy(L); // fill(0); M.show(6);
L.scaleBy(-1); L.normalize();
if (abs(h)>=0.000001) L.scaleBy(abs(h+sq(d)/4/h)); //else print("/h");
pt N = M.makeClone(); N.translateBy(L);
F.O.rotateBy(-s*b,M);
};
return(F);
}
//************************************************************************
//**** CURVES
//************************************************************************
pt cubicBezier(pt A, pt B, pt C, pt D, float t) {return( s( s( s(A,t,B) ,t, s(B,t,C) ) ,t, s( s(B,t,C) ,t, s(C,t,D) ) ) ); }
void drawCubicBezier(pt A, pt B, pt C, pt D) { beginShape(); for (float t=0; t<=1; t+=0.02) {cubicBezier(A,B,C,D,t).v(); }; endShape(); }
float cubicBezierAngle (pt A, pt B, pt C, pt D, float t) {pt P = s(s(A,t,B),t,s(B,t,C)); pt Q = s(s(B,t,C),t,s(C,t,D)); vec V=P.makeVecTo(Q); float a=atan2(V.y,V.x); return(a);}
void drawParabolaInHat(pt A, pt B, pt C, int rec) {
if (rec==0) { B.showSegmentTo(A); B.showSegmentTo(C); }
else {
float w = (A.makeVecTo(B).norm()+C.makeVecTo(B).norm())/2;
float l = A.makeVecTo(C).norm()/2;
float t = l/(w+l);
pt L = new pt(A);
L.translateBy(t,A.makeVecTo(B));
pt R = new pt(C); R.translateBy(t,C.makeVecTo(B));
pt M = average(L,R);
drawParabolaInHat(A,L, M,rec-1); drawParabolaInHat(M,R, C,rec-1);
};
};
/**
@brief computes the center of a circumscirbing circle to triangle (A,B,C)
*/
pt circumCenter (pt A, pt B, pt C) { // computes the center of a circumscirbing circle to triangle (A,B,C)
vec AB = A.makeVecTo(B); float ab2 = dot(AB,AB);
vec AC = A.makeVecTo(C); AC.turnLeft(); float ac2 = dot(AC,AC);
float d = 2*dot(AB,AC);
AB.turnLeft();
AB.scaleBy(-ac2);
AC.scaleBy(ab2);
AB.add(AC);
AB.scaleBy(1./d);
pt X = A.makeClone();
X.translateBy(AB);
return(X);
};
void showArcThrough (pt A, pt B, pt C) {
pt O = circumCenter ( A, B, C);
float r=2.*(O.disTo(A) + O.disTo(B)+ O.disTo(C))/3.;
float a = O.makeVecTo(A).angle(); average(O,A).showLabel(str(toDeg(a)));
float c = O.makeVecTo(C).angle(); average(O,C).showLabel(str(toDeg(c)));
if(isLeftTurn(A,B,C)) arc(O.x,O.y,r,r,a,c); else arc(O.x,O.y,r,r,c,a);
}
//************************************************************************
//**** TRIANGLES
//************************************************************************
//!constant variable
float nonlinear = -1000000;
//!constant variable
float tolerence = 0.1;
/**
@brief \class intersect
This class for calculate intersection.
*/
//This class for intersection points
class intersect
{
pt logicalPt = new pt();
pt realStartPt = new pt(); // this means the start point to display
pt realEndPt = new pt(); // this means the end point to display
/**
@brief constructor
*/
intersect() { }
void reset()
{
logicalPt.setTo(-1,-1);
realStartPt.setTo(-1,-1);
realEndPt.setTo(-1,-1);
}
void setTo(intersect inter)
{
logicalPt.setTo(inter.logicalPt);
realStartPt.setTo(inter.realStartPt);
realEndPt.setTo(inter.realEndPt);
}
}
/**
@brief \class triangle
This class represent a triangle.
*/
class triangle
{
pt[] Pt = new pt[3]; // vertices
String[] Label = new String[3]; // labels of vertices
intersect[] Intersect = new intersect[2]; // intersection points with a line
int weight = 1; // weight of edges
/**
@brief constructor
*/
triangle()
{
for ( int i = 0; i < 3; i++ ) { Pt[i] = new pt(); } for ( int i = 0; i < 2; i++ ) { Intersect[i] = new intersect(); }
}
// set functions
void setPt (pt A, pt B, pt C)
{
Pt[0].setTo(A);
Pt[1].setTo(B);
Pt[2].setTo(C);
}
void setLabel (String A, String B, String C)
{
Label[0] = A; Label[1] = B; Label[2] = C;
}
void setWeight(int w) { weight = w; }
/**
@brief check whether P is on a edge of this triangle
@param P Point P
@return TRUE when P is on a edge of this triangle
*/
boolean isOnEdge(pt P)
{
for ( int i = 0; i < 3; i++ )
{
if (isOnLine(Pt[i%3], Pt[(i+1)%3], P))return true;
}
return false;
}
/**
@brief check whether P is in this triangle
@param P Point P
@return TRUE when P is in this triangle
*/
boolean isIn(pt P)
{
// from pt class
return (P.isInTriangle(Pt[0], Pt[1], Pt[2]));
}
/**
@brief display two triangles accodring to the operation such as union, intersection, difference
@param Triangle2 a triangle
@param lineColor the color of edges
@param fillColor the color to fill in triangles
@param intersectionColor the color to fill in the intersection area
@param op operation : 0 = nothing, 1 = uniion, 2 = intersection, 3 = difference(this-Triangle2)
@return none
*/
void show(triangle Triangle2, color lineColor, color fillColor, color intersectionColor, int op)
{
// fill trinagles
if ( op == 0 )
{
show(lineColor, fillColor);
Triangle2.show(lineColor, fillColor);
}
if ( op == 1 ) // union
{
show(lineColor, intersectionColor);
Triangle2.show(lineColor, intersectionColor);
}
else if ( op == 2 ) // intersection
{
show(lineColor, fillColor);
Triangle2.show(lineColor, fillColor);
showIntersection(Triangle2, intersectionColor);
}
else if ( op == 3 ) // difference
{
// to diplay difference, we use just the intersection area
show(lineColor, intersectionColor);
Triangle2.show(lineColor, fillColor);
showIntersection(Triangle2, fillColor);
}
// draw edges
for (int i = 0; i < 3; i++)
{
drawLine(Triangle2.Pt[i%3], Triangle2.Pt[(i+1)%3]);
Triangle2.drawLine(Pt[i%3], Pt[(i+1)%3]);
}
}
/**
@brief diplay the intersection area of two triangles
@param Triangle2 a triangle
@param intersectionColor the color to fill in the interection area
@return none
*/
void showIntersection(triangle Triangle2, color intersectionColor)
{
pt[] vertexPoly = new pt[6];
for ( int i = 0; i < 6; i++ )
{
vertexPoly[i] = new pt();
}
// Find out vertices of the intersection area
// vertices of the intersection area are intersection points and each vertices are in the other triangle.
int numPoly = 0;
for ( int i = 0; i < 3; i++ )
{
pt S = Triangle2.Pt[i%3];
pt E = Triangle2.Pt[(i+1)%3];
if ( isIn(S) ) { vertexPoly[numPoly].setTo(S); numPoly++; }
findIntersect( S, E );
int num = getNumOfIntersect();
for ( int k = 0; k < num; k++ )
{
vertexPoly[numPoly].setTo(Intersect[k].logicalPt);
numPoly++;
}
}
for ( int i = 0; i < 3; i++ )
{
if ( Triangle2.isIn(Pt[i]) )
{
vertexPoly[numPoly].setTo(Pt[i]);
numPoly++;
}
}
// visualize
if ( numPoly >= 3 )
{
// To keep the rotaion direction right or left, sort vertices according to cosine of angle
//
float[] dotproduct = new float[numPoly];
int[] ptIndex = new int[numPoly];
vec vec1 = new vec();
vec1.setTo(vertexPoly[0], vertexPoly[1]);
vec1.normalize();
dotproduct[0] = 1;
dotproduct[1] = 1;
ptIndex[0] = 0;
ptIndex[1] = 1;
for ( int i = 2; i < numPoly; i++ )
{
vec vec2 = new vec();
vec2.setTo(vertexPoly[0], vertexPoly[i]);
vec2.normalize();
dotproduct[i] = dot(vec1, vec2);
ptIndex[i] = i;
}
// just bubble sort
for( int i = 0; i < numPoly-1; i++ )
{
for ( int j = 0; j < numPoly-1-i; j++ )
{
if ( dotproduct[j] < dotproduct[j+1] )
{
float tempProduct = dotproduct[j];
dotproduct[j] = dotproduct[j+1];
dotproduct[j+1] = tempProduct;
int tempIndex = ptIndex[j];
ptIndex[j] = ptIndex[j+1];
ptIndex[j+1] = tempIndex;
}
}
}
// fill area
noStroke();
fill(intersectionColor);
beginShape();
for (int i=0; i 1 ) t1 = 1;
if ( t2 < 0 ) t2 = 0;
if ( t2 > 1 ) t2 = 1;
// sort
float st, et;
if ( t1 < t2 ) { st = t1; et = t2; }
else { st = t2; et = t1; }
Intersect[0].logicalPt.setTo(P, v1, st);
Intersect[1].logicalPt.setTo(P, v1, et);
return true;
}
}
return false;
}
void resetIntersect ()
{
for ( int i = 0; i < 2; i++ )
{
Intersect[i].reset();
}
}
/**
@brief This function find intersection points of PQ and this triangle.
@brief
@param P Start point of a line
@param Q End point of a line
@return none
*/
void findIntersect (pt P, pt Q)
{
resetIntersect(); // reset intersection points
// make a vector for line (PQ)
vec v1 = new vec();
v1.setTo( P, Q );
float normPQ = v1.norm();
v1.normalize(); // normalize
// find intersection points
int i = 0;
int j = 0;
float oldt = -1;
float t = -1;
for ( i = 0, j = 0; i < 3 && j < 2; i++ )
{
pt S = Pt[i%3]; // start point of edge
pt E = Pt[(i+1)%3]; // end point of edge
if(isCross(P,Q, S, E))
{
t = findPoint(P,Q,S,E);
if ( oldt != t ) // check whether this vertex has been already used.
{
int index = 0;
// arrage order of intersection points according to distance from P
if ( t < oldt && j > 0)
{
Intersect[j].setTo(Intersect[j-1]);
index = j-1;
}
else
{
index = j;
}
Intersect[index].logicalPt.setTo(P, v1, t);
// calculate boundies of the intersetions
vec v2 = new vec();
v2.setTo( S, E );
v2.normalize(); // normalize
float cosAngle = abs(dot(v1, v2.makeTurnedLeft()));
if (cosAngle < 0.000001 )
{
cosAngle = 0.0000001;
}
vec vecSI = new vec();
vecSI.setTo( S, Intersect[index].logicalPt );
vec vecEI = new vec();
vecEI.setTo( E, Intersect[index].logicalPt );
float delta = weight*0.5 / cosAngle;
float realStart = t-delta;
float realEnd = t+delta;
float edge1Norm;
float edge2Norm;
if ( dot(v1, v2) > 0 )
{
edge1Norm = vecSI.norm();
edge2Norm = vecEI.norm();
}
else
{
edge1Norm = vecEI.norm();
edge2Norm = vecSI.norm();
}
// if two lines becomes colinear, the boundary go to infinity
// so we have to force the boundary to be in an edge or a line PQ.
if ( t < edge1Norm && delta > t )
{
realStart = 0;
}
else if ( t >= edge1Norm && delta > edge1Norm )
{
realStart = t-edge1Norm;
}
if ( normPQ - t < edge2Norm && delta > normPQ - t)
{
realEnd = normPQ;
}
else if ( normPQ - t >= edge2Norm && delta > edge2Norm)
{
realEnd = t+edge2Norm;
}
Intersect[index].realStartPt.setTo(P, v1, realStart);
Intersect[index].realEndPt.setTo(P, v1, realEnd);
j++;
}
oldt = t;
}
}
}
/**
@brief This function returns the number of intersection points.
@return the number of intersection points.
*/
int getNumOfIntersect()
{
int num = 0;
for ( int i = 0; i < 2; i++ )
{
if ( Intersect[i].logicalPt.x != -1 || Intersect[i].logicalPt.y != -1 )
{
num++;
}
}
return num;
}
intersect getIntersect(int i)
{
return Intersect[i];
}
}
// end of triangle class
/**
@brief This function decide whether two of lines are crossed or not.
@see To clearly understand this function,
please refer Slide 10 of this file.
@param A Start point of line 1
@param B End point of line 1
@param P Start point of line 2
@param Q End point of line 2
@return True if two of lines are crossed, false otherwise.
*/
boolean isCross( pt A, pt B, pt P, pt Q )
{
if( ( isLeftTurn( A, B, P ) != isLeftTurn( A, B, Q ) ) && ( isLeftTurn( P, Q, A ) != isLeftTurn( P, Q, B ) ) )
{
return true;
}
else
{
return false;
}
}
/**
@brief This function calculates the distance from the pt A to the crossed point.
@see To clearly understand this function,
please refer Slide 11 of this file.
@param A Start point of line 1
@param B End point of line 1
@param P Start point of line 2
@param Q End point of line 2
@return distance from S to t in float value.
*/
float findPoint( pt A, pt B, pt P, pt Q )
{
//! First, we make a vector for line 1(AB)
vec v1 = new vec();
v1.setTo( A, B );
v1.normalize(); //! normalize
//! And then, we need another vector.. so make a vector for line 2(PQ)
vec v2 = new vec();
v2.setTo( P, Q );
v2.turnLeft(); //! turn left to find the N
v2.normalize(); //! normalize
//! We also need to make a temporary vector SQ
vec SQ = new vec();
SQ.setTo( A, Q );
//! And calculate all together using Professor Jarek's lecture.
float SQN = dot( SQ, v2 ); //! We calculate SQ.N
float TN = dot( v1, v2 ); //! And T.N
//! YAY! We got the "t" which is the distance from S.
float t = SQN/TN;
return t;
}
/**
@brief This function get the relative position of P on line AB.\n
@see To clearly understand this function,
please refer Slide 11 of this file.
@param A Point A
@param B Point B
@param P Point P
@return -1000000 to indicate nonlinear when P is out of bound.
@return the relative position of P when P in on AB
*/
float getRelativePosOnLine( pt A, pt B, pt P )
{
// using AB line equation : A + t(B-A) ( 0 <= t <= 1 )
if ( abs(B.x - A.x) < tolerence && abs(B.y - A.y) < tolerence )
{
return nonlinear;
}
float t1, t2;
// AB is pararell to y-axis
if ( abs(B.x - A.x) < tolerence)
{
if ( (P.x >= A.x && P.x <= B.x) || (P.x >= B.x && P.x <= A.x) )
{
t2 = (P.y - A.y ) / (B.y - A.y);
t1 = t2;
}
else
{
return nonlinear;
}
}
// AB is pararell to x-axis
else if ( abs(B.y-A.y) < tolerence)
{
if ( (P.y >= A.y && P.y <= B.y) || (P.y >= B.y && P.y <= A.y) )
{
t1 = (P.x - A.x ) / (B.x - A.x);
t2 = t1;
}
else
{
return nonlinear;
}
}
else
{
t1 = (P.x - A.x ) / (B.x - A.x);
t2 = (P.y - A.y ) / (B.y - A.y);
}
if ( abs(t1 - t2) < tolerence )
{
return t1;
}
else
{
// not linear
return nonlinear;
}
}
/**
@brief check whether P is on a line AB
*/
boolean isOnLine(pt A, pt B, pt P)
{
float t = getRelativePosOnLine( A, B, P );
//println("t="+t);
if ( t >= 0 && t <= 1) return true;
else return false;
}