From 080730b2d41dbff7045e264a07c85b707532395f Mon Sep 17 00:00:00 2001 From: Fred Tinf Date: Sat, 1 Apr 2023 12:56:36 +0100 Subject: [PATCH] Made a fix that worked for me to stop Stackoverflow exception. Replaced recursion with iterating over a stack --- CSG/Classes/Node.cs | 88 ++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/CSG/Classes/Node.cs b/CSG/Classes/Node.cs index 32446b9..b0570d1 100644 --- a/CSG/Classes/Node.cs +++ b/CSG/Classes/Node.cs @@ -86,45 +86,59 @@ public void Invert() // (no heuristic is used to pick a good split). public void Build(List list) { - if (list.Count < 1) - return; + Stack<(Node, List)> buildStack = new Stack<(Node, List)>(); + buildStack.Push((this, list)); - bool newNode = plane == null || !plane.Valid(); - - if (newNode) - { - plane = new Plane(); - plane.normal = list[0].plane.normal; - plane.w = list[0].plane.w; - } - - if (polygons == null) - polygons = new List(); - - var listFront = new List(); - var listBack = new List(); - - for (int i = 0; i < list.Count; i++) - plane.SplitPolygon(list[i], polygons, polygons, listFront, listBack); - - - if (listFront.Count > 0) - { - // SplitPolygon can fail to correctly identify coplanar planes when the epsilon value is too low. When - // this happens, the front or back list will be filled and built into a new node recursively. This - // check catches that case and sorts the front/back lists into the coplanar polygons collection. - if (newNode && list.SequenceEqual(listFront)) - polygons.AddRange(listFront); - else - (front ?? (front = new Node())).Build(listFront); - } - - if (listBack.Count > 0) + while (buildStack.Count > 0) { - if (newNode && list.SequenceEqual(listBack)) - polygons.AddRange(listBack); - else - (back ?? (back = new Node())).Build(listBack); + var current = buildStack.Pop(); + Node currentNode = current.Item1; + List currentList = current.Item2; + + if (currentList.Count < 1) + continue; + + bool newNode = currentNode.plane == null || !currentNode.plane.Valid(); + + if (newNode) + { + currentNode.plane = new Plane(); + currentNode.plane.normal = currentList[0].plane.normal; + currentNode.plane.w = currentList[0].plane.w; + } + + if (currentNode.polygons == null) + currentNode.polygons = new List(); + + var listFront = new List(); + var listBack = new List(); + + for (int i = 0; i < currentList.Count; i++) + currentNode.plane.SplitPolygon(currentList[i], currentNode.polygons, currentNode.polygons, listFront, listBack); + + if (listFront.Count > 0) + { + if (newNode && currentList.SequenceEqual(listFront)) + currentNode.polygons.AddRange(listFront); + else + { + if (currentNode.front == null) + currentNode.front = new Node(); + buildStack.Push((currentNode.front, listFront)); + } + } + + if (listBack.Count > 0) + { + if (newNode && currentList.SequenceEqual(listBack)) + currentNode.polygons.AddRange(listBack); + else + { + if (currentNode.back == null) + currentNode.back = new Node(); + buildStack.Push((currentNode.back, listBack)); + } + } } }