def test_subdivide_csg_subdivide_children(self): s1 = Sphere() s1.transform = Transformations.translation(-1.5, 0, 0) s2 = Sphere() s2.transform = Transformations.translation(1.5, 0, 0) left = Group() left.add_child(s1) left.add_child(s2) s3 = Sphere() s3.transform = Transformations.translation(0, 0, -1.5) s4 = Sphere() s4.transform = Transformations.translation(0, 0, 1.5) right = Group() right.add_child(s3) right.add_child(s4) shape = CSG("difference", left, right) shape.divide(1) self.assertIsInstance(left.members[0], Group) self.assertEqual(left.members[0].members, [s1]) self.assertIsInstance(left.members[1], Group) self.assertEqual(left.members[1].members, [s2]) self.assertIsInstance(right.members[0], Group) self.assertEqual(right.members[0].members, [s3]) self.assertIsInstance(right.members[1], Group) self.assertEqual(right.members[1].members, [s4])
def test_intersect_ray_csg_test_children(self): left = TestShape() right = TestShape() shape = CSG("difference", left, right) r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) xs = shape.intersect(r) self.assertIsNotNone(left.saved_ray) self.assertIsNotNone(right.saved_ray)
def test_csg_bounding_box(self): left = Sphere() right = Sphere() right.transform = Transformations.translation(2, 3, 4) shape = CSG("difference", left, right) box = shape.bounds_of() self.assertEqual(box.min, Point(-1, -1, -1)) self.assertEqual(box.max, Point(3, 4, 5))
def _create_polygons(solid, face, color, polygons): vertices = [] for i in face.indices[:-1]: v = solid.vertices[i] vertices.append(CSG.Vector(v)) polygon = CSG.Polygon(vertices, False) polygon.shared = color polygons.append(polygon)
def _create_tri_polygon(solid, i0, i1, i2): # CSG.js (WebGL) では時計回りが表 p0 = solid.vertices[i0] p1 = solid.vertices[i1] p2 = solid.vertices[i2] vertices = [] vertices.append(CSG.Vector(p0)) vertices.append(CSG.Vector(p1)) vertices.append(CSG.Vector(p2)) return CSG.Polygon(vertices, False)
def test_ray_hits_csg_object(self): s1 = Sphere() s2 = Sphere() s2.transform = Transformations.translation(0, 0, 0.5) c = CSG("union", s1, s2) r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) xs = c.local_intersect(r) self.assertEqual(len(xs), 2) self.assertEqual(xs[0].t, 4) self.assertEqual(xs[0].object, s1) self.assertEqual(xs[1].t, 6.5) self.assertEqual(xs[1].object, s2)
def test_filtering_list_intersections(self): s1 = Sphere() s2 = Cube() Operation = namedtuple("Operation", ["operation", "x0", "x1"]) operatios = [ Operation("union", 0, 3), Operation("intersection", 1, 2), Operation("difference", 0, 1) ] for operation in operatios: c = CSG(operation.operation, s1, s2) xs = Intersection.intersections(Intersection(1, s1), Intersection(2, s2), Intersection(3, s1), Intersection(4, s2)) result = c.filter_intersections(xs) self.assertEqual(len(result), 2) self.assertEqual(result[0], xs[operation.x0]) self.assertEqual(result[1], xs[operation.x1])
def test_csg_operation_rule(self): OperationResult = namedtuple("OperationResult", ["op", "lhit", "inl", "inr", "result"]) operation_results = [ OperationResult("union", True, True, True, False), OperationResult("union", True, True, False, True), OperationResult("union", True, False, True, False), OperationResult("union", True, False, False, True), OperationResult("union", False, True, True, False), OperationResult("union", False, True, False, False), OperationResult("union", False, False, True, True), OperationResult("union", False, False, False, True), OperationResult("intersection", True, True, True, True), OperationResult("intersection", True, True, False, False), OperationResult("intersection", True, False, True, True), OperationResult("intersection", True, False, False, False), OperationResult("intersection", False, True, True, True), OperationResult("intersection", False, True, False, True), OperationResult("intersection", False, False, True, False), OperationResult("intersection", False, False, False, False), OperationResult("difference", True, True, True, False), OperationResult("difference", True, True, False, True), OperationResult("difference", True, False, True, False), OperationResult("difference", True, False, False, True), OperationResult("difference", False, True, True, True), OperationResult("difference", False, True, False, True), OperationResult("difference", False, False, True, False), OperationResult("difference", False, False, False, False) ] for operation_result in operation_results: result = CSG.intersection_allowed(operation_result.op, operation_result.lhit, operation_result.inl, operation_result.inr) self.assertEqual(result, operation_result.result)
def test_csg_create(self): s1 = Sphere() s2 = Sphere() c = CSG("union", s1, s2) self.assertEqual(c.operation, "union") self.assertEqual(c.left, s1) self.assertEqual(c.right, s2) self.assertEqual(s1.parent, c) self.assertEqual(s2.parent, c)
def csg_from_solid(solid, as_tri=True): as_tri = True # 三角パッチじゃないと、CSG.Node.build で無限ループになってしまう。 polygons = [] for f in solid.faces: indices = f.indices # face は最後が閉じていることに注意 color = map(lambda c: c / 255.0, f.color) if f.color else None if as_tri: _create_tri_polygons(solid, f, color, polygons) else: _create_polygons(solid, f, color, polygons) return CSG(polygons)
def add_(self, primitive): assert primitive.is_primitive assert self.curr.is_operator if self.curr.left is None: self.curr.left = primitive elif self.curr.right is None: self.curr.right = primitive else: # need to grow a new operator... either growing upwards or downwards log.info( "grow new operator from curr %r depth %d root.height %d elev %d " % (self.curr, self.curr.depth, self.root.height, self.curr.elevation)) elev = self.curr.elevation upwards = elev <= 1 if upwards: oldroot = self.root self.root = CSG(self.operator) self.root.left = oldroot newop = CSG(self.operator) newop.left = primitive self.root.right = newop self.curr = newop else: # growing downwards add intermediary opnode oldcurr = self.curr newop = CSG(self.operator) newop.left = oldcurr newop.right = primitive assert oldcurr.parent.right == oldcurr oldcurr.parent.right = newop self.curr = newop pass pass
if __name__ == '__main__': pass plt.ion() plt.close("all") fig = plt.figure() ax = fig.add_subplot(1,1,1, aspect='equal') bb = BBox([[0.,0.,0.],[80.,80.,80.]]) bb.set_lim(ax) root = CSG("sphere", param=[40.,40.,0,20.]) rdr = Renderer(ax) rdr.render(root) level = 7 dim = 2 maxcorner = (1 << (1 << dim)) - 1 # 2d:0xf 3d:0xff one bit for each child msk = (1 << dim) - 1 # 2d:0b11 3d:0b111 one bit for each dimension grids = [] for lev in range(Grid.maxlevel): g = Grid(bb, level=lev) grids.append(g) pass
def __init__(self): self.root = CSG(self.operator) self.curr = self.root
class HomogeneousTree(object): def __init__(self): self.root = CSG(self.operator) self.curr = self.root def add(self, primitive): self.add_(primitive) self.root.analyse() log.info("root.height after add %r " % self.root.height) def _get_curr(self): return self._curr def _set_curr(self, node): if hasattr(self, '_curr') and hasattr(self._curr, 'textra'): del self._curr.textra pass self._curr = node self._curr.textra = "*" pass curr = property(_get_curr, _set_curr) def add_(self, primitive): assert primitive.is_primitive assert self.curr.is_operator if self.curr.left is None: self.curr.left = primitive elif self.curr.right is None: self.curr.right = primitive else: # need to grow a new operator... either growing upwards or downwards log.info( "grow new operator from curr %r depth %d root.height %d elev %d " % (self.curr, self.curr.depth, self.root.height, self.curr.elevation)) elev = self.curr.elevation upwards = elev <= 1 if upwards: oldroot = self.root self.root = CSG(self.operator) self.root.left = oldroot newop = CSG(self.operator) newop.left = primitive self.root.right = newop self.curr = newop else: # growing downwards add intermediary opnode oldcurr = self.curr newop = CSG(self.operator) newop.left = oldcurr newop.right = primitive assert oldcurr.parent.right == oldcurr oldcurr.parent.right = newop self.curr = newop pass pass pass
def test_ray_misses_csg_object(self): c = CSG("union", Sphere(), Sphere()) r = Ray(Point(0, 2, -5), Vector(0, 0, 1)) xs = c.local_intersect(r) self.assertEqual(len(xs), 0)