def _line(pieces): if len(pieces) != 7: raise PartError("Invalid line data") colour = colour_from_str(pieces[0]) point1 = map(float, pieces[1:4]) point2 = map(float, pieces[4:7]) return Line(Colour(colour), Vector(*point1), Vector(*point2))
def get_bounding_box(points): return BoudingBox( Vector(min(p.x for p in points), min(p.y for p in points), min(p.z for p in points)), Vector(max(p.x for p in points), max(p.y for p in points), max(p.z for p in points)), )
def _write_triangle(self, v1, v2, v3): self.minimum = Vector(min(self.minimum.x, v1.x, v2.x, v3.x), min(self.minimum.y, -v1.y, -v2.y, -v3.y), min(self.minimum.z, v1.z, v2.z, v3.z)) self.maximum = Vector(max(self.maximum.x, v1.x, v2.x, v3.x), max(self.maximum.y, -v1.y, -v2.y, -v3.y), max(self.maximum.z, v1.z, v2.z, v3.z)) #normal vector = cross product of any two of the edges #vec1 = p1-p2 vec1 = numpy.matrix([v1.x - v2.x, v1.y - v2.y, v1.z - v2.z]) #vec2 = p1-p3 #vec2 = numpy.matrix([v1.x-v3.x,v1.y-v3.y,v1.z-v3.z]) vec2 = numpy.matrix([v2.x - v3.x, v2.y - v3.y, v2.z - v3.z]) #vec2 = numpy.matrix([v3.x-v1.x,v3.y-v1.y,v3.z-v1.z]) normal_vector = numpy.cross(vec1, vec2) self.stl_file.write("facet normal %1.3f %1.3f %1.3f\n" "\touter loop\n" "\t\tvertex %1.3f %1.3f %1.3f\n" "\t\tvertex %1.3f %1.3f %1.3f\n" "\t\tvertex %1.3f %1.3f %1.3f\n" "\tendloop\n" "endfacet\n" % (normal_vector.item(0), normal_vector.item(1), normal_vector.item(2), v1.x, -v1.y, v1.z, v2.x, -v2.y, v2.z, v3.x, -v3.y, v3.z))
def __init__(self, parts, pov_file): self.parts = parts self.pov_file = pov_file self.lights = [] self.minimum = Vector(0, 0, 0) self.maximum = Vector(0, 0, 0) self.warnings = []
def __init__(self, parts, pov_file): self.parts = parts self.pov_file = pov_file self.lights = [] self.minimum = Vector(0, 0, 0) self.maximum = Vector(0, 0, 0) self.bbox_cache = {}
def _triangle(pieces): if len(pieces) != 10: raise PartError("Invalid triangle data") colour = colour_from_str(pieces[0]) point1 = map(float, pieces[1:4]) point2 = map(float, pieces[4:7]) point3 = map(float, pieces[7:10]) return Triangle(Colour(colour), Vector(*point1), Vector(*point2), Vector(*point3))
def __init__(self, camera_position, axes, parts): self.parts = parts self.lights = [] self.minimum = Vector(0, 0, 0) self.maximum = Vector(0, 0, 0) self.bbox_cache = {} self.camera_position = camera_position self.axes = axes
def _optional_line(pieces): if len(pieces) != 13: raise PartError("Invalid line data") colour = colour_from_str(pieces[0]) point1 = map(float, pieces[1:4]) point2 = map(float, pieces[4:7]) point3 = map(float, pieces[7:10]) point4 = map(float, pieces[10:13]) return OptionalLine(Colour(colour), Vector(*point1), Vector(*point2), Vector(*point3), Vector(*point4))
def _quadrilateral(pieces): if len(pieces) != 13: raise PartError("Invalid quadrilateral data") colour = colour_from_str(pieces[0]) point1 = map(float, pieces[1:4]) point2 = map(float, pieces[4:7]) point3 = map(float, pieces[7:10]) point4 = map(float, pieces[10:13]) return Quadrilateral(Colour(colour), Vector(*point1), Vector(*point2), Vector(*point3), Vector(*point4))
def _polygons_from_objects(self, model, top_level_piece=None, current=Current(Identity(), White.code, Vector(0, 0, 0))): # Extract polygons from objects, filtering out those behind the camera. polygons = [] poly_handlers = { Piece: self._subpart_get_poly, Line: self._line_get_poly, Triangle: self._triangle_get_poly, Quadrilateral: self._quadrilateral_get_poly, } for obj in model.objects: if isinstance(obj, Piece) and obj.part == "LIGHT": continue try: args = (obj, top_level_piece or obj, current) poly = poly_handlers[type(obj)](*args) except KeyError: continue if poly: polygons.extend(poly) else: continue return polygons
def write(self, model, current_matrix=Identity(), current_position=Vector(0, 0, 0), level=0): for obj in model.objects: if isinstance(obj, Piece): part = self.parts.part(code=obj.part) if part: matrix = obj.matrix self.write( part, current_matrix * matrix, current_position + current_matrix * obj.position, level + 1) else: sys.stderr.write("Part not found: %s\n" % obj.part) elif isinstance(obj, Triangle): p1 = current_matrix * obj.p1 + current_position p2 = current_matrix * obj.p2 + current_position p3 = current_matrix * obj.p3 + current_position if abs((p3 - p1).cross(p2 - p1)) != 0: self._write_triangle(p1, p2, p3) elif isinstance(obj, Quadrilateral): p1 = current_matrix * obj.p1 + current_position p2 = current_matrix * obj.p2 + current_position p3 = current_matrix * obj.p3 + current_position p4 = current_matrix * obj.p4 + current_position if abs((p3 - p1).cross(p2 - p1)) != 0: self._write_triangle(p1, p2, p3) if abs((p3 - p1).cross(p4 - p1)) != 0: self._write_triangle(p3, p4, p1)
def vector_position(input_str): """ a type for comma separated vector """ position = input_str.split(",") if len(position) != 3: raise argparse.ArgumentTypeError( "Expecting comma-separated elements for the position") return Vector(*map(float, position))
def head(self, colour, angle=0, part=Head): """ Displacement from torso """ displacement = self.matrix * Vector(0, -24, 0) piece = Piece(colour, self.position + displacement, self.matrix * Identity().rotate(angle, YAxis), part, self.group) self.pieces_info["head"] = piece return piece
def __init__(self, position=Vector(0, 0, 0), matrix=Identity(), group=None): self.position = position self.matrix = matrix self.pieces_info = {} self.group = group
def right_leg(self, colour, angle=0, part=LegRight): """" Add a right leg""" displacement = self.matrix * Vector(0, 44, 0) piece = Piece(colour, self.position + displacement, self.matrix * Identity().rotate(angle, XAxis), part, self.group) self.pieces_info["right leg"] = piece return piece
def left_hand(self, left_arm, colour, angle=0, part=Hand): # Displacement from left hand displacement = left_arm.position + left_arm.matrix * Vector(4, 17, -9) matrix = left_arm.matrix * Identity().rotate( 40, XAxis) * Identity().rotate(angle, ZAxis) piece = Piece(colour, displacement, matrix, part, self.group) self.pieces_info["left hand"] = piece return piece
def _write_triangle(self, colour, *vectors): indent = 2 assert len(vectors) == 3 self.minimum = Vector(min(self.minimum.x, vectors[0].x, vectors[1].x, vectors[2].x), min(self.minimum.y, -vectors[0].y, -vectors[1].y, -vectors[2].y), min(self.minimum.z, vectors[0].z, vectors[1].z, vectors[2].z)) self.maximum = Vector(max(self.maximum.x, vectors[0].x, vectors[1].x, vectors[2].x), max(self.maximum.y, -vectors[0].y, -vectors[1].y, -vectors[2].y), max(self.maximum.z, vectors[0].z, vectors[1].z, vectors[2].z)) triangle = ( vectors[0].x, vectors[0].y, vectors[0].z, vectors[1].x, vectors[1].y, vectors[1].z, vectors[2].x, vectors[2].y, vectors[2].z ) lines = ["triangle", "{", POV_FORMAT_STRING_TRIANGLE % triangle] self.pov_file.write("\n".join(indent * " " + x for x in lines)) self._write_colour(colour, indent + 2) self.pov_file.write(" " * indent + "}\n\n")
def right_hand(self, right_arm, colour, angle=0, part=Hand): # Displacement from right arm displacement = right_arm.position + right_arm.matrix * Vector( -4, 17, -9) matrix = right_arm.matrix * Identity().rotate( 40, XAxis) * Identity().rotate(angle, ZAxis) piece = Piece(colour, displacement, matrix, part, self.group) self.pieces_info["right hand"] = piece return piece
def left_shoe(self, left_leg, colour, angle=0, part=None): """ Add a shoe on the left""" if not part: return None # Displacement from left leg displacement = left_leg.position + left_leg.matrix * Vector(10, 28, 0) matrix = left_leg.matrix * Identity().rotate(angle, YAxis) piece = Piece(colour, displacement, matrix, part, self.group) return piece
def left_arm(self, colour, angle=0, part=ArmLeft): """ Displacement from torso """ displacement = self.matrix * Vector(15, 8, 0) piece = Piece( colour, self.position + displacement, self.matrix * Identity().rotate(-10, ZAxis) * Identity().rotate(angle, XAxis), part, self.group) self.pieces_info["left arm"] = piece return piece
def project(self, distance): """ project to screen px/c = x/(c + z) px = c * x / (c + z) """ for point in self.points: self.projected.append( Vector((distance * point.x) / (distance + -point.z), (distance * point.y) / (distance + -point.z), -point.z))
def get_coordinate_system(camera_position, look_at_position): """" get coordinate system of the view """ system = CoordinateSystem() system.z = (camera_position - look_at_position) system.z.norm() system.x = UP_DIRECTION.cross(system.z) if abs(system.x) == 0.0: system.x = system.z.cross(Vector(1.0, 0, 0)) system.x.norm() system.y = system.z.cross(system.x) return system
def _write_triangle(self, v1, v2, v3, colour, indent=0): self.minimum = Vector(min(self.minimum.x, v1.x, v2.x, v3.x), min(self.minimum.y, -v1.y, -v2.y, -v3.y), min(self.minimum.z, v1.z, v2.z, v3.z)) self.maximum = Vector(max(self.maximum.x, v1.x, v2.x, v3.x), max(self.maximum.y, -v1.y, -v2.y, -v3.y), max(self.maximum.z, v1.z, v2.z, v3.z)) lines = [ "triangle", "{", " <%1.3f, %1.3f, %1.3f>, " "<%1.3f, %1.3f, %1.3f>, " "<%1.3f, %1.3f, %1.3f>\n" % (v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z) ] self.pov_file.write("\n".join(map(lambda x: indent * " " + x, lines))) self._write_colour(colour, indent + 2) self.pov_file.write(" " * indent + "}\n\n")
def test_add_piece(): group1 = Group() group2 = Group() piece = Piece(White, Vector(0, 0, 0), Identity(), Brick1X1, group=group1) assert piece in group1.pieces assert piece not in group2.pieces group2.add_piece(piece) assert piece in group2.pieces assert piece not in group1.pieces
def _write_triangle_old(self, v1, v2, v3): self.minimum = Vector(min(self.minimum.x, v1.x, v2.x, v3.x), min(self.minimum.y, -v1.y, -v2.y, -v3.y), min(self.minimum.z, v1.z, v2.z, v3.z)) self.maximum = Vector(max(self.maximum.x, v1.x, v2.x, v3.x), max(self.maximum.y, -v1.y, -v2.y, -v3.y), max(self.maximum.z, v1.z, v2.z, v3.z)) #normal vector = cross product of any two of the edges #vec1 = p1-p2 vec1 = numpy.matrix([v1.x - v2.x, v1.y - v2.y, v1.z - v2.z]) #vec2 = p1-p3 #vec2 = numpy.matrix([v1.x-v3.x,v1.y-v3.y,v1.z-v3.z]) vec2 = numpy.matrix([v2.x - v3.x, v2.y - v3.y, v2.z - v3.z]) #vec2 = numpy.matrix([v3.x-v1.x,v3.y-v1.y,v3.z-v1.z]) normal_vector = numpy.cross(vec1, vec2) #StlMesh_MeshTriangle (const Standard_Integer V1, const Standard_Integer V2, const Standard_Integer V3, const Standard_Real Xn, const Standard_Real Yn, const Standard_Real Zn) self.occ_model.AddTriangle(vec1.item(0), vec1.item(1), vec1.item(2), vec2.item(0), vec2.item(1), vec2.item(2), normal_vector.item(0), normal_vector.item(1), normal_vector.item(2))
def _sub_file(pieces): if len(pieces) != 14: raise PartError("Invalid part data") colour = colour_from_str(pieces[0]) position = list(map(float, pieces[1:4])) rows = [ list(map(float, pieces[4:7])), list(map(float, pieces[7:10])), list(map(float, pieces[10:13])) ] part = pieces[13].upper() if re.search(ENDS_DOT_DAT, part): part = part[:-4] return Piece(Colour(colour), Vector(*position), Matrix(rows), part)
def collides_with(self, other): bb1 = get_bounding_box(get_points( parts.part(code=self.part))) + Vector(*tuple(self.pos)) bb2 = get_bounding_box(get_points( parts.part(code=other.part))) + Vector(*tuple(other.pos)) return bounding_boxes_collide(bb1, bb2)
return Vector(*map(float, position)) def get_model(ldraw_path): """" get model from ldraw path """ config = get_config() parts = Parts(config['parts.lst']) try: model = Part(ldraw_path) except PartError: sys.stderr.write("Failed to read LDraw file: %s\n" % ldraw_path) sys.exit(1) return model, parts UP_DIRECTION = Vector(0, -1.0, 0) def get_coordinate_system(camera_position, look_at_position): """" get coordinate system of the view """ system = CoordinateSystem() system.z = (camera_position - look_at_position) system.z.norm() system.x = UP_DIRECTION.cross(system.z) if abs(system.x) == 0.0: system.x = system.z.cross(Vector(1.0, 0, 0)) system.x.norm() system.y = system.z.cross(system.x) return system
def _polygons_from_objects(self, model, top_level_piece = None, current_colour = 15, current_matrix = Identity(), current_position = Vector(0, 0, 0)): # Extract polygons from objects, filtering out those behind the camera. polygons = [] c = self.camera_position x, y, z = self.axes for obj in model.objects: if isinstance(obj, Piece): if obj.part == "LIGHT": continue colour = self._current_colour(obj.colour, current_colour) part = self.parts.part(code = obj.part) if part: matrix = obj.matrix polygons += self._polygons_from_objects( part, top_level_piece or obj, colour, current_matrix * matrix, current_position + current_matrix * obj.position) else: sys.stderr.write("Part not found: %s\n" % obj.part) elif isinstance(obj, Line): p1 = current_matrix * obj.p1 + current_position - c p2 = current_matrix * obj.p2 + current_position - c r1 = Vector(p1.dot(x), p1.dot(y), p1.dot(z)) r2 = Vector(p2.dot(x), p2.dot(y), p2.dot(z)) if r1.z >= 0 or r2.z >= 0: continue colour = self._current_colour(obj.colour, current_colour) polygons.append(Polygon(min(r1.z, r2.z), [r1, r2], colour, top_level_piece)) elif isinstance(obj, Triangle): p1 = current_matrix * obj.p1 + current_position - c p2 = current_matrix * obj.p2 + current_position - c p3 = current_matrix * obj.p3 + current_position - c if abs((p3 - p1).cross(p2 - p1)) == 0: continue r1 = Vector(p1.dot(x), p1.dot(y), p1.dot(z)) r2 = Vector(p2.dot(x), p2.dot(y), p2.dot(z)) r3 = Vector(p3.dot(x), p3.dot(y), p3.dot(z)) if r1.z >= 0 or r2.z >= 0 or r3.z >= 0: continue colour = self._current_colour(obj.colour, current_colour) polygons.append(Polygon(min(r1.z, r2.z, r3.z), [r1, r2, r3], colour, top_level_piece)) elif isinstance(obj, Quadrilateral): p1 = current_matrix * obj.p1 + current_position - c p2 = current_matrix * obj.p2 + current_position - c p3 = current_matrix * obj.p3 + current_position - c p4 = current_matrix * obj.p4 + current_position - c if abs((p3 - p1).cross(p2 - p1)) == 0: continue if abs((p3 - p1).cross(p4 - p1)) == 0: continue r1 = Vector(p1.dot(x), p1.dot(y), p1.dot(z)) r2 = Vector(p2.dot(x), p2.dot(y), p2.dot(z)) r3 = Vector(p3.dot(x), p3.dot(y), p3.dot(z)) r4 = Vector(p4.dot(x), p4.dot(y), p4.dot(z)) if r1.z >= 0 or r2.z >= 0 or r3.z >= 0 or r4.z >= 0: continue colour = self._current_colour(obj.colour, current_colour) polygons.append(Polygon(min(r1.z, r2.z, r3.z, r4.z), [r1, r2, r3, r4], colour, top_level_piece)) return polygons
image_dimensions = match["image size"].split("x") if len(image_dimensions) != 2: sys.stderr.write( "Incorrect number of values specified for the image size: %s\n" % match["image size"]) sys.exit(1) try: image_size = map(int, image_dimensions) except ValueError: sys.stderr.write( "Non-integer value specified for the image size: %s\n" % match["image size"]) sys.exit(1) camera_position = Vector(*map(float, match["camera position"].split(","))) look_at_position = Vector( *map(float, match.get("look-at position", "0.0,0.0,0.0").split(","))) parts = Parts(parts_path) try: model = Part(ldraw_path) except PartError: sys.stderr.write("Failed to read LDraw file: %s\n" % ldraw_path) sys.exit(1) if match.has_key("sky"): background_colour = match["background colour"] else: