private static SplitLayout Split(this PlainShape self, long maxEgeSize, Allocator allocator) { var originalCount = self.points.Length; var nodes = new DynamicArray <Node>(originalCount, allocator); var layouts = new DynamicArray <PathLayout>(originalCount, allocator); var sqrMaxSize = maxEgeSize * maxEgeSize; var begin = 0; var originalIndex = 0; var extraIndex = originalCount; for (int j = 0; j < self.layouts.Length; ++j) { var layout = self.layouts[j]; var last = layout.end; var a = self.points[last]; var length = 0; for (int i = layout.begin; i <= layout.end; ++i) { var b = self.points[i]; var dx = b.x - a.x; var dy = b.y - a.y; var sqrSize = dx * dx + dy * dy; if (sqrSize > sqrMaxSize) { var l = (long)Mathf.Sqrt(sqrSize); int s = (int)(l / maxEgeSize); double ds = s; double sx = dx / ds; double sy = dy / ds; double fx = 0; double fy = 0; for (int k = 1; k < s; ++k) { fx += sx; fy += sy; long x = a.x + (long)fx; long y = a.y + (long)fy; nodes.Add(new Node(extraIndex, new IntVector(x, y))); extraIndex += 1; } length += s - 1; } length += 1; nodes.Add(new Node(originalIndex, b)); originalIndex += 1; a = b; } layouts.Add(new PathLayout(begin, length, layout.isClockWise)); begin += length; } return(new SplitLayout(layouts.Convert(), nodes.Convert())); }
public NativeArray <Hexagon> HexagonDivide(NativeArray <Triangle> triangles, Allocator allocator) { var result = new DynamicArray <Hexagon>(maxCount, allocator); var bufferA = new DynamicArray <Triangle>(maxCount / 3, tempAllocator); var bufferB = new DynamicArray <Triangle>(maxCount / 3, tempAllocator); bufferA.Add(triangles); do { for (int i = 0; i < bufferA.Count; ++i) { var triangle = bufferA[i]; if (hexagonDivide(triangle, out var hexagon, ref bufferB)) { result.Add(hexagon); if (result.Count >= maxCount) { goto onFinish; } } } bufferA.RemoveAll(); if (bufferB.Count > 0) { for (int i = 0; i < bufferB.Count; ++i) { var triangle = bufferB[i]; if (hexagonDivide(triangle, out var hexagon, ref bufferA)) { result.Add(hexagon); if (result.Count >= maxCount) { goto onFinish; } } } } bufferB.RemoveAll(); } while (bufferA.Count > 0); onFinish: bufferA.Dispose(); bufferB.Dispose(); return(result.Convert()); }
public static MonotoneLayout Split(this PlainShape shape, long maxEdge, NativeArray <IntVector> extraPoints, Allocator allocator) { var navigator = shape.GetNavigator(maxEdge, extraPoints, Allocator.Temp); var links = new DynamicArray <Link>(navigator.links, allocator); var natures = navigator.natures; var sortIndices = navigator.indices; int n = sortIndices.Length; var subs = new DynamicArray <Sub>(8, Allocator.Temp); var dSubs = new DynamicArray <DualSub>(8, Allocator.Temp); var indices = new DynamicArray <int>(16, allocator); var slices = new DynamicArray <Slice>(16, allocator); int i = 0; nextNode: while (i < n) { int sortIndex = sortIndices[i]; var node = links[sortIndex]; var nature = natures[sortIndex]; int j; switch (nature) { case LinkNature.start: subs.Add(new Sub(node)); ++i; goto nextNode; case LinkNature.extra: j = 0; while (j < dSubs.Count) { var dSub = dSubs[j]; var pA = dSub.next.vertex.point; var pB = links[dSub.next.next].vertex.point; var pC = links[dSub.prev.prev].vertex.point; var pD = dSub.prev.vertex.point; var p = node.vertex.point; if (IsTetragonContain(p, pA, pB, pC, pD)) { var hand = links[dSub.middle]; slices.Add(new Slice(hand.vertex.index, node.vertex.index)); links.ConnectExtraPrev(hand.self, node.self); dSubs[j] = new DualSub(links[dSub.next.self], node.self, links[dSub.prev.self]); i += 1; goto nextNode; } j += 1; } // while dSubs j = 0; while (j < subs.Count) { var sub = subs[j]; var pA = sub.next.vertex.point; var pB = links[sub.next.next].vertex.point; var pC = links[sub.prev.prev].vertex.point; var pD = sub.prev.vertex.point; var p = node.vertex.point; if (IsTetragonContain(p, pA, pB, pC, pD)) { if (!sub.isEmpty) { if (pA.x > pD.x) { var hand = sub.next; slices.Add(new Slice(hand.vertex.index, node.vertex.index)); var newHandIndex = links.ConnectExtraNext(hand.self, node.self); dSubs.Add(new DualSub(links[newHandIndex], node.self, links[sub.prev.self])); } else { var hand = sub.prev; slices.Add(new Slice(hand.vertex.index, node.vertex.index)); var newHandIndex = links.ConnectExtraPrev(hand.self, node.self); dSubs.Add(new DualSub(links[sub.next.self], node.self, links[newHandIndex])); } } else { var hand = links[sub.next.self]; slices.Add(new Slice(hand.vertex.index, b: node.vertex.index)); var newPrev = links.ConnectExtraPrev(hand.self, node.self); dSubs.Add(new DualSub(links[hand.self], node.self, links[newPrev])); } subs.Exclude(j); i += 1; goto nextNode; } j += 1; } break; case LinkNature.merge: var newNextSub = new Sub(true); var newPrevSub = new Sub(true); j = 0; while (j < dSubs.Count) { var dSub = dSubs[j]; if (dSub.next.next == node.self) { var a = node.self; var b = dSub.middle; var bridge = links.Connect(a, b); indices.Add(links.FindStart(bridge.a.self)); slices.Add(bridge.Slice); var prevSub = new Sub(links[a], dSub.prev); if (!newNextSub.isEmpty) { dSubs[j] = new DualSub(newNextSub, prevSub); ++i; goto nextNode; } dSubs.Exclude(j); newPrevSub = prevSub; continue; } else if (dSub.prev.prev == node.self) { var a = dSub.middle; var b = node.self; var bridge = links.Connect(a, b); indices.Add(links.FindStart(bridge.a.self)); slices.Add(bridge.Slice); var nextSub = new Sub(dSub.next, links[b]); if (!newPrevSub.isEmpty) { dSubs[j] = new DualSub(nextSub, newPrevSub); ++i; goto nextNode; } dSubs.Exclude(j); newNextSub = nextSub; continue; } ++j; } // while dSubs j = 0; while (j < subs.Count) { var sub = subs[j]; if (sub.next.next == node.self) { sub.next = node; subs.Exclude(j); if (!newNextSub.isEmpty) { dSubs.Add(new DualSub(newNextSub, sub)); ++i; goto nextNode; } newPrevSub = sub; continue; } else if (sub.prev.prev == node.self) { sub.prev = node; subs.Exclude(j); if (!newPrevSub.isEmpty) { dSubs.Add(new DualSub(sub, newPrevSub)); ++i; goto nextNode; } newNextSub = sub; continue; } ++j; } break; case LinkNature.split: j = 0; while (j < subs.Count) { var sub = subs[j]; var pA = sub.next.vertex.point; var pB = links[sub.next.next].vertex.point; var pC = links[sub.prev.prev].vertex.point; var pD = sub.prev.vertex.point; var p = node.vertex.point; if (IsTetragonContain(p, pA, pB, pC, pD)) { var a0 = sub.next.self; var a1 = sub.prev.self; var b = node.self; if (pA.x > pD.x) { var bridge = links.Connect(a0, b); subs.Add(new Sub(bridge.b, links[a1])); slices.Add(bridge.Slice); } else { var bridge = links.Connect(a1, b); subs.Add(new Sub(bridge.b, bridge.a)); slices.Add(bridge.Slice); } subs[j] = new Sub(links[a0], links[b]); ++i; goto nextNode; } ++j; } j = 0; while (j < dSubs.Count) { var dSub = dSubs[j]; var pA = dSub.next.vertex.point; var pB = links[dSub.next.next].vertex.point; var pC = links[dSub.prev.prev].vertex.point; var pD = dSub.prev.vertex.point; var p = node.vertex.point; if (IsTetragonContain(p, pA, pB, pC, pD)) { var a = dSub.middle; var b = node.self; var bridge = links.Connect(a, b); subs.Add(new Sub(dSub.next, links[b])); subs.Add(new Sub(bridge.b, dSub.prev)); slices.Add(bridge.Slice); dSubs.Exclude(j); ++i; goto nextNode; } ++j; } // while dSubs break; case LinkNature.end: j = 0; while (j < subs.Count) { var sub = subs[j]; // second condition is useless because it repeats the first if (sub.next.next == node.self) /* || sub.prev.prev.index == node.this */ { indices.Add(links.FindStart(node.self)); subs.Exclude(j); ++i; goto nextNode; } ++j; } j = 0; while (j < dSubs.Count) { var dSub = dSubs[j]; // second condition is useless because it repeats the first if (dSub.next.next == node.self) /*|| dSub.prevSub.prev.prev.index == node.this*/ { var a = dSub.middle; var b = node.self; var bridge = links.Connect(a, b); indices.Add(links.FindStart(a)); indices.Add(links.FindStart(bridge.a.self)); slices.Add(bridge.Slice); dSubs.Exclude(j); // goto next node ++i; goto nextNode; } ++j; } // while dSubs break; case LinkNature.simple: j = 0; while (j < subs.Count) { var sub = subs[j]; if (sub.next.next == node.self) { sub.next = node; subs[j] = sub; ++i; goto nextNode; } else if (sub.prev.prev == node.self) { sub.prev = node; subs[j] = sub; // goto next node ++i; goto nextNode; } ++j; } j = 0; while (j < dSubs.Count) { var dSub = dSubs[j]; if (dSub.next.next == node.self) { var a = dSub.middle; var b = node.self; var bridge = links.Connect(a, b); indices.Add(links.FindStart(node.self)); slices.Add(bridge.Slice); var newSub = new Sub(bridge.b, dSub.prev); subs.Add(newSub); dSubs.Exclude(j); // goto next node ++i; goto nextNode; } else if (dSub.prev.prev == node.self) { var a = node.self; var b = dSub.middle; var bridge = links.Connect(a, b); indices.Add(links.FindStart(node.self)); slices.Add(bridge.Slice); var newSub = new Sub(links[dSub.next.self], bridge.a); subs.Add(newSub); dSubs.Exclude(j); // goto next node ++i; goto nextNode; } ++j; } // while dSubs break; } // switch } subs.Dispose(); dSubs.Dispose(); navigator.Dispose(); int pathCount = navigator.pathCount; int extraCount = navigator.extraCount; return(new MonotoneLayout(pathCount, extraCount, links.Convert(), slices.Convert(), indices.Convert())); }