Esempio n. 1
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
            }
        }
Esempio n. 2
0
	public void generatePolygon(int which, int nbEdges, float phase, Vector2 dimensions) {
		if (which<0||which>=polys.Length) return;
		polys[which] = new PolygonModel(nbEdges,phase,dimensions,nbVertex,1);
		updateSimpleSplines(which);
		updateCompositeSplines(which);
		updateFinalSpline();
	}
Esempio n. 3
0
        //public static

        // Layer 0: Grid points / axis
        // Layer 1: Input Layer
        // Layer 2: Input Annotation Layer
        // Layer 3: Algorithm Layer
        // Layer 4: Algorithm Annotation Layer

        public CanvasWrapper(Canvas c, CanvasConfiguration config = null)
        {
            AttachedCanvas = c;

            Layers = new List <CanvasLayer>();

            CreateNewLayer("Base Grid Layer");
            ActiveLayer = Layers[0];
            CreateNewLayer("Input Layer");
            CreateNewLayer("Input Annotation Layer");
            CreateNewLayer("Algorithm Layer");
            CreateNewLayer("Algorithm Annotation Layer");

            //Config = new CanvasConfiguration();
            Config = config;
            //Config.BuildConfiguration(-200, 200, -100, 100,
            //                          AttachedCanvas.ActualWidth, AttachedCanvas.ActualHeight,
            //                          40, 20, 5, 5);
            InputPoints   = new List <Vector>();
            InputLines    = new List <LineModel>();
            InputPolygons = new List <PolygonModel>();

            ActivePolygon = null;

            DrawGrid();
            HookEvents();
            CreateDefaultShapes();
        }
Esempio n. 4
0
 public void DrawPolygonUsingValues(PolygonModel poly)
 {
     foreach (var line in poly.Lines)
     {
         DrawLineUsingValues(line.StartPoint.X, line.StartPoint.Y, line.EndPoint.X, line.EndPoint.Y);
     }
 }
Esempio n. 5
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();
                }
            }
        }
Esempio n. 6
0
	public void generateRhombus(int which, Vector2 dimensions) {
		if (which<0||which>=polys.Length) return;
		polys[which] = new PolygonModel(4,0.0f,dimensions,nbVertex,1);
		updateSimpleSplines(which);
		updateCompositeSplines(which);
		updateFinalSpline();
	}
Esempio n. 7
0
	public void generateEllipse(int which, Vector2 dimensions) {
		if (which<0||which>=polys.Length) return;
		polys[which] = new PolygonModel(0,0,dimensions,nbVertex,0);
		updateSimpleSplines(which);
		polys[which].compositePoly=polys[which].simplePoly;
		polys[which].compositeGenerated = true;
		updateFinalSpline();
	}
Esempio n. 8
0
 private Polygon GetPolygon(PolygonModel xmlPolygon)
 {
     return(new Polygon()
     {
         Points = new PointCollection(xmlPolygon.Points),
         StrokeThickness = xmlPolygon.Stroke,
         Fill = new SolidColorBrush(xmlPolygon.Color),
         Stroke = new SolidColorBrush(Colors.Black)
     });
 }
Esempio n. 9
0
        private void CompletePolygon()
        {
            if (ActivePolygon == null || !ActivePolygon.IsClosed)
            {
                return;
            }

            InputPolygons.Add(ActivePolygon);

            polygonLinesInProgress.Clear();
            ActivePolygon = null;
        }
        private RigidBodyModel readRigidBody(OrderedDictionary bodyElem)
        {
            RigidBodyModel rbModel = new RigidBodyModel();

            rbModel.name      = (String)bodyElem["name"];
            rbModel.imagePath = (String)bodyElem["imagePath"];

            var bodyElemObject           = bodyElem["origin"] as JObject;
            OrderedDictionary originElem = bodyElemObject.ToObject <OrderedDictionary>();

            rbModel.origin.X = Convert.ToSingle(originElem["x"]);
            rbModel.origin.Y = Convert.ToSingle(originElem["y"]);


            // polygons
            var bEA = bodyElem["polygons"] as JArray;

            for (int i = 0; i < bEA.Count; i++)
            {
                PolygonModel polygon = new PolygonModel();
                rbModel.polygons.Add(polygon);

                var verticesElem = bEA[i] as JArray;
                for (int ii = 0; ii < verticesElem.Count; ii++)
                {
                    OrderedDictionary vertexElem = verticesElem[ii].ToObject <OrderedDictionary>();
                    float             x          = Convert.ToSingle(vertexElem["x"]);
                    float             y          = Convert.ToSingle(vertexElem["y"]);

                    polygon.vertices.Add(new Vector2(x, y));
                }

                polygon.buffer = new Vertices(polygon.vertices.Count);
            }

            // circles

            var circlesElem = bodyElem["circles"] as JArray;

            for (int i = 0; i < circlesElem.Count; i++)
            {
                CircleModel circle = new CircleModel();
                rbModel.circles.Add(circle);

                OrderedDictionary circleElem = circlesElem[i].ToObject <OrderedDictionary>();
                circle.center.X = (float)circleElem["cx"];
                circle.center.Y = (float)circleElem["cy"];
                circle.radius   = (float)circleElem["r"];
            }

            return(rbModel);
        }
Esempio n. 11
0
        public IActionResult InsertPolygon(string values)
        {
            var newPolygon = new PolygonModel();

            JsonConvert.PopulateObject(values, newPolygon);

            if (!TryValidateModel(newPolygon))
            {
                return(BadRequest(ModelState.GetFullErrorMessage()));
            }
            polygons.Add(newPolygon);

            return(Ok(newPolygon));
        }
        //public BodyEditorLoader(string str) {
        //    if (str == null) throw new NullReferenceException("str is null");
        //    model = readJson(str);
        //}

        // -------------------------------------------------------------------------
        // Public API
        // -------------------------------------------------------------------------

        /**
         * Creates and applies the fixtures defined in the editor. The name
         * parameter is used to retrieve the right fixture from the loaded file.
         * <br/><br/>
         *
         * The body reference point (the red cross in the tool) is by default
         * located at the bottom left corner of the image. This reference point
         * will be put right over the BodyDef position point. Therefore, you should
         * place this reference point carefully to let you place your body in your
         * world easily with its BodyDef.position point. Note that to draw an image
         * at the position of your body, you will need to know this reference point
         * (see {@link #getOrigin(java.lang.String, float)}.
         * <br/><br/>
         *
         * Also, saved shapes are normalized. As shown in the tool, the width of
         * the image is considered to be always 1 meter. Thus, you need to provide
         * a scale factor so the polygons get resized according to your needs (not
         * every body is 1 meter large in your game, I guess).
         *
         * @param body The Box2d body you want to attach the fixture to.
         * @param name The name of the fixture you want to load.
         * @param fd The fixture parameters to apply to the created body fixture.
         * @param scale The desired scale of the body. The default width is 1.
         */

        public void attachFixture(Body body, String name, float scale)
        {
            // deleted FixtureDef
            RigidBodyModel rbModel = model.rigidBodies[name];

            if (rbModel == null)
            {
                throw new SystemException("Name '" + name + "' was not found.");
            }

            vec = rbModel.origin * scale;
            Vector2 origin = vec;

            for (int i = 0, n = rbModel.polygons.Count; i < n; i++)
            {
                PolygonModel polygon  = rbModel.polygons[i];
                Vertices     vertices = new Vertices(polygon.vertices);

                for (int ii = 0, nn = vertices.Count; ii < nn; ii++)
                {
                    var v = NewVec();
                    v             = vertices[ii] * scale;
                    vertices[ii]  = v;
                    vertices[ii] -= origin;
                }

                polygonShape.Set(vertices);
                body.CreateFixture(polygonShape);

                for (int ii = 0, nn = vertices.Count; ii < nn; ii++)
                {
                    Free(vertices[ii]);
                }
            }

            for (int i = 0, n = rbModel.circles.Count; i < n; i++)
            {
                CircleModel circle = rbModel.circles[i];
                var         v2     = NewVec();
                v2 = circle.center * scale;
                Vector2 center = v2;
                float   radius = circle.radius * scale;

                circleShape.Position = center;
                circleShape.Radius   = radius;
                body.CreateFixture(circleShape);

                Free(center);
            }
        }
Esempio n. 13
0
        public void CancelActivePolygon()
        {
            if (ActivePolygon == null)
            {
                return;
            }

            foreach (var cc in polygonLinesInProgress)
            {
                GetInputLayer().RemoveComponent(cc);
            }

            polygonLinesInProgress.Clear();
            ActivePolygon = null;
        }
Esempio n. 14
0
	public void setArbitraryPolygon(int which, Vector2[] arbitraryPolygon) {
		if (which<0||which>=polys.Length) return;
		Vector2 bottomLeft = arbitraryPolygon[0];
		Vector2 topRight = arbitraryPolygon[0];
		for (int i=0;i<arbitraryPolygon.Length;i++) {
			bottomLeft.x = Mathf.Min(arbitraryPolygon[i].x,bottomLeft.x);
			bottomLeft.y = Mathf.Min(arbitraryPolygon[i].y,bottomLeft.y);
			topRight.x = Mathf.Max(arbitraryPolygon[i].x,topRight.x);
			topRight.y = Mathf.Max(arbitraryPolygon[i].y,topRight.y);
		}
		polys[which] = new PolygonModel(arbitraryPolygon.Length,0,new Vector2(topRight.x-bottomLeft.x,topRight.y-bottomLeft.y), nbVertex, 1);
		polys[which].arbitrary = true;
		polys[which].simplePoly = arbitraryPolygon;
		updateCompositeSplines(which);
		updateFinalSpline();
	}
Esempio n. 15
0
 /// <summary>
 /// Deserialize chosen polygon
 /// </summary>
 /// <param name="xmlPolygon"></param>
 /// <returns>Polygon</returns>
 public Polygon GetPolygon(PolygonModel xmlPolygon)
 {
     if (xmlPolygon != null)
     {
         return(new Polygon()
         {
             Points = new PointCollection(xmlPolygon.Points),
             StrokeThickness = xmlPolygon.Stroke,
             Fill = new SolidColorBrush(xmlPolygon.Color),
             Stroke = new SolidColorBrush(Colors.Black)
         });
     }
     else
     {
         throw new ArgumentException("There was no Polygon to get.");
     }
 }
Esempio n. 16
0
        public void PolygonService_GetPolygon_Test()
        {
            Point        Point1     = new Point(1, 50);
            Point        Point2     = new Point(10, 80);
            Point        Point3     = new Point(50, 50);
            List <Point> pointsList = new List <Point>();

            pointsList.Add(Point1);
            pointsList.Add(Point2);
            pointsList.Add(Point3);
            Color color = new Color();

            color = Color.FromRgb(255, 0, 0);
            PolygonModel    pm        = new PolygonModel(pointsList, color, 1);
            PolygonsService ps        = new PolygonsService();
            Polygon         myPolygon = ps.GetPolygon(pm);

            Assert.AreEqual(myPolygon.StrokeThickness, 1);
        }
Esempio n. 17
0
        private void DrawPolygons(PolygonModel polygon)
        {
            if (polygon == null)
            {
                return;
            }

            GL.Begin(PrimitiveType.Triangles);

            for (int l = 0; l < polygon.Faces.Count; l++)
            {
                var normal = polygon.Faces[l].Normal();
                GL.Color4(Math.Abs(normal.X), Math.Abs(normal.Y), Math.Abs(normal.Z), 0);
                GL.Normal3(N2TK(normal));
                GL.Vertex3(N2TK(polygon.Faces[l].Vertices[0].P));
                GL.Vertex3(N2TK(polygon.Faces[l].Vertices[2].P));
                GL.Vertex3(N2TK(polygon.Faces[l].Vertices[1].P));
            }

            GL.End();
        }
Esempio n. 18
0
        public void PolygonModel_Test()
        {
            PolygonModel polygon1   = new PolygonModel();
            Point        Point1     = new Point(1, 50);
            Point        Point2     = new Point(10, 80);
            Point        Point3     = new Point(50, 50);
            List <Point> points_arr = new List <Point>();

            points_arr.Add(Point1);
            points_arr.Add(Point2);
            points_arr.Add(Point3);
            Color color = new Color();

            color = Color.FromRgb(255, 0, 0);
            PolygonModel polygon2 = new PolygonModel(points_arr, color, 2);

            polygon1.Stroke = 2;
            Assert.AreNotEqual(3, polygon1.Stroke);
            Assert.AreEqual(3, polygon2.Points.Count);
            Assert.AreEqual(2, polygon2.Stroke);
            Assert.AreEqual(color, polygon2.Color);
        }
Esempio n. 19
0
        public void Render(PolygonModel polygon)
        {
            Polygon = polygon;

            // clear buffer
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            // set camera setting
            Vector3 vec_rotate = new Vector3((float)rotateX, (float)rotateY, (float)rotateZ);
            Vector3 center     = new Vector3(N2TK(Polygon.GravityPoint()));
            Vector3 eye        = center + vec_rotate * center.LengthFast / zoom;
            Matrix4 modelView  = Matrix4.LookAt(eye, center, Vector3.UnitY);

            // set disp mode
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelView);

            // display shape model
            DrawPolygons(polygon);

            glControl.SwapBuffers();
        }
Esempio n. 20
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
                        }
                    });
                }
            }
        }
Esempio n. 21
0
        //public Delaunator(IEnumerable<DelaunatorPoint> points)
        public override void Run()
        {
            if (InputPoints.Count() < 2)
            {
                throw new ArgumentOutOfRangeException("Need at least 3 points");
            }
            //Points = points.ToList();
            coords = new double[InputPoints.Count * 2];

            for (var i = 0; i < InputPoints.Count; i++)
            {
                var p = InputPoints.ElementAtOrDefault(i);
                coords[2 * i]     = p.X;
                coords[2 * i + 1] = p.Y;
            }

            var n            = coords.Length >> 1;
            var maxTriangles = 2 * n - 5;

            Triangles = new int[maxTriangles * 3];

            Halfedges = new int[maxTriangles * 3];
            hashSize  = (int)Math.Ceiling(Math.Sqrt(n));

            hullPrev = new int[n];
            hullNext = new int[n];
            hullTri  = new int[n];
            hullHash = new int[hashSize];

            var ids = new int[n];

            var minX = double.PositiveInfinity;
            var minY = double.PositiveInfinity;
            var maxX = double.NegativeInfinity;
            var maxY = double.NegativeInfinity;

            for (var i = 0; i < n; i++)
            {
                var x = coords[2 * i];
                var y = coords[2 * i + 1];
                if (x < minX)
                {
                    minX = x;
                }
                if (y < minY)
                {
                    minY = y;
                }
                if (x > maxX)
                {
                    maxX = x;
                }
                if (y > maxY)
                {
                    maxY = y;
                }
                ids[i] = i;
            }

            var cx = (minX + maxX) / 2;
            var cy = (minY + maxY) / 2;

            var minDist = double.PositiveInfinity;
            int i0 = 0, i1 = 0, i2 = 0;

            // pick a seed point close to the center
            for (int i = 0; i < n; i++)
            {
                var d = Dist(cx, cy, coords[2 * i], coords[2 * i + 1]);
                if (d < minDist)
                {
                    i0      = i;
                    minDist = d;
                }
            }
            var i0x = coords[2 * i0];
            var i0y = coords[2 * i0 + 1];

            minDist = double.PositiveInfinity;

            // find the point closest to the seed
            for (int i = 0; i < n; i++)
            {
                if (i == i0)
                {
                    continue;
                }
                var d = Dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]);
                if (d < minDist && d > 0)
                {
                    i1      = i;
                    minDist = d;
                }
            }

            var i1x = coords[2 * i1];
            var i1y = coords[2 * i1 + 1];

            var minRadius = double.PositiveInfinity;

            // find the third point which forms the smallest circumcircle with the first two
            for (int i = 0; i < n; i++)
            {
                if (i == i0 || i == i1)
                {
                    continue;
                }
                var r = Circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]);
                if (r < minRadius)
                {
                    i2        = i;
                    minRadius = r;
                }
            }
            var i2x = coords[2 * i2];
            var i2y = coords[2 * i2 + 1];

            if (minRadius == double.PositiveInfinity)
            {
                throw new Exception("No Delaunay triangulation exists for this input.");
            }

            if (Orient(i0x, i0y, i1x, i1y, i2x, i2y))
            {
                var i = i1;
                var x = i1x;
                var y = i1y;
                i1  = i2;
                i1x = i2x;
                i1y = i2y;
                i2  = i;
                i2x = x;
                i2y = y;
            }

            var center = Circumcenter(i0x, i0y, i1x, i1y, i2x, i2y);

            _cx = center.X;
            _cy = center.Y;

            var dists = new double[n];

            for (var i = 0; i < n; i++)
            {
                dists[i] = Dist(coords[2 * i], coords[2 * i + 1], center.X, center.Y);
            }

            // sort the points by distance from the seed triangle circumcenter
            Quicksort(ids, dists, 0, n - 1);

            // set up the seed triangle as the starting hull
            hullStart = i0;
            hullSize  = 3;

            hullNext[i0] = hullPrev[i2] = i1;
            hullNext[i1] = hullPrev[i0] = i2;
            hullNext[i2] = hullPrev[i1] = i0;

            hullTri[i0] = 0;
            hullTri[i1] = 1;
            hullTri[i2] = 2;

            hullHash[HashKey(i0x, i0y)] = i0;
            hullHash[HashKey(i1x, i1y)] = i1;
            hullHash[HashKey(i2x, i2y)] = i2;

            trianglesLen = 0;
            AddTriangle(i0, i1, i2, -1, -1, -1);

            double xp = 0;
            double yp = 0;

            for (var k = 0; k < ids.Length; k++)
            {
                var i = ids[k];
                var x = coords[2 * i];
                var y = coords[2 * i + 1];

                // skip near-duplicate points
                if (k > 0 && Math.Abs(x - xp) <= EPSILON && Math.Abs(y - yp) <= EPSILON)
                {
                    continue;
                }
                xp = x;
                yp = y;

                // skip seed triangle points
                if (i == i0 || i == i1 || i == i2)
                {
                    continue;
                }

                // find a visible edge on the convex hull using edge hash
                var start = 0;
                for (var j = 0; j < hashSize; j++)
                {
                    var key = HashKey(x, y);
                    start = hullHash[(key + j) % hashSize];
                    if (start != -1 && start != hullNext[start])
                    {
                        break;
                    }
                }

                start = hullPrev[start];
                var e = start;
                var q = hullNext[e];

                while (!Orient(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1]))
                {
                    e = q;
                    if (e == start)
                    {
                        e = int.MaxValue;
                        break;
                    }

                    q = hullNext[e];
                }

                if (e == int.MaxValue)
                {
                    continue;                    // likely a near-duplicate point; skip it
                }
                // add the first triangle from the point
                var t = AddTriangle(e, i, hullNext[e], -1, -1, hullTri[e]);

                // recursively flip triangles from the point until they satisfy the Delaunay condition
                hullTri[i] = Legalize(t + 2);
                hullTri[e] = t; // keep track of boundary triangles on the hull
                hullSize++;

                // walk forward through the hull, adding more triangles and flipping recursively
                var next = hullNext[e];
                q = hullNext[next];

                while (Orient(x, y, coords[2 * next], coords[2 * next + 1], coords[2 * q], coords[2 * q + 1]))
                {
                    t              = AddTriangle(next, i, q, hullTri[i], -1, hullTri[next]);
                    hullTri[i]     = Legalize(t + 2);
                    hullNext[next] = next; // mark as removed
                    hullSize--;
                    next = q;

                    q = hullNext[next];
                }

                // walk backward from the other side, adding more triangles and flipping
                if (e == start)
                {
                    q = hullPrev[e];

                    while (Orient(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1]))
                    {
                        t = AddTriangle(q, i, e, -1, hullTri[e], hullTri[q]);
                        Legalize(t + 2);
                        hullTri[q]  = t;
                        hullNext[e] = e; // mark as removed
                        hullSize--;
                        e = q;

                        q = hullPrev[e];
                    }
                }

                // update the hull indices
                hullStart   = hullPrev[i] = e;
                hullNext[e] = hullPrev[next] = i;
                hullNext[i] = next;

                // save the two new edges in the hash table
                hullHash[HashKey(x, y)] = i;
                hullHash[HashKey(coords[2 * e], coords[2 * e + 1])] = e;
            }

            hull = new int[hullSize];
            var s = hullStart;

            for (var i = 0; i < hullSize; i++)
            {
                hull[i] = s;
                s       = hullNext[s];
            }

            hullPrev = hullNext = hullTri = null; // get rid of temporary arrays

            //// trim typed triangle mesh arrays
            Triangles = Triangles.Take(trianglesLen).ToArray();
            Halfedges = Halfedges.Take(trianglesLen).ToArray();

            var layer = History.CreateAndAddNewLayer("Final Result");

            //AddEdgesToLayer(layer);
            if (!voronoiOperation)
            {
                foreach (var edge in GetEdges())
                {
                    var v1 = edge.P;
                    var v2 = edge.Q;

                    AddLineCommand(layer, v1, v2);
                }
            }
            else
            {
                //foreach (var edge in GetVoronoDelaunatorEdges())
                //{
                //    var v1 = edge.P;
                //    var v2 = edge.Q;

                //    AddNonIndexedLineCommand(layer, v1, v2);
                //}
                foreach (var cell in GetVoronoiCells())
                {
                    var poly = new PolygonModel();

                    //foreach (var p in cell.Points)
                    for (int i = 0; i < cell.Points.Count; i++)
                    {
                        var sp = cell.Points[i];
                        var np = cell.Points[(i + 1) % cell.Points.Count];

                        poly.Lines.Add(new LineModel
                        {
                            StartPoint = new Vector {
                                X = sp.X, Y = sp.Y
                            },
                            EndPoint = new Vector {
                                X = np.X, Y = np.Y
                            }
                        });
                    }

                    AddNonIndexedPolygonCommand(layer, poly);
                }
            }
        }