}//end Solve3 public bool Solve2(double L1, double L2, cPointi target, cPointd J) { cPointi c1 = new cPointi(list.head.Point.X, list.head.Point.Y); // center of circle 1 int nsoln; // # of solns: 0,1,2,3(infinite) nsoln = TwoCircles(c1, L1, target, L2, J); return(nsoln != 0); }// end Solve2
}//end Solve public bool Solve3(double L1, double L2, double L3, cPointi target0) { cPointi target; cPointd Jk; // coords of kinked joint returned by Solve2 cPointi J1; // Joint1 on x-axis cPointi Ttarget; // translated target target = new cPointi(target0.X, target0.Y); System.Diagnostics.Debug.WriteLine("==>Solve3: links = " + L1 + ", " + L2 + ", " + L3); Jk = new cPointd(0, 0); if (Solve2(L1 + L2, L3, target, Jk)) { firstlinks++; nlinks = 2; System.Diagnostics.Debug.WriteLine("Solve3: link1=" + (L1 + L2) + ", link2=" + L3 + ", joint=\n"); LineTo_d(Jk); SetAChain(Jk, target); return(true); } else if (Solve2(L1, L2 + L3, target, Jk)) { System.Diagnostics.Debug.WriteLine("Solve3: link1= " + L1 + ", link2= " + (L2 + L3) + ", joint=\n"); nlinks = 2; LineTo_d(Jk); SetAChain(Jk, target); return(true); } else { // pin J0 to 0. // Shift so J1 is origin. //J1.x = L1; J1.y = 0; J1 = new cPointi(L1, 0); Ttarget = new cPointi(0, 0); SubVec(target, J1, Ttarget); if (Solve2(L2, L3, Ttarget, Jk)) { // Shift solution back to origin. Jk.x += L1; System.Diagnostics.Debug.WriteLine("Solve3: link1=" + L1 + ", link2= " + L2 + ", link3= " + L1 + ", joints=\n"); nlinks = 3; LineTo_i(J1); LineTo_d(Jk); SetAChain(Jk, target); cVertex VJ1 = new cVertex(list.head.Point.X + J1.X, list.head.Point.Y); list.InsertBefore(VJ1, list.head.NextVertex); return(true); } else { return(false); } } }//end Solve3
private bool diagdrawn = true; //diag-s've been drawn after triang? public cPolygoni(cVertexList list) { this.list = list; listcopy = new cVertexList(); diaglist = new cDiagonalList(); CG = new cPointd(0, 0); intCount = 0; diagdrawn = true; }
/*--------------------------------------------------------------------- * SegSegInt: Finds the point of intersection p between two closed * segments ab and cd. Returns p and a char with the following meaning: * 'e': The segments collinearly overlap, sharing a point. * 'v': An endpoint (vertex) of one segment is on the other segment, * but 'e' doesn't hold. * '1': The segments intersect properly (i.e., they share a point and * neither 'v' nor 'e' holds). * '0': The segments do not intersect (i.e., they share no points). * Note that two collinear segments that share just one point, an endpoint * of each, returns 'e' rather than 'v' as one might expect. * ---------------------------------------------------------------------*/ public char SegSegInt(cPointi a, cPointi b, cPointi c, cPointi d, cPointd p, cPointd q) { double s, t; /* The two parameters of the parametric eqns. */ double num, denom; /* Numerator and denoninator of equations. */ char code = '?'; /* Return char characterizing intersection. */ p.x = p.y = 100.0; /* For testing purposes only... */ denom = a.X * (double)(d.Y - c.Y) + b.X * (double)(c.Y - d.Y) + d.X * (double)(b.Y - a.Y) + c.X * (double)(a.Y - b.Y); /* If denom is zero, then segments are parallel: handle separately. */ if (denom == 0.0) { return(ParallelInt(a, b, c, d, p, q)); } num = a.X * (double)(d.Y - c.Y) + c.X * (double)(a.Y - d.Y) + d.X * (double)(c.Y - a.Y); if ((num == 0.0) || (num == denom)) { code = 'v'; } s = num / denom; System.Diagnostics.Debug.WriteLine("SegSegInt: num=" + num + ",denom=" + denom + ",s=" + s); num = -(a.X * (double)(c.Y - b.Y) + b.X * (double)(a.Y - c.Y) + c.X * (double)(b.Y - a.Y)); if ((num == 0.0) || (num == denom)) { code = 'v'; } t = num / denom; System.Diagnostics.Debug.WriteLine("SegSegInt: num=" + num + ",denom=" + denom + ",t=" + t); if ((0.0 < s) && (s < 1.0) && (0.0 < t) && (t < 1.0)) { code = '1'; } else if ((0.0 > s) || (s > 1.0) || (0.0 > t) || (t > 1.0)) { code = '0'; } p.x = a.X + s * (b.X - a.X); p.y = a.Y + s * (b.Y - a.Y); return(code); }
//--------------------------------------------------------------------- //TwoCircles00 assumes circle centers are (0,0) and (a2,0). //--------------------------------------------------------------------- public void TwoCircles00(double r1, double a2, double r2, cPointd p) { double r1sq, r2sq; r1sq = r1 * r1; r2sq = r2 * r2; // Return only positive-y soln in p. p.x = (a2 + (r1sq - r2sq) / a2) / 2; p.y = Math.Sqrt(r1sq - p.x * p.x); }//end TwoCircles00
public void SetAChain(cPointd Jk, cPointi target) { cPointi vaux1; cPointi vaux2; vaux1 = new cPointi(list.head.Point.X, list.head.Point.Y); vaux2 = new cPointi(target.X, target.Y); list.ClearVertexList(); list.SetVertex(vaux1.X, vaux1.Y); list.SetVertex((int)(Jk.x + .5), (int)(Jk.y + .5)); list.SetVertex(vaux2.X, vaux2.Y); }
}// end Solve2 //--------------------------------------------------------------------- //TwoCircles finds an intersection point between two circles. //General routine: no assumptions. Returns # of intersections; point in p. //--------------------------------------------------------------------- public int TwoCircles(cPointi c1, double r1, cPointi c2, double r2, cPointd p) { cPointi c; cPointd q; int nsoln = -1; // Translate so that c1={0,0}. c = new cPointi(0, 0); SubVec(c2, c1, c); q = new cPointd(0, 0); nsoln = TwoCircles0a(r1, c, r2, p);//p instead of // Translate back. p.x = p.x + c1.X; p.y = p.y + c1.Y; return(nsoln); }
/*--------------------------------------------------------------------- * Prints out the double point of intersection, and toggles in/out flag. * ---------------------------------------------------------------------*/ public cInFlag InOut(cPointd p, cInFlag inflag, int aHB, int bHA) { InsertInters(p.x, p.y); /* Update inflag. */ if (aHB > 0) { inflag.f = cInFlag.Pin; return(inflag); } else if (bHA > 0) { inflag.f = cInFlag.Qin; return(inflag); } else /* Keep status quo. */ { return(inflag); } }
}//end TwoCircles0a //--------------------------------------------------------------------- //TwoCircles0b also assumes that the 1st circle is origin-centered. //--------------------------------------------------------------------- public int TwoCircles0b(double r1, cPointi c2, double r2, cPointd p) { double a2; // center of 2nd circle when rotated to x-axis cPointd q; // one solution when c2 on x-axis double cost, sint; // sine and cosine of angle of c2 // Rotate c2 to a2 on x-axis. a2 = Math.Sqrt(Length2(c2)); cost = c2.X / a2; sint = c2.Y / a2; q = new cPointd(0, 0); TwoCircles00(r1, a2, r2, q); // Rotate back p.x = cost * q.x + -sint * q.y; p.y = sint * q.x + cost * q.y; return(2); }
//--------------------------------------------------------------------- //TwoCircles0a assumes that the first circle is centered on the origin. //Returns # of intersections: 0, 1, 2, 3 (inf); point in p. //----------------------------------------------------------------------- public int TwoCircles0a(double r1, cPointi c2, double r2, cPointd p) { double dc2; // dist to center 2 squared double rplus2, rminus2; // (r1 +/- r2)^2 double f; // fraction along c2 for nsoln=1 // Handle special cases. dc2 = Length2(c2); rplus2 = (r1 + r2) * (r1 + r2); rminus2 = (r1 - r2) * (r1 - r2); // No solution if c2 out of reach + or -. if ((dc2 > rplus2) || (dc2 < rminus2)) { return(0); } // One solution if c2 just reached. // Then solution is r1-of-the-way (f) to c2. if (dc2 == rplus2) { f = r1 / (double)(r1 + r2); p.x = f * c2.X; p.y = f * c2.Y; return(1); } if (dc2 == rminus2) { if (rminus2 == 0) { // Circles coincide. p.x = r1; p.y = 0; return(3); } f = r1 / (double)(r1 - r2); p.x = f * c2.X; p.x = f * c2.Y; return(1); } // Two intersections. int auxint = TwoCircles0b(r1, c2, r2, p); return(auxint); }//end TwoCircles0a
//************************************** public bool Solven(double x, double y) /*Is called when the user drags the last point of the link or releases it. * Corresponds to the Solven method in C*/ { double halfLength; //floor of half os total cPointi target; //point for storing the target cPointd Jk; // coords of kinked joint returned by Solve2 cPointi J1; // Joint1 on x-axis //create target target = new cPointi(x, y); //Compute Length array and # of links cVertex v0; v1 = list.head; for (i = 0; i < list.n - 1; i++) { linklen[i] = (Length(v1.Point, v1.NextVertex.Point) + .5); v1 = v1.NextVertex; } nlinks = list.n - 1; //Compute total&half Length totLength = 0; for (i = 0; i < nlinks; i++) { totLength += linklen[i]; } halfLength = totLength / 2; //Find median link if (nlinks > 2) { L1 = 0; for (m = 0; m < nlinks; m++) { if ((L1 + linklen[m]) > halfLength) { break; } L1 += linklen[m]; }//end for L2 = linklen[m]; L3 = totLength - L1 - L2; firstlinks = m; for (i = 0; i < nlinks; i++) { linklenback[i] = linklen[i]; } nlinksback = nlinks; } else if (nlinks == 2) { L1 = linklen[0]; L2 = linklen[1]; L3 = 0; } else { System.Diagnostics.Debug.WriteLine("Just one link!!!"); L1 = L2 = L3 = 0; } if ((nlinks == 3) && (nlinksback == 0)) { nlinksback = 3; } if (nlinks == 2) { Jk = new cPointd(0, 0); if (Solve2(L1, L2, target, Jk)) { System.Diagnostics.Debug.WriteLine("Solve2 for 2 links: link1= " + L1 + ", link2= " + L2 + ", joint=\n"); LineTo_d(Jk); SetAChain(Jk, target); return(true); } else { return(false); } }//end if nlinks==2 else { if (Solve3(L1, L2, L3, target)) { return(true); } else { return(false); } } }//end Solve
public void LineTo_d(cPointd p) { System.Diagnostics.Debug.WriteLine(" Line to d" + p.x + ", " + p.y); }
public void Assigndi(cPointd p, cPointi a) { p.x = a.X; p.y = a.Y; }
public char ParallelInt(cPointi a, cPointi b, cPointi c, cPointi d, cPointd p, cPointd q) { if (!a.Collinear(a, b, c)) { return('0'); } if (Between1(a, b, c) && Between1(a, b, d)) { Assigndi(p, c); Assigndi(q, d); return('e'); } if (Between1(c, d, a) && Between1(c, d, b)) { Assigndi(p, a); Assigndi(q, b); return('e'); } if (Between1(a, b, c) && Between1(c, d, b)) { Assigndi(p, c); Assigndi(q, b); return('e'); } if (Between1(a, b, c) && Between1(c, d, a)) { Assigndi(p, c); Assigndi(q, a); return('e'); } if (Between1(a, b, d) && Between1(c, d, b)) { Assigndi(p, d); Assigndi(q, b); return('e'); } if (Between1(a, b, d) && Between1(c, d, a)) { Assigndi(p, d); Assigndi(q, a); return('e'); } return('0'); /* * if ( Between1( a, b, c ) ) { * Assigndi( p, c ); * return 'e'; * } * if ( Between1( a, b, d ) ) { * Assigndi( p, d ); * return 'e'; * } * if ( Between1( c, d, a ) ) { * Assigndi( p, a ); * return 'e'; * } * if ( Between1( c, d, b ) ) { * Assigndi( p, b ); * return 'e'; * } * return '0'; */ }
/*--------------------------------------------------------------------- * Consult the book for explanations *--------------------------------------------------------------------*/ private void ConvexIntersect(cVertexList P, cVertexList Q, int n, int m) /* P has n pointCloud, Q has m pointCloud. */ { /* Initialize variables. */ a = new cVertex(); b = new cVertex(); a = P.head; b = Q.head; aa = ba = 0; Origin = new cPointi(); /* (0,0) */ inflag = new cInFlag(); FirstPoint = true; cVertex a1, b1; A = new cPointi(); B = new cPointi(); p = new cPointd(); q = new cPointd(); p0 = new cPointd(); do { /* System.Diagnostics.Debug.WriteLine("Before Advances:a="+a.v.x+","+a.v.y+ * ", b="+b.v.x+","+b.v.y+"; aa="+aa+", ba="+ba+"; inflag="+ * inflag.f); */ /* Computations of key variables. */ a1 = a.PrevVertex; b1 = b.PrevVertex; SubVec(a.Point, a1.Point, A); SubVec(b.Point, b1.Point, B); cross = Origin.TriangleSign(Origin, A, B); aHB = b1.Point.TriangleSign(b1.Point, b.Point, a.Point); bHA = a1.Point.TriangleSign(a1.Point, a.Point, b.Point); System.Diagnostics.Debug.WriteLine("cross=" + cross + ", aHB=" + aHB + ", bHA=" + bHA); /* If A & B intersect, update inflag. */ code = a1.Point.SegSegInt(a1.Point, a.Point, b1.Point, b.Point, p, q); System.Diagnostics.Debug.WriteLine("SegSegInt: code = " + code); if (code == '1' || code == 'v') { if (inflag.f == cInFlag.Unknown && FirstPoint) { aa = ba = 0; FirstPoint = false; p0.x = p.x; p0.y = p.y; InsertInters(p0.x, p0.y); } inflag = InOut(p, inflag, aHB, bHA); System.Diagnostics.Debug.WriteLine("InOut sets inflag=" + inflag.f); } /*-----Advance rules-----*/ /* Special case: A & B overlap and oppositely oriented. */ if ((code == 'e') && (Dot(A, B) < 0)) { InsertSharedSeg(p, q); return; } /* Special case: A & B parallel and separated. */ if ((cross == 0) && (aHB < 0) && (bHA < 0)) { System.Diagnostics.Debug.WriteLine("P and Q are disjoint."); return; } /* Special case: A & B collinear. */ else if ((cross == 0) && (aHB == 0) && (bHA == 0)) { /* Advance but do not output point. */ if (inflag.f == cInFlag.Pin) { b = Advance(b, "ba", inflag.f == cInFlag.Qin, b.Point); } else { a = Advance(a, "aa", inflag.f == cInFlag.Pin, a.Point); } } /* Generic cases. */ else if (cross >= 0) { if (bHA > 0) { a = Advance(a, "aa", inflag.f == cInFlag.Pin, a.Point); } else { b = Advance(b, "ba", inflag.f == cInFlag.Qin, b.Point); } } else /* if ( cross < 0 ) */ { if (aHB > 0) { b = Advance(b, "ba", inflag.f == cInFlag.Qin, b.Point); } else { a = Advance(a, "aa", inflag.f == cInFlag.Pin, a.Point); } } System.Diagnostics.Debug.WriteLine("After advances:a=(" + a.Point.X + ", " + a.Point.Y + "), b=(" + b.Point.X + ", " + b.Point.Y + "); aa=" + aa + ", ba=" + ba + "; inflag=" + inflag.f); /* Quit when both adv. indices have cycled, or one has cycled twice. */ } while (((aa < n) || (ba < m)) && (aa < 2 * n) && (ba < 2 * m)); if (!FirstPoint) /* If at least one point output, close up. */ { InsertInters(p0.x, p0.y); } /* Deal with special cases: not implemented. */ if (inflag.f == cInFlag.Unknown) { System.Diagnostics.Debug.WriteLine("The boundaries of P and Q do not cross."); intersection = false; } }
public void InsertSharedSeg(cPointd p, cPointd q) { InsertInters((int)p.x, (int)p.y); InsertInters((int)q.x, (int)q.y); }
char code = '0'; /* intersection code returned by SegSegInt*/ public cSegSeg(cVertexList list) { p = new cPointd(0, 0); this.list = list; }