internal SweepComparator(com.epl.geometry.EditShape shape, double tol, bool bIsSimple) : base(true) { m_shape = shape; m_sweep_y = com.epl.geometry.NumberUtils.TheNaN; m_sweep_x = 0; m_prev_x = 0; m_prev_y = com.epl.geometry.NumberUtils.TheNaN; m_tolerance = tol; m_tolerance_10 = 10 * tol; m_prevx_2 = com.epl.geometry.NumberUtils.TheNaN; m_prevx_1 = com.epl.geometry.NumberUtils.TheNaN; m_b_intersection_detected = false; m_prev_1 = -1; m_prev_2 = -1; m_vertex_1 = -1; m_vertex_2 = -1; m_current_node = -1; m_b_is_simple = bIsSimple; m_temp_simple_edge_1 = new com.epl.geometry.SweepComparator.SimpleEdge(); m_temp_simple_edge_2 = new com.epl.geometry.SweepComparator.SimpleEdge(); int s = System.Math.Min(shape.GetTotalPointCount() * 3 / 2, (int)(67)); /* SIMPLEDGE_CACHESIZE */ int cache_size = System.Math.Min((int)7, s); // m_simple_edges_buffer.reserve(cache_size);//must be reserved and // never grow beyond reserved size m_simple_edges_buffer = new System.Collections.Generic.List <com.epl.geometry.SweepComparator.SimpleEdge>(); m_simple_edges_recycle = new System.Collections.Generic.List <com.epl.geometry.SweepComparator.SimpleEdge>(); m_simple_edges_cache = new System.Collections.Generic.List <com.epl.geometry.SweepComparator.SimpleEdge>(); for (int i = 0; i < cache_size; i++) { m_simple_edges_cache.Add(null); } }
// The value has not been cached // Creates a cached edge. May fail and return NULL. internal virtual com.epl.geometry.SweepComparator.SimpleEdge TryCreateCachedEdge_(int value) { int ind = (value & com.epl.geometry.NumberUtils.IntMax()) % m_simple_edges_cache.Count; com.epl.geometry.SweepComparator.SimpleEdge se = m_simple_edges_cache[ind]; if (se == null) { if ((m_simple_edges_recycle.Count == 0)) { // assert(m_simple_edges_buffer.size() < // m_simple_edges_buffer.capacity());//should never happen // assert(m_simple_edges_buffer.size() < // m_simple_edges_cache.size());//should never happen m_simple_edges_buffer.Add(new com.epl.geometry.SweepComparator.SimpleEdge()); se = m_simple_edges_buffer[m_simple_edges_buffer.Count - 1]; } else { se = m_simple_edges_recycle[m_simple_edges_recycle.Count - 1]; m_simple_edges_recycle.RemoveAt(m_simple_edges_recycle.Count - 1); } se.m_value = value; m_simple_edges_cache[ind] = se; return(se); } else { System.Diagnostics.Debug.Assert((se.m_value != value)); } // do not call TryCreateCachedEdge // twice. return(null); }
// Removes cached edge from the cache for the given value. internal virtual void TryDeleteCachedEdge_(int value) { int ind = (value & com.epl.geometry.NumberUtils.IntMax()) % m_simple_edges_cache.Count; com.epl.geometry.SweepComparator.SimpleEdge se = m_simple_edges_cache[ind]; if (se != null && se.m_value == value) { // this value is cached m_simple_edges_recycle.Add(se); m_simple_edges_cache[ind] = null; } }
// Index 1 corresponds to the left segments, index 2 - right, e.g. m_line_1, // m_line_2 // Returns a cached edge for the given value. May return NULL. internal virtual com.epl.geometry.SweepComparator.SimpleEdge TryGetCachedEdge_(int value) { com.epl.geometry.SweepComparator.SimpleEdge se = m_simple_edges_cache[(value & com.epl.geometry.NumberUtils.IntMax()) % m_simple_edges_cache.Count]; if (se != null) { if (se.m_value == value) { return(se); } } // int i = 0; // cache collision return(null); }
internal virtual void InitSimpleEdge_(com.epl.geometry.SweepComparator.SimpleEdge se, int vertex) { se.m_segment = m_shape.GetSegment(vertex); se.m_b_curve = se.m_segment != null; if (!se.m_b_curve) { m_shape.QueryLineConnector(vertex, se.m_line); se.m_segment = se.m_line; se.m_env.SetCoordsNoNaN_(se.m_line.GetStartX(), se.m_line.GetEndX()); se.m_env.vmax += m_tolerance; se.m_line.OrientBottomUp_(); se.m_b_horizontal = se.m_line.GetEndY() == se.m_line.GetStartY(); if (!se.m_b_horizontal) { se.m_dxdy = (se.m_line.GetEndX() - se.m_line.GetStartX()) / (se.m_line.GetEndY() - se.m_line.GetStartY()); } } }
internal virtual int CompareNonHorizontal_(com.epl.geometry.SweepComparator.SimpleEdge line_1, com.epl.geometry.SweepComparator.SimpleEdge line_2) { if (line_1.m_line.GetStartY() == line_2.m_line.GetStartY() && line_1.m_line.GetStartX() == line_2.m_line.GetStartX()) { // connected // at // the // start // V // shape if (line_1.m_line.GetEndY() == line_2.m_line.GetEndY() && line_1.m_line.GetEndX() == line_2.m_line.GetEndX()) { // connected // at // another // end // also if (m_b_is_simple) { return(ErrorCoincident()); } return(0); } return(CompareNonHorizontalUpperEnd_(line_1, line_2)); } if (line_1.m_line.GetEndY() == line_2.m_line.GetEndY() && line_1.m_line.GetEndX() == line_2.m_line.GetEndX()) { // the case of upside-down V. return(CompareNonHorizontalLowerEnd_(line_1, line_2)); } int lower = CompareNonHorizontalLowerEnd_(line_1, line_2); int upper = CompareNonHorizontalUpperEnd_(line_1, line_2); if (lower < 0 && upper < 0) { return(-1); } if (lower > 0 && upper > 0) { return(1); } return(ErrorCracking()); }
internal virtual int CompareNonHorizontalUpperEnd_(com.epl.geometry.SweepComparator.SimpleEdge line_1, com.epl.geometry.SweepComparator.SimpleEdge line_2) { int sign = 1; if (line_2.m_line.GetEndY() < line_1.m_line.GetEndY()) { sign = -1; com.epl.geometry.SweepComparator.SimpleEdge tmp = line_1; line_1 = line_2; line_2 = tmp; } com.epl.geometry.Line l1 = line_1.m_line; com.epl.geometry.Line l2 = line_2.m_line; // Now line_1 has End point lower than line_2 endpoint. double x_1 = l1.GetEndX() - l2.GetStartX(); double x2 = line_2.m_dxdy * (l1.GetEndY() - l2.GetStartY()); double tol = m_tolerance_10; if (x_1 < x2 - tol) { return(-sign); } else { if (x_1 > x2 + tol) { return(sign); } else { // Possible problem if (l2._isIntersectingPoint(l1.GetEndXY(), m_tolerance, true)) { return(ErrorCracking()); } return(x_1 < x2 ? -sign : sign); } } }
internal virtual int CompareSegments(int leftElm, int left_vertex, int right_elm, int right_vertex) { com.epl.geometry.SweepComparator.SimpleEdge edgeLeft = TryGetCachedEdge_(leftElm); if (edgeLeft == null) { if (m_vertex_1 == left_vertex) { edgeLeft = m_temp_simple_edge_1; } else { m_vertex_1 = left_vertex; edgeLeft = TryCreateCachedEdge_(leftElm); if (edgeLeft == null) { edgeLeft = m_temp_simple_edge_1; m_temp_simple_edge_1.m_value = leftElm; } InitSimpleEdge_(edgeLeft, left_vertex); } } else { m_vertex_1 = left_vertex; } com.epl.geometry.SweepComparator.SimpleEdge edgeRight = TryGetCachedEdge_(right_elm); if (edgeRight == null) { if (m_vertex_2 == right_vertex) { edgeRight = m_temp_simple_edge_2; } else { m_vertex_2 = right_vertex; edgeRight = TryCreateCachedEdge_(right_elm); if (edgeRight == null) { edgeRight = m_temp_simple_edge_2; m_temp_simple_edge_2.m_value = right_elm; } InitSimpleEdge_(edgeRight, right_vertex); } } else { m_vertex_2 = right_vertex; } if (edgeLeft.m_b_curve || edgeRight.m_b_curve) { return(CompareSegments_(left_vertex, right_vertex, edgeLeft, edgeRight)); } // Usually we work with lines, so process them in the fastest way. // First check - assume segments are far apart. compare x intervals if (edgeLeft.m_env.vmax < edgeRight.m_env.vmin) { return(-1); } if (edgeRight.m_env.vmax < edgeLeft.m_env.vmin) { return(1); } // compare case by case. int kind = edgeLeft.m_b_horizontal ? 1 : 0; kind |= edgeRight.m_b_horizontal ? 2 : 0; if (kind == 0) { // both segments are non-horizontal return(CompareNonHorizontal_(edgeLeft, edgeRight)); } else { if (kind == 1) { // line_1 horizontal, line_2 is not return(CompareHorizontal1_(edgeLeft.m_line, edgeRight.m_line)); } else { if (kind == 2) { // line_2 horizontal, line_1 is not return(CompareHorizontal1_(edgeRight.m_line, edgeLeft.m_line) * -1); } else { // if (kind == 3) //both horizontal return(CompareHorizontal2_(edgeLeft.m_line, edgeRight.m_line)); } } } }
internal virtual int CompareSegments_(int left, int right, com.epl.geometry.SweepComparator.SimpleEdge segLeft, com.epl.geometry.SweepComparator.SimpleEdge segRight) { if (m_b_intersection_detected) { return(-1); } bool sameY = m_prev_y == m_sweep_y && m_prev_x == m_sweep_x; double xleft; if (sameY && left == m_prev_1) { xleft = m_prevx_1; } else { xleft = com.epl.geometry.NumberUtils.NaN(); m_prev_1 = -1; } double xright; if (sameY && right == m_prev_2) { xright = m_prevx_2; } else { xright = com.epl.geometry.NumberUtils.NaN(); m_prev_2 = -1; } // Quickly compare x projections. com.epl.geometry.Envelope1D envLeft = segLeft.m_segment.QueryInterval(com.epl.geometry.VertexDescription.Semantics.POSITION, 0); com.epl.geometry.Envelope1D envRight = segRight.m_segment.QueryInterval(com.epl.geometry.VertexDescription.Semantics.POSITION, 0); if (envLeft.vmax < envRight.vmin) { return(-1); } if (envRight.vmax < envLeft.vmin) { return(1); } m_prev_y = m_sweep_y; m_prev_x = m_sweep_x; // Now do intersection with the sweep line (it is a line parallel to the // axis x.) if (com.epl.geometry.NumberUtils.IsNaN(xleft)) { m_prev_1 = left; double x = segLeft.m_segment.IntersectionOfYMonotonicWithAxisX(m_sweep_y, m_sweep_x); xleft = x; m_prevx_1 = x; } if (com.epl.geometry.NumberUtils.IsNaN(xright)) { m_prev_2 = right; double x = segRight.m_segment.IntersectionOfYMonotonicWithAxisX(m_sweep_y, m_sweep_x); xright = x; m_prevx_2 = x; } if (System.Math.Abs(xleft - xright) <= m_tolerance) { // special processing as we cannot decide in a simple way. return(CompareTwoSegments_(segLeft.m_segment, segRight.m_segment)); } else { return(xleft <xright ? -1 : xleft> xright ? 1 : 0); } }