public void SmoothCorner_BezierArc()
        {
            var sketch      = Sketch.Create();
            var p1          = sketch.AddPoint(new Pnt2d(0, 0));
            var p2          = sketch.AddPoint(new Pnt2d(2, 9));
            var p3          = sketch.AddPoint(new Pnt2d(10, 10));
            var p4          = sketch.AddPoint(new Pnt2d(20, 0));
            var p5          = sketch.AddPoint(new Pnt2d(18, 7));
            var bezier1     = new SketchSegmentBezier(p1, p2, p3);
            var s1          = sketch.AddSegment(bezier1);
            var arc         = new SketchSegmentArc(p3, p4, p5);
            var s2          = sketch.AddSegment(arc);
            var constraint1 = new SketchConstraintSmoothCorner(p3, true);
            var c1          = sketch.AddConstraint(constraint1);

            Assert.IsTrue(sketch.SolveConstraints(true));

            var tan1      = new Vec2d(sketch.Points[p2], sketch.Points[p3]);
            var parameter = new double[2];
            var circle    = arc.GetCircle(sketch.Points, parameter);
            var pnt       = new Pnt2d();
            var tan2      = new Vec2d();

            ElCLib.D1(parameter[0], circle, ref pnt, ref tan2);
            Assert.IsTrue(tan1.IsParallel(tan2, 0.01));
        }
        public void SmoothCorner_BezierLine()
        {
            var sketch      = Sketch.Create();
            var p1          = sketch.AddPoint(new Pnt2d(0, 0));
            var p2          = sketch.AddPoint(new Pnt2d(2, 9));
            var p3          = sketch.AddPoint(new Pnt2d(10, 10));
            var p4          = sketch.AddPoint(new Pnt2d(15, 0));
            var bezier1     = new SketchSegmentBezier(p1, p2, p3);
            var s1          = sketch.AddSegment(bezier1);
            var line        = new SketchSegmentLine(p3, p4);
            var s2          = sketch.AddSegment(line);
            var constraint1 = new SketchConstraintSmoothCorner(p3, true);
            var c1          = sketch.AddConstraint(constraint1);

            Assert.IsTrue(sketch.SolveConstraints(true));

            var tan1 = new Vec2d(sketch.Points[p2], sketch.Points[p3]);
            var tan2 = new Vec2d(sketch.Points[p3], sketch.Points[p4]);

            Assert.IsTrue(tan1.IsParallel(tan2, 0.01));
        }
        public void SmoothCorner_BezierBezier_Symmetric()
        {
            var sketch      = Sketch.Create();
            var p1          = sketch.AddPoint(new Pnt2d(0, 0));
            var p2          = sketch.AddPoint(new Pnt2d(2, 9));
            var p3          = sketch.AddPoint(new Pnt2d(10, 10));
            var p4          = sketch.AddPoint(new Pnt2d(15, 9));
            var p5          = sketch.AddPoint(new Pnt2d(20, 7));
            var p6          = sketch.AddPoint(new Pnt2d(20, 0));
            var bezier1     = new SketchSegmentBezier(p1, p2, p3);
            var s1          = sketch.AddSegment(bezier1);
            var bezier2     = new SketchSegmentBezier(p3, p4, p5, p6);
            var s2          = sketch.AddSegment(bezier2);
            var constraint1 = new SketchConstraintSmoothCorner(p3, true);
            var c1          = sketch.AddConstraint(constraint1);

            Assert.IsTrue(sketch.SolveConstraints(true));

            var tan1 = new Vec2d(sketch.Points[p2], sketch.Points[p3]);
            var tan2 = new Vec2d(sketch.Points[p3], sketch.Points[p4]);

            Assert.IsTrue(tan1.IsParallel(tan2, 0.1));
            Assert.AreEqual(tan1.Magnitude(), tan2.Magnitude(), 0.0001);
        }
        public static bool CanCreate <T>(Sketch sketch, List <int> points, List <int> segments) where T : SketchConstraint
        {
            if (points == null || segments == null)
            {
                return(false);
            }

            var type = typeof(T);

            // Requirements for point constraints
            if (points.Any())
            {
                if (segments.Count == 1)
                {
                    if (type == typeof(SketchConstraintPointOnSegment) ||
                        type == typeof(SketchConstraintPointOnMidpoint))
                    {
                        var segment = sketch.Segments[segments[0]];
                        return((segment is SketchSegmentLine || segment is SketchSegmentCircle) &&
                               !sketch.Constraints.Any(c => (c is SketchConstraintPointOnSegment || c is SketchConstraintPointOnMidpoint) && (c.Segments[0] == segments[0]) && points.Contains(c.Points[0])) &&
                               !sketch.Constraints.Any(c => c is SketchConstraintFixed && c.Points != null && points.Contains(c.Points[0])) &&
                               !points.Any(p => segment.Points.Contains(p)));
                    }
                }
                if (!segments.Any())
                {
                    if (sketch.Constraints.Any(c => c is SketchConstraintFixed &&
                                               c.Segments != null && c.Segments.Any(si => sketch.Segments[si].Points?.Any(pi => points.Contains(pi)) ?? false)))
                    {
                        // If already fixed, skip the others
                        return(false);
                    }

                    if (type == typeof(SketchConstraintHorizontalDistance))
                    {
                        return(!sketch.Constraints.Any(c => (c is SketchConstraintHorizontalDistance || c is SketchConstraintFixed) &&
                                                       c.Points != null && points.Contains(c.Points[0])));
                    }
                    if (type == typeof(SketchConstraintVerticalDistance))
                    {
                        return(!sketch.Constraints.Any(c => (c is SketchConstraintVerticalDistance || c is SketchConstraintFixed) &&
                                                       c.Points != null && points.Contains(c.Points[0])));
                    }
                    if (type == typeof(SketchConstraintFixed))
                    {
                        return(!sketch.Constraints.Any(c => (c is SketchConstraintHorizontalDistance || c is SketchConstraintVerticalDistance || c is SketchConstraintFixed) &&
                                                       c.Points != null && points.Contains(c.Points[0])));
                    }
                    if (type == typeof(SketchConstraintSmoothCorner))
                    {
                        return(SketchConstraintSmoothCorner.CanCreate(sketch, points, segments));
                    }
                }
            }

            // Requirements for segment constraints
            else if (segments.Any())
            {
                // Specific requirements for relation of exactly two segments
                if (segments.Count == 2)
                {
                    bool containsAngleBasedConstraint =
                        sketch.Constraints.Any(c => (c is SketchConstraintPerpendicular || c is SketchConstraintParallel || c is SketchConstraintAngle) &&
                                               segments.Contains(c.Segments[0]) && segments.Contains(c.Segments[1]));

                    if (type == typeof(SketchConstraintPerpendicular))
                    {
                        return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                               !containsAngleBasedConstraint);
                    }

                    if (type == typeof(SketchConstraintParallel))
                    {
                        return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                               !containsAngleBasedConstraint &&
                               !sketch.Segments[segments[0]].IsConnected(sketch.Segments[segments[1]]));
                    }

                    if (type == typeof(SketchConstraintAngle))
                    {
                        return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                               !containsAngleBasedConstraint);
                    }

                    if (type == typeof(SketchConstraintTangent))
                    {
                        return(segments.Any(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                               segments.Any(segIndex => sketch.Segments[segIndex] is SketchSegmentCircle || sketch.Segments[segIndex] is SketchSegmentArc) &&
                               !containsAngleBasedConstraint);
                    }
                }

                // Specific requirements for relation of minimum two segments
                if (segments.Count >= 2)
                {
                    if (type == typeof(SketchConstraintConcentric))
                    {
                        return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentCircle || sketch.Segments[segIndex] is SketchSegmentArc) &&
                               !sketch.Constraints.Any(c => c is SketchConstraintConcentric && segments.Contains(c.Segments[0])));
                    }

                    if (type == typeof(SketchConstraintEqual))
                    {
                        return((segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentCircle) || segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine)) &&
                               !sketch.Constraints.Any(c => c is SketchConstraintEqual && segments.Contains(c.Segments[0])));
                    }
                }

                // Specific requirements for individual segment
                if (sketch.Constraints.Any(c => c is SketchConstraintFixed && c.Segments != null && segments.Contains(c.Segments[0])))
                {
                    // If already fixed, skip the others
                    return(false);
                }

                if (type == typeof(SketchConstraintRadius))
                {
                    return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentCircle || sketch.Segments[segIndex] is SketchSegmentArc) &&
                           !sketch.Constraints.Any(c => c is SketchConstraintRadius && segments.Contains(c.Segments[0])));
                }

                if (type == typeof(SketchConstraintLength))
                {
                    return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                           !sketch.Constraints.Any(c => c is SketchConstraintLength && segments.Contains(c.Segments[0])));
                }

                if (type == typeof(SketchConstraintHorizontal))
                {
                    return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                           !sketch.Constraints.Any(c => (c is SketchConstraintHorizontal || c is SketchConstraintVertical) && segments.Contains(c.Segments[0])));
                }

                if (type == typeof(SketchConstraintVertical))
                {
                    return(segments.All(segIndex => sketch.Segments[segIndex] is SketchSegmentLine) &&
                           !sketch.Constraints.Any(c => (c is SketchConstraintHorizontal || c is SketchConstraintVertical) && segments.Contains(c.Segments[0])));
                }

                if (type == typeof(SketchConstraintFixed))
                {
                    return(!sketch.Constraints.Any(c => c.Segments != null && c.Segments.Length <= 1 && segments.Contains(c.Segments[0])));
                }
            }

            return(false);
        }