List <Vector2d> collapse_by_deviation_tol(List <Vector2d> input, bool[] keep_segments, double offset_threshold) { int N = input.Count; int NStop = (IsLoop) ? input.Count : input.Count - 1; List <Vector2d> result = new List <Vector2d>(); result.Add(input[0]); double thresh_sqr = offset_threshold * offset_threshold; int last_i = 0; int cur_i = 1; int skip_count = 0; if (keep_segments[0]) // if first segment is constrained { result.Add(input[1]); last_i = 1; cur_i = 2; } while (cur_i < NStop) { int i0 = cur_i, i1 = (cur_i + 1) % N; if (keep_segments[i0]) { if (last_i != i0) { // skip join segment if it is degenerate double join_dist = input[i0].Distance(result[result.Count - 1]); if (join_dist > MathUtil.Epsilon) { result.Add(input[i0]); } } result.Add(input[i1]); last_i = i1; skip_count = 0; if (i1 == 0) { cur_i = NStop; } else { cur_i = i1; } continue; } Vector2d dir = input[i1] - input[last_i]; Line2d accum_line = new Line2d(input[last_i], dir.Normalized); // find deviation of vertices between last_i and next double max_dev_sqr = 0; for (int k = last_i + 1; k <= cur_i; k++) { double distSqr = accum_line.DistanceSquared(input[k]); if (distSqr > max_dev_sqr) { max_dev_sqr = distSqr; } } // if we deviated too much, we keep this first vertex if (max_dev_sqr > thresh_sqr) { result.Add(input[cur_i]); last_i = cur_i; cur_i++; skip_count = 0; } else { // skip this vertex cur_i++; skip_count++; } } if (IsLoop) { // if we skipped everything, rest of code doesn't work if (result.Count < 3) { return(handle_tiny_case(result, input, keep_segments, offset_threshold)); } Line2d last_line = Line2d.FromPoints(input[last_i], input[cur_i % N]); bool collinear_startv = last_line.DistanceSquared(result[0]) < thresh_sqr; bool collinear_starts = last_line.DistanceSquared(result[1]) < thresh_sqr; if (collinear_startv && collinear_starts && result.Count > 3) { // last seg is collinear w/ start seg, merge them result[0] = input[last_i]; result.RemoveAt(result.Count - 1); } else if (collinear_startv) { // skip last vertex } else { result.Add(input[input.Count - 1]); } } else { // in polyline we always add last vertex result.Add(input[input.Count - 1]); } return(result); }
public IntrLine2Triangle2(Line2d l, Triangle2d t) { line = l; triangle = t; }
protected virtual void do_split(Line2d line, bool insert_edges, int insert_gid) { if (EdgeSigns.Length < Graph.MaxVertexID) { EdgeSigns.resize(Graph.MaxVertexID); } foreach (int vid in Graph.VertexIndices()) { EdgeSigns[vid] = line.WhichSide(Graph.GetVertex(vid), OnVertexTol); } hits.Clear(); foreach (int eid in Graph.EdgeIndices()) { Index2i ev = Graph.GetEdgeV(eid); var signs = new Index2i(EdgeSigns[ev.a], EdgeSigns[ev.b]); if (signs.a * signs.b > 0) { continue; // both positive or negative, ignore } var hit = new edge_hit() { hit_eid = eid, vtx_signs = signs, hit_vid = -1 }; Vector2d a = Graph.GetVertex(ev.a); Vector2d b = Graph.GetVertex(ev.b); // parallel-edge case (both are zero) if (signs.a == signs.b) { if (a.DistanceSquared(b) > MathUtil.Epsilon) { // we need to somehow not insert a new segment for this span below. // so, insert two hit points for the ray-interval, with same eid. // This will result in this span being skipped by the same-eid test below // *however*, if other edges self-intersect w/ this segment, this will *not work* // and duplicate edges will be inserted hit.hit_vid = ev.a; hit.line_t = line.Project(a); hits.Add(hit); hit.hit_vid = ev.b; hit.line_t = line.Project(b); hits.Add(hit); } else { // degenerate edge - fall through to a == 0 case below signs.b = 1; } } if (signs.a == 0) { hit.hit_pos = a; hit.hit_vid = ev.a; hit.line_t = line.Project(a); } else if (signs.b == 0) { hit.hit_pos = b; hit.hit_vid = ev.b; hit.line_t = line.Project(b); } else { var intr = new IntrLine2Segment2(line, new Segment2d(a, b)); if (intr.Find() == false) { throw new Exception("GraphSplitter2d.Split: signs are different but ray did not it?"); } if (intr.IsSimpleIntersection) { hit.hit_pos = intr.Point; hit.line_t = intr.Parameter; } else { throw new Exception("GraphSplitter2d.Split: got parallel edge case!"); } } hits.Add(hit); } // sort by increasing ray-t hits.Sort((hit0, hit1) => { return(hit0.line_t.CompareTo(hit1.line_t)); }); // insert segments between successive intersection points int N = hits.Count; for (int i = 0; i < N - 1; ++i) { int j = i + 1; // note: skipping parallel segments depends on this eid == eid test (see above) if (hits[i].line_t == hits[j].line_t || hits[i].hit_eid == hits[j].hit_eid) { continue; } int vi = hits[i].hit_vid; int vj = hits[j].hit_vid; if (vi == vj && vi >= 0) { continue; } if (vi >= 0 && vj >= 0) { int existing = Graph.FindEdge(vi, vj); if (existing >= 0) { continue; } } if (vi == -1) { DGraph2.EdgeSplitInfo split; var result = Graph.SplitEdge(hits[i].hit_eid, out split); if (result != MeshResult.Ok) { throw new Exception("GraphSplitter2d.Split: first edge split failed!"); } vi = split.vNew; Graph.SetVertex(vi, hits[i].hit_pos); edge_hit tmp = hits[i]; tmp.hit_vid = vi; hits[i] = tmp; } if (vj == -1) { DGraph2.EdgeSplitInfo split; var result = Graph.SplitEdge(hits[j].hit_eid, out split); if (result != MeshResult.Ok) { throw new Exception("GraphSplitter2d.Split: second edge split failed!"); } vj = split.vNew; Graph.SetVertex(vj, hits[j].hit_pos); edge_hit tmp = hits[j]; tmp.hit_vid = vj; hits[j] = tmp; } // check if we actually want to add this segment if (InsideTestF != null) { Vector2d midpoint = 0.5 * (Graph.GetVertex(vi) + Graph.GetVertex(vj)); if (InsideTestF(midpoint) == false) { continue; } } if (insert_edges) { Graph.AppendEdge(vi, vj, insert_gid); } } }
public IntrLine2Segment2(Line2d line, Segment2d seg) { this.line = line; segment = seg; }
public IntrLine2Line2(Line2d l1, Line2d l2) { line1 = l1; line2 = l2; }
static public double MinDistance(Line2d line, Segment2d segment) { return(new DistLine2Segment2(line, segment).Get()); }
public DistLine2Segment2(Line2d LineIn, Segment2d SegmentIn) { this.segment = SegmentIn; this.line = LineIn; }
static public double MinDistance(Line2d line1, Line2d line2) { return(new DistLine2Line2(line1, line2).Get()); }
public DistLine2Line2(Line2d Line1, Line2d Line2) { this.line2 = Line2; this.line1 = Line1; }