Example #1
0
        public static PolyCurve Offset(this PolyCurve curve, double offset, Vector normal = null, bool tangentExtensions = false, double tolerance = Tolerance.Distance)
        {
            if (curve == null || curve.Length() < tolerance)
            {
                return(null);
            }

            //if there are only Line segmensts switching to polyline method which is more reliable
            if (curve.Curves.All(x => x is Line))
            {
                Polyline polyline = ((Polyline)curve).Offset(offset, normal, tangentExtensions, tolerance);
                if (polyline == null)
                {
                    return(null);
                }

                return(new PolyCurve {
                    Curves = polyline.SubParts().Cast <ICurve>().ToList()
                });
            }

            List <ICurve> subParts = curve.SubParts();

            //Check if contains any circles, if so, handle them explicitly, and offset any potential leftovers by backcalling this method
            if (subParts.Any(x => x is Circle))
            {
                IEnumerable <Circle> circles            = subParts.Where(x => x is Circle).Cast <Circle>().Select(x => x.Offset(offset, normal, tangentExtensions, tolerance));
                PolyCurve            nonCirclePolyCurve = new PolyCurve {
                    Curves = curve.Curves.Where(x => !(x is Circle)).ToList()
                };
                if (nonCirclePolyCurve.Curves.Count != 0)
                {
                    nonCirclePolyCurve = nonCirclePolyCurve.Offset(offset, normal, tangentExtensions, tolerance);
                }

                nonCirclePolyCurve.Curves.AddRange(circles);
                return(nonCirclePolyCurve);
            }

            if (!curve.IsPlanar(tolerance))
            {
                BH.Engine.Reflection.Compute.RecordError("Offset works only on planar curves");
                return(null);
            }

            if (curve.IsSelfIntersecting(tolerance))
            {
                BH.Engine.Reflection.Compute.RecordError("Offset works only on non-self intersecting curves");
                return(null);
            }

            if (offset == 0)
            {
                return(curve);
            }

            bool isClosed = curve.IsClosed(tolerance);

            if (normal == null)
            {
                if (!isClosed)
                {
                    BH.Engine.Reflection.Compute.RecordError("Normal is missing. Normal vector is not needed only for closed curves");
                    return(null);
                }
                else
                {
                    normal = curve.Normal();
                }
            }

            if (offset > 0.05 * curve.Length())
            {
                return((curve.Offset(offset / 2, normal, tangentExtensions, tolerance))?.Offset(offset / 2, normal, tangentExtensions, tolerance));
            }

            PolyCurve result = new PolyCurve();

            Vector normalNormalised = normal.Normalise();

            //First - offseting each individual element
            List <ICurve> offsetCurves = new List <ICurve>();

            foreach (ICurve crv in subParts)
            {
                if (crv.IOffset(offset, normal, false, tolerance) != null)
                {
                    offsetCurves.Add(crv.IOffset(offset, normal, false, tolerance));
                }
            }

            int counter = 0;

            //removing curves that are on a wrong side of the main curve
            for (int i = 0; i < offsetCurves.Count; i++)
            {
                Point  sp        = offsetCurves[i].IStartPoint();
                Point  ep        = offsetCurves[i].IEndPoint();
                Point  mp        = offsetCurves[i].IPointAtParameter(0.5);
                Point  spOnCurve = curve.ClosestPoint(sp);
                Point  epOnCurve = curve.ClosestPoint(ep);
                Point  mpOnCurve = curve.ClosestPoint(mp);
                Vector sTan      = curve.TangentAtPoint(spOnCurve, tolerance);
                Vector eTan      = curve.TangentAtPoint(epOnCurve, tolerance);
                Vector mTan      = curve.TangentAtPoint(mpOnCurve, tolerance);
                Vector sCheck    = sp - spOnCurve;
                Vector eCheck    = ep - epOnCurve;
                Vector mCheck    = mp - mpOnCurve;
                Vector sCP       = sTan.CrossProduct(sCheck).Normalise();
                Vector eCP       = eTan.CrossProduct(eCheck).Normalise();
                Vector mCP       = mTan.CrossProduct(mCheck).Normalise();
                if (offset > 0)
                {
                    if (sCP.IsEqual(normalNormalised, tolerance) && eCP.IsEqual(normalNormalised, tolerance) && mCP.IsEqual(normalNormalised, tolerance))
                    {
                        offsetCurves.RemoveAt(i);
                        i--;
                        counter++;
                    }
                }
                else
                {
                    if (!sCP.IsEqual(normalNormalised, tolerance) && !eCP.IsEqual(normalNormalised, tolerance) && !mCP.IsEqual(normalNormalised, tolerance))
                    {
                        offsetCurves.RemoveAt(i);
                        i--;
                        counter++;
                    }
                }
            }

            //Again if there are only Line segments switching to polyline method as it is more reliable
            if (offsetCurves.All(x => x is Line))
            {
                Polyline polyline = new Polyline {
                    ControlPoints = curve.DiscontinuityPoints()
                };
                result.Curves.AddRange(polyline.Offset(offset, normal, tangentExtensions, tolerance).SubParts());
                return(result);
            }

            bool connectingError = false;

            //Filleting offset curves to create continuous curve
            for (int i = 0; i < offsetCurves.Count; i++)
            {
                int j;
                if (i == offsetCurves.Count - 1)
                {
                    if (isClosed)
                    {
                        j = 0;
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    j = i + 1;
                }

                PolyCurve temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance);
                if (temp == null) //trying to fillet with next curve
                {
                    offsetCurves.RemoveAt(j);

                    if (j == 0)
                    {
                        i--;
                    }

                    if (j == offsetCurves.Count)
                    {
                        j = 0;
                    }
                    temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance);
                }

                if (!(temp == null)) //inserting filetted curves
                {
                    if (j != 0)
                    {
                        offsetCurves.RemoveRange(i, 2);
                        offsetCurves.InsertRange(i, temp.Curves);
                    }
                    else
                    {
                        offsetCurves.RemoveAt(i);
                        offsetCurves.RemoveAt(0);
                        offsetCurves.InsertRange(i - 1, temp.Curves);
                    }
                    i = i + temp.Curves.Count - 2;
                }
                else
                {
                    connectingError = true;
                }
            }

            //removing curves that are to close to the main curve
            for (int i = 0; i < offsetCurves.Count; i++)
            {
                if ((offsetCurves[i].IPointAtParameter(0.5).Distance(curve) + tolerance < Math.Abs(offset) &&
                     (offsetCurves[i].IStartPoint().Distance(curve) + tolerance < Math.Abs(offset) ||
                      offsetCurves[i].IEndPoint().Distance(curve) + tolerance < Math.Abs(offset))))
                {
                    PolyCurve temp = offsetCurves[((i - 1) + offsetCurves.Count) % offsetCurves.Count].Fillet(offsetCurves[(i + 1) % offsetCurves.Count], tangentExtensions, true, false, tolerance);
                    if (temp != null)
                    {
                        if (i == 0)
                        {
                            offsetCurves.RemoveRange(0, 2);
                            offsetCurves.RemoveAt(offsetCurves.Count - 1);
                            offsetCurves.InsertRange(0, temp.Curves);
                            i = temp.Curves.Count - 1;
                        }
                        else if (i == offsetCurves.Count - 1)
                        {
                            offsetCurves.RemoveRange(i - 1, 2);
                            offsetCurves.RemoveAt(0);
                            offsetCurves.InsertRange(offsetCurves.Count - 1, temp.Curves);
                            i = offsetCurves.Count - 1;
                        }
                        else
                        {
                            offsetCurves.RemoveRange(i - 1, 3);
                            offsetCurves.InsertRange(i - 1, temp.Curves);
                            i = i - 3 + temp.Curves.Count;
                        }
                    }

                    if (offsetCurves.Count < 1)
                    {
                        Reflection.Compute.ClearCurrentEvents();
                        Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null.");
                        return(null);
                    }
                    counter++;
                }
            }

            Reflection.Compute.ClearCurrentEvents();

            if (connectingError)
            {
                Reflection.Compute.RecordWarning("Couldn't connect offset subCurves properly.");
            }

            if (offsetCurves.Count == 0)
            {
                Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null.");
                return(null);
            }

            List <PolyCurve> resultList = Compute.IJoin(offsetCurves, tolerance);

            if (resultList.Count == 1)
            {
                result = resultList[0];
            }
            else
            {
                result.Curves = offsetCurves;
                Reflection.Compute.RecordWarning("Offset may be wrong. Please inspect the results.");
            }

            if (counter > 0)
            {
                Reflection.Compute.RecordWarning("Reduced " + counter + " line(s). Please inspect the results.");
            }

            if (result.IsSelfIntersecting(tolerance) || result.CurveIntersections(curve, tolerance).Count != 0)
            {
                Reflection.Compute.RecordWarning("Intersections occured. Please inspect the results.");
            }

            if (isClosed && !result.IsClosed(tolerance))
            {
                Reflection.Compute.RecordError("Final curve is not closed. Please inspect the results.");
            }

            return(result);
        }
Example #2
0
        /***************************************************/

        private static PolyCurve Fillet(this ICurve curve1, ICurve curve2, bool tangentExtensions, bool keepCurve1StartPoint, bool keepCurve2StartPoint, double tolerance = Tolerance.Distance)
        {
            //TODO:
            //Write a proper fillet method, test and make it public

            if (!((curve1 is Line || curve1 is Arc) && (curve2 is Line || curve2 is Arc))) //for now works only with combinations of lines and arcs
            {
                Reflection.Compute.RecordError("Private method fillet is implemented only for PolyCurves consisting of Lines or Arcs.");
                return(null);
            }

            List <PolyCurve> joinCurves = Compute.IJoin(new List <ICurve> {
                curve1, curve2
            }, tolerance).ToList();

            if (joinCurves.Count == 1)
            {
                return(joinCurves[0]);
            }

            List <ICurve> resultCurves = new List <ICurve>();

            bool C1SP = keepCurve1StartPoint;
            bool C2SP = keepCurve2StartPoint;

            List <Point> intersections = curve1.ICurveIntersections(curve2, tolerance);

            if (intersections.Count > 2)
            {
                Reflection.Compute.RecordError("Invalid number of intersections between curves. Two lines/arcs can have no more than two intersections.");
            }
            else if (intersections.Count == 2 || intersections.Count == 1)
            {
                Point intersection = intersections[0];
                if (intersections.Count == 2)
                {
                    double maxdist = double.MaxValue;
                    if (C1SP)
                    {
                        foreach (Point p in intersections)
                        {
                            double dist = p.SquareDistance(curve1.IStartPoint());
                            if (dist < maxdist)
                            {
                                intersection = p;
                                maxdist      = dist;
                            }
                        }
                    }
                    else
                    {
                        foreach (Point p in intersections)
                        {
                            double dist = p.SquareDistance(curve1.IEndPoint());
                            if (dist < maxdist)
                            {
                                intersection = p;
                                maxdist      = dist;
                            }
                        }
                    }
                }
                else
                {
                    intersection = intersections[0];
                }

                if (C1SP && C2SP)
                {
                    resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                    resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance));
                    resultCurves[1] = resultCurves[1].IFlip();
                }
                else if (C1SP && !C2SP)
                {
                    resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                    resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                }
                else if (!C1SP && C2SP)
                {
                    resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance));
                    resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance));
                    resultCurves[0] = resultCurves[0].IFlip();
                    resultCurves[1] = resultCurves[1].IFlip();
                }
                else
                {
                    resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance));
                    resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                    resultCurves[0] = resultCurves[0].IFlip();
                }
            }
            else
            {
                if (curve1 is Line && curve2 is Line)
                {
                    Point intersection = (curve1 as Line).LineIntersection(curve2 as Line, true, tolerance);
                    if (C1SP && C2SP)
                    {
                        if ((curve1.IStartPoint().Distance((curve2 as Line), true) < curve1.IEndPoint().Distance((curve2 as Line), true) &&
                             !intersection.IIsOnCurve(curve1)) ||
                            (curve2.IStartPoint().Distance((curve1 as Line), true) < curve2.IEndPoint().Distance((curve1 as Line), true) &&
                             !intersection.IIsOnCurve(curve2)))
                        {
                            Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input");
                            return(null);
                        }
                        resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                        resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance));
                        resultCurves[1] = resultCurves[1].IFlip();
                    }
                    else if (C1SP && !C2SP)
                    {
                        if ((curve1.IStartPoint().Distance((curve2 as Line), true) < curve1.IEndPoint().Distance((curve2 as Line), true) &&
                             !intersection.IIsOnCurve(curve1)) ||
                            (curve2.IStartPoint().Distance((curve1 as Line), true) > curve2.IEndPoint().Distance((curve1 as Line), true) &&
                             !intersection.IIsOnCurve(curve2)))
                        {
                            Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input");
                            return(null);
                        }
                        resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                        resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                    }
                    else if (!C1SP && C2SP)
                    {
                        if ((curve1.IStartPoint().Distance((curve2 as Line), true) > curve1.IEndPoint().Distance((curve2 as Line), true) &&
                             !intersection.IIsOnCurve(curve1)) ||
                            (curve2.IStartPoint().Distance((curve1 as Line), true) < curve2.IEndPoint().Distance((curve1 as Line), true) &&
                             !intersection.IIsOnCurve(curve2)))
                        {
                            Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input");
                            return(null);
                        }
                        resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance));
                        resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance));
                        resultCurves[0] = resultCurves[0].IFlip();
                        resultCurves[1] = resultCurves[1].IFlip();
                    }
                    else
                    {
                        if ((curve1.IStartPoint().Distance((curve2 as Line), true) > curve1.IEndPoint().Distance((curve2 as Line), true) &&
                             !intersection.IIsOnCurve(curve1)) ||
                            (curve2.IStartPoint().Distance((curve1 as Line), true) > curve2.IEndPoint().Distance((curve1 as Line), true) &&
                             !intersection.IIsOnCurve(curve2)))
                        {
                            Reflection.Compute.RecordWarning("Couldn't provide correct fillet for given input");
                            return(null);
                        }
                        resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance));
                        resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                        resultCurves[0] = resultCurves[0].IFlip();
                    }
                }
                else
                {
                    Point intersection;
                    if (!tangentExtensions)
                    {
                        PolyCurve pCurve1 = new PolyCurve();
                        PolyCurve pCurve2 = new PolyCurve();
                        if (curve1 is Arc)
                        {
                            pCurve1.Curves.Add(new Circle {
                                Centre = (curve1 as Arc).Centre(), Normal = (curve1 as Arc).Normal(), Radius = (curve1 as Arc).Radius
                            });
                        }
                        else
                        {
                            pCurve1.Curves.Add(new Line {
                                Start = (curve1 as Line).Start, End = (curve1 as Line).End, Infinite = true
                            });
                        }

                        if (curve2 is Arc)
                        {
                            pCurve2.Curves.Add(new Circle {
                                Centre = (curve2 as Arc).Centre(), Normal = (curve2 as Arc).Normal(), Radius = (curve2 as Arc).Radius
                            });
                        }
                        else
                        {
                            pCurve2.Curves.Add(new Line {
                                Start = (curve2 as Line).Start, End = (curve2 as Line).End, Infinite = true
                            });
                        }

                        List <Point> curveIntersections = pCurve1.CurveIntersections(pCurve2, tolerance);
                        if (curveIntersections.Count == 0)
                        {
                            Reflection.Compute.RecordError("Curves' extensions do not intersect");
                            return(null);
                        }
                        if (C1SP && C2SP)
                        {
                            intersection = curveIntersections.ClosestPoint(curve1.IEndPoint());

                            resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                            resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance));
                            resultCurves[1] = resultCurves[1].IFlip();
                        }
                        else if (C1SP && !C2SP)
                        {
                            intersection = curveIntersections.ClosestPoint(curve1.IEndPoint());
                            resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                            resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                        }
                        else if (!C1SP && C2SP)
                        {
                            intersection = curveIntersections.ClosestPoint(curve1.IStartPoint());
                            resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance));
                            resultCurves.AddRange(curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance));
                            resultCurves[0] = resultCurves[0].IFlip();
                            resultCurves[1] = resultCurves[1].IFlip();
                        }
                        else
                        {
                            intersection = curveIntersections.ClosestPoint(curve1.IStartPoint());
                            resultCurves.AddRange(curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance));
                            resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                            resultCurves[0] = resultCurves[0].IFlip();
                        }
                    }
                    else
                    {
                        if (C1SP && C2SP)
                        {
                            Line tanLine1 = Create.Line(curve1.IEndPoint(), curve1.IEndDir() / tolerance);
                            tanLine1.Infinite = false;
                            PolyCurve pCurve1 = new PolyCurve {
                                Curves = { curve1, tanLine1 }
                            };

                            Line tanLine2 = Create.Line(curve2.IEndPoint(), curve2.IEndDir() / tolerance);
                            tanLine2.Infinite = false;
                            PolyCurve pCurve2 = new PolyCurve {
                                Curves = { curve2, tanLine2 }
                            };

                            List <Point> curveIntersecions = pCurve1.CurveIntersections(pCurve2, tolerance);
                            if (curveIntersecions.Count > 0)
                            {
                                intersection = curveIntersecions.ClosestPoint(curve1.IEndPoint());
                            }
                            else
                            {
                                Reflection.Compute.RecordWarning("Couldn't create fillet");
                                return(null);
                            }

                            PolyCurve subResult1 = new PolyCurve
                            {
                                Curves = curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance).ToList()
                            };

                            PolyCurve subResult2 = new PolyCurve
                            {
                                Curves = curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance).ToList()
                            };

                            subResult2 = subResult2.Flip();

                            resultCurves.AddRange(subResult1.Curves);
                            resultCurves.AddRange(subResult2.Curves);
                        }
                        else if (C1SP && !C2SP)
                        {
                            Line tanLine1 = Create.Line(curve1.IEndPoint(), curve1.IEndDir() / tolerance);
                            tanLine1.Infinite = false;
                            PolyCurve pCurve1 = new PolyCurve {
                                Curves = { curve1, tanLine1 }
                            };

                            Line tanLine2 = Create.Line(curve2.IStartPoint(), curve2.IStartDir().Reverse() / tolerance);
                            tanLine2.Infinite = false;
                            PolyCurve pCurve2 = new PolyCurve {
                                Curves = { tanLine2, curve2 }
                            };

                            List <Point> curveIntersecions = pCurve1.ICurveIntersections(pCurve2, tolerance);

                            if (curveIntersecions.Count > 0)
                            {
                                intersection = curveIntersecions.ClosestPoint(curve1.IEndPoint());
                            }
                            else
                            {
                                Reflection.Compute.RecordWarning("Couldn't create fillet");
                                return(null);
                            }

                            resultCurves.AddRange(curve1.ExtendToPoint(curve1.IStartPoint(), intersection, tangentExtensions, tolerance));
                            resultCurves.AddRange(curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance));
                        }
                        else if (!C1SP && C2SP)
                        {
                            Line tanLine1 = Create.Line(curve1.IStartPoint(), curve1.IStartDir().Reverse() / tolerance);
                            tanLine1.Infinite = false;
                            PolyCurve pCurve1 = new PolyCurve {
                                Curves = { tanLine1, curve1 }
                            };

                            Line tanLine2 = Create.Line(curve2.IEndPoint(), curve2.IEndDir() / tolerance);
                            tanLine2.Infinite = false;
                            PolyCurve pCurve2 = new PolyCurve {
                                Curves = { curve2, tanLine2 }
                            };

                            List <Point> curveIntersecions = pCurve1.ICurveIntersections(pCurve2, tolerance);
                            if (curveIntersecions.Count > 0)
                            {
                                intersection = curveIntersecions.ClosestPoint(curve1.IStartPoint());
                            }
                            else
                            {
                                Reflection.Compute.RecordWarning("Couldn't create fillet");
                                return(null);
                            }
                            PolyCurve subResult1 = new PolyCurve
                            {
                                Curves = curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance).ToList()
                            };
                            PolyCurve subResult2 = new PolyCurve
                            {
                                Curves = curve2.ExtendToPoint(curve2.IStartPoint(), intersection, tangentExtensions, tolerance).ToList()
                            };

                            subResult1 = subResult1.Flip();
                            subResult2 = subResult2.Flip();

                            resultCurves.AddRange(subResult1.Curves);
                            resultCurves.AddRange(subResult2.Curves);
                        }
                        else
                        {
                            Line tanLine1 = Create.Line(curve1.IStartPoint(), curve1.IStartDir().Reverse() / tolerance);
                            tanLine1.Infinite = false;
                            PolyCurve pCurve1 = new PolyCurve {
                                Curves = { tanLine1, curve1 }
                            };

                            Line tanLine2 = Create.Line(curve2.IStartPoint(), curve2.IStartDir().Reverse() / tolerance);
                            tanLine2.Infinite = false;
                            PolyCurve pCurve2 = new PolyCurve {
                                Curves = { tanLine2, curve2 }
                            };

                            List <Point> curveIntersecions = pCurve1.ICurveIntersections(pCurve2, tolerance);
                            if (curveIntersecions.Count > 0)
                            {
                                intersection = curveIntersecions.ClosestPoint(curve1.IStartPoint());
                            }
                            else
                            {
                                Reflection.Compute.RecordWarning("Couldn't create fillet");
                                return(null);
                            }
                            PolyCurve subResult1 = new PolyCurve
                            {
                                Curves = curve1.ExtendToPoint(intersection, curve1.IEndPoint(), tangentExtensions, tolerance).ToList()
                            };
                            PolyCurve subResult2 = new PolyCurve
                            {
                                Curves = curve2.ExtendToPoint(intersection, curve2.IEndPoint(), tangentExtensions, tolerance).ToList()
                            };

                            subResult1 = subResult1.Flip();

                            resultCurves.AddRange(subResult1.Curves);
                            resultCurves.AddRange(subResult2.Curves);
                        }
                    }
                }
            }

            for (int i = resultCurves.Count - 1; i >= 0; i--)
            {
                if (resultCurves[i] is PolyCurve)
                {
                    PolyCurve temp = (PolyCurve)resultCurves[i];
                    resultCurves.RemoveAt(i);
                    resultCurves.InsertRange(i, temp.Curves);
                }
            }

            PolyCurve result = new PolyCurve {
                Curves = resultCurves
            };

            return(result);
        }
Example #3
0
        public static PolyCurve OffsetVariable(this PolyCurve curve, List <double> offsets, Vector normal = null, bool tangentExtensions = false, double tolerance = Tolerance.Distance)
        {
            //TODO:
            //Migrate to Geometry Engine and align with Offset method
            if (curve == null || curve.Length() < tolerance)
            {
                return(null);
            }

            List <ICurve> subParts = curve.SubParts();

            if (subParts.Count != offsets.Count)
            {
                BH.Engine.Reflection.Compute.RecordError("PolyCurve segment count does not match amount of offset values provided.");
                return(null);
            }

            //Check if contains any circles, if so, handle them explicitly, and offset any potential leftovers by backcalling this method
            if (subParts.Any(x => x is Circle))
            {
                curve.Offset(offsets[0]);
                return(null);
            }

            if (!curve.IsPlanar(tolerance))
            {
                BH.Engine.Reflection.Compute.RecordError("Offset works only on planar curves");
                return(null);
            }

            if (curve.IsSelfIntersecting(tolerance))
            {
                BH.Engine.Reflection.Compute.RecordError("Offset works only on non-self intersecting curves");
                return(null);
            }

            bool isClosed = curve.IsClosed(tolerance);

            if (normal == null)
            {
                if (!isClosed)
                {
                    BH.Engine.Reflection.Compute.RecordError("Normal is missing. Normal vector is not needed only for closed curves");
                    return(null);
                }
                else
                {
                    normal = curve.Normal();
                }
            }

            PolyCurve result           = new PolyCurve();
            Vector    normalNormalised = normal.Normalise();

            //First - offseting each individual element
            List <ICurve> offsetCurves = new List <ICurve>();

            for (int i = 0; i < subParts.Count; i++)
            {
                if (subParts[i].IOffset(offsets[i], normal, false, tolerance) != null)
                {
                    offsetCurves.Add(subParts[i].IOffset(offsets[i], normal, false, tolerance));
                }
            }

            bool connectingError = false;

            //Filleting offset curves to create continuous curve
            for (int i = 0; i < offsetCurves.Count; i++)
            {
                int j;
                if (i == offsetCurves.Count - 1)
                {
                    if (isClosed)
                    {
                        j = 0;
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    j = i + 1;
                }

                PolyCurve temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance);
                if (temp == null) //trying to fillet with next curve
                {
                    offsetCurves.RemoveAt(j);

                    if (j == 0)
                    {
                        i--;
                    }

                    if (j == offsetCurves.Count)
                    {
                        j = 0;
                    }
                    temp = offsetCurves[i].Fillet(offsetCurves[j], tangentExtensions, true, false, tolerance);
                }

                if (!(temp == null)) //inserting filetted curves
                {
                    if (j != 0)
                    {
                        offsetCurves.RemoveRange(i, 2);
                        offsetCurves.InsertRange(i, temp.Curves);
                    }
                    else
                    {
                        offsetCurves.RemoveAt(i);
                        offsetCurves.RemoveAt(0);
                        offsetCurves.InsertRange(i - 1, temp.Curves);
                    }
                    i = i + temp.Curves.Count - 2;
                }
                else
                {
                    connectingError = true;
                }
            }

            Reflection.Compute.ClearCurrentEvents();

            if (connectingError)
            {
                Reflection.Compute.RecordWarning("Couldn't connect offset subCurves properly.");
            }

            if (offsetCurves.Count == 0)
            {
                Reflection.Compute.RecordError("Method failed to produce correct offset. Returning null.");
                return(null);
            }

            List <PolyCurve> resultList = Geometry.Compute.IJoin(offsetCurves, tolerance);

            if (resultList.Count == 1)
            {
                result = resultList[0];
            }
            else
            {
                result.Curves = offsetCurves;
                Reflection.Compute.RecordWarning("Offset may be wrong. Please inspect the results.");
            }

            if (result.IsSelfIntersecting(tolerance) || result.CurveIntersections(curve, tolerance).Count != 0)
            {
                Reflection.Compute.RecordWarning("Intersections occured. Please inspect the results.");
            }

            if (isClosed && !result.IsClosed(tolerance))
            {
                Reflection.Compute.RecordError("Final curve is not closed. Please inspect the results.");
            }

            return(result);
        }