Ejemplo n.º 1
0
        /// <summary>
        /// Find the next connecting perimeter segment along the cutting curve
        /// </summary>
        /// <param name="segments"></param>
        /// <param name="tFrom"></param>
        /// <param name="backwards"></param>
        /// <returns></returns>
        private static PerimeterSegment FindNextPerimeterSegment(IList <PerimeterSegment> segments, double tFrom, bool backwards)
        {
            PerimeterSegment next = null;

            if (backwards)
            {
                foreach (var pSeg in segments)
                {
                    if (pSeg.CutterDomain.Start < tFrom)
                    {
                        if (next == null || next.CutterDomain.Start < pSeg.CutterDomain.Start)
                        {
                            next = pSeg;
                        }
                    }
                }
            }
            else
            {
                foreach (var pSeg in segments)
                {
                    if (pSeg.CutterDomain.Start > tFrom)
                    {
                        if (next == null || next.CutterDomain.Start > pSeg.CutterDomain.Start)
                        {
                            next = pSeg;
                        }
                    }
                }
            }
            return(next);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Split this region into two (or more) sub-regions along a straight line
        /// </summary>
        /// <param name="splitPt">A point on the splitting line</param>
        /// <param name="splitDir">The direction of the line</param>
        /// <param name="splitWidth">Optional.  The width of the split.</param>
        /// <returns>The resultant list of regions.  If the line does not bisect
        /// this region and the region could not be split, this collection will contain
        /// only the original region.</returns>
        public IList <PlanarRegion> SplitByLineXY(Vector splitPt, Vector splitDir, double splitWidth = 0)
        {
            var result    = new List <PlanarRegion>();
            var lineInts  = new List <double>();
            var outerInts = Intersect.CurveLineXY(Perimeter, splitPt, splitDir, null, 0, 1, false, lineInts);

            if (outerInts.Count > 1)
            {
                // Sort intersections by position along curve:
                var sortedInts = new SortedList <double, double>(outerInts.Count);
                for (int i = 0; i < outerInts.Count; i++)
                {
                    sortedInts.Add(outerInts[i], lineInts[i]);
                }

                outerInts = sortedInts.Keys.ToList();
                lineInts  = sortedInts.Values.ToList();
                int offset = lineInts.IndexOfMin();
                outerInts.Shift(offset);
                lineInts.Shift(offset);

                // Create segments data structure
                var segments = new List <PerimeterSegment>(outerInts.Count - 1);
                for (int i = 0; i < outerInts.Count; i++)
                {
                    double t0      = outerInts[i];
                    double t1      = outerInts.GetWrapped(i + 1);
                    double tC0     = lineInts[i];
                    double tC1     = lineInts.GetWrapped(i + 1);
                    var    segment = new PerimeterSegment(Perimeter, t0, t1, tC0, tC1);
                    segments.Add(segment);
                }

                //TODO: void intersections

                bool backwards = true;
                while (segments.Count > 0)
                {
                    var offsets = new List <double>();
                    PerimeterSegment segment = segments.First();

                    PolyCurve newPerimeter = segment.Extract().ToPolyCurve();
                    for (int i = 0; i < newPerimeter.SegmentCount; i++)
                    {
                        offsets.Add(0);
                    }
                    PerimeterSegment nextSegment = FindNextPerimeterSegment(segments, segment.CutterDomain.End, backwards);
                    while (nextSegment != null && nextSegment != segment)
                    {
                        Curve nextCurve = nextSegment.Extract();
                        newPerimeter.AddLine(nextCurve.StartPoint);
                        offsets.Add(splitWidth / 2);
                        newPerimeter.Add(nextCurve);
                        for (int i = 0; i < nextCurve.SegmentCount; i++)
                        {
                            offsets.Add(0);
                        }
                        segments.Remove(nextSegment);
                        nextSegment = FindNextPerimeterSegment(segments, nextSegment.CutterDomain.End, backwards);
                    }
                    segments.RemoveAt(0);
                    if (!newPerimeter.Closed)
                    {
                        /*if (splitWidth > 0)
                         * {
                         *  // Temporary bodge to get rid of 'blades' at ends of split
                         *  Vector endToEnd = (newPerimeter.StartPoint - newPerimeter.EndPoint).Unitize();
                         *  var line = new Line(
                         *      newPerimeter.EndPoint - endToEnd * splitWidth / 4,
                         *      newPerimeter.StartPoint + endToEnd * splitWidth / 4);
                         *  newPerimeter.AddLine(line.StartPoint);
                         *  offsets.Add(0);
                         *  newPerimeter.Add(line);
                         *  offsets.Add(splitWidth / 2);
                         *  newPerimeter.Close();
                         *  offsets.Add(0);
                         * }
                         * else
                         * {*/
                        newPerimeter.Close();
                        offsets.Add(splitWidth / 2);
                        //}
                    }
                    backwards = !backwards;

                    if (splitWidth > 0)
                    {
                        var newNewPerimeter = newPerimeter.OffsetInwards(offsets);
                        // Check offset has not inverted perimeter:
                        // TODO: Do this automatically when offsetting?
                        if (newNewPerimeter != null && newNewPerimeter.IsClockwiseXY() == newPerimeter.IsClockwiseXY())
                        {
                            newPerimeter = newNewPerimeter.ToPolyCurve();
                        }
                        else
                        {
                            newPerimeter = null;
                        }
                    }

                    if (newPerimeter != null)
                    {
                        result.Add(new PlanarRegion(newPerimeter, Attributes?.Duplicate()));
                    }
                }

                // OLD VERSION:

                /*for (int i = 0; i < outerInts.Count; i++)
                 * {
                 *  double t0 = outerInts[i];
                 *  double t1 = outerInts.GetWrapped(i + 1);
                 *  Curve newPerimeter = Perimeter.Extract(new Interval(t0, t1))?.ToPolyCurve();
                 *  //TODO: Cut through and include voids
                 *  if (!newPerimeter.Closed)
                 *  {
                 *      ((PolyCurve)newPerimeter).Close();
                 *      if (splitWidth > 0)
                 *      {
                 *          var offsets = new double[newPerimeter.SegmentCount];
                 *          offsets[offsets.Length - 1] = splitWidth / 2;
                 *          var newNewPerimeter = newPerimeter.OffsetInwards(offsets);
                 *          // Check offset has not inverted perimeter:
                 *          // TODO: Do this automatically when offsetting?
                 *          if (newNewPerimeter != null && newNewPerimeter.IsClockwiseXY() == newPerimeter.IsClockwiseXY())
                 *          {
                 *              newPerimeter = newNewPerimeter;
                 *          }
                 *          else newPerimeter = null;
                 *      }
                 *  }
                 *  if (newPerimeter != null) result.Add(new PlanarRegion(newPerimeter, Attributes?.Duplicate()));
                 * }*/
            }
            else
            {
                result.Add(this); //Return the original
            }
            return(result);
        }