public Node clone() { Node node = new Node(); if (this.plane != null) node.plane = this.plane.clone(); if (this.front != null) node.front = this.front.clone(); if (this.back != null) node.back = this.back.clone(); foreach (Polygon p in this.polygons) { node.polygons.Add(p.clone()); } return node; }
/// <summary> /// Recursively remove all polygons in `polygons` that are inside this BSP tree. /// </summary> /// <param name="polys"></param> /// <returns></returns> public List<Polygon> clipPolygons(List<Polygon> polys) { if (this.plane == null) return new List<Polygon>(polys); List<Polygon> front = new List<Polygon>(); List<Polygon> back = new List<Polygon>(); for (int i = 0; i < polys.Count; i++) { this.plane.splitPolygon(polys[i], ref front, ref back, ref front, ref back); } if (this.front != null) front = this.front.clipPolygons(front); if (this.back != null) { back = this.back.clipPolygons(back); } else { back.Clear(); } front.AddRange(back); return front; }
/// <summary> /// Convert solid space to empty space and empty space to solid space. /// </summary> public void invert() { if (this.polygons.Count == 0) { Debug.LogError("No polygons?"); return; } for (int i = 0; i < this.polygons.Count; i++) { this.polygons[i].flip(); } this.plane.flip(); if (this.front != null) this.front.invert(); if (this.back != null) this.back.invert(); Node temp = this.front; this.front = this.back; this.back = temp; }
/// <summary> /// Return a new CSG solid representing space both this solid and in the /// solid `csg`. Neither this solid nor the solid `csg` are modified. /// </summary> /// <remarks> /// A.intersect(B) /// /// +-------+ /// | | /// | A | /// | +--+----+ = +--+ /// +----+--+ | +--+ /// | B | /// | | /// +-------+ /// </remarks> /// <param name="csg"></param> /// <returns>CSG of the intersection</returns> public CSG intersect(CSG csg) { Node a = new Node(this.polygons); Node b = new Node(csg.polygons); a.invert(); b.invert(); a.clipTo(b); b.clipTo(a); a.build(b.allPolygons()); return CSG.fromPolygons(a.allPolygons()).inverse(); }
/// <summary> /// Return a new CSG solid representing space in this solid but not in the /// solid `csg`. Neither this solid nor the solid `csg` are modified. /// </summary> /// <remarks> /// A.subtract(B) /// +-------+ +-------+ /// | | | | /// | A | | | /// | +--+----+ = | +--+ /// +----+--+ | +----+ /// | B | /// | | /// +-------+ /// </remarks> /// <param name="csg"></param> /// <returns></returns> public CSG subtract(CSG csg) { Node a = new Node(this.polygons); Node b = new Node(csg.polygons); //Debug.Log(this.clone().polygons.Count + " -- " + csg.clone().polygons.Count); //Debug.Log("CSG.subtract: Node a = " + a.polygons.Count + " polys, Node b = " + b.polygons.Count + " polys."); a.invert(); a.clipTo(b); b.clipTo(a); b.invert(); b.clipTo(a); b.invert(); a.build(b.allPolygons()); a.invert(); return CSG.fromPolygons(a.allPolygons()); }
/// <summary> /// Remove all polygons in this BSP tree that are inside the other BSP tree `bsp`. /// </summary> /// <param name="bsp"></param> public void clipTo(Node bsp) { this.polygons = bsp.clipPolygons(this.polygons); if (this.front != null) this.front.clipTo(bsp); if (this.back != null) this.back.clipTo(bsp); }
/// <summary> /// Build a BSP tree out of `polygons`. When called on an existing tree, the /// new polygons are filtered down to the bottom of the tree and become new /// nodes there. Each set of polygons is partitioned using the first polygon /// (no heuristic is used to pick a good split). /// </summary> /// <param name="polys"></param> /// <param name="stack"></param> public void build(List<Polygon> polys, int stack = 6000) { if (stack < 0) { Debug.LogWarning("Stack overflow prevented"); return; } if (polys.Count == 0) return; if (this.plane == null) this.plane = polys[0].plane.clone(); List<Polygon> tfront = new List<Polygon>(); List<Polygon> tback = new List<Polygon>(); for (int i = 0; i < polys.Count; i++) { this.plane.splitPolygon(polys[i], ref this.polygons, ref this.polygons, ref tfront, ref tback); } if (tfront.Count > 0) { if (this.front == null) this.front = new Node(); this.front.build(tfront, stack - 1); } if (tback.Count > 0) { if (this.back == null) this.back = new Node(); this.back.build(tback, stack - 1); } }