public Path2D(List<PolyLine3d> pls3d) { try { points = new List<Point2D>(); segments = new List<Segment2D>(); polys = new List<Polyline2D>(); minx = miny = Double.MaxValue; maxx = maxy = Double.MinValue; // create dummy points to help with sorting GetCreatePoint(0, 0); //GetCreatePoint(1000000, 1000000); foreach (PolyLine3d p3d in pls3d) { Point2D pt1 = GetCreatePoint(p3d.m_points[0].x, p3d.m_points[0].y); Point2D pt2 = GetCreatePoint(p3d.m_points[1].x, p3d.m_points[1].y); if (Object.ReferenceEquals(pt1, pt2)) // invalid segment continue; Segment2D seg = new Segment2D(pt1, pt2, p3d.m_derived.m_normal.x, p3d.m_derived.m_normal.y); segments.Add(seg); } FindIntersections(); RemoveRedundant(); ConstructPolyLines(); } catch (Exception ex) { DebugLogger.Instance().LogError(ex); } }
public double a, b; // for y = a * x + b public SegPoint(Segment2D seg, int segix, bool isleft) { isLeft = isleft; if (isleft) { pt = seg.p1.CompareTo(seg.p2) < 0 ? seg.p1 : seg.p2; if (seg.p1.x == seg.p2.x) { a = 0; b = pt.y; } else { a = (seg.p2.y - seg.p1.y) / (seg.p2.x - seg.p1.x); b = seg.p2.y - a * seg.p2.x; } } else { pt = seg.p1.CompareTo(seg.p2) < 0 ? seg.p2 : seg.p1; } this.seg = seg; this.segix = segix; }
public void Add(Segment2D seg) { // horizontal if (Math.Abs(seg.p1.x - seg.p2.x) > Path2D.Epsilon) { int from = (int)((seg.pmin.x - minx - thgap) / hgap); if (from < 0) from = 0; int to = (int)((seg.pmax.x - minx + thgap) / hgap); for (int i = from; i <= to; i++) hbins[i].Add(seg); } // vertical if (Math.Abs(seg.p1.y - seg.p2.y) > Path2D.Epsilon) { int from = (int)((seg.pmin.y - miny - tvgap) / vgap); if (from < 0) from = 0; int to = (int)((seg.pmax.y - miny + tvgap) / vgap); for (int i = from; i <= to; i++) vbins[i].Add(seg); } }
// find intersection between 2 segments. if they do intersect return new segments after // splitting originals on the intersection point. public List<Segment2D> Intersect(Segment2D seg, Path2D path) { // quickly eliminate non adjacent lines if ((seg.pmax.y <= pmin.y) || (seg.pmin.y >= pmax.y) || (seg.pmax.x <= pmin.x) || (seg.pmin.x >= pmax.x)) return null; // special case 1: sigments have same endpoints, nothing to do if ((Object.ReferenceEquals(p1, seg.p1) && Object.ReferenceEquals(p2, seg.p2)) || (Object.ReferenceEquals(p2, seg.p1) && Object.ReferenceEquals(p1, seg.p2))) return null; double x21 = p2.x - p1.x; double x43 = seg.p2.x - seg.p1.x; double y21 = p2.y - p1.y; double y43 = seg.p2.y - seg.p1.y; double c = x21 * y43 - y21 * x43; List<Segment2D> segments; // if lines are parrallel, nothing to do if (Math.Abs(c) <= Path2D.DEpsilon) return null; // lines are not parallel. if both lines share any edge, nothing to do if (Object.ReferenceEquals(p1, seg.p1) || Object.ReferenceEquals(p2, seg.p2) || Object.ReferenceEquals(p2, seg.p1) || Object.ReferenceEquals(p1, seg.p2)) return null; double x31 = seg.p1.x - p1.x; double y31 = seg.p1.y - p1.y; double u = (y43 * x31 - x43 * y31) / c; double v = (y21 * x31 - x21 * y31) / c; // if u or v are outside the 0-1 range, no intersection if ((u < -Path2D.Epsilon) || (u > 1 + Path2D.Epsilon) || (v < -Path2D.Epsilon) || (v > 1 + Path2D.Epsilon)) return null; // get intersection point Point2D ip = path.GetCreatePoint(p1.x + u * x21, p1.y + u * y21); segments = new List<Segment2D>(); // if ip is not on edge of lines, split them if (!Object.ReferenceEquals(p1, ip) && !Object.ReferenceEquals(p2, ip)) segments.AddRange(SplitAt(ip)); else segments.Add(this); if (!Object.ReferenceEquals(seg.p1, ip) && !Object.ReferenceEquals(seg.p2, ip)) segments.AddRange(seg.SplitAt(ip)); else segments.Add(seg); return segments; }
// this function finds intersection of seg with y line // if no intersection or intersecton too close to x, do nothing // find position of intersection, if it is to the right of x, update rightCount with segment direction // otherwise update leftCount with segment direction public void UpdateYcrossing(double y, double x, Segment2D seg, ref int leftCount, ref int rightCount) { int dir = 0; if ((y >= seg.p1.y) && (y < seg.p2.y)) dir = -1; else if ((y <= seg.p1.y) && (y > seg.p2.y)) dir = 1; if (dir != 0) { double u = (y - seg.p1.y) / (seg.p2.y - seg.p1.y); double xpos = seg.p1.x + u * (seg.p2.x - seg.p1.x); if (Math.Abs(xpos - x) > Path2D.Epsilon) { if (xpos > x) rightCount += dir; else leftCount -= dir; } } }
// same as UpdateYcrossing but in vertical direction public void UpdateXcrossing(double x, double y, Segment2D seg, ref int botCount, ref int topCount) { int dir = 0; if ((x >= seg.p1.x) && (x < seg.p2.x)) dir = 1; else if ((x <= seg.p1.x) && (x > seg.p2.x)) dir = -1; if (dir != 0) { double u = (x - seg.p1.x) / (seg.p2.x - seg.p1.x); double ypos = seg.p1.y + u * (seg.p2.y - seg.p1.y); if (Math.Abs(ypos - y) > Path2D.Epsilon) { if (ypos > y) topCount += dir; else botCount -= dir; } } }
// segments represent an edge where the right side is inside the object and the left side is // outside. when objects intersect some segments fall totaly inside the object. (left and right // side is in the object). These segments are now redundant so we remove them. public void RemoveRedundant() { int i, j, n_nonhoriz; List <Segment2D> lineSegs; try { // collect all horizontal segments and push them to the end, they will be processed in the vertical sweep n_nonhoriz = segments.Count; for (i = 0; i < n_nonhoriz; i++) { while ((i < n_nonhoriz) && (Math.Abs(segments[i].p1.y - segments[i].p2.y) <= Path2D.Epsilon)) { Segment2D seg = segments[i]; segments.RemoveAt(i); segments.Add(seg); n_nonhoriz--; } } SegmentBin sbin = new SegmentBin(minx, miny, maxx, maxy, 100); sbin.Add(segments); // horizontal sweep for (i = 0; i < n_nonhoriz; i++) { Segment2D seg = segments[i]; double y = seg.p1.y + 0.61263546 * (seg.p2.y - seg.p1.y); // arbitrary point between y1 and y2. double u = (y - seg.p1.y) / (seg.p2.y - seg.p1.y); double xpos = seg.p1.x + u * (seg.p2.x - seg.p1.x); int rightCount = 0; int leftCount = 0; /*for (j = 0; j < n_nonhoriz; j++) * { * if (j == i) * continue; * UpdateYcrossing(y, xpos, segments[j], ref leftCount, ref rightCount); * }*/ lineSegs = sbin.GetVbin(y); foreach (Segment2D seg1 in lineSegs) { if (!Object.ReferenceEquals(seg, seg1)) { UpdateYcrossing(y, xpos, seg1, ref leftCount, ref rightCount); } } // mark valid only the segments that one side count is zero and the other non zero if (((leftCount == 0) && (rightCount != 0)) || ((leftCount != 0) && (rightCount == 0))) { seg.isValid = true; } } // vertical sweep for (i = n_nonhoriz; i < segments.Count; i++) { Segment2D seg = segments[i]; double x = seg.p1.x + 0.61263546f * (seg.p2.x - seg.p1.x); // arbitrary point between y1 and y2. double u = (x - seg.p1.x) / (seg.p2.x - seg.p1.x); double ypos = seg.p1.y + u * (seg.p2.y - seg.p1.y); int topCount = 0; int botCount = 0; /*for (j = 0; j < segments.Count; j++) * { * if ((j == i) || (Math.Abs(segments[j].p1.x - segments[j].p2.x) <= Path2D.Epsilon)) // skip vertical lines * continue; * UpdateXcrossing(x, ypos, segments[j], ref botCount, ref topCount); * }*/ lineSegs = sbin.GetHbin(x); foreach (Segment2D seg1 in lineSegs) { if (!Object.ReferenceEquals(seg, seg1)) { UpdateXcrossing(x, ypos, seg1, ref botCount, ref topCount); } } // mark valid only the segments that one side count is zero and the other non zero if (((botCount == 0) && (topCount != 0)) || ((botCount != 0) && (topCount == 0))) { seg.isValid = true; } } } catch (Exception ex) { DebugLogger.Instance().LogError(ex); } }
// find intersection between 2 segments. if they do intersect return new segments after // splitting originals on the intersection point. public List <Segment2D> Intersect(Segment2D seg, Path2D path) { // quickly eliminate non adjacent lines if ((seg.pmax.y <= pmin.y) || (seg.pmin.y >= pmax.y) || (seg.pmax.x <= pmin.x) || (seg.pmin.x >= pmax.x)) { return(null); } // special case 1: sigments have same endpoints, nothing to do if ((Object.ReferenceEquals(p1, seg.p1) && Object.ReferenceEquals(p2, seg.p2)) || (Object.ReferenceEquals(p2, seg.p1) && Object.ReferenceEquals(p1, seg.p2))) { return(null); } double x21 = p2.x - p1.x; double x43 = seg.p2.x - seg.p1.x; double y21 = p2.y - p1.y; double y43 = seg.p2.y - seg.p1.y; double c = x21 * y43 - y21 * x43; List <Segment2D> segments; // if lines are parrallel, nothing to do if (Math.Abs(c) <= Path2D.DEpsilon) { return(null); } // lines are not parallel. if both lines share any edge, nothing to do if (Object.ReferenceEquals(p1, seg.p1) || Object.ReferenceEquals(p2, seg.p2) || Object.ReferenceEquals(p2, seg.p1) || Object.ReferenceEquals(p1, seg.p2)) { return(null); } double x31 = seg.p1.x - p1.x; double y31 = seg.p1.y - p1.y; double u = (y43 * x31 - x43 * y31) / c; double v = (y21 * x31 - x21 * y31) / c; // if u or v are outside the 0-1 range, no intersection if ((u < -Path2D.Epsilon) || (u > 1 + Path2D.Epsilon) || (v < -Path2D.Epsilon) || (v > 1 + Path2D.Epsilon)) { return(null); } // get intersection point Point2D ip = path.GetCreatePoint(p1.x + u * x21, p1.y + u * y21); segments = new List <Segment2D>(); // if ip is not on edge of lines, split them if (!Object.ReferenceEquals(p1, ip) && !Object.ReferenceEquals(p2, ip)) { segments.AddRange(SplitAt(ip)); } else { segments.Add(this); } if (!Object.ReferenceEquals(seg.p1, ip) && !Object.ReferenceEquals(seg.p2, ip)) { segments.AddRange(seg.SplitAt(ip)); } else { segments.Add(seg); } return(segments); }