def get_sub_triangles(triangle: Triangle): """ Return the sub-triangles (central triangle and 3 corner triangles) resulting from connecting the mid-points of triangle's sides. Parameters: triangle -- The triangle to be split into sub-triangles. Return value: Length-2 tuple containing: -- The central triangle (Triangle class instance). -- The 3 corner triangles (length-3 tuple containing Triangle class instances). """ central_triangle = Triangle(get_mid_point(triangle[0], triangle[1]), get_mid_point(triangle[1], triangle[2]), get_mid_point(triangle[2], triangle[0])) corner_triangles = (Triangle(triangle[0], central_triangle[0], central_triangle[2]), Triangle(triangle[1], central_triangle[1], central_triangle[0]), Triangle(triangle[2], central_triangle[2], central_triangle[1])) return (central_triangle, corner_triangles)
def get_main_triangle(side_len, margin_width) -> Triangle: """ Return the main (outermost) triangle (an equilateral triangle with a horizontal base). """ height = get_triangle_height(side_len) lower_left = Point(margin_width, margin_width) top = Point(margin_width + side_len / 2.0, margin_width + height) lower_right = Point(margin_width + side_len, margin_width) return Triangle(lower_left, top, lower_right)
def cart_to_screen(points, size): """ Convert Cartesian coordinates to screen coordinates. Arguments: points is a list of Point objects or a vertex-defined Triangle object size is a 2-tuple of the screen dimensions (width, height) Returns: A list of Point objects or a Triangle object, depending on the type of the input """ if isinstance(points, Triangle): return Triangle(Point(points.a.x, size[1] - points.a.y), Point(points.b.x, size[1] - points.b.y), Point(points.c.x, size[1] - points.c.y)) else: trans_points = [Point(p.x, size[1] - p.y) for p in points] return trans_points
def parse_stl(filename): """Parse un fichier STL.""" data = { 'triangles': [], # Extremums 'xmin': float('inf'), 'xmax': float('-inf'), 'ymin': float('inf'), 'ymax': float('-inf'), 'zmin': float('inf'), 'zmax': float('-inf'), } file = open(filename, 'rb') parser = BinaryParser(file) parser.read_bytes(80) data['num_triangles'] = parser.read_uint32() print('Nombre de triangles :', data['num_triangles']) for _ in range(data['num_triangles']): # Vecteur normal parser.read_float(3) vertices = [] for _ in range(3): vertex = Vertex(parser.read_float(3)) data['xmin'], data['xmax'] = extremums( data['xmin'], data['xmax'], vertex.x) data['ymin'], data['ymax'] = extremums( data['ymin'], data['ymax'], vertex.y) data['zmin'], data['zmax'] = extremums( data['zmin'], data['zmax'], vertex.z) vertices.append(vertex) # Attribute byte count parser.read_uint16() triangle = Triangle(vertices) data['triangles'].append(triangle) file.close() return data
def get_triangles(self): #f = open(self._filename) with open(self._filename) as f: #try: self._log.debug(u"Opened file '%s' as OFF file." % self._filename) vertices = [] triangles = TriangleList() first_line = f.readline() if first_line.startswith("OFF"): vertice_count, polygon_count, edge_count = [ int(value.strip()) for value in f.readline().split(" ") ] for vertex_index in range(vertice_count): vertices.append( array([ float(coord.strip()) for coord in f.readline().split(" ") if coord.strip() != "" ])) for polygon_index in range(polygon_count): n, v1, v2, v3 = [ int(value.strip()) for value in f.readline().split(" ") if value.strip() != "" ] if n != 3: raise FileFormatException( "The file '%s' contains polygons, that are not triangles." % self._filename) triangles.append( Triangle([vertices[v1], vertices[v2], vertices[v3]])) else: raise FileFormatException( "The file '%s' is not of the expected format: %s" % (self._filename, first_line)) #finally: # f.close() self._log.debug(u"Read %d triangles from file '%s'." % (len(triangles), self._filename)) return triangles
from geometry import Triangle, Circle, Point, Square if __name__ == '__main__': figure_list = [ Triangle(Point(0, 0), Point(0, 2), Point(3, 4)), Circle(2, Point(0, 0)), Square(Point(0, 0), Point(2, 2)) ] for figure in figure_list: figure.figure_square() figure.figure_perimeter() print(f'{figure.square},{figure.perimeter}')
def main(): """Calculate Delaunay triangulation and output an image""" # Anti-aliasing amount -- multiply screen dimensions by this when supersampling aa_amount = 4 # Some gradients gradient = { 'sunshine': Gradient(Color(255, 248, 9), Color(255, 65, 9)), 'purples': Gradient(Color(255, 9, 204), Color(4, 137, 232)), 'grass': Gradient(Color(255, 232, 38), Color(88, 255, 38)), 'valentine': Gradient(Color(102, 0, 85), Color(255, 25, 216)), 'sky': Gradient(Color(0, 177, 255), Color(9, 74, 102)), 'ubuntu': Gradient(Color(119, 41, 83), Color(221, 72, 20)), 'fedora': Gradient(Color(41, 65, 114), Color(60, 110, 180)), 'debian': Gradient(Color(215, 10, 83), Color(10, 10, 10)), 'opensuse': Gradient(Color(151, 208, 5), Color(34, 120, 8)) } # Get command line arguments parser = argparse.ArgumentParser() parser.set_defaults(output_filename='triangles.png') parser.set_defaults(n_points=100) parser.set_defaults(distribution='uniform') # Value options parser.add_argument( '-o', '--output', dest='output_filename', help= 'The filename to write the image to. Supported filetypes are BMP, TGA, PNG, and JPEG' ) parser.add_argument( '-n', '--npoints', dest='n_points', type=int, help='The number of points to use when generating the triangulation.') parser.add_argument('-x', '--width', dest='width', type=int, help='The width of the image.') parser.add_argument('-y', '--height', dest='height', type=int, help='The height of the image.') parser.add_argument('-g', '--gradient', dest='gradient', help='The name of the gradient to use.') parser.add_argument( '-i', '--image-file', dest='input_filename', help= 'An image file to use when calculating triangle colors. Image dimensions will override dimensions set by -x and -y.' ) parser.add_argument( '-k', '--darken', dest='darken_amount', type=int, help= 'Darken random triangles my the given amount to make the pattern stand out more' ) # Flags parser.add_argument( '-a', '--antialias', dest='antialias', action='store_true', help= 'If enabled, draw the image at 4x resolution and downsample to reduce aliasing.' ) parser.add_argument( '-l', '--lines', dest='lines', action='store_true', help='If enabled, draw lines along the triangle edges.') parser.add_argument( '--linethickness', dest='line_thickness', type=int, help='The thickness (in px) of edges drawn on the graph. Implies -l.') parser.add_argument( '--linecolor', dest='line_color', type=str, help= 'The color of edges drawn on the graph in hex (e.g. ffffff for white). Implies -l.' ) parser.add_argument( '-p', '--points', dest='points', action='store_true', help='If enabled, draw a circle for each vertex on the graph.') parser.add_argument( '--vertexradius', dest='vert_radius', type=int, help= 'The radius (in px) of the vertices drawn on the graph. Implies -p.') parser.add_argument( '--vertexcolor', dest='vert_color', type=str, help= 'The color of vertices drawn on the graph in hex (e.g. ffffff for white). Implies -p.' ) parser.add_argument( '--distribution', dest='distribution', type=str, help= 'The desired distribution of the random points. Options are uniform (default) or Halton.' ) parser.add_argument( '-d', '--decluster', dest='decluster', action='store_true', help= 'If enabled, try to avoid generating clusters of points in the triangulation. This will significantly slow down point generation.' ) parser.add_argument( '-r', '--right', dest='right_tris', action='store_true', help='If enabled, generate right triangles rather than random ones.') parser.add_argument( '-e', '--equilateral', dest='equilateral_tris', action='store_true', help= 'If enabled, generate equilateral triangles rather than random ones.') # Parse the arguments options = parser.parse_args() # Set the number of points to use npoints = options.n_points # Make sure the gradient name exists (if applicable) gname = options.gradient if not gname and not options.input_filename: print( 'Require either gradient (-g) or input image (-i). Try --help for details.' ) sys.exit(64) elif gname not in gradient and not options.input_filename: print('Invalid gradient name') sys.exit(64) elif options.input_filename: # Warn if a gradient was selected as well as an image if options.gradient: print('Image supercedes gradient; gradient selection ignored') background_image = Image.open(options.input_filename) # Input and output files can't be the same if options.input_filename == options.output_filename: print('Input and output files must be different.') sys.exit(64) # If an image is being used as the background, set the canvas size to match it if options.input_filename: # Warn if overriding user-defined width and height if options.width or options.height: print('Image dimensions supercede specified width and height') size = background_image.size else: # Make sure width and height are positive if options.width <= 0 or options.height <= 0: print('Width and height must be greater than zero.') sys.exit(64) size = (options.width, options.height) # Generate points on this portion of the canvas scale = 1.25 if options.equilateral_tris: points = generate_equilateral_points(npoints, size) elif options.right_tris: points = generate_rectangular_points(npoints, size) else: if options.distribution == 'uniform': points = generate_random_points(npoints, size, scale, options.decluster) elif options.distribution == 'halton': points = generate_halton_points(npoints, size) else: print('Unrecognized distribution type.') sys.exit(64) # Dedup the points points = list(set(points)) # Calculate the triangulation triangulation = delaunay_triangulation(points) # Failed to find a triangulation if not triangulation: print('Failed to find a triangulation.') sys.exit(1) # Translate the points to screen coordinates trans_triangulation = list( map(lambda x: cart_to_screen(x, size), triangulation)) # Assign colors to the triangles if options.input_filename: colors = color_from_image(background_image, trans_triangulation) else: colors = color_from_gradient(gradient[gname], size, trans_triangulation) # Darken random triangles if options.darken_amount: for i in range(0, len(colors)): c = colors[i] d = randrange(options.darken_amount) darkened = Color(max(c.r - d, 0), max(c.g - d, 0), max(c.b - d, 0)) colors[i] = darkened # Set up for anti-aliasing if options.antialias: # Scale the image dimensions size = (size[0] * aa_amount, size[1] * aa_amount) # Scale the graph trans_triangulation = [ Triangle(Point(t.a.x * aa_amount, t.a.y * aa_amount), Point(t.b.x * aa_amount, t.b.y * aa_amount), Point(t.c.x * aa_amount, t.c.y * aa_amount)) for t in trans_triangulation ] # Create image object image = Image.new('RGB', size, 'white') # Get a draw object draw = ImageDraw.Draw(image) # Draw the triangulation draw_polys(draw, colors, trans_triangulation) if options.lines or options.line_thickness or options.line_color: if options.line_color is None: line_color = Color(255, 255, 255) else: line_color = hex_to_color(options.line_color) draw_lines(draw, line_color, trans_triangulation, options.line_thickness) if options.points or options.vert_radius or options.vert_color: if options.vert_color is None: vertex_color = Color(255, 255, 255) else: vertex_color = hex_to_color(options.vert_color) draw_points(draw, vertex_color, trans_triangulation, options.vert_radius) # Resample the image using the built-in Lanczos filter if options.antialias: size = (int(size[0] / aa_amount), int(size[1] / aa_amount)) image = image.resize(size, Image.ANTIALIAS) # Write the image to a file image.save(options.output_filename) print('Image saved to %s' % options.output_filename) sys.exit(0)
for line in stringlines: # split the line by comma fields = line.split(",") points.append( Point(float(fields[1]), float(fields[2]), float(fields[3].replace('\n', '')), int(fields[0]))) # Reading triangles with open('triangulation.txt', "r", encoding="utf8") as stringlines: next(stringlines) for line in stringlines: # split the line by comma fields = line.split(",") triangles.append( Triangle(points[int(fields[1]) - 1], points[int(fields[2]) - 1], points[int(fields[3].replace('\n', '')) - 1], int(fields[0]))) plt.axes().set_aspect('equal') # Plotting both points and triangles (with duplicates) for i in range(0, len(points)): plt.plot(points[i].x, points[i].y, 'bo--') for i in range(0, len(triangles)): plt.plot([ triangles[i].p1.x, triangles[i].p2.x, triangles[i].p3.x, triangles[i].p1.x ], [ triangles[i].p1.y, triangles[i].p2.y, triangles[i].p3.y, triangles[i].p1.y ], 'b') # plt.show() axes = plt.axis() # Saving ratio of plot axes
def __init__(self, filename="scene.json"): self.lights = [] self.objects = [] # read in the json with open(filename, "r") as json_file: scene = json.load(json_file) for light in scene['scene']['lights']: l = Light(origin=light['origin'], radius=light['radius'], brightness=light['brightness'], color=light['color']) self.lights.append(l) self.objects.append(l) for object in scene['scene']['objects']: texture = None scale = 1.0 if 'texture' in object: texture = object['texture'] if 'scale' in object: scale = object['scale'] if (object['shape'] == "Sphere"): self.objects.append( Sphere(origin=object['origin'], radius=object['radius'], diffuse=object['diffuse'], reflection=object['reflection'], shiny=object['shiny'], k=object['k'], refraction=object['refraction'], index=object['index'], color=object['color'], texture=texture, uv=object['uv'])) elif (object['shape'] == "Skybox"): self.objects.append( Skybox(origin=object['origin'], radius=object['radius'], diffuse=object['diffuse'], reflection=object['reflection'], shiny=object['shiny'], k=object['k'], refraction=object['refraction'], index=object['index'], color=object['color'], texture=texture, uv=object['uv'])) elif (object['shape'] == "Plane"): self.objects.append( Plane.Plane(origin=object['origin'], normal=object['normal'], diffuse=object['diffuse'], reflection=object['reflection'], refraction=object['refraction'], index=object['index'], shiny=object['shiny'], k=object['k'], color=object['color'], texture=texture, scale=scale)) elif (object['shape'] == "Triangle"): self.objects.append( Triangle.Triangle(v0=object['v0'], v1=object['v1'], v2=object['v2'], diffuse=object['diffuse'], reflection=object['reflection'], refraction=object['refraction'], index=object['index'], shiny=object['shiny'], k=object['k'], color0=object['color0'], color1=object['color1'], color2=object['color2'])) camera = scene['scene']['camera'] self.camera = Camera(origin=camera['origin'], target=camera['target'], length=camera['length'], aperture=camera['aperture'], samples=camera['samples']) self.ambient = np.array(scene['scene']['ambient']) self.background = np.array(scene['scene']['background'])
if darken_amount: for i in range(0, len(colors)): c = colors[i] d = randrange(darken_amount) darkened = Color(max(c.r - d, 0), max(c.g - d, 0), max(c.b - d, 0)) colors[i] = darkened # Set up for anti-aliasing if antialias: # Scale the image dimensions size = (size[0] * aa_amount, size[1] * aa_amount) # Scale the graph trans_triangulation = [ Triangle(Point(t.a.x * aa_amount, t.a.y * aa_amount), Point(t.b.x * aa_amount, t.b.y * aa_amount), Point(t.c.x * aa_amount, t.c.y * aa_amount)) for t in trans_triangulation ] # Create image object image = Image.new('RGB', size, 'white') # Get a draw object draw = ImageDraw.Draw(image) # Draw the triangulation draw_polys(draw, colors, trans_triangulation) if lines or line_thickness or line_color: if line_color is None: line_color = Color(255, 255, 255) else:
@author: Gosha ''' from geometry import Point, Camera, Direction, Triangle from objects import DPoint, DCamera, DSurface from screen import Screen if(__name__ == '__main__'): cam = Camera(Point((0, 0, 0)), Direction((0, 0, 0))) dCam = DCamera(cam) screen = Screen() screen.linkCamera(dCam) sides = [] sides.append(DSurface([Triangle(Point((-10, 10, 10)), Point((10, 10, 10)), Point((10, 10, -10))), Triangle(Point((-10, 10, 10)), Point((-10, 10, -10)), Point((10, 10, -10)))], (1, 1, 0), (0, 0, 0))) sides.append(DSurface([Triangle(Point((-10, -10, 10)), Point((10, -10, 10)), Point((10, -10, -10))), Triangle(Point((-10, -10, 10)), Point((-10, -10, -10)), Point((10, -10, -10)))], (0.5, 0.5, 0.5), (0, 0, 0))) sides.append(DSurface([Triangle(Point((10, -10, 10)), Point((10, 10, 10)), Point((10, 10, -10))), Triangle(Point((10, -10, 10)), Point((10, -10, -10)), Point((10, 10, -10)))], (0, 1, 0), (0, 0, 0))) for side in sides: dCam.show(side) for x in [-10, 10]: for y in [-10, 10]: for z in [-10, 10]: dCam.show(DPoint(Point((x, y, z)))) screen.updateLoop()