private int FindAngles(int[] e, double[] a, Vector v, Vector n) { Vector[] u = new Vector[4]; //for (int i = 0; i < 4; i++) // u[i] = (m_chull[(e[i] + 1) % size] - m_chull[e[i]]).normalize(); int size = hull.Count; for (int i = 0; i < 4; i++) { u[i] = GeomMath.Subtract(hull[(e[i] + 1) % size], hull[e[i]]).normalize(); } int w = 0; //a[0] = fabs(v * u[0]); //a[1] = fabs(n * u[1]); if (a[1] > a[w]) { w = 1; } //larger dot product means smaller angle //a[2] = fabs(v * u[2]); if (a[2] > a[w]) { w = 2; } //a[3] = fabs(n * u[3]); if (a[3] > a[w]) { w = 3; } a[0] = Math.Abs(GeomMath.DotProduct(v, u[0])); a[1] = Math.Abs(GeomMath.DotProduct(n, u[1])); if (a[1] > a[w]) { w = 1; } a[2] = Math.Abs(GeomMath.DotProduct(v, u[2])); if (a[2] > a[w]) { w = 2; } a[3] = Math.Abs(GeomMath.DotProduct(n, u[3])); if (a[3] > a[w]) { w = 3; } return(w); }
private BoundingBox CreateBoundingBox(int[] e, Vector v, Vector n) { //box.corners[0] = m_chull[e[0]] + v * ((m_chull[e[1]] - m_chull[e[0]]) * v); //box.corners[3] = m_chull[e[0]] + v * ((m_chull[e[3]] - m_chull[e[0]]) * v); //box.corners[1] = m_chull[e[2]] + v * ((m_chull[e[1]] - m_chull[e[2]]) * v); //box.corners[2] = m_chull[e[2]] + v * ((m_chull[e[3]] - m_chull[e[2]]) * v); //box.width = fabs((m_chull[e[3]] - m_chull[e[1]]) * v); //box.height = fabs((m_chull[e[2]] - m_chull[e[0]]) * n); var box = new BoundingBox(); box.Corners[0] = GeomMath.Add(hull[e[0]], GeomMath.Multiply(v, GeomMath.DotProduct(GeomMath.Subtract(hull[e[1]], hull[e[0]]), v))); box.Corners[3] = GeomMath.Add(hull[e[0]], GeomMath.Multiply(v, GeomMath.DotProduct(GeomMath.Subtract(hull[e[3]], hull[e[0]]), v))); box.Corners[1] = GeomMath.Add(hull[e[2]], GeomMath.Multiply(v, GeomMath.DotProduct(GeomMath.Subtract(hull[e[1]], hull[e[2]]), v))); box.Corners[2] = GeomMath.Add(hull[e[2]], GeomMath.Multiply(v, GeomMath.DotProduct(GeomMath.Subtract(hull[e[3]], hull[e[2]]), v))); box.Width = Math.Abs(GeomMath.DotProduct(GeomMath.Subtract(hull[e[3]], hull[e[1]]), v)); box.Height = Math.Abs(GeomMath.DotProduct(GeomMath.Subtract(hull[e[2]], hull[e[0]]), n)); return(box); }
public void Compute() { SortPolygons(); List <Vector> P = SortedPoly1; List <Vector> Q = SortedPoly2; int n = SortedPoly1.Count; int m = SortedPoly2.Count; int a, b; int a1, b1; Vector A = new Vector(), B = new Vector(); int cross; int bHA, aHB; Vector origin = new Vector { X = 0, Y = 0 }; Vector p = new Vector(), q = new Vector(); int inFlag; int aa, ba; bool firstPoint; Vector p0 = new Vector(); int code; a = 0; b = 0; aa = 0; ba = 0; inFlag = INFLAG_UNKNOWN; firstPoint = true; activeStatusLayer = History.CreateAndAddNewLayer("Setup"); activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "The 'in' flag starts as unknown, initial vectors start at index 0" }); do { a1 = (a + n - 1) % n; b1 = (b + m - 1) % m; activeStatusLayer = History.CreateAndAddNewLayer("Main loop, a=" + a + ", b=" + b + ", a1=" + a1 + ", b1=" + b1); // SubVec(P[a], P[a1], A); A.X = P[a].X - P[a1].X; A.Y = P[a].Y - P[a1].Y; // SubVec(Q[b], Q[b1], B); B.X = Q[b].X - Q[b1].X; B.Y = Q[b].Y - Q[b1].Y; activeStatusLayer.AddCommand(new ClearTextStatusCommand { AssociatedAlgorithm = this }); AddNonIndexedLineCommand(activeStatusLayer, new Vector { X = P[a1].X, Y = P[a1].Y }, new Vector { X = P[a].X, Y = P[a].Y }); AddNonIndexedLineCommand(activeStatusLayer, new Vector { X = Q[b1].X, Y = Q[b1].Y }, new Vector { X = Q[b].X, Y = Q[b].Y }); cross = AreaSign(origin, A, B); aHB = AreaSign(Q[b1], Q[b], P[a]); bHA = AreaSign(P[a1], P[a], Q[b]); activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "cross=" + cross }); activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "aHB=" + aHB }); activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "bHA=" + bHA }); code = SegSegInt(P[a1], P[a], Q[b1], Q[b], p, q); activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Segment intersection status: " + TranslateCode(code) }); if (code == STATUS_1 || code == STATUS_V) { if (inFlag == STATUS_UNKNOWN && firstPoint) { aa = 0; ba = 0; firstPoint = false; p0.X = p.X; p0.Y = p.Y; // moveto p0 MoveTo(p0); } LineTo(p); inFlag = InOut(p, inFlag, aHB, bHA); activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Newly computed 'in' flag: " + TranslateInOut(inFlag) }); } if (code == STATUS_E && GeomMath.DotProduct(A, B) < 0) { activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Shared segement and ..." }); // print shared segment // return } if (cross == 0 && aHB < 0 && bHA < 0) { // disjoint // return activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Polygons are disjoint" }); } else if (cross == 0 && aHB == 0 && bHA == 0) { // advance but do not output point // page 262 if (inFlag == INFLAG_PIN) { // b = Advance(b, &ba, m, inflag == Qin, Q[b]); // if inFlag == Qin // always false here // lineto Q[b] ba++; b = (b + 1) % m; activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Advancing b vector but not including in output as not part of interection" }); } else { // a = Advance(a, &aa, n, inflag == Pin, P[a]); // if inFlag == Pin // always false here // lineto P[a] aa++; a = (a + 1) % n; activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Advancing a vector but not including in output as not part of interection" }); } } else if (cross >= 0) { if (bHA > 0) { // if inflag == PIN // lineto P[a] if (inFlag == INFLAG_PIN) { LineTo(P[a]); } aa++; a = (a + 1) % n; activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Advancing a vector and including in output as part of interection" }); } else { // if inflag == QIN // lineto Q[b] if (inFlag == INFLAG_QIN) { LineTo(Q[b]); } ba++; b = (b + 1) % m; activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Advancing b vector and including in output as part of interection" }); } } else { // cross < 0 if (aHB > 0) { // if inflag == QIN // lineto Q[b] if (inFlag == INFLAG_QIN) { LineTo(Q[b]); } ba++; b = (b + 1) % m; activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Advancing b vector and including in output as part of interection" }); } else { // if inflag == PIN // lineto P[a] if (inFlag == INFLAG_PIN) { LineTo(P[a]); } aa++; a = (a + 1) % n; activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Advancing a vector and including in output as part of interection" }); } } } while (((aa < n) || (ba < m)) && (aa < 2 * n) && (ba < 2 * m)); if (aa >= 2 * n) { activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Termination condition met: aa >= 2*n" }); } else if (aa >= n) { activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Termination condition met: aa >= n" }); } if (ba >= 2 * m) { activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Termination condition met: ba >= 2*m" }); } else if (ba >= m) { activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Termination condition met: ba >= m" }); } if (!firstPoint) { // close intesection, line to p0 LineTo(p0); } if (inFlag == INFLAG_UNKNOWN) { // boundaries do not cross activeStatusLayer.AddCommand(new AddTextStatusCommand { AssociatedAlgorithm = this, Comments = "Boundaries of polygons do not cross, no intersection" }); } }
public BoundingBox FindSmallestBoundingBox() { // mathtool::Vector2d v, n; // int e[4]; //vertex indices of extreme points // float a[4]; //angles // int w; //index (0~3), so that e[w] has the smallest value a[w] // int hullsize = m_chull.size(); Vector v, n = new Vector(); int[] e = new int[4]; double[] a = new double[4]; int w; //int hullsize = hull.Count; // //init extreme points // e[0] = 0; // v = (m_chull[1] - m_chull[0]).normalize(); // n.set(-v[1], v[0]); // const mathtool::Vector2d v0 = v; e[0] = 0; v = GeomMath.Subtract(hull[1], hull[0]).normalize(); n.X = -v.Y; n.Y = v.X; //Vector v0 = v; // float max_v = -FLT_MAX, min_v = FLT_MAX, max_n = -FLT_MAX; // for (int i = 2; i < hullsize; i++) // { // auto & pt = m_chull[i]; // double dv = (pt - m_chull[0]) * v; // double dn = (pt - m_chull[0]) * n; // if (dv > max_v) { max_v = dv; e[1] = i; } // if (dv < min_v) { min_v = dv; e[3] = i; } // if (dn > max_n) { max_n = dn; e[2] = i; } // } double max_v = Double.MinValue; double min_v = Double.MaxValue; double max_n = Double.MinValue; for (int i = 2; i < hull.Count; i++) { Vector pt = hull[i]; double dv = GeomMath.DotProduct(GeomMath.Subtract(pt, hull[0]), v); double dn = GeomMath.DotProduct(GeomMath.Subtract(pt, hull[0]), n); if (dv > max_v) { max_v = dv; e[1] = i; } if (dv < min_v) { min_v = dv; e[3] = i; } if (dn > max_n) { max_n = dn; e[2] = i; } } // w = findAngles(e, a, v, n); w = FindAngles(e, a, v, n); // //update extreme points // char svg_filename[256]; // for (int i = 0; i < m_chull.size(); i++) // { //#if DEBUG // cout << "box=" << box << endl; // sprintf(svg_filename, "%s%03d.svg", "DEBUG_", i); // saveSVG(svg_filename, m_chull_ply, box); // //saveSVG(svg_filename,m_ply.front(),box); //#endif // } double smallestArea = Double.MaxValue; BoundingBox smallestBox = null; for (int i = 0; i < hull.Count; i++) { // //create a box from v,n,e[4] // obb box = createOBB(e, v, n); var box = CreateBoundingBox(e, v, n); double area = box.Width * box.Height; if (smallestBox == null) { smallestBox = box; smallestArea = area; } else if (area < smallestArea) { smallestBox = box; smallestArea = area; } Console.WriteLine("Bounding Box #" + i + ": " + area); // //check if this box solve the problem // if (problem.solved(box)) break; // //update // int ne = (e[w] + 1) % hullsize; // mathtool::Vector2d nev = (m_chull[ne] - m_chull[e[w]]).normalize(); // if (w == 0 || w == 2) // { // v = nev; // n.set(-v[1], v[0]); // } // else // { // n = nev; // v.set(-n[1], n[0]); // } // e[w] = ne; // w = findAngles(e, a, v, n); int ne = (e[w] + 1) % hull.Count; Vector nev = GeomMath.Subtract(hull[ne], hull[e[w]]).normalize(); if (w == 0 || w == 2) { v = nev; n.X = -v.Y; n.Y = v.X; } else { n = nev; v.X = -n.Y; v.Y = n.X; } e[w] = ne; w = FindAngles(e, a, v, n); } return(smallestBox); }