Пример #1
0
 private void AddSeparatorsForPair(VertexConstraints constraint1, VertexConstraints constraint2, bool swapDirection)
 {
     for (int i = 0; i < 4; ++i)
     {
         this.AddSeparatorsForPoint(constraint1.Corners[i], constraint2, swapDirection);
     }
 }
        private static void MinMaxDistanceForEdge(
            Vector point,
            Polygon convexHull,
            VertexConstraints constraints1,
            VertexConstraints constraints2,
            out double minDistanceSqr,
            out double maxDistanceSqr)
        {
            if (convexHull.IsPointInside(point))
            {
                minDistanceSqr = 0;
            }
            else
            {
                minDistanceSqr = Double.PositiveInfinity;
                for (int i = 0; i < convexHull.Vertices.Count; ++i)
                {
                    double distanceSqr = point.DistanceToSegmentSquared(
                        convexHull.Vertices[i],
                        convexHull.Vertices[(i + 1) % convexHull.Vertices.Count]);
                    minDistanceSqr = Math.Min(minDistanceSqr, distanceSqr);
                }
            }

            maxDistanceSqr = 0;
            foreach (Vector vertex1 in constraints1.Corners)
            {
                foreach (Vector vertex2 in constraints2.Corners)
                {
                    double distanceSqr = point.DistanceToSegmentSquared(vertex1, vertex2);
                    maxDistanceSqr = Math.Max(maxDistanceSqr, distanceSqr);
                }
            }
        }
 public LengthAngleSpaceSeparatorSet(VertexConstraints constraint1, VertexConstraints constraint2)
 {
     if (constraint1.Freedom < 1e-6 || constraint2.Freedom < 1e-6)
         throw new ArgumentException("Coord constraints should not be singular.");
     
     this.AddSeparatorsForPair(constraint1, constraint2, false);
     this.AddSeparatorsForPair(constraint2, constraint1, true);
 }
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
                return false;

            VertexConstraints objCasted = (VertexConstraints) obj;
            return objCasted.MinCoord == this.MinCoord && objCasted.MaxCoord == this.MaxCoord;
        }
 public EdgeDescription(
     VertexConstraints vertexConstraints1,
     VertexConstraints vertexConstraints2,
     EdgeConstraints edgeConstraints)
 {
     this.VertexConstraints1 = vertexConstraints1;
     this.VertexConstraints2 = vertexConstraints2;
     this.EdgeConstraints    = edgeConstraints;
 }
Пример #6
0
        public LengthAngleSpaceSeparatorSet(VertexConstraints constraint1, VertexConstraints constraint2)
        {
            if (constraint1.Freedom < 1e-6 || constraint2.Freedom < 1e-6)
            {
                throw new ArgumentException("Coord constraints should not be singular.");
            }

            this.AddSeparatorsForPair(constraint1, constraint2, false);
            this.AddSeparatorsForPair(constraint2, constraint1, true);
        }
Пример #7
0
        private static List <ILengthAngleConstraints> CalculateLengthAngleConstraints(ShapeConstraints shapeConstraints)
        {
            List <ILengthAngleConstraints> result = new List <ILengthAngleConstraints>();

            for (int i = 0; i < shapeConstraints.ShapeStructure.Edges.Count; ++i)
            {
                ShapeEdge         edge = shapeConstraints.ShapeStructure.Edges[i];
                VertexConstraints vertex1Constraints = shapeConstraints.VertexConstraints[edge.Index1];
                VertexConstraints vertex2Constraints = shapeConstraints.VertexConstraints[edge.Index2];
                result.Add(BoxSetLengthAngleConstraints.FromVertexConstraints(vertex1Constraints, vertex2Constraints, 1, 16));
            }

            return(result);
        }
        public AllowedLengthAngleChecker(
            VertexConstraints constraint1,
            VertexConstraints constraint2,
            GeneralizedDistanceTransform2D checkingTransform,
            double lengthRatio,
            double meanAngle)
        {
            this.lengthAngleStatus = new Image2D <byte>(checkingTransform.GridSize.Width, checkingTransform.GridSize.Height);
            LengthAngleSpaceSeparatorSet separator = new LengthAngleSpaceSeparatorSet(constraint1, constraint2);

            this.checkingTransform = checkingTransform;

            // Initial fill
            for (int i = 0; i < checkingTransform.GridSize.Width; ++i)
            {
                double scaledLength = checkingTransform.GridIndexToCoordX(i);
                double length       = scaledLength / lengthRatio;

                for (int j = 0; j < checkingTransform.GridSize.Height; ++j)
                {
                    double shiftedAngle = checkingTransform.GridIndexToCoordY(j);
                    double angle        = shiftedAngle + meanAngle;

                    if (separator.IsInside(length, angle))
                    {
                        this.lengthAngleStatus[i, j] = 2;
                    }
                    else if (i == 0 || j == 0 || this.lengthAngleStatus[i - 1, j] == 1 || this.lengthAngleStatus[i, j - 1] == 1)
                    {
                        this.lengthAngleStatus[i, j] = 1;
                    }
                }
            }

            // Fill holes
            for (int i = 0; i < checkingTransform.GridSize.Width; ++i)
            {
                for (int j = 0; j < checkingTransform.GridSize.Height; ++j)
                {
                    if (lengthAngleStatus[i, j] == 0)
                    {
                        lengthAngleStatus[i, j] = 2;
                    }
                }
            }
        }
        public static BoxSetLengthAngleConstraints FromVertexConstraints(
            VertexConstraints vertexConstraints1, VertexConstraints vertexConstraints2,
            int maxSplitDepth,
            double nonSplittableArea)
        {
            BoxLengthAngleConstraints overallRange = BoxLengthAngleConstraints.FromVertexConstraints(
                vertexConstraints1, vertexConstraints2);

            IEnumerable<VertexConstraints> split1 = GenerateSplit(vertexConstraints1, maxSplitDepth, nonSplittableArea);
            IEnumerable<VertexConstraints> split2 = GenerateSplit(vertexConstraints2, maxSplitDepth, nonSplittableArea);
            List<BoxLengthAngleConstraints> childConstraints = new List<BoxLengthAngleConstraints>();
            foreach (VertexConstraints childVertexConstraints1 in split1)
                foreach (VertexConstraints childVertexConstraints2 in split2)
                    childConstraints.Add(BoxLengthAngleConstraints.FromVertexConstraints(childVertexConstraints1, childVertexConstraints2));

            return new BoxSetLengthAngleConstraints(childConstraints, overallRange);
        }
        private static IEnumerable<VertexConstraints> GenerateSplit(
            VertexConstraints constraints,
            int maxSplitDepth,
            double nonSplittableArea)
        {
            List<VertexConstraints> split = new List<VertexConstraints> { constraints };
            int iteration = 0;
            int splitIndex = 0;
            while (split[iteration].Area > nonSplittableArea && iteration < maxSplitDepth)
            {
                int length = split.Count;
                for (int i = splitIndex; i < length; ++i)
                    split.AddRange(split[i].Split());
                splitIndex = length;
                ++iteration;
            }

            return split.Skip(splitIndex);
        }
Пример #11
0
        private void AddSeparatorsForPoint(Vector point, VertexConstraints constraint2, bool swapDirection)
        {
            this.separatorLists.Add(new List <LengthAngleSpaceSeparator>());

            Vector middlePoint = 0.5 * (constraint2.Corners[0] + constraint2.Corners[2]);

            for (int j = 0; j < 4; ++j)
            {
                Vector segmentStart  = constraint2.Corners[j];
                Vector segmentEnd    = constraint2.Corners[(j + 1) % 4];
                Vector segmentMiddle = 0.5 * (segmentStart + segmentEnd);
                Vector allowedPoint  = segmentMiddle + (middlePoint - segmentMiddle) * 0.01;
                Vector allowedVec    = allowedPoint - point;
                double allowedLength = allowedVec.Length;
                double allowedAngle  = Vector.AngleBetween(Vector.UnitX, allowedVec);

                this.separatorLists[this.separatorLists.Count - 1].Add(
                    new LengthAngleSpaceSeparator(segmentStart, segmentEnd, point, allowedLength, allowedAngle, swapDirection));
            }
        }
        private void AddSeparatorsForPoint(Vector point, VertexConstraints constraint2, bool swapDirection)
        {
            this.separatorLists.Add(new List<LengthAngleSpaceSeparator>());

            Vector middlePoint = 0.5 * (constraint2.Corners[0] + constraint2.Corners[2]);

            for (int j = 0; j < 4; ++j)
            {
                Vector segmentStart = constraint2.Corners[j];
                Vector segmentEnd = constraint2.Corners[(j + 1) % 4];
                Vector segmentMiddle = 0.5 * (segmentStart + segmentEnd);
                Vector allowedPoint = segmentMiddle + (middlePoint - segmentMiddle) * 0.01;
                Vector allowedVec = allowedPoint - point;
                double allowedLength = allowedVec.Length;
                double allowedAngle = Vector.AngleBetween(Vector.UnitX, allowedVec);

                this.separatorLists[this.separatorLists.Count - 1].Add(
                    new LengthAngleSpaceSeparator(segmentStart, segmentEnd, point, allowedLength, allowedAngle, swapDirection));
            }
        }
        public AllowedLengthAngleChecker(
            VertexConstraints constraint1,
            VertexConstraints constraint2,
            GeneralizedDistanceTransform2D checkingTransform,
            double lengthRatio,
            double meanAngle)
        {
            this.lengthAngleStatus = new Image2D<byte>(checkingTransform.GridSize.Width, checkingTransform.GridSize.Height);
            LengthAngleSpaceSeparatorSet separator = new LengthAngleSpaceSeparatorSet(constraint1, constraint2);

            this.checkingTransform = checkingTransform;
            
            // Initial fill
            for (int i = 0; i < checkingTransform.GridSize.Width; ++i)
            {
                double scaledLength = checkingTransform.GridIndexToCoordX(i);
                double length = scaledLength / lengthRatio;

                for (int j = 0; j < checkingTransform.GridSize.Height; ++j)
                {
                    double shiftedAngle = checkingTransform.GridIndexToCoordY(j);
                    double angle = shiftedAngle + meanAngle;

                    if (separator.IsInside(length, angle))
                        this.lengthAngleStatus[i, j] = 2;
                    else if (i == 0 || j == 0 || this.lengthAngleStatus[i - 1, j] == 1 || this.lengthAngleStatus[i, j - 1] == 1)
                        this.lengthAngleStatus[i, j] = 1;
                }
            }

            // Fill holes
            for (int i = 0; i < checkingTransform.GridSize.Width; ++i)
            {
                for (int j = 0; j < checkingTransform.GridSize.Height; ++j)
                {
                    if (lengthAngleStatus[i, j] == 0)
                        lengthAngleStatus[i, j] = 2;
                }
            }
        }
Пример #14
0
        public static BoxSetLengthAngleConstraints FromVertexConstraints(
            VertexConstraints vertexConstraints1, VertexConstraints vertexConstraints2,
            int maxSplitDepth,
            double nonSplittableArea)
        {
            BoxLengthAngleConstraints overallRange = BoxLengthAngleConstraints.FromVertexConstraints(
                vertexConstraints1, vertexConstraints2);

            IEnumerable <VertexConstraints>  split1           = GenerateSplit(vertexConstraints1, maxSplitDepth, nonSplittableArea);
            IEnumerable <VertexConstraints>  split2           = GenerateSplit(vertexConstraints2, maxSplitDepth, nonSplittableArea);
            List <BoxLengthAngleConstraints> childConstraints = new List <BoxLengthAngleConstraints>();

            foreach (VertexConstraints childVertexConstraints1 in split1)
            {
                foreach (VertexConstraints childVertexConstraints2 in split2)
                {
                    childConstraints.Add(BoxLengthAngleConstraints.FromVertexConstraints(childVertexConstraints1, childVertexConstraints2));
                }
            }

            return(new BoxSetLengthAngleConstraints(childConstraints, overallRange));
        }
Пример #15
0
        private static IEnumerable <VertexConstraints> GenerateSplit(
            VertexConstraints constraints,
            int maxSplitDepth,
            double nonSplittableArea)
        {
            List <VertexConstraints> split = new List <VertexConstraints> {
                constraints
            };
            int iteration  = 0;
            int splitIndex = 0;

            while (split[iteration].Area > nonSplittableArea && iteration < maxSplitDepth)
            {
                int length = split.Count;
                for (int i = splitIndex; i < length; ++i)
                {
                    split.AddRange(split[i].Split());
                }
                splitIndex = length;
                ++iteration;
            }

            return(split.Skip(splitIndex));
        }
        public void CalculateShapeTerms(ShapeModel model, ShapeConstraints constraintsSet, Image2D <ObjectBackgroundTerm> result)
        {
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }
            if (constraintsSet == null)
            {
                throw new ArgumentNullException("constraintsSet");
            }
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (model.Structure != constraintsSet.ShapeStructure)
            {
                throw new ArgumentException("Shape model and shape constraints correspond to different shape structures.");
            }

            if (model != this.shapeModel || result.Rectangle.Size != this.imageSize)
            {
                this.SetTarget(model, result.Rectangle.Size);
            }

            for (int x = 0; x < imageSize.Width; ++x)
            {
                for (int y = 0; y < imageSize.Height; ++y)
                {
                    result[x, y] = new ObjectBackgroundTerm(Double.PositiveInfinity, 0);
                }
            }

            for (int edgeIndex = 0; edgeIndex < this.shapeModel.Structure.Edges.Count; ++edgeIndex)
            {
                ShapeEdge         edge = this.shapeModel.Structure.Edges[edgeIndex];
                VertexConstraints vertexConstraints1 = constraintsSet.VertexConstraints[edge.Index1];
                VertexConstraints vertexConstraints2 = constraintsSet.VertexConstraints[edge.Index2];
                EdgeConstraints   edgeConstraints    = constraintsSet.EdgeConstraints[edgeIndex];

                Image2D <ObjectBackgroundTerm> edgeTerms;
                EdgeDescription edgeDescription = new EdgeDescription(
                    vertexConstraints1, vertexConstraints2, edgeConstraints);
                if (!this.cachedEdgeTerms.TryGetValue(edgeDescription, out edgeTerms))
                {
                    edgeTerms = this.AllocateImage();
                    this.cachedEdgeTerms.Add(edgeDescription, edgeTerms);

                    Polygon convexHull = constraintsSet.GetConvexHullForVertexPair(edge.Index1, edge.Index2);

                    Parallel.For(
                        0,
                        imageSize.Width,
                        x =>
                    {
                        for (int y = 0; y < imageSize.Height; ++y)
                        {
                            Vector pointAsVec = new Vector(x, y);
                            double minDistanceSqr, maxDistanceSqr;
                            MinMaxDistanceForEdge(
                                pointAsVec,
                                convexHull,
                                vertexConstraints1,
                                vertexConstraints2,
                                out minDistanceSqr,
                                out maxDistanceSqr);

                            edgeTerms[x, y] = new ObjectBackgroundTerm(
                                this.shapeModel.CalculateObjectPenaltyForEdge(
                                    minDistanceSqr, edgeConstraints.MaxWidth),
                                this.shapeModel.CalculateBackgroundPenaltyForEdge(
                                    maxDistanceSqr, edgeConstraints.MinWidth));
                        }
                    });
                }

                for (int x = 0; x < imageSize.Width; ++x)
                {
                    for (int y = 0; y < imageSize.Height; ++y)
                    {
                        result[x, y] = new ObjectBackgroundTerm(
                            Math.Min(result[x, y].ObjectTerm, edgeTerms[x, y].ObjectTerm),
                            Math.Max(result[x, y].BackgroundTerm, edgeTerms[x, y].BackgroundTerm));
                    }
                }
            }
        }
 private void AddSeparatorsForPair(VertexConstraints constraint1, VertexConstraints constraint2, bool swapDirection)
 {
     for (int i = 0; i < 4; ++i)
         this.AddSeparatorsForPoint(constraint1.Corners[i], constraint2, swapDirection);
 }
Пример #18
0
        public static BoxLengthAngleConstraints FromVertexConstraints(VertexConstraints constraints1, VertexConstraints constraints2)
        {
            Range angleRange;

            Range xRange1 = new Range(constraints1.MinCoord.X, constraints1.MaxCoord.X);
            Range yRange1 = new Range(constraints1.MinCoord.Y, constraints1.MaxCoord.Y);
            Range xRange2 = new Range(constraints2.MinCoord.X, constraints2.MaxCoord.X);
            Range yRange2 = new Range(constraints2.MinCoord.Y, constraints2.MaxCoord.Y);

            bool xIntersection = xRange1.IntersectsWith(xRange2);
            bool yIntersection = yRange1.IntersectsWith(yRange2);

            double minLength = Double.PositiveInfinity, maxLength = 0;

            if (xIntersection && yIntersection)
            {
                // Special case: intersecting rectangles
                angleRange = new Range(-Math.PI, Math.PI);
                minLength  = 0;
            }
            else
            {
                // Angle changes from PI to -PI when second constraint is to the left of the first one
                bool angleSignChanges = constraints1.MinCoord.X > constraints2.MaxCoord.X && yIntersection;

                double minAngle = angleSignChanges ? -Math.PI : Math.PI;
                double maxAngle = angleSignChanges ? Math.PI : -Math.PI;
                foreach (Vector point1 in constraints1.Corners)
                {
                    foreach (Vector point2 in constraints2.Corners)
                    {
                        double angle = Vector.AngleBetween(new Vector(1, 0), point2 - point1);
                        if (angleSignChanges)
                        {
                            if (angle < 0)
                            {
                                minAngle = Math.Max(minAngle, angle);
                            }
                            else
                            {
                                maxAngle = Math.Min(maxAngle, angle);
                            }
                        }
                        else
                        {
                            minAngle = Math.Min(minAngle, angle);
                            maxAngle = Math.Max(maxAngle, angle);
                        }
                    }
                }
                angleRange = new Range(minAngle, maxAngle, angleSignChanges);

                // One constraint is on top or on bottom of another
                if (xIntersection)
                {
                    // 1 on top of 2
                    if (constraints1.MinCoord.Y > constraints2.MaxCoord.Y)
                    {
                        minLength = Math.Min(minLength, constraints1.MinCoord.Y - constraints2.MaxCoord.Y);
                    }
                    // 2 on top of 1
                    else
                    {
                        minLength = Math.Min(minLength, constraints2.MinCoord.Y - constraints1.MaxCoord.Y);
                    }
                }
                else if (yIntersection)
                {
                    // 1 to the left of 2
                    if (constraints1.MaxCoord.X < constraints2.MinCoord.X)
                    {
                        minLength = Math.Min(minLength, constraints2.MinCoord.X - constraints1.MaxCoord.X);
                    }
                    // 2 to the left of 1
                    else
                    {
                        minLength = Math.Min(minLength, constraints1.MinCoord.X - constraints2.MaxCoord.X);
                    }
                }
            }

            foreach (Vector point1 in constraints1.Corners)
            {
                foreach (Vector point2 in constraints2.Corners)
                {
                    double length = (point1 - point2).Length;
                    minLength = Math.Min(minLength, length);
                    maxLength = Math.Max(maxLength, length);
                }
            }

            Range lengthRange = new Range(minLength, maxLength);

            return(new BoxLengthAngleConstraints(lengthRange, angleRange));
        }
        static void LengthAngleDependenceExperiment(
            VertexConstraints constraint1, VertexConstraints constraint2, string fileName)
        {
            const int GeneratedPointCount = 100000;

            List<Vector> lengthAnglePoints = new List<Vector>();
            double maxLength = 0;
            for (int i = 0; i < GeneratedPointCount; ++i)
            {
                double randomX1 = constraint1.MinCoord.X + Random.Double() * (constraint1.MaxCoord.X - constraint1.MinCoord.X);
                double randomY1 = constraint1.MinCoord.Y + Random.Double() * (constraint1.MaxCoord.Y - constraint1.MinCoord.Y);
                double randomX2 = constraint2.MinCoord.X + Random.Double() * (constraint2.MaxCoord.X - constraint2.MinCoord.X);
                double randomY2 = constraint2.MinCoord.Y + Random.Double() * (constraint2.MaxCoord.Y - constraint2.MinCoord.Y);
                Vector vector1 = new Vector(randomX1, randomY1);
                Vector vector2 = new Vector(randomX2, randomY2);
                if (vector1 == vector2)
                    continue;

                Vector diff = vector2 - vector1;
                double length = diff.Length;
                double angle = Vector.AngleBetween(Vector.UnitX, diff);
                lengthAnglePoints.Add(new Vector(length, angle));

                maxLength = Math.Max(maxLength, length);
            }

            //ShapeConstraints constraintSet = ShapeConstraints.CreateFromConstraints(
            //    CreateSimpleShapeModel1(),
            //    new[] { constraint1, constraint2 },
            //    new[] { new EdgeConstraints(1) },
            //    1,
            //    1);
            BoxSetLengthAngleConstraints lengthAngleConstraints =
                BoxSetLengthAngleConstraints.FromVertexConstraints(constraint1, constraint2, 2, 0);

            const int lengthImageSize = 360;
            const int angleImageSize = 360;
            double lengthScale = (lengthImageSize - 20) / maxLength;

            //Image2D<bool> myAwesomeMask = new Image2D<bool>(lengthImageSize, angleImageSize);
            //LengthAngleSpaceSeparatorSet myAwesomeSeparator = new LengthAngleSpaceSeparatorSet(constraint1, constraint2);
            //for (int i = 0; i < lengthImageSize; ++i)
            //    for (int j = 0; j < angleImageSize; ++j)
            //    {
            //        double length = i / lengthScale;
            //        double angle = MathHelper.ToRadians(j - 180.0);
            //        if (myAwesomeSeparator.IsInside(length, angle))
            //            myAwesomeMask[i, j] = true;
            //    }

            using (Bitmap image = new Bitmap(lengthImageSize, angleImageSize))
            using (Graphics graphics = Graphics.FromImage(image))
            {
                graphics.Clear(Color.White);

                // Draw generated points
                for (int i = 0; i < lengthAnglePoints.Count; ++i)
                    DrawLengthAngle(graphics, Pens.Black, lengthAnglePoints[i].X, lengthAnglePoints[i].Y, lengthScale, 1);

                // Draw estimated ranges
                foreach (BoxLengthAngleConstraints child in lengthAngleConstraints.ChildConstraints)
                    DrawLengthAngleConstraintBox(graphics, Pens.Green, child, lengthScale);
                DrawLengthAngleConstraintBox(graphics, new Pen(Color.Red, 2), lengthAngleConstraints.OverallRange, lengthScale);

                // Draw constraint corners
                //for (int i = 0; i < 4; ++i)
                //{
                //    for (int j = 0; j < 4; ++j)
                //    {
                //        Vector diff = constraint2.Corners[j] - constraint1.Corners[i];
                //        DrawLengthAngle(diff.Length, Vector.AngleBetween(Vector.UnitX, diff), lengthScale, 5, graphics, Pens.Blue);
                //    }
                //}

                // Draw my awesome separation lines
                //for (int i = 0; i < lengthImageSize - 1; ++i)
                //    for (int j = 0; j < lengthImageSize - 1; ++j)
                //    {
                //        bool border = false;
                //        border |= myAwesomeMask[i, j] != myAwesomeMask[i + 1, j];
                //        border |= myAwesomeMask[i, j] != myAwesomeMask[i, j + 1];
                //        border |= myAwesomeMask[i, j] != myAwesomeMask[i + 1, j + 1];
                //        if (border)
                //            image.SetPixel(i, j, Color.Orange);
                //    }

                //graphics.DrawString(
                //    String.Format("Max length is {0:0.0}", maxLength), SystemFonts.DefaultFont, Brushes.Green, 5, 5);

                image.Save(fileName);
            }
        }
        static void PointIsClosestExperiment(
            Vector point,
            VertexConstraints point1Constraints,
            VertexConstraints point2Constraints,
            string fileName)
        {
            Console.WriteLine(string.Format("Doing experiment for {0}", fileName));

            Bitmap image = new Bitmap(320, 240);
            const int iterations = 200000;
            using (Graphics graphics = Graphics.FromImage(image))
            {
                for (int i = 0; i < iterations; ++i)
                {
                    Vector point1 = new Vector(
                        point1Constraints.MinCoord.X + (point1Constraints.MaxCoord.X - point1Constraints.MinCoord.X) * Random.Double(),
                        point1Constraints.MinCoord.Y + (point1Constraints.MaxCoord.Y - point1Constraints.MinCoord.Y) * Random.Double());
                    Vector point2 = new Vector(
                        point2Constraints.MinCoord.X + (point2Constraints.MaxCoord.X - point2Constraints.MinCoord.X) * Random.Double(),
                        point2Constraints.MinCoord.Y + (point2Constraints.MaxCoord.Y - point2Constraints.MinCoord.Y) * Random.Double());

                    double distanceSqr, alpha;
                    point.DistanceToSegmentSquared(point1, point2, out distanceSqr, out alpha);
                    alpha = MathHelper.Trunc(alpha, 0, 1);
                    Vector closestPoint = point1 + (point2 - point1) * alpha;
                    const float radius = 2;
                    graphics.FillEllipse(
                        Brushes.Green,
                        (float)closestPoint.X - radius,
                        (float)closestPoint.Y - radius,
                        radius * 2,
                        radius * 2);
                }

                graphics.DrawRectangle(
                    Pens.Blue,
                    point1Constraints.CoordRectangle.Left,
                    point1Constraints.CoordRectangle.Top,
                    point1Constraints.CoordRectangle.Width,
                    point1Constraints.CoordRectangle.Height);
                graphics.DrawRectangle(
                    Pens.Blue,
                    point2Constraints.CoordRectangle.Left,
                    point2Constraints.CoordRectangle.Top,
                    point2Constraints.CoordRectangle.Width,
                    point2Constraints.CoordRectangle.Height);
                graphics.FillEllipse(Brushes.Red, (float)point.X - 2, (float)point.Y - 2, 4, 4);
            }

            image.Save(fileName);
        }
 private static void MinMaxDistanceForEdge(
     Vector point,
     Polygon convexHull,
     VertexConstraints constraints1,
     VertexConstraints constraints2,
     out double minDistanceSqr,
     out double maxDistanceSqr)
 {
     if (convexHull.IsPointInside(point))
         minDistanceSqr = 0;
     else
     {
         minDistanceSqr = Double.PositiveInfinity;
         for (int i = 0; i < convexHull.Vertices.Count; ++i)
         {
             double distanceSqr = point.DistanceToSegmentSquared(
                 convexHull.Vertices[i],
                 convexHull.Vertices[(i + 1) % convexHull.Vertices.Count]);
             minDistanceSqr = Math.Min(minDistanceSqr, distanceSqr);
         }
     }
     
     maxDistanceSqr = 0;
     foreach (Vector vertex1 in constraints1.Corners)
     {
         foreach (Vector vertex2 in constraints2.Corners)
         {
             double distanceSqr = point.DistanceToSegmentSquared(vertex1, vertex2);
             maxDistanceSqr = Math.Max(maxDistanceSqr, distanceSqr);
         }
     }
 }
        public static BoxLengthAngleConstraints FromVertexConstraints(VertexConstraints constraints1, VertexConstraints constraints2)
        {
            Range angleRange;

            Range xRange1 = new Range(constraints1.MinCoord.X, constraints1.MaxCoord.X);
            Range yRange1 = new Range(constraints1.MinCoord.Y, constraints1.MaxCoord.Y);
            Range xRange2 = new Range(constraints2.MinCoord.X, constraints2.MaxCoord.X);
            Range yRange2 = new Range(constraints2.MinCoord.Y, constraints2.MaxCoord.Y);

            bool xIntersection = xRange1.IntersectsWith(xRange2);
            bool yIntersection = yRange1.IntersectsWith(yRange2);

            double minLength = Double.PositiveInfinity, maxLength = 0;

            if (xIntersection && yIntersection)
            {
                // Special case: intersecting rectangles
                angleRange = new Range(-Math.PI, Math.PI);
                minLength = 0;
            }
            else
            {
                // Angle changes from PI to -PI when second constraint is to the left of the first one
                bool angleSignChanges = constraints1.MinCoord.X > constraints2.MaxCoord.X && yIntersection;

                double minAngle = angleSignChanges ? -Math.PI : Math.PI;
                double maxAngle = angleSignChanges ? Math.PI : -Math.PI;
                foreach (Vector point1 in constraints1.Corners)
                {
                    foreach (Vector point2 in constraints2.Corners)
                    {
                        double angle = Vector.AngleBetween(new Vector(1, 0), point2 - point1);
                        if (angleSignChanges)
                        {
                            if (angle < 0)
                                minAngle = Math.Max(minAngle, angle);
                            else
                                maxAngle = Math.Min(maxAngle, angle);
                        }
                        else
                        {
                            minAngle = Math.Min(minAngle, angle);
                            maxAngle = Math.Max(maxAngle, angle);
                        }
                    }
                }
                angleRange = new Range(minAngle, maxAngle, angleSignChanges);

                // One constraint is on top or on bottom of another
                if (xIntersection)
                {
                    // 1 on top of 2
                    if (constraints1.MinCoord.Y > constraints2.MaxCoord.Y)
                        minLength = Math.Min(minLength, constraints1.MinCoord.Y - constraints2.MaxCoord.Y);
                    // 2 on top of 1
                    else
                        minLength = Math.Min(minLength, constraints2.MinCoord.Y - constraints1.MaxCoord.Y);
                }
                else if (yIntersection)
                {
                    // 1 to the left of 2
                    if (constraints1.MaxCoord.X < constraints2.MinCoord.X)
                        minLength = Math.Min(minLength, constraints2.MinCoord.X - constraints1.MaxCoord.X);
                    // 2 to the left of 1
                    else
                        minLength = Math.Min(minLength, constraints1.MinCoord.X - constraints2.MaxCoord.X);
                }
            }

            foreach (Vector point1 in constraints1.Corners)
            {
                foreach (Vector point2 in constraints2.Corners)
                {
                    double length = (point1 - point2).Length;
                    minLength = Math.Min(minLength, length);
                    maxLength = Math.Max(maxLength, length);
                }
            }

            Range lengthRange = new Range(minLength, maxLength);

            return new BoxLengthAngleConstraints(lengthRange, angleRange);
        }
 public EdgeDescription(
     VertexConstraints vertexConstraints1,
     VertexConstraints vertexConstraints2,
     EdgeConstraints edgeConstraints)
 {
     this.VertexConstraints1 = vertexConstraints1;
     this.VertexConstraints2 = vertexConstraints2;
     this.EdgeConstraints = edgeConstraints;
 }