Ejemplo n.º 1
0
        public void AddPolygonLine(int xi1, int yi1, int xi2, int yi2,
                                   double xv1, double yv1, double xv2, double yv2)
        {
            if (ActivePolygon == null)
            {
                ActivePolygon = new PolygonModel();
            }

            double xp1 = xi1 * Config.XIncrement + Config.XStart;
            double yp1 = yi1 * Config.YIncrement + Config.YStart;
            double xp2 = xi2 * Config.XIncrement + Config.XStart;
            double yp2 = yi2 * Config.YIncrement + Config.YStart;

            var line = new Line();

            line.Stroke          = new SolidColorBrush(Colors.Red);
            line.StrokeThickness = 3;
            line.Fill            = new SolidColorBrush(Colors.Red);
            line.X1 = xp1;
            line.Y1 = yp1;
            line.X2 = xp2;
            line.Y2 = yp2;

            ActivePolygon.Lines.Add(new LineModel
            {
                StartPoint = new Vector {
                    X = xv1, Y = yv1, Alternates = new CanvasPoint {
                        DotIndexLeft = xi1, DotIndexTop = yi1
                    }
                },
                EndPoint = new Vector {
                    X = xv2, Y = yv2, Alternates = new CanvasPoint {
                        DotIndexLeft = xi2, DotIndexTop = yi2
                    }
                }
            });

            var cc = new CanvasComponent();

            cc.AddUiElement(line);

            line.Tag = ActivePolygon.Lines[ActivePolygon.Lines.Count - 1];

            polygonLinesInProgress.Add(cc);

            GetInputLayer().AddComponent(cc);

            // if we're at least completing a triangle...
            if (ActivePolygon.Lines.Count > 2)
            {
                // if endpoint of current line matches start point of first line, we're connecting
                // back to start of polygon
                if (GeomMath.AlmostEqual(new Vector {
                    X = xv2, Y = yv2
                }, ActivePolygon.Lines[0].StartPoint))
                {
                    CompletePolygon();
                }
            }
        }
Ejemplo n.º 2
0
        private bool turn_left(Vector p1, Vector p2, Vector p3)
        {
            var v1 = GeomMath.Subtract(p2, p1);
            var v2 = GeomMath.Subtract(p3, p2);

            return((v1.X * v2.Y - v2.X * v1.Y) > 0);
        }
Ejemplo n.º 3
0
        public int GrahamSort(Vector v1, Vector v2)
        {
            if (v1 == v2 || (v1.X == v2.X && v1.Y == v2.Y))
            {
                return(0);
            }

            LowestPoint = FindLowestPoint();

            double thetaA = Math.Atan2(v1.Y - LowestPoint.Y, v1.X - LowestPoint.X);
            double thetaB = Math.Atan2(v2.Y - LowestPoint.Y, v2.X - LowestPoint.X);

            if (thetaA < thetaB)
            {
                return(-1);
            }
            else if (thetaA > thetaB)
            {
                return(1);
            }

            double distanceA = GeomMath.Distance(LowestPoint, v1);
            double distanceB = GeomMath.Distance(LowestPoint, v2);

            if (distanceA < distanceB)
            {
                return(-1);
            }
            else
            {
                return(1);
            }
        }
Ejemplo n.º 4
0
        private void LineTo(Vector p)
        {
            //Console.WriteLine("LineTo: " + p);

            if (IntersectingPolygon == null)
            {
                IntersectingPolygon = new PolygonModel();
            }

            if (!GeomMath.AlmostEqual(currentStartPoint, p))
            {
                IntersectingPolygon.Lines.Add(new LineModel {
                    StartPoint = new Vector {
                        X = currentStartPoint.X, Y = currentStartPoint.Y
                    },
                    EndPoint = new Vector {
                        X = p.X, Y = p.Y
                    }
                });
                currentStartPoint = new Vector {
                    X = p.X, Y = p.Y
                };
                //currentStartPoint = p; // point becomes start of next line
            }
        }
Ejemplo n.º 5
0
        public bool AlmostEqual(DelaunayTriangle t2)
        {
            bool side1 = GeomMath.AlmostEqual(V1, t2.V1) || GeomMath.AlmostEqual(V1, t2.V2) || GeomMath.AlmostEqual(V1, t2.V3);
            bool side2 = GeomMath.AlmostEqual(V2, t2.V1) || GeomMath.AlmostEqual(V2, t2.V2) || GeomMath.AlmostEqual(V2, t2.V3);
            bool side3 = GeomMath.AlmostEqual(V3, t2.V1) || GeomMath.AlmostEqual(V3, t2.V2) || GeomMath.AlmostEqual(V3, t2.V3);

            return(side1 && side2 && side3);
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        private bool AllPointsCollinear()
        {
            if (InputPoints.Count <= 2)
            {
                return(true);
            }

            Vector p1 = InputPoints[0];
            Vector p2 = InputPoints[1];

            for (int i = 2; i < InputPoints.Count; i++)
            {
                Vector p3 = InputPoints[i];

                if (GeomMath.GetTurnDirection(p1, p2, p3) != GeomMath.DIRECTION_NONE)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        public int VectorCompare(Vector v1, Vector v2)
        {
            if (v1 == v2 || (v1.X == v2.X && v1.Y == v2.Y))
            {
                return(0);
            }

            double thetaA = Math.Atan2(v1.Y - LowestPoint.Y, v1.X - LowestPoint.X);
            double thetaB = Math.Atan2(v2.Y - LowestPoint.Y, v2.X - LowestPoint.X);

            // Angle of difference vector v1 and LowestPoint, and the x-axis
            // If v1 has the smaller angle, return -1
            if (thetaA < thetaB)
            {
                return(-1);
            }
            // If v2 has the smaller angle, return 1
            else if (thetaA > thetaB)
            {
                return(1);
            }

            // If angles are the same, then choose the point that is closer to LowestPoint

            double distanceA = GeomMath.Distance(LowestPoint, v1);
            double distanceB = GeomMath.Distance(LowestPoint, v2);

            if (distanceA < distanceB)
            {
                return(-1);
            }
            else
            {
                return(1);
            }
        }
Ejemplo n.º 10
0
        public bool IsPolygonConvex()
        {
            if (InputPolygon == null || InputPolygon.Lines.Count < 3)
            {
                return(false);
            }

            if (InputPolygon.Lines.Count == 3)
            {
                return(true);
            }

            int  lastSign    = Math.Sign(0);
            bool hasLastSign = false;

            for (int i = 0; i < InputPolygon.Lines.Count; i++)
            {
                Vector v1 = GetPoint(i, 0);
                Vector v2 = GetPoint(i, 1);
                Vector v3 = GetPoint(i, 2);

                double cp = GeomMath.CrossProduct(v1, v2, v3);

                int sign = Math.Sign(cp);

                if (hasLastSign && sign != lastSign)
                {
                    return(false);
                }

                hasLastSign = true;
                lastSign    = sign;
            }

            return(true);
        }
Ejemplo n.º 11
0
 public bool HasVertex(Vector v)
 {
     return(GeomMath.AlmostEqual(V1, v) || GeomMath.AlmostEqual(V2, v) || GeomMath.AlmostEqual(V3, v));
 }
Ejemplo n.º 12
0
        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"
                });
            }
        }
Ejemplo n.º 13
0
        public override void Run()
        {
            // Algorithm Setup: save input points
            var layer = History.CreateAndAddNewLayer("Setup (sorting input)");

            layer.AddCommand(new UpdatePointSetCommand
            {
                Label  = "Input",
                Points = AlgorithmUtil.CopyVectorList(InputPoints)
            });
            layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_SORT_START, SECTION_SORT));

            SortedInput = new List <Vector>();

            // algorithm step 1: sort, saved sorted input points

            foreach (var v in InputPoints)
            {
                SortedInput.Add(new Vector {
                    X = v.X, Y = v.Y, Alternates = v.Alternates
                });
            }

            SortedInput.Sort(GrahamSort);

            layer.AddCommand(new UpdatePointSetCommand
            {
                Label  = "Sorted Input",
                Points = AlgorithmUtil.CopyVectorList(SortedInput)
            });

            // check degenerate case #1: 0,1,2 points
            layer = History.CreateAndAddNewLayer("Degenerate Case Checks");

            if (SortedInput.Count <= 2)
            {
                layer.AddCommand(new AddTextStatusCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Algorithm cannot execute, it requires at least 3 points"
                });
                layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_DEGENERATE));
                return;
            }

            // check degenerate case #2: all points on same line
            if (AllPointsCollinear())
            {
                layer.AddCommand(new AddTextStatusCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Algorithm cannot execute if all points are collinear"
                });
                layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_DEGENERATE));
                return;
            }

            // points cannot be collinear, points must be at least 3

            Stack <Vector> grahamStack = new Stack <Vector>();

            grahamStack.Push(SortedInput[0]);
            grahamStack.Push(SortedInput[1]);

            // starting points: first two sorted points, pushed onto stack

            // STATIC LAYER: "Starting Points", has only input points
            // layer commentary: if 0, 1 or 2 points, cannot perform graham scan
            //                   if all points on same line, cannot perform graham scan

            layer = History.CreateAndAddNewLayer("Initiailzation");
            layer.AddCommand(new AlgorithmStartingCommand {
                AssociatedAlgorithm = this
            });
            layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_PRE));
            var hip = new HighlightPointsCommand
            {
                AssociatedAlgorithm = this,
                HighlightLevel      = 1
            };

            hip.Points.Add(new Vector {
                X = SortedInput[0].X, Y = SortedInput[0].Y
            });
            hip.Points.Add(new Vector {
                X = SortedInput[1].X, Y = SortedInput[1].Y
            });

            layer.AddCommand(hip);

            layer.AddCommand(new VectorProcessingStackUpdatedCommand
            {
                AssociatedAlgorithm = this,
                ProcessingStack     = AlgorithmUtil.CopyVectorStack(grahamStack),
                Comments            = "Initial stack"
            });
            AddStackLinesToLayer(layer, grahamStack);

            for (int i = 2; i < SortedInput.Count; i++)
            {
                layer = History.CreateAndAddNewLayer("Processing Point, index=" + i);

                layer.AddCommand(new AlgorithmStepStartingCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Step Starting"
                });

                layer.AddCommand(new ClearPointHighlightsCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = ""
                });

                layer.AddCommand(new ClearTextStatusCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = ""
                });

                // NORMAL LAYER: "Algorithm Layer (i-2)"
                // Commentary: "We examine the next point in sorted order with the top two
                //              elements from the stack status structure, popping the first one"
                // stack visualization: highlight top of stack, label it "tail"
                // standalone visualization: show SortedInput[i] as "head"
                //                           show popped element as "middle"
                // highlight the "head" point in yellow, and the "middle" / "tail" points in green
                // layer commentary:

                // loop iteration "i"
                Vector head   = SortedInput[i];
                Vector middle = grahamStack.Pop();
                Vector tail   = grahamStack.Peek();

                layer.AddCommand(new HighlightInputPointCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Next input point",
                    X = head.X,
                    Y = head.Y,
                    HightlightLevel = 1
                });

                hip = new HighlightPointsCommand
                {
                    AssociatedAlgorithm = this,
                    HighlightLevel      = 1
                };

                hip.Points.Add(new Vector {
                    X = head.X, Y = head.Y
                });
                hip.Points.Add(new Vector {
                    X = middle.X, Y = middle.Y
                });
                hip.Points.Add(new Vector {
                    X = tail.X, Y = tail.Y
                });
                layer.AddCommand(hip);

                layer.AddCommand(new HighlightInputPointCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Freshly popped from top of stack",
                    X = middle.X,
                    Y = middle.Y,
                    HightlightLevel = 2
                });

                layer.AddCommand(new HighlightInputPointCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Top of stack, which is left on stack and peeked",
                    X = tail.X,
                    Y = tail.Y,
                    HightlightLevel = 2
                });

                // we examine next point in sorted list, with top element of stack (which we pop)
                // and 2nd element of stack (which we leave as new top of stack)

                // Commentary: "The turn direction of these three points is calculated using
                //              the cross product of these three points"
                int turn = GeomMath.GetTurnDirection(tail, middle, head);

                // determine "turn" of these 3 points, in sequence tail / middle / head
                string turnString = "Counter-clockwise";
                if (turn == GeomMath.DIRECTION_CLOCKWISE)
                {
                    turnString = "Clockwise";
                }
                else if (turn == GeomMath.DIRECTION_NONE)
                {
                    turnString = "None";
                }

                layer.AddCommand(new AddTextStatusCommand
                {
                    AssociatedAlgorithm = this,
                    Comments            = "Computed turn: " + turnString
                });

                // Standalone visualization: "The turn direction for these three points is: "
                switch (turn)
                {
                case GeomMath.DIRECTION_COUNTERCLOCKWISE:
                    layer.AddCommand(new AddTextStatusCommand
                    {
                        AssociatedAlgorithm = this,
                        Comments            = "The point popped is pushed back onto stack since it is part of the hull"
                    });
                    layer.AddCommand(new AddTextStatusCommand
                    {
                        AssociatedAlgorithm = this,
                        Comments            = "The input point is also pushed since it is potentially part of the hull"
                    });
                    layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_COUNTERCLOCKWISE));

                    grahamStack.Push(middle);
                    grahamStack.Push(head);

                    layer.AddCommand(new VectorProcessingStackUpdatedCommand
                    {
                        AssociatedAlgorithm = this,
                        ProcessingStack     = AlgorithmUtil.CopyVectorStack(grahamStack),
                        Comments            = "Updated processing stack"
                    });
                    break;

                case GeomMath.DIRECTION_CLOCKWISE:
                    layer.AddCommand(new AddTextStatusCommand
                    {
                        AssociatedAlgorithm = this,
                        Comments            = "The point on the top of the stack is discarded, but the input point is preserved for re-consideration"
                    });
                    layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_CLOCKWISE));
                    i--;
                    break;

                case GeomMath.DIRECTION_NONE:
                    layer.AddCommand(new AddTextStatusCommand
                    {
                        AssociatedAlgorithm = this,
                        Comments            = "Input point is co-linear with other points, so it is part of the hull"
                    });
                    layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_NONE));

                    grahamStack.Push(head);

                    layer.AddCommand(new VectorProcessingStackUpdatedCommand
                    {
                        AssociatedAlgorithm = this,
                        ProcessingStack     = AlgorithmUtil.CopyVectorStack(grahamStack),
                        Comments            = "Updated processing stack"
                    });
                    break;
                }

                AddStackLinesToLayer(layer, grahamStack);
            }

            layer = History.CreateAndAddNewLayer("Final Results");
            layer.AddCommand(new AlgorithmCompleteCommand {
                AssociatedAlgorithm = this
            });
            layer.AddCommand(new ClearPointHighlightsCommand
            {
                AssociatedAlgorithm = this,
                Comments            = ""
            });

            layer.AddCommand(new ClearTextStatusCommand
            {
                AssociatedAlgorithm = this,
                Comments            = ""
            });
            layer.AddCommand(new HighlightLiveCodeSectionsCommand(AlgorithmId, SECTION_POST));

            grahamStack.Push(SortedInput[0]);

            layer.AddCommand(new VectorProcessingStackUpdatedCommand
            {
                AssociatedAlgorithm = this,
                ProcessingStack     = AlgorithmUtil.CopyVectorStack(grahamStack),
                Comments            = "Final stack, first input point is pushed to complete the hull"
            });
            AddStackLinesToLayer(layer, grahamStack);

            Hull = new PolygonModel();

            var a = grahamStack.ToArray <Vector>();

            for (int i = 0; i < a.Length - 1; i++)
            {
                var ap  = a[i].Alternates;
                var ap2 = a[i + 1].Alternates;

                if (ap != null && ap2 != null)
                {
                    // Main operation
                    Hull.Lines.Add(new LineModel
                    {
                        StartPoint = new Vector {
                            X          = a[i].X,
                            Y          = a[i].Y,
                            Alternates = new CanvasPoint {
                                DotIndexLeft = ap.DotIndexLeft, DotIndexTop = ap.DotIndexTop
                            }
                        },
                        EndPoint = new Vector
                        {
                            X          = a[i + 1].X,
                            Y          = a[i + 1].Y,
                            Alternates = new CanvasPoint {
                                DotIndexLeft = ap2.DotIndexLeft, DotIndexTop = ap2.DotIndexTop
                            }
                        }
                    });
                }
                else
                {
                    // Side operation that doesn't involve points from grid
                    Hull.Lines.Add(new LineModel
                    {
                        StartPoint = new Vector {
                            X = a[i].X, Y = a[i].Y
                        },
                        EndPoint = new Vector
                        {
                            X = a[i + 1].X, Y = a[i + 1].Y
                        }
                    });
                }
            }
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
 public bool AlmostEquals(DelaunayEdge de)
 {
     return((GeomMath.AlmostEqual(VStart, de.VStart) && GeomMath.AlmostEqual(VEnd, de.VEnd)) ||
            (GeomMath.AlmostEqual(VStart, de.VEnd) && GeomMath.AlmostEqual(VEnd, de.VStart)));
 }