Advertisement
Guest User

csg.cs

a guest
Nov 3rd, 2013
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 23.00 KB | None | 0 0
  1. using System;
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Collections;
  6.  
  7. namespace CSG
  8. {
  9.     // Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean
  10.     // operations like union and intersection to combine 3D solids. This library
  11.     // implements CSG operations on meshes elegantly and concisely using BSP trees,
  12.     // and is meant to serve as an easily understandable implementation of the
  13.     // algorithm. All edge cases involving overlapping coplanar polygons in both
  14.     // solids are correctly handled.
  15.     //
  16.     // Example usage:
  17.     //
  18.     //     var cube = CSG.cube();
  19.     //     var sphere = CSG.sphere({ radius: 1.3 });
  20.     //     var polygons = cube.subtract(sphere).toPolygons();
  21.     //
  22.     // ## Implementation Details
  23.     //
  24.     // All CSG operations are implemented in terms of two functions, `clipTo()` and
  25.     // `invert()`, which remove parts of a BSP tree inside another BSP tree and swap
  26.     // solid and empty space, respectively. To find the union of `a` and `b`, we
  27.     // want to remove everything in `a` inside `b` and everything in `b` inside `a`,
  28.     // then combine polygons from `a` and `b` into one solid:
  29.     //
  30.     //     a.clipTo(b);
  31.     //     b.clipTo(a);
  32.     //     a.build(b.allPolygons());
  33.     //
  34.     // The only tricky part is handling overlapping coplanar polygons in both trees.
  35.     // The code above keeps both copies, but we need to keep them in one tree and
  36.     // remove them in the other tree. To remove them from `b` we can clip the
  37.     // inverse of `b` against `a`. The code for union now looks like this:
  38.     //
  39.     //     a.clipTo(b);
  40.     //     b.clipTo(a);
  41.     //     b.invert();
  42.     //     b.clipTo(a);
  43.     //     b.invert();
  44.     //     a.build(b.allPolygons());
  45.     //
  46.     // Subtraction and intersection naturally follow from set operations. If
  47.     // union is `A | B`, subtraction is `A - B = ~(~A | B)` and intersection is
  48.     // `A & B = ~(~A | ~B)` where `~` is the complement operator.
  49.     //
  50.     // ## License
  51.     //
  52.     // Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license.
  53.    
  54.    
  55.     public struct Options
  56.     {
  57.         public Vector3 center;
  58.         public float radius;
  59.         public int slices;
  60.         public int stacks;
  61.     }
  62.    
  63.     // # class CSG
  64.    
  65.     public class CSG
  66.     {
  67.         // Holds a binary space partition tree representing a 3D solid. Two solids can
  68.         // be combined using the `union()`, `subtract()`, and `intersect()` methods.
  69.         List<Polygon> polygons;
  70.        
  71.         // Construct a CSG solid from a list of `CSG.Polygon` instances.
  72.         public static CSG FromPolygons(List<Polygon> polygons)
  73.         {
  74.             var csg = new CSG();
  75.             csg.polygons = polygons;
  76.             return csg;
  77.         }
  78.        
  79.         public CSG Clone()
  80.         {
  81.             var csg = new CSG();
  82.             csg.polygons = this.polygons.Select(p => p.Clone()).ToList();
  83.             return csg;
  84.         }
  85.        
  86.         public List<Polygon> ToPolygons() {
  87.             return this.polygons;
  88.         }
  89.        
  90.         public Mesh ToMesh()
  91.         {
  92.             Mesh newMesh = new Mesh();
  93.             List<int> triangles = new List<int>(); List<Vector3> vertices = new List<Vector3>();
  94.             int c = 0;
  95.             foreach (Polygon poly in this.polygons)
  96.             {
  97.                 vertices.AddRange(poly.vertices.Select(v => v.pos));
  98.                 triangles.AddRange(new int[6] { 0+c,1+c,3+c,1+c,2+c,3+c });
  99.                
  100.                 Vector3[] crossed = new Vector3[poly.vertices.Count];
  101.                 for (int i=0; i<poly.vertices.Count; i++)
  102.                 {
  103.                    
  104.                     //Quaternion.
  105.                     //Camera.main.
  106.                     //crossed[i] = Vector3.(poly.vertices[i].pos, poly.plane.normal);
  107.                 }
  108.                 c+=4;
  109.             }
  110.             newMesh.vertices = vertices.ToArray();
  111.             newMesh.triangles = triangles.ToArray();       
  112.            
  113.             return newMesh;
  114.         }
  115.        
  116.         // Return a new CSG solid representing space in either this solid or in the
  117.         // solid `csg`. Neither this solid nor the solid `csg` are modified.
  118.         //
  119.         //     A.union(B)
  120.         //
  121.         //     +-------+            +-------+
  122.         //     |       |            |       |
  123.         //     |   A   |            |       |
  124.         //     |    +--+----+   =   |       +----+
  125.         //     +----+--+    |       +----+       |
  126.         //          |   B   |            |       |
  127.         //          |       |            |       |
  128.         //          +-------+            +-------+
  129.         //
  130.         public CSG Union(CSG csg)
  131.         {
  132.             var a = new Node(Clone().polygons);
  133.             var b = new Node(csg.Clone().polygons);
  134.             a.ClipTo(b);
  135.             b.ClipTo(a);
  136.             b.Invert();
  137.             b.ClipTo(a);
  138.             b.Invert();
  139.             a.Build(b.AllPolygons());
  140.             return CSG.FromPolygons(a.AllPolygons());
  141.         }
  142.        
  143.         // Return a new CSG solid representing space in this solid but not in the
  144.         // solid `csg`. Neither this solid nor the solid `csg` are modified.
  145.         //
  146.         //     A.subtract(B)
  147.         //
  148.         //     +-------+            +-------+
  149.         //     |       |            |       |
  150.         //     |   A   |            |       |
  151.         //     |    +--+----+   =   |    +--+
  152.         //     +----+--+    |       +----+
  153.         //          |   B   |
  154.         //          |       |
  155.         //          +-------+
  156.         //
  157.         public CSG Subtract(CSG csg)
  158.         {
  159.             //var a = new CSG.Node(this.clone().polygons);
  160.             //var b = new CSG.Node(csg.clone().polygons);
  161.             //a.invert();
  162.             //a.clipTo(b);
  163.             //b.clipTo(a);
  164.             //b.invert();
  165.             //b.clipTo(a);
  166.             //b.invert();
  167.             //a.build(b.allPolygons());
  168.             //a.invert();
  169.             //return CSG.fromPolygons(a.allPolygons());
  170.             return new CSG();
  171.         }
  172.        
  173.         // Return a new CSG solid representing space both this solid and in the
  174.         // solid `csg`. Neither this solid nor the solid `csg` are modified.
  175.         //
  176.         //     A.intersect(B)
  177.         //
  178.         //     +-------+
  179.         //     |       |
  180.         //     |   A   |
  181.         //     |    +--+----+   =   +--+
  182.         //     +----+--+    |       +--+
  183.         //          |   B   |
  184.         //          |       |
  185.         //          +-------+
  186.         //
  187.         public CSG Intersect(CSG csg) {
  188.             //var a = new CSG.Node(this.clone().polygons);
  189.             //var b = new CSG.Node(csg.clone().polygons);
  190.             //a.invert();
  191.             //b.clipTo(a);
  192.             //b.invert();
  193.             //a.clipTo(b);
  194.             //b.clipTo(a);
  195.             //a.build(b.allPolygons());
  196.             //a.invert();
  197.             //return CSG.fromPolygons(a.allPolygons());
  198.             return new CSG();
  199.         }
  200.        
  201.         // Return a new CSG solid with solid and empty space switched. This solid is
  202.         // not modified.
  203.         public void Inverse()
  204.         {
  205.             //var csg = this.clone();
  206.             //csg.polygons.map(function(p) { p.flip(); });
  207.             //return csg;
  208.         }
  209.        
  210.         // Construct an axis-aligned solid cuboid. Optional parameters are `center` and
  211.         // `radius`, which default to `[0, 0, 0]` and `[1, 1, 1]`. The radius can be
  212.         // specified using a single number or a list of three numbers, one for each axis.
  213.         //
  214.         // Example code:
  215.         //
  216.         //     var cube = CSG.cube({
  217.         //       center: [0, 0, 0],
  218.         //       radius: 1
  219.         //     });
  220.         public static CSG Cube(Options options)
  221.         {
  222.             Vector3 c, r;
  223.             if (options.center!=null)
  224.                 c = options.center;
  225.             else
  226.                 c = Vector3.zero;
  227.             if (options.radius>0)
  228.                 r = new Vector3(options.radius, options.radius, options.radius);
  229.             else
  230.                 r = new Vector3(1, 1, 1);
  231.  
  232.             Vertex[] vertices = new Vertex[8];
  233.             for (int i=0; i<vertices.Length; i++)
  234.             {
  235.                 vertices[i] = new Vertex( new Vector3 (
  236.                 c.x + r[0] * (((i & 1) == 1) ? 1 : -1 ),
  237.                 c.y + r[1] * (((i & 2) == 2) ? 1 : -1 ),
  238.                 c.z + r[2] * (((i & 4) == 4) ? 1 : -1 )),
  239.                 Vector3.zero);
  240.             }
  241.             int[,] indices = new int[6,4]
  242.             {
  243.                 {0, 4, 6, 2},
  244.                 {1, 3, 7, 5},
  245.                 {0, 1, 5, 4},
  246.                 {2, 6, 7, 3},
  247.                 {0, 2, 3, 1},
  248.                 {4, 5, 7, 6},
  249.             };
  250.             Vector3[] shared = new Vector3[6]
  251.             {
  252.                 new Vector3(-1, 0, 0),      
  253.                 new Vector3(+1, 0, 0),
  254.                 new Vector3(0, -1, 0),
  255.                 new Vector3(0, +1, 0),
  256.                 new Vector3(0, 0, -1),
  257.                 new Vector3(0, 0, +1)
  258.             };
  259.             List<Polygon> polys = new List<Polygon>();
  260.             for (int i=0; i<indices.GetLength(0); i++)
  261.             {
  262.                 polys.Add(new Polygon( new List<Vertex>() {
  263.                     vertices[indices[i,0]],
  264.                     vertices[indices[i,1]],
  265.                     vertices[indices[i,2]],
  266.                     vertices[indices[i,3]]
  267.                     }
  268.                 ));
  269.             }
  270.             return CSG.FromPolygons(polys);
  271.         }
  272.        
  273.         // Construct a solid sphere. Optional parameters are `center`, `radius`,
  274.         // `slices`, and `stacks`, which default to `[0, 0, 0]`, `1`, `16`, and `8`.
  275.         // The `slices` and `stacks` parameters control the tessellation along the
  276.         // longitude and latitude directions.
  277.         //
  278.         // Example usage:
  279.         //
  280.         //     var sphere = CSG.sphere({
  281.         //       center: [0, 0, 0],
  282.         //       radius: 1,
  283.         //       slices: 16,
  284.         //       stacks: 8
  285.         //     });
  286.         public static CSG Sphere(Options options) {/*
  287.             options = options || {};
  288.             var c = new CSG.Vector(options.center || [0, 0, 0]);
  289.             var r = options.radius || 1;
  290.             var slices = options.slices || 16;
  291.             var stacks = options.stacks || 8;
  292.             var polygons = [], vertices;
  293.             function vertex(theta, phi) {
  294.             theta *= Math.PI * 2;
  295.             phi *= Math.PI;
  296.             var dir = new CSG.Vector(
  297.                 Math.cos(theta) * Math.sin(phi),
  298.                 Math.cos(phi),
  299.                 Math.sin(theta) * Math.sin(phi)
  300.             );
  301.             vertices.push(new CSG.Vertex(c.plus(dir.times(r)), dir));
  302.         }
  303.         for (var i = 0; i < slices; i++) {
  304.             for (var j = 0; j < stacks; j++) {
  305.                 vertices = [];
  306.                 vertex(i / slices, j / stacks);
  307.                 if (j > 0) vertex((i + 1) / slices, j / stacks);
  308.                 if (j < stacks - 1) vertex((i + 1) / slices, (j + 1) / stacks);
  309.                     vertex(i / slices, (j + 1) / stacks);
  310.                     polygons.push(new CSG.Polygon(vertices));
  311.                 }
  312.             }
  313.         return CSG.fromPolygons(polygons);*/
  314.             return new CSG();
  315.         }
  316.        
  317.    
  318.         // Construct a solid cylinder. Optional parameters are `start`, `end`,
  319.         // `radius`, and `slices`, which default to `[0, -1, 0]`, `[0, 1, 0]`, `1`, and
  320.         // `16`. The `slices` parameter controls the tessellation.
  321.         //
  322.         // Example usage:
  323.         //
  324.         //     var cylinder = CSG.cylinder({
  325.         //       start: [0, -1, 0],
  326.         //       end: [0, 1, 0],
  327.         //       radius: 1,
  328.         //       slices: 16
  329.         //     });
  330.         public static CSG Cylinder(Options options)
  331.         {
  332.             /*options = options || {};
  333.             var s = new CSG.Vector(options.start || [0, -1, 0]);
  334.             var e = new CSG.Vector(options.end || [0, 1, 0]);
  335.             var ray = e.minus(s);
  336.             var r = options.radius || 1;
  337.             var slices = options.slices || 16;
  338.             var axisZ = ray.unit(), isY = (Math.abs(axisZ.y) > 0.5);
  339.             var axisX = new CSG.Vector(isY, !isY, 0).cross(axisZ).unit();
  340.             var axisY = axisX.cross(axisZ).unit();
  341.             var start = new CSG.Vertex(s, axisZ.negated());
  342.             var end = new CSG.Vertex(e, axisZ.unit());
  343.             var polygons = [];
  344.             function point(stack, slice, normalBlend) {
  345.                 var angle = slice * Math.PI * 2;
  346.                 var out = axisX.times(Math.cos(angle)).plus(axisY.times(Math.sin(angle)));
  347.                 var pos = s.plus(ray.times(stack)).plus(out.times(r));
  348.                 var normal = out.times(1 - Math.abs(normalBlend)).plus(axisZ.times(normalBlend));
  349.                 return new CSG.Vertex(pos, normal);
  350.             }
  351.             for (var i = 0; i < slices; i++) {
  352.                 var t0 = i / slices, t1 = (i + 1) / slices;
  353.                 polygons.push(new CSG.Polygon([start, point(0, t0, -1), point(0, t1, -1)]));
  354.                 polygons.push(new CSG.Polygon([point(0, t1, 0), point(0, t0, 0), point(1, t0, 0), point(1, t1, 0)]));
  355.                 polygons.push(new CSG.Polygon([end, point(1, t1, 1), point(1, t0, 1)]));
  356.             }
  357.             return CSG.fromPolygons(polygons);*/
  358.             return new CSG();
  359.         }
  360.     }
  361.  
  362.    
  363.  
  364.     public enum PolygonType
  365.     {
  366.         COPLANAR =0,
  367.         FRONT = 1,
  368.         BACK = 2,
  369.         SPANNING = 3
  370.     }
  371.  
  372.    
  373.     // # class Vertex
  374.    
  375.     // Represents a vertex of a polygon. Use your own vertex class instead of this
  376.     // one to provide additional features like texture coordinates and vertex
  377.     // colors. Custom vertex classes need to provide a `pos` property and `clone()`,
  378.     // `flip()`, and `interpolate()` methods that behave analogous to the ones
  379.     // defined by `CSG.Vertex`. This class provides `normal` so convenience
  380.     // functions like `CSG.sphere()` can return a smooth vertex normal, but `normal`
  381.     // is not used anywhere else.
  382.     public class Vertex
  383.     {
  384.         public Vector3 pos;
  385.         public Vector3 normal;
  386.        
  387.         public Vertex(Vector3 pos, Vector3 normal)
  388.         {
  389.             this.pos = pos;
  390.             this.normal = normal;
  391.         }
  392.        
  393.         public Vertex Clone()
  394.         {  
  395.             return new Vertex(this.pos, this.normal);
  396.         }
  397.        
  398.         // Invert all orientation-specific data (e.g. vertex normal). Called when the
  399.         // orientation of a polygon is flipped.
  400.         public void Flip()
  401.         {
  402.             normal = -normal;  
  403.         }
  404.         // Create a new vertex between this vertex and `other` by linearly
  405.         // interpolating all properties using a parameter of `t`. Subclasses should
  406.         // override this to interpolate additional properties.
  407.         public Vertex Interpolate(Vertex other, float t)
  408.         {
  409.             return new Vertex(Vector3.Lerp(this.pos, other.pos, t), Vector3.Lerp(this.normal, other.normal, t));
  410.         }
  411.     }
  412.  
  413.    
  414.     // # class Plane
  415.    
  416.     // Represents a plane in 3D space.
  417.     public class Plane
  418.     {
  419.         public Vector3 normal;
  420.         public float w;
  421.        
  422.         public Plane(Vector3 normal, float w)
  423.         {
  424.             this.normal = normal;
  425.             this.w = w;
  426.         }
  427.        
  428.         // `CSG.Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a
  429.         // point is on the plane.  
  430.         public static float EPSILON = 1e-5f;
  431.        
  432.         public static Plane FromPoints(Vector3 a, Vector3 b, Vector3 c)
  433.         {
  434.             Vector3 n = Vector3.Cross((b-a), (c-a)).normalized;
  435.             return new Plane(n, Vector3.Dot(n, a));
  436.         }
  437.        
  438.         public Plane Clone()   
  439.         {
  440.             return new Plane(this.normal ,this.w);
  441.         }
  442.         public void Flip()
  443.         {
  444.             normal = -normal;
  445.             w = -w;
  446.         }
  447.        
  448.         // Split `polygon` by this plane if needed, then put the polygon or polygon
  449.         // fragments in the appropriate lists. Coplanar polygons go into either
  450.         // `coplanarFront` or `coplanarBack` depending on their orientation with
  451.         // respect to this plane. Polygons in front or in back of this plane go into
  452.         // either `front` or `back`.
  453.         public void SplitPolygon(Polygon polygon, ref List<Polygon> coplanar, ref List<Polygon> front, ref List<Polygon> back)
  454.         {
  455.             // Classify each point as well as the entire polygon into one of the above
  456.             // four classes.
  457.             PolygonType polygonType = PolygonType.COPLANAR;
  458.             List<PolygonType> types = new List<PolygonType>();
  459.             for (var i = 0; i < polygon.vertices.Count; i++) {
  460.               var t = Vector3.Dot(this.normal, polygon.vertices[i].pos) - this.w;
  461.               var type = (t < -Plane.EPSILON) ? PolygonType.BACK : (t > Plane.EPSILON) ? PolygonType.FRONT : PolygonType.COPLANAR;
  462.               polygonType |= type;
  463.               types.Add(type);
  464.             }
  465.        
  466.             // Put the polygon in the correct list, splitting it when necessary.
  467.             switch (polygonType) {
  468.               case PolygonType.COPLANAR:
  469.                 if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
  470.                     coplanar.Add(polygon);
  471.                 else
  472.                     coplanar.Add(polygon);
  473.                 break;
  474.               case PolygonType.FRONT:
  475.                 front.Add(polygon);
  476.                 break;
  477.               case PolygonType.BACK:
  478.                 back.Add(polygon);
  479.                 break;
  480.               case PolygonType.SPANNING:
  481.                 List<Vertex> f = new List<Vertex>(); List<Vertex> b = new List<Vertex>();
  482.                 for (var i = 0; i < polygon.vertices.Count; i++) {
  483.                     var j = (i + 1) % polygon.vertices.Count;
  484.                     PolygonType ti = types[i]; PolygonType tj = types[j];
  485.                     Vertex vi = polygon.vertices[i]; Vertex vj = polygon.vertices[j];
  486.                     if (ti != PolygonType.BACK)
  487.                         f.Add(vi);
  488.                     if (ti != PolygonType.FRONT)
  489.                         b.Add(ti != PolygonType.BACK ? vi.Clone() : vi);
  490.                     if ((ti | tj) == PolygonType.SPANNING) {
  491.                         var t = (this.w - Vector3.Dot(this.normal, vi.pos)) / Vector3.Dot(this.normal, vj.pos-vi.pos);
  492.                         var v = vi.Interpolate(vj, t);
  493.                         f.Add(v);
  494.                         b.Add(v.Clone());
  495.                     }
  496.                 }
  497.                     if (f.Count >= 3)
  498.                         front.Add(new Polygon(f, polygon.shared));
  499.                     if (b.Count >= 3)
  500.                         back.Add(new Polygon(b, polygon.shared));
  501.                     break;
  502.                 default:
  503.                     break;
  504.             }
  505.         }
  506.        
  507.         public void SplitPolygon(Polygon polygon, ref List<Polygon> front, ref List<Polygon> back)
  508.         {
  509.             // Classify each point as well as the entire polygon into one of the above
  510.             // four classes.
  511.             PolygonType polygonType = PolygonType.COPLANAR;
  512.             List<PolygonType> types = new List<PolygonType>();
  513.             for (var i = 0; i < polygon.vertices.Count; i++) {
  514.               var t = Vector3.Dot(this.normal, polygon.vertices[i].pos) - this.w;
  515.               var type = (t < -Plane.EPSILON) ? PolygonType.BACK : (t > Plane.EPSILON) ? PolygonType.FRONT : PolygonType.COPLANAR;
  516.               polygonType |= type;
  517.               types.Add(type);
  518.             }
  519.        
  520.             // Put the polygon in the correct list, splitting it when necessary.
  521.             switch (polygonType) {
  522.               case PolygonType.COPLANAR:
  523.                 if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
  524.                     front.Add(polygon);
  525.                 else
  526.                     back.Add(polygon);
  527.                 break;
  528.               case PolygonType.FRONT:
  529.                 front.Add(polygon);
  530.                 break;
  531.               case PolygonType.BACK:
  532.                 back.Add(polygon);
  533.                 break;
  534.               case PolygonType.SPANNING:
  535.                 List<Vertex> f = new List<Vertex>(); List<Vertex> b = new List<Vertex>();
  536.                 for (var i = 0; i < polygon.vertices.Count; i++) {
  537.                     var j = (i + 1) % polygon.vertices.Count;
  538.                     PolygonType ti = types[i]; PolygonType tj = types[j];
  539.                     Vertex vi = polygon.vertices[i]; Vertex vj = polygon.vertices[j];
  540.                     if (ti != PolygonType.BACK)
  541.                         f.Add(vi);
  542.                     if (ti != PolygonType.FRONT)
  543.                         b.Add(ti != PolygonType.BACK ? vi.Clone() : vi);
  544.                     if ((ti | tj) == PolygonType.SPANNING) {
  545.                         var t = (this.w - Vector3.Dot(this.normal, vi.pos)) / Vector3.Dot(this.normal, vj.pos-vi.pos);
  546.                         var v = vi.Interpolate(vj, t);
  547.                         f.Add(v);
  548.                         b.Add(v.Clone());
  549.                     }
  550.                 }
  551.                     if (f.Count >= 3)
  552.                         front.Add(new Polygon(f, polygon.shared));
  553.                     if (b.Count >= 3)
  554.                         back.Add(new Polygon(b, polygon.shared));
  555.                     break;
  556.                 default:
  557.                     break;
  558.             }
  559.         }
  560.     }
  561.        
  562.     // # class Polygon
  563.    
  564.     // Represents a convex polygon. The vertices used to initialize a polygon must
  565.     // be coplanar and form a convex loop. They do not have to be `CSG.Vertex`
  566.     // instances but they must behave similarly (duck typing can be used for
  567.     // customization).
  568.     //
  569.     // Each convex polygon has a `shared` property, which is shared between all
  570.     // polygons that are clones of each other or were split from the same polygon.
  571.     // This can be used to define per-polygon properties (such as surface color).      
  572.     public class Polygon
  573.     {
  574.         public List<Vertex> vertices;
  575.         public Vector3 shared;
  576.         public Plane plane;
  577.        
  578.         public Polygon(List<Vertex> vertices)
  579.         {
  580.             this.vertices = vertices;
  581.             this.plane = Plane.FromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
  582.         }
  583.         public Polygon(List<Vertex> vertices, Vector3 shared)
  584.         {
  585.             this.vertices = vertices;
  586.             this.shared = shared;
  587.             this.plane = Plane.FromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
  588.         }
  589.        
  590.        
  591.         public Polygon Clone()
  592.         {
  593.             List<Vertex> vertices = this.vertices.Select(v => v.Clone()).ToList();
  594.             return new Polygon(vertices);
  595.         }
  596.            
  597.         public void Flip()
  598.         {
  599.             this.vertices.ForEach( v => v.Flip());
  600.             this.plane.Flip();
  601.         }
  602.     }
  603.  
  604.        
  605.    
  606.     // # class Node
  607.    
  608.     // Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
  609.     // by picking a polygon to split along. That polygon (and all other coplanar
  610.     // polygons) are added directly to that node and the other polygons are added to
  611.     // the front and/or back subtrees. This is not a leafy BSP tree since there is
  612.     // no distinction between internal and leaf nodes.
  613.    
  614.     public class Node
  615.     {
  616.         Plane plane;
  617.         List<Polygon> polygons;
  618.         Node front;
  619.         Node back;
  620.        
  621.         public Node(List<Polygon> polygons)
  622.         {
  623.             this.plane = null;
  624.             this.front = null;
  625.             this.back = null;
  626.             this.polygons = new List<Polygon>();
  627.             if (polygons.Count>0)
  628.                 Build(polygons);
  629.         }
  630.         public Node()
  631.         {
  632.             this.plane = null;
  633.             this.front = null;
  634.             this.back = null;
  635.             this.polygons = new List<Polygon>();
  636.         }          
  637.         public Node Clone()
  638.         {
  639.             Node node = new Node(polygons);
  640.             node.plane = plane.Clone();
  641.             node.front = front.Clone();
  642.             node.back = back.Clone();
  643.             node.polygons = polygons.Select(p => p.Clone()).ToList();
  644.             return node;
  645.         }
  646.            
  647.         public void Invert()
  648.         {
  649.             for (var i = 0; i < polygons.Count; i++) {
  650.               polygons[i].Flip();
  651.             }
  652.             this.plane.Flip();
  653.             if (front!=null) this.front.Invert();
  654.             if (back!=null) this.back.Invert();
  655.             var temp = this.front;
  656.             this.front = this.back;
  657.             this.back = temp;
  658.         }
  659.            
  660.    
  661.         // Recursively remove all polygons in `polygons` that are inside this BSP
  662.         // tree.
  663.         public List<Polygon> ClipPolygons(List<Polygon> polygons)
  664.         {
  665.             if (polygons!=null)
  666.             {
  667.                 if (polygons.Count<1)
  668.                     return new List<Polygon>();
  669.             }
  670.             else
  671.             {
  672.                 return new List<Polygon>();
  673.             }
  674.             if (plane==null) return new List<Polygon>();
  675.             List<Polygon> front = new List<Polygon>();
  676.             List<Polygon> back = new List<Polygon>();
  677.             for (var i = 0; i < polygons.Count; i++) {
  678.               this.plane.SplitPolygon(polygons[i], ref front, ref back);
  679.             }
  680.             if (this.front!=null)
  681.                 front = this.front.ClipPolygons(front);
  682.             if (this.back!=null)
  683.                 back = this.back.ClipPolygons(back);
  684.             else
  685.                 back = new List<Polygon>();
  686.             return front.Concat(back).ToList();
  687.         }
  688.            
  689.         // Remove all polygons in this BSP tree that are inside the other BSP tree
  690.         // `bsp`.          
  691.         public void ClipTo(Node bsp)
  692.         {
  693.             this.polygons = bsp.ClipPolygons(this.polygons);
  694.             if (this.front!=null)
  695.                 this.front.ClipTo(bsp);
  696.             if (this.back!=null)
  697.                 this.back.ClipTo(bsp);
  698.         }
  699.            
  700.         // Return a list of all polygons in this BSP tree.
  701.         public List<Polygon> AllPolygons()
  702.         {
  703.             var polygons = this.polygons;
  704.             if (this.front!=null) polygons = polygons.Concat(this.front.AllPolygons()).ToList();
  705.             if (this.back!=null) polygons = polygons.Concat(this.back.AllPolygons()).ToList();
  706.             return polygons;
  707.         }
  708.            
  709.         // Build a BSP tree out of `polygons`. When called on an existing tree, the
  710.         // new polygons are filtered down to the bottom of the tree and become new
  711.         // nodes there. Each set of polygons is partitioned using the first polygon
  712.         // (no heuristic is used to pick a good split).
  713.         public void Build(List<Polygon> polygons) {
  714.             if (polygons.Count==0) return;
  715.             if (this.plane==null) this.plane = polygons[0].plane.Clone();
  716.             List<Polygon> front = new List<Polygon>();
  717.             List<Polygon> back = new List<Polygon>();
  718.             for (var i = 0; i < polygons.Count; i++) {
  719.             this.plane.SplitPolygon(polygons[i], ref this.polygons, ref front, ref back);
  720.             }
  721.             if (front.Count>0) {
  722.                 if (this.front==null)
  723.                     this.front = new Node();
  724.                 this.front.Build(front);
  725.             }
  726.             if (back.Count>0) {
  727.                 if (this.back==null)
  728.                     this.back = new Node();
  729.                 this.back.Build(back);
  730.             }
  731.         }
  732.     }
  733. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement