def validate(self): if self.point is None: self.point = Point( float(self.settings.get("x", 0)), float(self.settings.get("y", 0)) ) if self.matrix is None: self.matrix = Matrix()
def tick(self): if self.last_position is None: return friction = 0.05 attraction = 500 vx = self.velocity[0] * (1 - friction) vy = self.velocity[1] * (1 - friction) angle = Point.angle(self.last_position, self.track_object) vx -= attraction * math.cos(angle) vy -= attraction * math.sin(angle) self.velocity[0] = vx self.velocity[1] = vy self.track_object[0] += vx self.track_object[1] += vy self.pos += 1 if self.pos & 2: self.series.append((self.last_position[0], self.last_position[1])) else: self.series.append((self.track_object[0], self.track_object[1])) self.scene.request_refresh() if self.stop: return False return (abs(self.last_position[0] - self.track_object[0]) > 1000 or abs(self.last_position[1] - self.track_object[1]) > 1000)
def test_plotplanner_constant_xy_end(self): """ With raster_smooth set to 1 we should smooth the x axis so that no y=0 occurs. @return: """ for q in range(100): settings = { "power": 1000, "constant_move_x": bool(random.randint(0, 1)), "constant_move_y": bool(random.randint(0, 1)), } plan = PlotPlanner(settings) goal_x = None goal_y = None for i in range(10): goal_x = random.randint(0, 100) goal_y = random.randint(0, 100) plan.push( LineCut( Point(random.randint(0, 100), random.randint(0, 100)), Point(goal_x, goal_y), settings=settings, )) break_list = list(plan.queue) last_x = None last_y = None for x, y, on in plan.gen(): if on == 4: last_x = x last_y = y if on > 1: continue last_x = x last_y = y if last_x != goal_x: print(settings.get("constant_move_x")) print(settings.get("constant_move_y")) for seg in break_list: print(repr(seg)) self.assertEqual(last_x, goal_x) if last_y != goal_y: print(settings.get("constant_move_x")) print(settings.get("constant_move_y")) for seg in break_list: print(repr(seg)) self.assertEqual(last_y, goal_y)
def test_plotplanner_constant_move_xy(self): """ With raster_smooth set to 1 we should smooth the x axis so that no y=0 occurs. @return: """ settings = { "power": 1000, "constant_move_x": True, "constant_move_y": True } plan = PlotPlanner(settings) self.constant_move_x = True self.constant_move_y = True for i in range(100): plan.push( LineCut( Point(random.randint(0, 1000), random.randint(0, 1000)), Point(random.randint(0, 1000), random.randint(0, 1000)), settings=settings, )) last_x = None last_y = None for x, y, on in plan.gen(): if on == 4: last_x = x last_y = y if on > 1: continue cx = x cy = y if cx is None: continue if last_x is not None: total_dx = cx - last_x total_dy = cy - last_y dx = 1 if total_dx > 0 else 0 if total_dx == 0 else -1 dy = 1 if total_dy > 0 else 0 if total_dy == 0 else -1 for i in range(1, max(abs(total_dx), abs(total_dy)) + 1): nx = last_x + (i * dx) ny = last_y + (i * dy) # print(nx, ny, on) # print(x, y, on) last_x = cx last_y = cy print(f"Moving to {x} {y}")
def test_plotplanner_static_issue(self): settings = { "power": 1000, "constant_move_x": True, "constant_move_y": False, } plan = PlotPlanner(settings) plan.debug = True lines = ( ((41, 45), (14, 43)), ((32, 67), (32, 61)), ) for line in lines: plan.push( LineCut( Point(line[0][0], line[0][1]), Point(line[1][0], line[1][1]), settings=settings, )) goal_x = lines[-1][-1][0] goal_y = lines[-1][-1][1] break_list = list(plan.queue) last_x = None last_y = None for x, y, on in plan.gen(): if on == 4: last_x = x last_y = y if on > 1: continue last_x = x last_y = y if last_x != goal_x: for seg in break_list: print(repr(seg)) self.assertEqual(last_x, goal_x) if last_y != goal_y: for seg in break_list: print(repr(seg)) self.assertEqual(last_y, goal_y)
def test_plotplanner_flush(self): """ Intro test for plotplanner. This is needlessly complex. final value is "on", and provides commands. 128 means settings were changed. 64 indicates x_axis major 32 indicates x_dir, y_dir 256 indicates ended. 1 means cut. 0 means move. :return: """ settings = {"power": 1000} plan = PlotPlanner(settings) for i in range(211): plan.push(LineCut(Point(0, 0), Point(5, 100), settings=settings)) plan.push(LineCut(Point(100, 50), Point(0, 0), settings=settings)) plan.push( LineCut(Point(50, -50), Point(100, -100), settings={"power": 0})) q = 0 for x, y, on in plan.gen(): # print(x, y, on) if q == i: # for x, y, on in plan.process_plots(None): # print("FLUSH!", x, y, on) plan.clear() break q += 1
def test_cutcode(self): """ Test intro to Cutcode. :return: """ cutcode = CutCode() settings = dict() cutcode.append(LineCut(Point(0, 0), Point(100, 100), settings=settings)) cutcode.append(LineCut(Point(100, 100), Point(0, 0), settings=settings)) cutcode.append(LineCut(Point(50, -50), Point(100, -100), settings=settings)) cutcode.append( QuadCut(Point(0, 0), Point(100, 100), Point(200, 0), settings=settings) ) path = Path(*list(cutcode.as_elements())) self.assertEqual( path, "M 0,0 L 100,100 L 0,0 M 50,-50 L 100,-100 M 0,0 Q 100,100 200,0" )
def event(self, window_pos=None, space_pos=None, event_type=None, nearest_snap=None): response = RESPONSE_CHAIN if event_type == "leftclick": if nearest_snap is None: point = Point(space_pos[0], space_pos[1]) else: point = Point(nearest_snap[0], nearest_snap[1]) elements = self.scene.context.elements node = elements.elem_branch.add(point=point, matrix=Matrix(), type="elem point") if self.scene.context.elements.default_stroke is not None: node.stroke = self.scene.context.elements.default_stroke if self.scene.context.elements.default_fill is not None: node.fill = self.scene.context.elements.default_fill if elements.classify_new: elements.classify([node]) self.notify_created(node) response = RESPONSE_CONSUME return response
def find_hit_chain(self, position): """ Processes the hittable_elements list and find which elements are hit at a given position. This gives the actual hits with regard to the position of the event. """ self.hit_chain.clear() for current_widget, current_matrix in self.hittable_elements: try: hit_point = Point( current_matrix.point_in_inverse_space(position)) except ZeroDivisionError: current_matrix.reset() # Some object is zero matrixed, reset it. return if current_widget.contains(hit_point.x, hit_point.y): self.hit_chain.append((current_widget, current_matrix))
def test_plotplanner_constant_move_x_ppi(self): """ With raster_smooth set to 1 we should smooth the x axis so that no y=0 occurs. @return: """ settings = {"power": 500, "constant_move_x": True} plan = PlotPlanner(settings) plan.push(LineCut(Point(0, 0), Point(20, 2), settings=settings)) plan.push(LineCut(Point(20, 2), Point(20, 5), settings=settings)) plan.push(LineCut(Point(20, 5), Point(100, 10), settings=settings)) last_x = None last_y = None last_on = None for x, y, on in plan.gen(): if on == 4: last_x = x last_y = y if on > 1: continue if last_on is not None: self.assertNotEqual(last_on, on) last_on = on cx = x cy = y if cx is None: continue if last_x is not None: total_dx = cx - last_x total_dy = cy - last_y dx = 1 if total_dx > 0 else 0 if total_dx == 0 else -1 dy = 1 if total_dy > 0 else 0 if total_dy == 0 else -1 self.assertFalse(dx == 0) for i in range(1, max(abs(total_dx), abs(total_dy)) + 1): nx = last_x + (i * dx) ny = last_y + (i * dy) # print(nx, ny, on) # print(x, y, on) last_x = cx last_y = cy
def test_plotplanner_constant_move_y(self): """ With smooth_raster set to 2 we should never have x = 0. The x should *always* be in motion. @return: """ settings = {"power": 1000, "constant_move_y": True} plan = PlotPlanner(settings) plan.push(LineCut(Point(0, 0), Point(2, 20), settings=settings)) plan.push(LineCut(Point(2, 20), Point(5, 20), settings=settings)) plan.push(LineCut(Point(5, 20), Point(10, 100), settings=settings)) last_x = None last_y = None for x, y, on in plan.gen(): if on == 4: last_x = x last_y = y if on > 1: continue cx = x cy = y if cx is None: continue if last_x is not None: total_dx = cx - last_x total_dy = cy - last_y dx = 1 if total_dx > 0 else 0 if total_dx == 0 else -1 dy = 1 if total_dy > 0 else 0 if total_dy == 0 else -1 self.assertFalse(dy == 0) for i in range(0, max(abs(total_dx), abs(total_dy))): nx = last_x + (i * dx) ny = last_y + (i * dy) # print(nx, ny, on) last_x = cx last_y = cy print(f"Moving to {x} {y}")
def add_point(self, point): if len(self.series): last = self.series[-1] if Point.distance(last, point) < self.preferred_length: return self.series.append(point)
def __init__(self, x, y=None): Point.__init__(self, x, y) self.connections = [] self.visited = 0 self.value = None
def plot_arc(arc): """ Plots an arc by converting it into a series of cubic Bézier curves and plotting those instead. @param arc: @return: """ # TODO: Should actually plot the arc according to the pixel-perfect standard. # TODO: In this case we would plot a Bernstein weighted bezier curve. sweep_limit = tau / 12 arc_required = int(ceil(abs(arc.sweep) / sweep_limit)) if arc_required == 0: return slice = arc.sweep / float(arc_required) theta = arc.get_rotation() rx = arc.rx ry = arc.ry p_start = arc.start current_t = arc.get_start_t() x0 = arc.center[0] y0 = arc.center[1] cos_theta = cos(theta) sin_theta = sin(theta) for i in range(0, arc_required): next_t = current_t + slice alpha = sin(slice) * (sqrt(4 + 3 * pow(tan(slice / 2.0), 2)) - 1) / 3.0 cos_start_t = cos(current_t) sin_start_t = sin(current_t) ePrimen1x = -rx * cos_theta * sin_start_t - ry * sin_theta * cos_start_t ePrimen1y = -rx * sin_theta * sin_start_t + ry * cos_theta * cos_start_t cos_end_t = cos(next_t) sin_end_t = sin(next_t) p2En2x = x0 + rx * cos_end_t * cos_theta - ry * sin_end_t * sin_theta p2En2y = y0 + rx * cos_end_t * sin_theta + ry * sin_end_t * cos_theta p_end = (p2En2x, p2En2y) if i == arc_required - 1: p_end = arc.end ePrimen2x = -rx * cos_theta * sin_end_t - ry * sin_theta * cos_end_t ePrimen2y = -rx * sin_theta * sin_end_t + ry * cos_theta * cos_end_t p_c1 = (p_start[0] + alpha * ePrimen1x, p_start[1] + alpha * ePrimen1y) p_c2 = (p_end[0] - alpha * ePrimen2x, p_end[1] - alpha * ePrimen2y) for value in ZinglPlotter.plot_cubic_bezier( p_start[0], p_start[1], p_c1[0], p_c1[1], p_c2[0], p_c2[1], p_end[0], p_end[1], ): yield value p_start = Point(p_end) current_t = next_t