/// <summary> /// Scans the vertices on the polygon until either an advance or retard step can be made. /// Used when iterating over a section of the polygon not visible from z. /// </summary> /// <param name="v"></param> /// <param name="s"></param> /// <param name="iprev"></param> /// <param name="windowEnd"></param> /// <param name="ccw"></param> /// <returns> </returns> public static NextCall Scan(ref VsRep v, ref Stack <VertDispl> s, ref int i, ref VertDispl windowEnd, ref bool ccw) { while (i < v.n) { i++; if (ccw && // CounterClockWise MathUtil.GreaterEps(v.Get(i + 1).alpha, s.Peek().alpha) && MathUtil.GEQEps(s.Peek().alpha, v.Get(i).alpha)) { VertDispl intersec = IntersectWithWindow(v.Get(i), v.Get(i + 1), s.Peek(), windowEnd); if (intersec != null && !(windowEnd != null && MathUtil.EqualsEps(intersec.p.Cartesian, windowEnd.p.Cartesian))) { s.Push(intersec); return(NextCall.ADVANCE); } } else if (!ccw && // ClockWise MathUtil.LEQEps(v.Get(i + 1).alpha, s.Peek().alpha) && s.Peek().alpha < v.Get(i).alpha) { if (IntersectWithWindow(v.Get(i), v.Get(i + 1), s.Peek(), windowEnd) != null) { return(NextCall.RETARD); } } } return(NextCall.STOP); }
/// <summary> /// Pops all vertices from the stack that have become invisible after the addition /// of a new vertex. /// Calls appropriate method (advance, scan, retard) after being done based on next vertex. /// </summary> /// <param name="v"></param> /// <param name="sOld"></param> /// <param name="iprev"></param> /// <returns></returns> public static NextCall Retard(ref VsRep v, ref Stack <VertDispl> s, ref int i, ref VertDispl w, ref bool ccw) { // LocateSj will pop vertices from the stack // until appropriated s_j is found // see paper var sjNext = LocateSj(v.Get(i), v.Get(i + 1), s); if (s.Count == 0) { return(NextCall.STOP); } var sj = s.Peek(); if (sj.alpha < v.Get(i + 1).alpha) { i++; var vi = v.Get(i); var p = (new LineSegment(sj.p.Cartesian, sjNext.p.Cartesian)).Intersect(vi.p.Ray); // fallback method, return point closest to intersection with segment line if (p == null) { var line = new Line(vi.p.Ray.origin, vi.p.Ray.origin + vi.p.Ray.direction); p = (new LineSegment(sj.p.Cartesian, sjNext.p.Cartesian)).Line.Intersect(line); p = Vector2.Distance(p.Value, sj.p.Cartesian) < Vector2.Distance(p.Value, sjNext.p.Cartesian) ? sj.p.Cartesian : sjNext.p.Cartesian; } var st1 = DisplacementInBetween(new PolarPoint2D(p.Value), sj, sjNext); if (st1 != null) { s.Push(st1); } s.Push(vi); // paper does i == v.n if (i == v.n - 1) { // TODO order of returned list correct? (check stack to list conversion) return(NextCall.STOP); } else if (MathUtil.GEQEps(v.Get(i + 1).alpha, vi.alpha) && MathUtil.Orient2D(v.Get(i - 1).p.Cartesian, vi.p.Cartesian, v.Get(i + 1).p.Cartesian) <= 0) { // -1 is RighTurn return(NextCall.ADVANCE); } else if (MathUtil.GreaterEps(v.Get(i + 1).alpha, vi.alpha) && MathUtil.Orient2D(v.Get(i - 1).p.Cartesian, vi.p.Cartesian, v.Get(i + 1).p.Cartesian) > 0) { // 1 is LeftTurn s.Pop(); w = vi; ccw = false; return(NextCall.SCAN); } else { s.Pop(); return(NextCall.RETARD); } } else { if (MathUtil.EqualsEps(v.Get(i + 1).alpha, sj.alpha) && MathUtil.GreaterEps(v.Get(i + 2).alpha, v.Get(i + 1).alpha) && MathUtil.Orient2D(v.Get(i).p.Cartesian, v.Get(i + 1).p.Cartesian, v.Get(i + 2).p.Cartesian) <= 0) { // -1 is RightTurn s.Push(v.Get(i + 1)); return(NextCall.ADVANCE); } else { w = IntersectWithWindow(v.Get(i), v.Get(i + 1), sj, sjNext); ccw = true; if (w == null) { var seg = new LineSegment(v.Get(i).p, v.Get(i + 1).p); var res = seg.ClosestPoint(sj.p.Cartesian); w = DisplacementInBetween(new PolarPoint2D(res), v.Get(i), v.Get(i + 1)); } return(NextCall.SCAN); } } }
/// <summary> /// Pushes a new vertex on the stack and calls the appropriated function /// (advance, retard, scan) depending on the next vertex on the polygon. /// </summary> /// <param name="v"></param> /// <param name="s"></param> /// <param name="i"></param> /// <returns></returns> public static NextCall Advance(ref VsRep v, ref Stack <VertDispl> s, ref int i, ref VertDispl w, ref bool ccw) { var n = v.n - 1; Debug.Assert(i + 1 <= n); if (MathUtil.LEQEps(v.Get(i + 1).alpha, MathUtil.PI2)) { i++; s.Push(v.Get(i)); // TODO check order of returned list if (i == n) { return(NextCall.STOP); } if (MathUtil.LessEps(v.Get(i + 1).alpha, v.Get(i).alpha) && MathUtil.Orient2D(v.Get(i - 1).p.Cartesian, v.Get(i).p.Cartesian, v.Get(i + 1).p.Cartesian) < 0) { // -1 is RightTurn w = null; ccw = true; return(NextCall.SCAN); } else if (MathUtil.LessEps(v.Get(i + 1).alpha, v.Get(i).alpha) && MathUtil.Orient2D(v.Get(i - 1).p.Cartesian, v.Get(i).p.Cartesian, v.Get(i + 1).p.Cartesian) > 0) { // 1 is LeftTurn return(NextCall.RETARD); } else { return(NextCall.ADVANCE); } } else { var v0 = v.Get(0); if (MathUtil.LEQEps(s.Peek().alpha, MathUtil.PI2)) { var isect = (new LineSegment(v.Get(i).p.Cartesian, v.Get(i + 1).p.Cartesian)).Intersect(v0.p.Ray); Debug.Assert(isect != null); var st = DisplacementInBetween(new PolarPoint2D(isect.Value), v.Get(i), v.Get(i + 1)); s.Push(st); } w = v0; ccw = false; return(NextCall.SCAN); } }