void Flip(NativeArray <float2> points, ref NativeArray <int> stack, ref int stackCount, int a, int b, int x) { int y = OppositeOf(a, b); if (y < 0) { return; } if (b < a) { int tmp = a; a = b; b = tmp; tmp = x; x = y; y = tmp; } if (FindConstraint(a, b) != -1) { return; } if (TessUtils.IsInsideCircle(points[a], points[b], points[x], points[y])) { stack[stackCount++] = a; stack[stackCount++] = b; } }
static float FindSplit(TessHull hull, TessEvent edge) { float d = 0; if (hull.a.x < edge.a.x) { d = TessUtils.OrientFast(hull.a, hull.b, edge.a); } else { d = TessUtils.OrientFast(edge.b, edge.a, hull.a); } if (0 != d) { return(d); } if (edge.b.x < hull.b.x) { d = TessUtils.OrientFast(hull.a, hull.b, edge.b); } else { d = TessUtils.OrientFast(edge.b, edge.a, hull.b); } if (0 != d) { return(d); } return(hull.idx - edge.idx); }
public int Compare(TessEvent a, TessEvent b) { float f = (a.a.x - b.a.x); if (0 != f) { return((f > 0) ? 1 : -1); } f = (a.a.y - b.a.y); if (0 != f) { return((f > 0) ? 1 : -1); } int i = a.type - b.type; if (0 != i) { return(i); } if (a.type != (int)TessEventType.EVENT_POINT) { float o = TessUtils.OrientFast(a.a, a.b, b.b); if (0 != o) { return((o > 0) ? 1 : -1); } } return(a.idx - b.idx); }
void Prepare(NativeArray <TessEdge> edgesIn) { m_Stars = new NativeArray <TessStar>(edgesIn.Length, Allocator.Temp); for (int i = 0; i < edgesIn.Length; ++i) { TessEdge e = edgesIn[i]; e.a = (edgesIn[i].a < edgesIn[i].b) ? edgesIn[i].a : edgesIn[i].b; e.b = (edgesIn[i].a > edgesIn[i].b) ? edgesIn[i].a : edgesIn[i].b; edgesIn[i] = e; TessStar s = m_Stars[i]; s.points = new ArraySlice <int>(m_SPArray, i * m_StarCount, m_StarCount); s.pointCount = 0; m_Stars[i] = s; } unsafe { TessUtils.InsertionSort <TessEdge, TessEdgeCompare>( NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(edgesIn), 0, edgesIn.Length - 1, new TessEdgeCompare()); } m_Edges = new NativeArray <TessEdge>(edgesIn.Length, Allocator.Temp); m_Edges.CopyFrom(edgesIn); // Fill stars. for (int i = 0; i < m_CellCount; ++i) { int a = m_Cells[i].a; int b = m_Cells[i].b; int c = m_Cells[i].c; TessStar sa = m_Stars[a]; TessStar sb = m_Stars[b]; TessStar sc = m_Stars[c]; sa.points[sa.pointCount++] = b; sa.points[sa.pointCount++] = c; sb.points[sb.pointCount++] = c; sb.points[sb.pointCount++] = a; sc.points[sc.pointCount++] = a; sc.points[sc.pointCount++] = b; m_Stars[a] = sa; m_Stars[b] = sb; m_Stars[c] = sc; } }
void AddPoint(NativeArray <TessHull> hulls, int hullCount, NativeArray <float2> points, float2 p, int idx) { int l = GetLowerHullForVector(hulls, hullCount, p); int u = GetUpperHullForVector(hulls, hullCount, p); for (int i = l; i < u; ++i) { TessHull hull = hulls[i]; int m = hull.ilcount; while (m > 1 && TessUtils.OrientFast(points[hull.ilarray[m - 2]], points[hull.ilarray[m - 1]], p) > 0) { TessCell c = new TessCell(); c.a = hull.ilarray[m - 1]; c.b = hull.ilarray[m - 2]; c.c = idx; m_Cells[m_CellCount++] = c; m -= 1; } hull.ilcount = m + 1; hull.ilarray[m] = idx; m = hull.iucount; while (m > 1 && TessUtils.OrientFast(points[hull.iuarray[m - 2]], points[hull.iuarray[m - 1]], p) < 0) { TessCell c = new TessCell(); c.a = hull.iuarray[m - 2]; c.b = hull.iuarray[m - 1]; c.c = idx; m_Cells[m_CellCount++] = c; m -= 1; } hull.iucount = m + 1; hull.iuarray[m] = idx; hulls[i] = hull; } }
internal void ApplyDelaunay(NativeArray <float2> points, NativeArray <TessEdge> edgesIn) { NativeArray <int> stack = new NativeArray <int>(m_NumPoints * (m_NumPoints + 1), Allocator.Temp); int stackCount = 0; Prepare(edgesIn); for (int a = 0; a < m_NumPoints; ++a) { TessStar star = m_Stars[a]; for (int j = 1; j < star.pointCount; j += 2) { int b = star.points[j]; if (b < a) { continue; } if (FindConstraint(a, b) >= 0) { continue; } int x = star.points[j - 1], y = -1; for (int k = 1; k < star.pointCount; k += 2) { if (star.points[k - 1] == b) { y = star.points[k]; break; } } if (y < 0) { continue; } if (TessUtils.IsInsideCircle(points[a], points[b], points[x], points[y])) { stack[stackCount++] = a; stack[stackCount++] = b; } } } while (stackCount > 0) { int b = stack[stackCount - 1]; stackCount--; int a = stack[stackCount - 1]; stackCount--; int x = -1, y = -1; TessStar star = m_Stars[a]; for (int i = 1; i < star.pointCount; i += 2) { int s = star.points[i - 1]; int t = star.points[i]; if (s == b) { y = t; } else if (t == b) { x = s; } } if (x < 0 || y < 0) { continue; } if (!TessUtils.IsInsideCircle(points[a], points[b], points[x], points[y])) { continue; } EdgeFlip(a, b); Flip(points, ref stack, ref stackCount, x, a, y); Flip(points, ref stack, ref stackCount, a, y, x); Flip(points, ref stack, ref stackCount, y, b, x); Flip(points, ref stack, ref stackCount, b, x, y); } stack.Dispose(); }
internal void Triangulate(NativeArray <float2> points, NativeArray <TessEdge> edgesIn) { int numEdges = edgesIn.Length; const int kStarEdges = 16; m_NumPoints = points.Length; m_StarCount = m_NumPoints > kStarEdges ? m_NumPoints : kStarEdges; m_StarCount = m_StarCount * 2; m_CellCount = 0; m_Cells = new NativeArray <TessCell>(m_NumPoints * (m_NumPoints + 1), Allocator.Temp); m_ILArray = new NativeArray <int>(m_NumPoints * (m_NumPoints + 1), Allocator.Temp); // Make room for -1 node. m_IUArray = new NativeArray <int>(m_NumPoints * (m_NumPoints + 1), Allocator.Temp); // Make room for -1 node. m_SPArray = new NativeArray <int>(m_NumPoints * (m_StarCount), Allocator.Temp); // Make room for -1 node. NativeArray <TessHull> hulls = new NativeArray <TessHull>(m_NumPoints * 8, Allocator.Temp); int hullCount = 0; NativeArray <TessEvent> events = new NativeArray <TessEvent>(m_NumPoints + (numEdges * 2), Allocator.Temp); int eventCount = 0; for (int i = 0; i < m_NumPoints; ++i) { TessEvent evt = new TessEvent(); evt.a = points[i]; evt.b = new float2(); evt.idx = i; evt.type = (int)TessEventType.EVENT_POINT; events[eventCount++] = evt; } for (int i = 0; i < numEdges; ++i) { TessEdge e = edgesIn[i]; float2 a = points[e.a]; float2 b = points[e.b]; if (a.x < b.x) { TessEvent _s = new TessEvent(); _s.a = a; _s.b = b; _s.idx = i; _s.type = (int)TessEventType.EVENT_START; TessEvent _e = new TessEvent(); _e.a = b; _e.b = a; _e.idx = i; _e.type = (int)TessEventType.EVENT_END; events[eventCount++] = _s; events[eventCount++] = _e; } else if (a.x > b.x) { TessEvent _s = new TessEvent(); _s.a = b; _s.b = a; _s.idx = i; _s.type = (int)TessEventType.EVENT_START; TessEvent _e = new TessEvent(); _e.a = a; _e.b = b; _e.idx = i; _e.type = (int)TessEventType.EVENT_END; events[eventCount++] = _s; events[eventCount++] = _e; } } unsafe { TessUtils.InsertionSort <TessEvent, TessEventCompare>( NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(events), 0, eventCount - 1, new TessEventCompare()); ; } float minX = events[0].a.x - (1 + math.abs(events[0].a.x)) * math.pow(2.0f, -16.0f); TessHull hull; hull.a.x = minX; hull.a.y = 1; hull.b.x = minX; hull.b.y = 0; hull.idx = -1; hull.ilarray = new ArraySlice <int>(m_ILArray, m_NumPoints * m_NumPoints, m_NumPoints); // Last element hull.iuarray = new ArraySlice <int>(m_IUArray, m_NumPoints * m_NumPoints, m_NumPoints); hull.ilcount = 0; hull.iucount = 0; hulls[hullCount++] = hull; for (int i = 0, numEvents = eventCount; i < numEvents; ++i) { switch (events[i].type) { case (int)TessEventType.EVENT_POINT: { AddPoint(hulls, hullCount, points, events[i].a, events[i].idx); } break; case (int)TessEventType.EVENT_START: { SplitHulls(hulls, ref hullCount, points, events[i]); } break; default: { MergeHulls(hulls, ref hullCount, points, events[i]); } break; } } hulls.Dispose(); events.Dispose(); }
static float TestPoint(TessHull hull, float2 point) { return(TessUtils.OrientFast(hull.a, hull.b, point)); }
NativeArray <TessCell> Constrain(ref int count) { var cells = GetCells(ref count); int nc = count; for (int i = 0; i < nc; ++i) { TessCell c = cells[i]; int x = c.a, y = c.b, z = c.c; if (y < z) { if (y < x) { c.a = y; c.b = z; c.c = x; } } else if (z < x) { c.a = z; c.b = x; c.c = y; } cells[i] = c; } unsafe { TessUtils.InsertionSort <TessCell, TessCellCompare>( NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(cells), 0, m_CellCount - 1, new TessCellCompare()); } // Out m_Flags = new NativeArray <int>(nc, Allocator.Temp); m_Neighbors = new NativeArray <int>(nc * 3, Allocator.Temp); m_Constraints = new NativeArray <int>(nc * 3, Allocator.Temp); var next = new NativeArray <int>(nc * 3, Allocator.Temp); var active = new NativeArray <int>(nc * 3, Allocator.Temp); int side = 1, nextCount = 0, activeCount = 0; for (int i = 0; i < nc; ++i) { TessCell c = cells[i]; for (int j = 0; j < 3; ++j) { int x = j, y = (j + 1) % 3; x = (x == 0) ? c.a : (j == 1) ? c.b : c.c; y = (y == 0) ? c.a : (y == 1) ? c.b : c.c; int o = OppositeOf(y, x); int a = m_Neighbors[3 * i + j] = FindNeighbor(cells, count, y, x, o); int b = m_Constraints[3 * i + j] = (-1 != FindConstraint(x, y)) ? 1 : 0; if (a < 0) { if (0 != b) { next[nextCount++] = i; } else { active[activeCount++] = i; m_Flags[i] = 1; } } } } while (activeCount > 0 || nextCount > 0) { while (activeCount > 0) { int t = active[activeCount - 1]; activeCount--; if (m_Flags[t] == -side) { continue; } m_Flags[t] = side; TessCell c = cells[t]; for (int j = 0; j < 3; ++j) { int f = m_Neighbors[3 * t + j]; if (f >= 0 && m_Flags[f] == 0) { if (0 != m_Constraints[3 * t + j]) { next[nextCount++] = f; } else { active[activeCount++] = f; m_Flags[f] = side; } } } } for (int e = 0; e < nextCount; e++) { active[e] = next[e]; } activeCount = nextCount; nextCount = 0; side = -side; } active.Dispose(); next.Dispose(); return(cells); }