def forward(self, distance, share=True): #print 'taturtle.py: def forward' scaled_distance = distance * self._turtles.turtle_window.coord_scale old = self.get_xy() #Projected Point old_3D = self.get_3Dpoint() #Actual Point #xcor = old[0] + scaled_distance * sin(self._heading * DEGTOR) #ycor = old[1] + scaled_distance * cos(self._heading * DEGTOR) xcor = old_3D[0] + scaled_distance * self._direction[0] ycor = old_3D[1] + scaled_distance * self._direction[1] zcor = old_3D[2] + scaled_distance * self._direction[2] width = self._turtles.turtle_window.width height = self._turtles.turtle_window.height old_point = Point3D(old_3D[0], old_3D[1], old_3D[2]) # Old point as Point3D object p = old_point.project(width, height, 512, 512) # Projected Old Point new_x, new_y = p.x, p.y pair1 = [new_x, new_y] pos1 = self._turtles.screen_to_turtle_coordinates(pair1) ''' for i, val in enumerate(old_3D): if (abs(val) < 0.0001): old_3D[i] = 0. old_3D[i] = round(old_3D[i], 2) self._points.append([old_3D[0], old_3D[1], old_3D[2]]) if (self._pen_state): self._points_penstate.append(1) else: self._points_penstate.append(0) ''' self._3Dx, self._3Dy, self._3Dz = xcor, ycor, zcor self.store_data() new_point = Point3D(xcor, ycor, zcor) # New point as 3D object p = new_point.project(width, height, 512, 512) # Projected New Point new_x, new_y = p.x, p.y pair2 = [new_x, new_y] pos2 = self._turtles.screen_to_turtle_coordinates(pair2) #print 'new = ', new_point.x, new_point.y, new_point.z self._draw_line(pos1, pos2, True) #self.move_turtle((xcor, ycor)) self.move_turtle((pos2[0], pos2[1])) if self._turtles.turtle_window.sharing() and share: event = 'f|%s' % (data_to_string( [self._turtles.turtle_window.nick, int(distance)])) self._turtles.turtle_window.send_event(event)
def onclick(event): # from https://stackoverflow.com/questions/6748184/matplotlib-plot-surface-get-the-x-y-z-values-written-in-the-bottom-right-cor/9673338#9673338 if select_allowed and event.inaxes == ax and event.button == 1: try: data_string = ax.format_coord(event.xdata, event.ydata) except: return coord_list_parsed = re.split(r'[xyz=,\s]\s*', data_string) # contains empty strings coord_list = np.array( [float(s) for s in coord_list_parsed if len(s) > 0]) coord_list[0] = round(coord_list[0] * 10) / 10 coord_list[1] = round(coord_list[1] * 10) / 10 mag = np.linalg.norm(coord_list) scaled_point = coord_list / mag x, y, z = scaled_point[0], scaled_point[1], scaled_point[2] if (x, y, z) == (0, 0, 1): print("Please don't pick the north pole") return # scaled_point.resize(1,3) # for extraction purposes print("x = %f, y = %f, z = %f" % (x, y, z)) # ax.view_init(elev=default_elev, azim = default_azim) # default values new_point = Point3D(x, y, z) points.add(new_point) ax.scatter(x, y, z, c='r', linewidth=3.0) fig.canvas.draw()
def makeInfill(perimeters, infill, direction): """Returns a list of lists of points by either x or y coordinate from min to max""" # TODO: Support direction if (not perimeters): return None if (infill == 0): return None final = [] allSegments = [] maxY = perimeters[0][0].start.y minY = perimeters[0][0].start.y maxX = perimeters[0][0].start.x minX = perimeters[0][0].start.x for perimeter in perimeters: for segment in perimeter: maxY = max(maxY, max(segment.start.y, segment.end.y)) minY = min(minY, min(segment.start.y, segment.end.y)) maxX = max(maxX, max(segment.start.x, segment.end.x)) minX = min(minX, min(segment.start.x, segment.end.x)) allSegments.append(segment) #linear interpolation between 0-100% infill layerThickness = .4 #increment = (1-infill)*((abs(maxY) - abs(minY))) + infill*layerThickness increment = layerThickness / infill if (increment < 0): raise Exception("increment is negative") #increment = 1 scan = minY + increment while (scan <= maxY): scanLine = Segment(Point3D(minX, scan, 0), Point3D(maxX, scan, 0), None) # note: probably dangerous to have none lineHits = [] for seggy in allSegments: intersect = scanLine.intersect2D(seggy) if intersect: lineHits.append(intersect) # final.append(list(deleteDuplicates(lineHits))) sortedLineHits = sorted(lineHits, key=lambda x: x.x) final.append(sortedLineHits) scan += increment return final
def resizePerimeters(params, perimeters, brim=False, raft=False): """Resizes perimeters using params.thickness toward the inside of that perimeter using the perpIn(dicular) unit vector to each segment in the perimeter. If brim or raft is specified, this will generate a brim or raft (cool right?) Note: brim and raft not yet functional (less cool) """ if brim: raise Exception("brim not yet supported") # TODO if raft: raise Exception("raft not yet supported") # TODO thickness = params.thickness / 2.0 new_perimeters = [] for perimeter in perimeters: new_seggies = [] for seggy in perimeter: # Make copies to populate new_seggies.append(Segment(None, None, seggy.perpIn)) for i in xrange(len(perimeter)): # Start point translation algorithm seggy1 = perimeter[i] seggy2 = perimeter[(i + 1) % len(perimeter)] new_seggy1 = new_seggies[i] new_seggy2 = new_seggies[(i + 1) % len( new_seggies)] # len perimeter and new_seggies should be same # if seggy1.end != seggy2.start: # raise Exception("Found neighboring segments in perimeter which don't share a point") # print seggy1.end # print seggy2.start # Considering the float imperfections and the imperfections in perimeter handling # we ignore this error. We'll consider the end point of the first segment. If the # points printed are really different though, that indicates a bigger problem. point2d = [seggy1.end.x, seggy1.end.y] # is the same as seggy2.y # Find unit vector of distance thickness from the origin in direction of perpendicular trans_end1 = map(lambda x: x * thickness, seggy1.perpIn) trans_start2 = map(lambda x: x * thickness, seggy2.perpIn) trans_amt = map(lambda x, y: x + y, trans_end1, trans_start2) new_point2d = map(lambda x, y: x + y, point2d, trans_amt) # Populate the new segments with translated point new_seggy1.end = Point3D(new_point2d[0], new_point2d[1], float(0)) new_seggy2.start = Point3D(new_point2d[0], new_point2d[1], float(0)) new_perimeters.append(new_seggies) return new_perimeters
def __init__(self, v1, v2, v3, norm): for x in [v1, v2, v3, norm]: try: n = len(x) except Exception as e: print(e) n = 0 if n != 3: raise TypeError('Expected 3D vector.') for y in x: if not isinstance(y, numbers.Real): raise TypeError('Expected 3D vector.') verts = [Point3D(v1), Point3D(v2), Point3D(v3)] # Re-order vertices in a normalized order. while verts[0] > verts[1] or verts[0] > verts[2]: verts = verts[1:] + verts[:1] self.vertices = verts self.norm = Vector(norm) self.count = 1 self.fixup_normal()
def compute_infinite_center(p1, p2, join_points): ''' given two 3d points p1, p2, return the circumcenter with (0,0,1) representing the endpoint of this edge toward infinity uses join_points to determine which center to pick not guaranteed to be correct if p1, p2, (0,0,1), (0,0,0) are coplanar''' # mostly copied from above vec1 = np.array([p2.x - p1.x, p2.y - p1.y, p2.z - p1.z]) vec2 = np.array([-p1.x, -p1.y, 1 - p1.z]) normal = np.cross(vec1, vec2) mag = np.linalg.norm(normal) coords = normal / mag centerpoint = Point3D(coords[0], coords[1], coords[2]) if centerpoint in join_points: # print("join point found") # print(centerpoint) return centerpoint # print("not found") # print(-coords[0], -coords[1], -coords[2]) return Point3D(-coords[0], -coords[1], -coords[2])
def forward(self, distance, share=True): scaled_distance = distance * self._turtles.turtle_window.coord_scale old = self.get_xy() #Projected Point old_3D = self.get_3Dpoint() #Actual Point #xcor = old[0] + scaled_distance * sin(self._heading * DEGTOR) #ycor = old[1] + scaled_distance * cos(self._heading * DEGTOR) xcor = old_3D[0] + scaled_distance * self._direction[0] ycor = old_3D[1] + scaled_distance * self._direction[1] zcor = old_3D[2] + scaled_distance * self._direction[2] width = self._turtles.turtle_window.width height = self._turtles.turtle_window.height # Old point as Point3D object old_point = Point3D(old_3D[0], old_3D[1], old_3D[2]) # Projected Old Point p = old_point.project(width, height, self._camera) new_x, new_y = p.x, p.y pair1 = [new_x, new_y] pos1 = self._turtles.screen_to_turtle_coordinates(pair1) self._3Dx, self._3Dy, self._3Dz = xcor, ycor, zcor self.store_data() new_point = Point3D(xcor, ycor, zcor) # New point as 3D object p = new_point.project(width, height, self._camera) # Projected New Point new_x, new_y = p.x, p.y pair2 = [new_x, new_y] pos2 = self._turtles.screen_to_turtle_coordinates(pair2) self._draw_line(pos1, pos2, True) self.move_turtle((pos2[0], pos2[1])) if self._turtles.turtle_window.sharing() and share: event = 'f|%s' % (data_to_string([self._turtles.turtle_window.nick, int(distance)])) self._turtles.turtle_window.send_event(event)
def set_xyz(self, x, y, z): ''' Set the x, y and z coordinates ''' self._3Dx, self._3Dy, self._3Dz = x, y, z self.store_data() point_3D = Point3D(x, y, z) width = self._turtles.turtle_window.width height = self._turtles.turtle_window.height p = point_3D.project(width, height, 512, 512) new_x, new_y = p.x, p.y pair = [new_x, new_y] pos = self._turtles.screen_to_turtle_coordinates(pair) self.set_xy(pos[0], pos[1])
def draw_obj(self, file_name): vertices = [] lines = [] file_handle = open(file_name, 'r') for line in file_handle: temp = line.split() if temp[0] == 'v': vertices.append( [float(temp[1]), float(temp[2]), float(temp[3])]) if temp[0] == 'l': lines.append([int(temp[1]), int(temp[2])]) width = self._turtles.turtle_window.width height = self._turtles.turtle_window.height for line in lines: source = vertices[line[0] - 1] dest = vertices[line[1] - 1] source_point = Point3D(source[0], source[1], source[2]) p1 = source_point.project(width, height, 512, 512) pair1 = [p1.x, p1.y] pos1 = self._turtles.screen_to_turtle_coordinates(pair1) dest_point = Point3D(dest[0], dest[1], dest[2]) p2 = dest_point.project(width, height, 512, 512) pair2 = [p2.x, p2.y] pos2 = self._turtles.screen_to_turtle_coordinates(pair2) self._draw_line(pos1, pos2, True) self.move_turtle((pos2[0], pos2[1])) return vertices, lines
def compute_center(p1, p2, p3, invert=None, inverse_transform=None, sphere_to_plane=None): ''' given three Point3Ds, return Point3D on sphere that is equidistant from all of them and whose image is inside the circumcircle of the inverted triangle invert through (0,0,1) by default''' # compute normal to the plane using cross product to get equidistant line vec1 = np.array([p2.x - p1.x, p2.y - p1.y, p2.z - p1.z]) vec2 = np.array([p3.x - p1.x, p3.y - p1.y, p3.z - p1.z]) # normal = np.cross(vec1, vec2).reshape((1,3)) normal = np.cross(vec1, vec2) mag = np.linalg.norm(normal) coords = normal / mag # one of the circumline points on the sphere # print("NORMAL VECTOR") # print(normal) centerpoint = Point3D(coords[0], coords[1], coords[2]) # check orientation of center point if invert: inverted_center_arr = np.array( centerpoint.invert_through(invert)).reshape((3, 1)) p_coords = (inverse_transform @ inverted_center_arr).reshape((3, )) p = Point(p_coords[0], p_coords[1]) im_p1 = sphere_to_plane[p1] im_p2 = sphere_to_plane[p2] im_p3 = sphere_to_plane[p3] else: # do the same for normal inversion p = centerpoint.invert() im_p1 = p1.invert() im_p2 = p2.invert() im_p3 = p3.invert() if is_in_circle(p, im_p1, im_p2, im_p3): return centerpoint return Point3D(-coords[0], -coords[1], -coords[2])
def init_ui(self): self.darea = Gtk.DrawingArea() self.darea.connect("draw", self.on_expose) #self.darea.set_events(Gdk.EventMask.BUTTON_PRESS_MASK) self.add(self.darea) self.coords = [] self.xy = [] self.vert = [[1, 1, 1], [-1, 1, 1], [1, -1, 1], [1, 1, -1], [-1, -1, 1], [-1, 1, -1], [1, -1, -1], [-1, -1, -1]] for i in self.vert: self.coords.append(Point3D(i[0], i[1], i[2])) #self.darea.connect("button-press-event", self.on_button_press) self.set_title("Lines") self.resize(640, 480) self.set_position(Gtk.WindowPosition.CENTER) self.connect("delete-event", Gtk.main_quit) self.show_all()
mag = np.linalg.norm(normal) coords = normal / mag centerpoint = Point3D(coords[0], coords[1], coords[2]) if centerpoint in join_points: # print("join point found") # print(centerpoint) return centerpoint # print("not found") # print(-coords[0], -coords[1], -coords[2]) return Point3D(-coords[0], -coords[1], -coords[2]) if __name__ == '__main__': # point_set = {Point3D(0,1,0), Point3D(0,-1,0), Point3D(1,0,0), Point3D(-1,0,0)} # VoronoiSphere(point_set) # p = Point(0,1.5) # p1 = Point(1,0) # p2 = Point(0,1) # p3 = Point(-1,0) # print(is_in_circle(p, p1, p2, p3)) # p1 = Point3D(0,1,0) # p2 = Point3D(-0.8,0.6,0) # p3 = Point3D(0.64,0.48,0.6) # print(compute_center(p1, p2, p3)) p1 = Point3D(-0.726667, -0.121111, -0.676230) p2 = Point3D(-0.210467, -0.701558, 0.680823) print(compute_infinite_center(p1, p2))
''' def laplace(point1, point2, point3): try: vetor1 = point1.createVector(point2) vetor2 = point1.createVector(point3) x = vetor1.coordinates[1] * vetor2.coordinates[2] - vetor1.coordinates[ 2] * vetor2.coordinates[1] y = vetor1.coordinates[2] * vetor2.coordinates[0] - vetor1.coordinates[ 0] * vetor2.coordinates[2] z = vetor1.coordinates[0] * vetor2.coordinates[1] - vetor1.coordinates[ 1] * vetor2.coordinates[0] d = -(x * point1.point[0] + y * point1.point[1] + z * point1.point[2]) print("Normal Vector: n({}, {}, {})".format(x, y, z)) print("Plan Equation: {}x + {}y + {}z + {} = 0".format(x, y, z, d)) except TypeError: print("The argument have to be of type Point3D") ''' Main ''' if __name__ == '__main__': p1 = Point3D(5, 4, 3) p2 = Point3D(6, -1, 2) p3 = Point3D(7, 2, -4) laplace(p1, p2, p3)
def test(): """Because we're not using a real testing framework""" params = Parameters(filename="notused", perimeterLayers=3, infill=.20, layerHeight=.19, thickness=0.4, support=False) # Test data from layer 0.19 of the 3mmBox perimeter = [ Segment(Point3D(.19, 0.0, .19), Point3D(0.0, 0.0, .19), [0.0, 1.0]), Segment(Point3D(0.0, 0.0, 0.19), Point3D(0.0, 0.19, .19), [1.0, 0.0]), Segment(Point3D(0.0, .19, .19), Point3D(0.0, 15.0, .19), [1.0, 0.0]), Segment(Point3D(0.0, 15.0, .19), Point3D(14.810, 15.0, .19), [0.0, -1.0]), Segment(Point3D(14.810, 15.0, .19), Point3D(15.0, 15.0, .19), [0, -1.0]), Segment(Point3D(15.0, 15.0, .19), Point3D(15.0, 14.81, .19), [-1.0, 0.0]), Segment(Point3D(15.0, 14.81, .19), Point3D(15.0, 0.0, .19), [-1.0, 0.0]), Segment(Point3D(15.0, 0.0, .19), Point3D(0.19, 0.0, .19), [0.0, 1.0]) ] perimeters = [perimeter] print "=============== testing perimeter resizing ===============" map(printFunc, resizePerimeters(params, perimeters)[0]) print "=============== TEsting gcode Generation ===============" with open("test_gcode.gcode", "w") as gfile: generateSetup(gfile, params) generateGCode(gfile, params, 0.19, perimeters) generateCleanup(gfile) print "success"
# generate random points on unit sphere for i in range(n): point_selected = False while not point_selected: raw_x = random.uniform(-1, 1) raw_y = random.uniform(-1, 1) raw_z = random.uniform(-1, 1) magnitude = raw_x**2 + raw_y**2 + raw_z**2 # scale to sphere x = raw_x / magnitude y = raw_y / magnitude z = raw_z / magnitude if (x, y, z) == (0, 0, 1): # avoid north pole continue point_selected = True points.add(Point3D(x, y, z)) assert len(points) == n # track time start_time = time.process_time() voronoi = VoronoiSphere(points, False) # no printing while not voronoi.done(): voronoi.step() output_info = voronoi.output() # extra processing occurs during output # computation complete elapsed_time = time.process_time() - start_time print("Took %f seconds to compute on %d points" % (elapsed_time, n))
def find_far_section(self): ''' find the intersection of the second Voronoi diagram with the set of points closest to the image of (0,0,1) under inversion about eta ''' voronoi_edges = {} # hold final edge endpoints voronoi_sites = set() # hold sites adjacent to self.q_inv join_points = set( ) # hold circumcenters for matching to near side points later # extract edges and vertices for voronoi region of self.q_inv edge_to_sets = self.voronoi_north.output()[1] for edge in edge_to_sets: plane_sites = edge.get_sites() if self.q_inv in plane_sites: for circle_set in edge_to_sets[edge]: circle_list = list(circle_set) circle_list.remove(self.q_inv) for i in range(len(circle_list) - 1): site1 = circle_list[i] site2 = circle_list[i + 1] # add to collection of sites being considered voronoi_sites.add(site1) voronoi_sites.add(site2) # add this vertex to edges actually existing in the diagram sphere_site1 = self.plane2_to_sphere[site1] sphere_site2 = self.plane2_to_sphere[site2] sphere_edge = Edge(sphere_site1, sphere_site2) vertex = compute_center(sphere_site1, sphere_site2, Point3D(0, 0, 1), self.eta, self.inverse_transform, self.sphere_to_plane2) join_points.add(vertex) if sphere_edge in voronoi_edges: voronoi_edges[sphere_edge].add(vertex) else: voronoi_edges[sphere_edge] = {vertex} # now voronoi_edges contains all points on the boundary of the far cap # get the portion of the Voronoi diagram inside the cap for edge in self.voronoi2.voronoi_vertices: site1, site2 = edge.get_sites() if site1 not in voronoi_sites or site2 not in voronoi_sites: continue # only consider sites adjacent to q_inv # get points on the sphere sphere_site1 = self.plane2_to_sphere[site1] sphere_site2 = self.plane2_to_sphere[site2] sphere_edge = Edge(sphere_site1, sphere_site2) for circle_set in self.voronoi2.voronoi_vertices[edge]: circle_list = list(circle_set)[:3] intersection = compute_circumcenter( circle_list[0], circle_list[1], circle_list[2]) # a 2d point if intersection.distance(self.q_inv) <= intersection.distance( site1): # this point lies inside the region sphere_points = [ self.plane2_to_sphere[point] for point in circle_list ] # convert directly to 3D coordinates vertex = compute_center(sphere_points[0], sphere_points[1], sphere_points[2], self.eta, self.inverse_transform, self.sphere_to_plane2) if sphere_edge in voronoi_edges: voronoi_edges[sphere_edge].add(vertex) else: voronoi_edges[sphere_edge] = {vertex} return voronoi_edges, join_points
def __init__(self, point_set, verbose=True): ''' create a new VoronoiSphere object from given site points point_set is a set of Point3D objects representing the sites verbose indicates printing verbosity''' self.verbose = verbose self.points = point_set # maps for inversion from sphere to plane and vice versa self.sphere_to_plane = {} self.plane_to_sphere = {} for point in self.points: inverse = point.invert() self.sphere_to_plane[point] = inverse self.plane_to_sphere[inverse] = point # also want to pick a second center of inversion inside the convex hull planar_iter = iter(self.plane_to_sphere) triangle = [next(planar_iter) for i in range(3)] while (are_collinear(triangle[0], triangle[1], triangle[2])): triangle[2] = next(planar_iter) # triangle will now be a valid non-degenerate triangle weight = 0 while (True): eta_inv_x = 0.5 * triangle[0].get_x() + (0.25 - weight) * triangle[ 1].get_x() + (0.25 + weight) * triangle[2].get_x() eta_inv_y = 0.5 * triangle[0].get_y() + (0.25 - weight) * triangle[ 1].get_y() + (0.25 + weight) * triangle[2].get_y() eta_inv = Point(eta_inv_x, eta_inv_y) if eta_inv in self.plane_to_sphere or eta_inv == Point( 0, 0): # this point exists weight = 1 / 8 if weight == 0 else weight / 2 else: break # good eta found a, b, c = eta_inv.project_to_sphere() self.eta = Point3D(a, b, c) # second center of inversion # maps for inversion to second plane under coordinate transform, # where inverting is harder self.sphere_to_plane2 = {} self.plane2_to_sphere = {} # if x' are new coordinates, matrix_transform @ x' are old coords # new coordinates have z = -1 always z_dir = np.array([a, b, c]) # obtain orthonormal basis for new coords if a == b and b == c: non_collinear = np.array([-b, c, -a]) else: non_collinear = np.array([c, a, b]) x_dir = np.cross(non_collinear, z_dir) y_dir = np.cross(z_dir, x_dir) matrix_transform = np.stack((x_dir, y_dir, z_dir), axis=-1) inverse_transform = np.linalg.inv(matrix_transform) self.inverse_transform = inverse_transform # store for later # track the image of (0,0,1) q = np.array(Point3D(0, 0, 1).invert_through(self.eta)).reshape((3, 1)) inverted_q = (inverse_transform @ q).reshape((3, )) # image of (0,0,1) under second inversion self.q_inv = Point(inverted_q[0], inverted_q[1]) # print(self.q_inv) self.sphere_to_plane2[Point3D(0, 0, 1)] = self.q_inv for point in self.points: # these are 3d points inverted = np.array(point.invert_through(self.eta)).reshape((3, 1)) new_coords = (inverse_transform @ inverted).reshape((3, )) inverted_point = Point(new_coords[0], new_coords[1]) self.sphere_to_plane2[point] = inverted_point self.plane2_to_sphere[inverted_point] = point # print(point, inverted_point) # construct the voronoi diagrams self.voronoi1 = Voronoi(set(self.plane_to_sphere.keys()), verbose) self.voronoi2 = Voronoi(set(self.plane2_to_sphere.keys()), verbose) self.voronoi_north = Voronoi( set(self.plane2_to_sphere.keys()).union({self.q_inv}), verbose)