/// <summary>
            /// Visits all crossings of the current edge with all edges of the given index
            /// cell of B.  Terminates early and returns false if visitor_ returns false.
            /// </summary>
            private bool VisitEdgeCellCrossings(ShapeEdge a, S2ShapeIndexCell b_cell)
            {
                // Test the current edge of A against all edges of "b_cell".

                // Note that we need to use a new S2EdgeCrosser (or call Init) whenever we
                // replace the contents of b_shape_edges_, since S2EdgeCrosser requires that
                // its S2Point arguments point to values that persist between Init() calls.
                GetShapeEdges(b_index_, b_cell, b_shape_edges_);
                var crosser = new S2EdgeCrosser(a.V0, a.V1);

                foreach (var b in b_shape_edges_)
                {
                    if (crosser.C == S2Point.Empty || crosser.C != b.V0)
                    {
                        crosser.RestartAt(b.V0);
                    }
                    int sign = crosser.CrossingSign(b.V1);
                    if (sign >= min_crossing_sign_)
                    {
                        if (!VisitEdgePair(a, b, sign == 1))
                        {
                            return(false);
                        }
                    }
                }
                return(true);
            }
 private bool VisitEdgePair(ShapeEdge a, ShapeEdge b, bool is_interior)
 {
     if (swapped_)
     {
         return(visitor_(b, a, is_interior));
     }
     else
     {
         return(visitor_(a, b, is_interior));
     }
 }
        private void OnShapeEdgeMouseDown(object sender, MouseButtonEventArgs e)
        {
            System.Windows.Shapes.Shape edgeShape = (System.Windows.Shapes.Shape)sender;
            this.controlledEdgeIndex = this.edgeShapeToEdgeIndex[edgeShape];
            ShapeEdge edge = this.shape.Structure.Edges[this.controlledEdgeIndex.Value];

            this.initialEdgeWidth = this.shape.EdgeWidths[this.controlledEdgeIndex.Value];

            Point mousePos = e.GetPosition(this.shapeCanvas);

            this.initialDistanceFromEdgeLine = new Vector(mousePos.X, mousePos.Y).DistanceToLine(
                this.shape.VertexPositions[edge.Index1], this.shape.VertexPositions[edge.Index2]);
        }
        private Transform CalcEdgeTransform(int edgeIndex)
        {
            ShapeEdge edge       = this.shape.Structure.Edges[edgeIndex];
            Vector    pos1       = this.shape.VertexPositions[edge.Index1];
            Vector    pos2       = this.shape.VertexPositions[edge.Index2];
            Vector    middlePos  = 0.5 * (pos1 + pos2);
            double    edgeLength = pos1.DistanceToPoint(pos2);
            double    angle      = Vector.AngleBetween(Vector.UnitX, pos2 - pos1);

            TransformGroup result = new TransformGroup();

            result.Children.Add(new TranslateTransform(-0.5, -0.5));
            result.Children.Add(new ScaleTransform(edgeLength, this.shape.EdgeWidths[edgeIndex]));
            result.Children.Add(new RotateTransform(MathHelper.ToDegrees(angle)));
            result.Children.Add(new TranslateTransform(middlePos.X, middlePos.Y));

            return(result);
        }
        private void OnShapeCanvasMouseMove(object sender, MouseEventArgs e)
        {
            Point mousePos = e.GetPosition(this.shapeCanvas);

            if (this.controlledVertexIndex.HasValue)
            {
                this.shape.VertexPositions[this.controlledVertexIndex.Value] = new Vector(mousePos.X, mousePos.Y) - this.mouseOffset;
            }
            else if (this.controlledEdgeIndex.HasValue)
            {
                ShapeEdge edge = this.shape.Structure.Edges[this.controlledEdgeIndex.Value];
                double    distanceFromEdgeLine = new Vector(mousePos.X, mousePos.Y).DistanceToLine(
                    this.shape.VertexPositions[edge.Index1], this.shape.VertexPositions[edge.Index2]);
                this.shape.EdgeWidths[this.controlledEdgeIndex.Value] =
                    Math.Max(this.initialEdgeWidth + 2 * (distanceFromEdgeLine - this.initialDistanceFromEdgeLine), 5);
            }

            if (this.controlledVertexIndex.HasValue || this.controlledEdgeIndex.HasValue)
            {
                this.UpdateShapeControls();
            }
        }
        private Image DrawConstraintsOnTopOfImage(
            Image backgroundImage, float drawSizeRatio, ShapeConstraints shapeConstraints, bool drawVertexConstraints, bool drawMinEdgeWidth, bool drawMaxEdgeWidth, bool drawAverageEdgeWidth)
        {
            const float pointRadius = 4;
            const float lineWidth   = 2;

            Bitmap statusImage = new Bitmap((int)(backgroundImage.Width * drawSizeRatio), (int)(backgroundImage.Height * drawSizeRatio));

            using (Graphics graphics = Graphics.FromImage(statusImage))
            {
                graphics.DrawImage(backgroundImage, 0, 0, statusImage.Width, statusImage.Height);

                if (drawVertexConstraints)
                {
                    foreach (VertexConstraints vertexConstraint in shapeConstraints.VertexConstraints)
                    {
                        graphics.DrawRectangle(
                            new Pen(Color.Orange, lineWidth),
                            (float)vertexConstraint.MinCoord.X * drawSizeRatio,
                            (float)vertexConstraint.MinCoord.Y * drawSizeRatio,
                            (float)(vertexConstraint.MaxCoord.X - vertexConstraint.MinCoord.X) * drawSizeRatio,
                            (float)(vertexConstraint.MaxCoord.Y - vertexConstraint.MinCoord.Y) * drawSizeRatio);
                    }
                }

                foreach (VertexConstraints vertexConstraint in shapeConstraints.VertexConstraints)
                {
                    graphics.FillEllipse(
                        Brushes.Black,
                        (float)vertexConstraint.MiddleCoord.X * drawSizeRatio - pointRadius,
                        (float)vertexConstraint.MiddleCoord.Y * drawSizeRatio - pointRadius,
                        2 * pointRadius,
                        2 * pointRadius);
                }

                for (int i = 0; i < shapeConstraints.ShapeStructure.Edges.Count; ++i)
                {
                    ShapeEdge edge   = shapeConstraints.ShapeStructure.Edges[i];
                    Vector    point1 = shapeConstraints.VertexConstraints[edge.Index1].MiddleCoord * drawSizeRatio;
                    Vector    point2 = shapeConstraints.VertexConstraints[edge.Index2].MiddleCoord * drawSizeRatio;
                    graphics.DrawLine(new Pen(Color.Black, lineWidth), MathHelper.VecToPointF(point1), MathHelper.VecToPointF(point2));

                    if (drawMinEdgeWidth || drawMaxEdgeWidth || drawAverageEdgeWidth)
                    {
                        EdgeConstraints edgeConstraint = shapeConstraints.EdgeConstraints[i];
                        Vector          diff           = point2 - point1;
                        Vector          edgeNormal     = (new Vector(diff.Y, -diff.X)).GetNormalized();

                        if (drawMaxEdgeWidth)
                        {
                            DrawOrientedRectange(graphics, point1, point2, edgeNormal, (float)edgeConstraint.MaxWidth * drawSizeRatio, new Pen(Color.Cyan, lineWidth));
                        }
                        if (drawMinEdgeWidth)
                        {
                            DrawOrientedRectange(graphics, point1, point2, edgeNormal, (float)edgeConstraint.MinWidth * drawSizeRatio, new Pen(Color.Red, lineWidth));
                        }
                        if (drawAverageEdgeWidth)
                        {
                            DrawOrientedRectange(graphics, point1, point2, edgeNormal, (float)(edgeConstraint.MinWidth + edgeConstraint.MaxWidth) * drawSizeRatio * 0.5f, new Pen(Color.Blue, lineWidth));
                        }
                    }
                }
            }

            return(statusImage);
        }