LAK132

csg.py

Mar 5th, 2017
412
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.96 KB | None | 0 0
  1. class CSG(object):
  2.     def __init__(self):
  3.         self.polygons = []
  4.    
  5.     def fromPolygons(polygons):
  6.         csg = CSG()
  7.         csg.polygons = polygons
  8.         return csg
  9.        
  10.     def clone(self):
  11.         csg = CSG()
  12.         csg.polygons = copy.deepcopy(self.polygons)
  13.         return csg
  14.    
  15.     def toPolygons(self):
  16.         return self.polygons
  17.        
  18.    
  19.     def union(self, csg):
  20.         a = CSG_Node(self.clone().polygons)
  21.         b = CSG_Node(csg.clone().polygons)
  22.         a.clipTo(b)
  23.         b.clipTo(a)
  24.         b.invert()
  25.         b.clipTo(a)
  26.         b.invert()
  27.         a.build(b.allPolygons())
  28.         return CSG.fromPolygons(a.allPolygons())
  29.        
  30.     def subtract(self, csg):
  31.         a = CSG_Node(self.clone().polygons)
  32.         b = CSG_Node(csg.clone().polygons)
  33.         a.invert()
  34.         a.clipTo(b)
  35.         b.clipTo(a)
  36.         b.invert()
  37.         b.clipTo(a)
  38.         b.invert()
  39.         a.build(b.allPolygons())
  40.         a.invert()
  41.         return CSG.fromPolygons(a.allPolygons())
  42.        
  43.     def intersect(self, csg):
  44.         a = CSG_Node(self.clone().polygons)
  45.         b = CSG_Node(csg.clone().polygons)
  46.         a.invert()
  47.         b.clipTo(a)
  48.         b.invert()
  49.         a.clipTo(b)
  50.         b.clipTo(a)
  51.         a.build(b.allPolygons())
  52.         a.invert()
  53.         CSG.fromPolygons(a.allPolygons())
  54.        
  55.     def inverse(self):
  56.         csg = self.clone()
  57.         for poly in csg.polygons:
  58.             poly.flip()
  59.         return csg
  60.        
  61.     def CSG_Cube(self, origin, size):
  62.         s = [1.0, 1.0, 1.0]
  63.         if len(size) == 3:
  64.             s[0] = size[0]
  65.             s[1] = size[1]
  66.             s[2] = size[2]
  67.         elif 'x' in size:
  68.             s[0] = size.x
  69.             s[1] = size.y
  70.             s[2] = size.z
  71.         c = CSG_Vector(origin)
  72.         xNorm = 1 if s[0] >= 0 else -1
  73.         yNorm = 1 if s[1] >= 0 else -1
  74.         zNorm = 1 if s[2] >= 0 else -1
  75.         a = CSG.fromPolygons([
  76.             [[0, 4, 6, 2], [-xNorm, 0, 0]],
  77.             [[1, 3, 7, 5], [xNorm, 0, 0]],
  78.             [[0, 1, 5, 4], [0, -yNorm, 0]],
  79.             [[2, 6, 7, 3], [0, yNorm, 0]],
  80.             [[0, 2, 3, 1], [0, 0, -zNorm]],
  81.             [[4, 5, 7, 6], [0, 0, zNorm]]])
  82.         b = []
  83.         for poly in a.toPolygons():
  84.             d = []
  85.             for i in poly[0]:
  86.                 pos = CSG_Vector(
  87.                     c.x + (s[0] if i & 1 != 0 else 0),
  88.                     c.y + (s[1] if i & 2 != 0 else 0),
  89.                     c.z + (s[2] if i & 4 != 0 else 0)
  90.                 )
  91.                 d.append(CSG_Vertex(pos, CSG_Vector(poly[1])))
  92.             b.append(CSG_Polygon(d, None))
  93.         self.polygons = b
  94.                
  95. class CSG_Vector(object):
  96.     def __init__(self, *arg):
  97.         if len(arg) == 3:
  98.             self.x = arg[0]
  99.             self.y = arg[1]
  100.             self.z = arg[2]
  101.         elif hasattr(arg[0], 'x'):
  102.             self.x = arg[0].x
  103.             self.y = arg[0].y
  104.             self.z = arg[0].z
  105.         else:
  106.             self.x = arg[0][0]
  107.             self.y = arg[0][1]
  108.             self.z = arg[0][2]
  109.        
  110.     def clone(self):
  111.         return CSG_Vector(self.x, self.y, self.z)
  112.    
  113.     def negated(self):
  114.         return CSG_Vector(-sefl.x, -self.y, -self.z)
  115.    
  116.     def plus(self, a):
  117.         return CSG_Vector(self.x + a.x, self.y + a.y, self.z + a.z)
  118.    
  119.     def minus(self, a):
  120.         return CSG_Vector(self.x - a.x, self.y - a.y, self.z - a.z)
  121.    
  122.     def times(self, a):
  123.         return CSG_Vector(self.x * a, self.y * a, self.z * a)
  124.    
  125.     def dividedBy(self, a):
  126.         return CSG_Vector(self.x / a, self.y / a, self.z / a)
  127.    
  128.     def dot(self, a):
  129.         return ((self.x * a.x) + (self.y * a.y) + (self.z * a.z))
  130.    
  131.     def lerp(self, a, t):
  132.         return self.plus(a.minus(self).times(t))
  133.        
  134.     def length(self):
  135.         return math.sqrt(self.dot(self))
  136.        
  137.     def unit(self):
  138.         return self.dividedBy(self.length())
  139.        
  140.     def cross(self, a):
  141.         return CSG_Vector((self.y * a.z) - (self.z * a.y), (self.z * a.x) - (self.x * a.z), (self.x * a.y) - (self.y * a.x))
  142.    
  143. class CSG_Vertex(object):
  144.     def __init__(self, pos, normal):
  145.         self.pos = CSG_Vector(pos)
  146.         self.normal = CSG_Vector(normal)
  147.    
  148.     def clone(self):
  149.         return CSG_Vertex(copy.deepcopy(self.pos), copy.deepcopy(self.normal))
  150.        
  151.     def flip(self):
  152.         self.normal = self.normal.negated()
  153.        
  154.     def interpolate(self, other, t):
  155.         return CSG_Vertex(self.pos.lerp(other.pos, t), self.normal.lerp(other.normal, t))
  156.        
  157. class CSG_Plane(object):
  158.     def __init__(self, normal, w):
  159.         self.normal = normal
  160.         self.w = w
  161.        
  162.     EPSILON = 1e-5
  163.        
  164.     def fromPoints(a, b, c):
  165.         n = b.minus(a).cross(c.minus(a)).unit()
  166.         return CSG_Plane(n, n.dot(a))
  167.        
  168.     def clone(self):
  169.         return CSG_Plane(copy.deepcopy(self.normal), copy.copy(self.w))
  170.        
  171.     def flip(self):
  172.         self.normal = self.normal.negated()
  173.         self.w = -self.w
  174.        
  175.     def splitPolygon(self, polygon, coplanarFront, coplanarBack, front, back):
  176.         COPLANAR = 0
  177.         FRONT = 1
  178.         BACK = 2
  179.         SPANNING = 3
  180.        
  181.         polygonType = 0
  182.         types = []
  183.         for index in range(len(polygon.vertices)):
  184.             t = self.normal.dot(polygon.vertices[index].pos) - self.w
  185.             type = (BACK if t < -GSC_Plane.EPSILON else (FRONT if t > CSG_Plane.EPSILON else COPLANAR))
  186.             polygonType |= type
  187.             types.append(type)
  188.        
  189.         if polygonType == COPLANAR:
  190.             if self.normal.dot(polygon.plane.normal) > 0:
  191.                 coplanarFront.append(polygon)   #These should modify the list outside of this scope as well
  192.             else:
  193.                 coplanarBack.append(polygon)
  194.         elif polygonType == FRONT:
  195.             front.append(polygon)  
  196.         elif polygonType == BACK:
  197.             back.append(polygon)
  198.         elif polygonType == SPANNING:
  199.             f = []
  200.             b = []
  201.             for index in range(len(polygon.vertices)):
  202.                 j = (i + 1) % len(polygon.vertices)
  203.                 ti = types[i]
  204.                 tj = types[j]
  205.                 vi = polygon.vertices[i]
  206.                 vj = polygon.vertices[j]
  207.                 if ti != BACK:  
  208.                     f.append(vi)
  209.                 if ti != FRONT:
  210.                     b.append(vi.clone() if ti != BACK else vi)
  211.                 if (ti | tj) == SPANNING:
  212.                     t = (self.w + self.normal.dot(vi.pos)) / self.normal.dot(vj.pos.minus(vi.pos))
  213.                     v = vi.interpolated(vj, t)
  214.                     f.append(v)
  215.                     b.append(v.clone())
  216.             if len(f) >= 3:
  217.                 front.append(CSG_Polygon(f, polygon.shared))
  218.             if len(b) >= 3:
  219.                 back.append(CSG_Polygon(b, polygon.shared))
  220.                
  221. class CSG_Polygon(object):
  222.     def __init__(self, vertices, shared):
  223.         self.vertices = vertices
  224.         self.shared = shared
  225.         self.plane = CSG_Plane.fromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos)
  226.    
  227.     def clone(self):
  228.         vertices = copy.deepcopy(self.vertices)
  229.         return CSG_Polygon(vertices, self.shared)
  230.    
  231.     def flip(self):
  232.         self.vertices.reverse()
  233.         for vert in self.vertices:
  234.             vert.flip()
  235.         self.plane.flip()
  236.        
  237. class CSG_Node(object):
  238.     def __init__(self, *args):
  239.         self.plane = None
  240.         self.front = None
  241.         self.back = None
  242.         self.polygons = []
  243.         if len(args) == 1:
  244.             self.build(args[0])
  245.    
  246.     def clone(self):
  247.         node = CSG_Node()
  248.         node.plane = None if self.plane is None else self.plane.clone()
  249.         node.front = None if self.front is None else self.front.clone()
  250.         node.back = None if self.back is None else self.back.clone()
  251.         node.polygons = copy.deepcopy(self.polygons)
  252.         return node
  253.        
  254.     def invert(self):
  255.         for index in range(len(self.polygons)):
  256.             self.polygons[index].flip()
  257.         self.plane.flip()
  258.         if self.front is not None:
  259.             self.front.invert()
  260.         if self.back is not None:
  261.             self.back.invert()
  262.         temp = self.front
  263.         self.front = self.back
  264.         self.back = temp
  265.        
  266.     def clipPolygon(self, polygons):
  267.         if self.plane is None:
  268.             return polygons[:]
  269.         front = []
  270.         back = []
  271.         for index in range(len(polygons)):
  272.             self.plane.splitPolygon(polygons[index], front, back, front, back)
  273.         if self.front is not None:
  274.             front = self.front.clipPolygons(front)
  275.         if self.back is not None:
  276.             back = self.back.clipPolygons(back)
  277.         else:
  278.             back = []
  279.         front += back
  280.         return front
  281.        
  282.     def clipTo(self, bsp):
  283.         self.polygons = bsp.clipPolygons(self.polygons)
  284.         if self.front is not None:
  285.             self.front.clipTo(bsp)
  286.         if self.back is not None:
  287.             self.back.cliptTo(bsp)
  288.            
  289.     def allPolygons(self):
  290.         polygons = self.polygons[:]
  291.         if self.front is not None:
  292.             polygons += self.front.allPolygons()
  293.         if self.back is not None:
  294.             polygons += self.back.allPolygons()
  295.         return polygons
  296.    
  297.     def build(self, polygons):
  298.         if not len(polygons):
  299.             return
  300.         if self.plane is None:
  301.             self.plane = polygons[0].plane.clone()
  302.         front = []
  303.         back = []
  304.         for index in range(len(polygons)):
  305.             self.plane.splitPolygon(polygons[i], self.polygons, self.polygons, front, back)
  306.         if len(front):
  307.             if self.front is None:
  308.                 self.front = CSG_Node()
  309.                 self.front.build(front)
  310.         if len(back):
  311.             if self.back is None:
  312.                 self.back = CSG_Node()
  313.                 self.back.build(back)
Advertisement
Add Comment
Please, Sign In to add comment