예제 #1
0
    def draw_polygon_arc(self, center_point, radius, edge_count, start_angle,
                         end_angle, direction):
        """Draw a polygon."""
        if isinstance(edge_count, tuple):
            edge_count, arc_angle = edge_count
        else:
            arc_angle = end_angle - start_angle

        print 'draw_polygon_arc with {} edges, centered on {} with radius of {}, between {} and {}'.format(
            edge_count, center_point, radius, start_angle, end_angle)

        edge_count = int(math.ceil(edge_count))
        if edge_count < 3:
            raise ValueError('draw_polygon needs a minimum of 3 edges.')

        Display.debug_circle(center_point, radius)
        Display.debug_point(center_point, 'green')

        delta_step = Unit(arc_angle / float(edge_count))
        if direction == CW:
            delta_step = -abs(delta_step)
        elif direction == CCW:
            delta_step = abs(delta_step)

        polar = Polar(radius, start_angle)

        turtle.up()
        self.setpos(center_point + polar.cartesian())
        Display.debug_point(center_point + polar.cartesian(), 'pink')

        turtle.down()
        # direction = sign(delta_step)
        for i in range(int(edge_count)):
            polar.t += delta_step
            self.setpos(center_point + polar.cartesian())
예제 #2
0
		def step(self, steps):
			"""Step the motors in sync."""
			biggest = int(max(abs(steps.r), abs(steps.t)))
			step_size = Steps(float(steps.r) / biggest, float(steps.t) / biggest)
			
			self.r_motor.set_direction(sign(steps.r))
			self.t_motor.set_direction(sign(steps.t))

			accumulation = Steps(0.0, 0.0)
			for i in range(biggest):
				accumulation += step_size
				while abs(accumulation.r) >= 1.0 or abs(accumulation.t) >= 1.0:
					this_step = Polar(0.0, 0.0)
					if abs(accumulation.r) >= 1.0:
						r_step = self.r_motor.step()
						this_step.r = r_step
						if r_step.is_boundry:
							accumulation.r = 0.0
						else:
							accumulation.r = accumulation.r - sign(steps.r)
						
					if abs(accumulation.t) >= 1.0:
						this_step.t = self.t_motor.step()
						accumulation.t = accumulation.t - sign(steps.t)
					yield this_step
예제 #3
0
    def __init__(self, controller):
        """Init."""
        self.display = Display()
        self.c = controller

        self.polar = Polar(0.0, 0.0)
        self.polar_error = Polar(0.0, 0.0)

        self.cart = Cartesian(0.0, 0.0)
        self.cart_error = Cartesian(0.0, 0.0)
        self.grid_size = self.c.grid_size

        self.direction = CCW
예제 #4
0
    def __init__(self, radius_start, radius_end, turns, start_angle=None):

        super(Spiral, self).__init__(Polar(radius_start, start_angle))

        self.radius_start = radius_start
        self.radius_end = radius_end
        self.turns = turns

        radius_range = radius_end - radius_start
        self.radius_step = float(radius_range) / turns

        self.whole_step = Polar(self.radius_step, math.tau)

        if start_angle is None:
            start_angle = Radians(0.0)
예제 #5
0
    def move(self, polar):
        """Move relative to our current position."""
        # print 'PolarPlot.move({})'.format(polar)
        delta = polar
        if delta == Polar(0, 0):
            return

        steps_number = (delta / self.grid_size).max_abs_value()
        delta_step = delta / float(steps_number)
        current = self.polar_error
        for i in range(int(steps_number)):
            current += delta_step
            whole = Steps(current // self.grid_size)
            current = current % self.grid_size
            if whole.r == 0 and whole.t == 0:
                continue

            for movement in self.c.step(whole):
                if movement.r.is_boundry:
                    delta_step.r = 0.0

                self.polar = self.polar + movement
                self.display.setpos(self.polar)

        self.polar_error = current
예제 #6
0
		def step(self, steps):
			"""Step the motors in sync."""
			biggest = int(max(abs(steps.r), abs(steps.t)))
			step_size = Steps(float(steps.r) / biggest, float(steps.t) / biggest)
			
			accumulation = Steps(0.0, 0.0)
			for i in range(biggest):
				accumulation += step_size
				while abs(accumulation.r) >= 1.0 or abs(accumulation.t) >= 1.0:
					this_step = Polar(0.0, 0.0)
					if abs(accumulation.r) >= 1.0:
						r_step = self.r_motor.effective_step_distance * (self.r_motor.step_size * sign(steps.r))
						this_step.r = r_step
						accumulation.r = accumulation.r - sign(steps.r)
						
					if abs(accumulation.t) >= 1.0:
						this_step.t = self.t_motor.effective_step_distance * (self.t_motor.step_size * sign(steps.t))
						accumulation.t = accumulation.t - sign(steps.t)
					yield this_step
예제 #7
0
    def spiral(self, start_r, end_r, pitch_count):
        """A constant spiral."""
        turtle.up()
        start = Polar(start_r, self.polar_error.t)
        self.setpos(start)

        turtle.down()
        for step in Spiral(start_r, end_r, pitch_count,
                           self.polar_error.t).functor():
            self.setpos(step)
        turtle.up()
예제 #8
0
    def functor(self):
        stem_b = 50.0
        target_theta = Radians(math.tau * 1.5)

        theta_step = math.tau / 90.0  # self.grid_size.t
        while abs(self.internal_position.t) <= abs(target_theta):
            theta = self.internal_position.t + theta_step
            stem = self.stem_func(stem_b, theta)

            self.internal_position = Polar(stem, theta)
            yield self.internal_position

        stem_b = 30.0
        target_theta = Radians(0.0)
        self.internal_position.t -= math.tau
        while abs(self.internal_position.t) >= abs(target_theta):
            theta = self.internal_position.t - theta_step
            stem = self.stem_func(stem_b, theta)

            self.internal_position = Polar(stem, theta)
            yield self.internal_position
예제 #9
0
    def flower(self, petals, amplitude):
        """Flower."""
        n = float(petals) / 2.0
        if petals % 2 == 0:
            d = 1
        else:
            d = 0.5

        turtle.up()
        self.setpos(Polar(0.0, 0.0))
        turtle.down()

        self.rhodonea(n, d, amplitude)
예제 #10
0
    def koru(self):
        """A constant spiral."""
        turtle.up()
        start = Polar(0.0, 0.0)
        self.setpos(start)

        print 'koru'

        koru = Transform(Koru(), Cartesian(0.0, 150.0))

        turtle.down()
        for step in koru:
            self.setpos(step)
        turtle.up()
예제 #11
0
    def rhodonea(self, n, d, amplitude):
        """Drawing for the full set of rhodonea curves."""
        # amplitude *= 100
        # target_step_size = Millimeters(0.1)
        # circumference = Millimeters(math.tau * amplitude)
        # step_count = int(math.ceil(circumference / target_step_size))
        # # step_size_mm = circumference / step_count
        # step_size_rad = Radiansmath.tau / step_count
        step_count = 100

        k = float(n) / float(d)
        theta_range = Radians(math.tau) * d

        turtle.up()
        self.setpos(Polar(0.0, self.polar_error.t))

        turtle.down()
        step_size_rad = theta_range / float(step_count)
        for step in range(step_count + 1):
            t = step * step_size_rad
            r = amplitude * math.sin(k * t)
            self.setpos(Polar(r, t))
        turtle.up()
예제 #12
0
    def functor(self):
        func = Spiral.archimedean
        a, b, target_theta = self.to_archimedean_parameters(
            self.radius_start, self.radius_end, self.turns)

        func = Spiral.logarithmic
        a, b, target_theta = self.to_logarithmic_parameters(
            self.radius_start, self.radius_end, self.turns)

        while abs(self.internal_position.t) < abs(target_theta):
            delta = Polar(float(func(a, b, self.grid_size.t)),
                          self.grid_size.t)
            for rel_step in self.step_relative(delta, self.grid_size):
                self.internal_position += rel_step
                yield self.internal_position
예제 #13
0
    def setpos(self, polar):
        """Set to an absolute position."""
        # print 'PolarPlot.setpos({})'.format(polar)
        # Display.debug_line(self.polar.cartesian(), polar.cartesian(), 'yellow')
        r = polar.r - self.polar.r

        def shortest_angle(a, b):
            delta = (b - a) % math.tau
            if delta < 0:
                if abs(delta + math.tau) < abs(delta):
                    delta = delta + math.tau
            else:
                if abs(delta - math.tau) < abs(delta):
                    delta = delta - math.tau
            return delta

        delta_t = shortest_angle(self.polar.t, polar.t)

        self.move(Polar(r, delta_t))
예제 #14
0
    def __init__(self, radius, speed=1.0):
        """Init.

		radius of the cog
		speed multiplies the turning rate relative to the parent.
		"""
        self.radius = Millimeters(radius)
        self.offset = None

        self.children = list()
        self.track = Polar(0.0, 0.0)

        self.theta = Radians(0.0)
        self.speed_boost = speed
        self.base_speed = 1.0
        self.center = Cartesian(0.0, 0.0)
        self.direction = 1.0

        self.parent_radius = None

        self.id = uuid.uuid4()
예제 #15
0
class Display(object):
	"""Abstraction that converts our polar motor signals to pixels on the screen."""

	c = DisplayPosition(0, 0)
	p = Polar(0, 0)
	c_pixels = DisplayPosition(0, 0)
	c_pixels_whole = DisplayPosition(0, 0)

	offset = Cartesian(0, 0)

	hud = None
	canvas = None

	debug_enabled = True
	debug_pen = None

	class HUD(threading.Thread):
		"""HUD manager."""

		def __init__(self):
			"""Setup the HUD elements."""
			super(Display.HUD, self).__init__()
			self.canvas = turtle.screen.getcanvas()
			
			self.hud_lines = dict()
			self.queues = dict()

			self.next_pos = TkSpace(-102.0, -98.0)

			self.stop = False
			self.daemon = True

		def __setitem__(self, queue_name, value):
			"""Set text on HUD item.

			Use a queue to make the value avaiable when we refresh the HUD.
			Passing new keys into here will create new HUD lines.
			"""
			if queue_name not in self.queues:
				self.queues[queue_name] = LifoQueue()
			if queue_name not in self.hud_lines:
				self.hud_lines[queue_name] = self.canvas.create_text(*self.next_pos, text='', fill='grey', anchor=tk.SW)
				self.next_pos.y += 5.0

			try:
				while True:
					self.queues[queue_name].get_nowait()
			except Empty:
				pass
			self.queues[queue_name].put_nowait(value)

		def run(self):
			"""Update the HUD text."""
			while not self.stop:
				for queue_name, q in self.queues.iteritems():
					try:
						self.canvas.itemconfig(self.hud_lines[queue_name], text=q.get_nowait())
					except Empty:
						pass
				time.sleep(0.5)

	def __init__(self):
		"""Set the HUD elements."""
		if Display.hud is None:
			Display.hud = Display.HUD()
			Display.hud.start()

		if Display.canvas is None:
			Display.canvas = turtle.screen.getcanvas()
			Display.debug_pen = Pen()

		self.pen = Pen()

	def setpos(self, polar):
		"""Set the position of of the polar coordinates to pixels on the screen."""
		self.p = polar
		self.c = self.p.cartesian()
		new_pixel_position = self.c.pixels().trunc(factor=10)
		if self.c_pixels != new_pixel_position:

			# a = new_pixel_position * 0.86666666666666666666666
			# self.pen.down()
			# self.pen.setpos(self.c)
			# self.pen.up()

			# TODO: What is going on here?!?
			# Some how my converion from mm to pixels that works everywhere else doesn't here.
			turtle.setpos(new_pixel_position * 0.86666666666666666 * 0.86666666666666666666666)
			if not FAST:
				turtle.setheading(polar.t.degrees())
			self.c_pixels = new_pixel_position

		# Post values to the HUD
		self.hud['hud_polar'] = self.p
		self.hud['hud_cartesian'] = self.c

	@classmethod
	def set_offset(cls, offset):
		"""Apply an offset to align with the real drawings."""
		cls.offset = offset

	@classmethod
	def debug_point(cls, point, color):
		"""Draw a colored dot."""
		if cls.debug_enabled:
			pen = Display.debug_pen
			pen.color = color
			if cls.offset:
				point = point + cls.offset

			pen.setpos(point)
			pen.down()
			pen.dot(5, color)
			pen.up()
	
	@classmethod
	def debug_line(cls, start_point, end_point, color='grey'):
		"""Draw a line."""
		if cls.debug_enabled:
			pen = Display.debug_pen
			if cls.offset:
				start_point = start_point + cls.offset
				end_point = end_point + cls.offset

			pen.down()
			pen.line(start_point, end_point)
			pen.up()

	@classmethod
	def debug_circle(cls, center_point, radius, color='grey'):
		"""Draw a line."""
		if cls.debug_enabled:
			pen = Display.debug_pen
			if cls.offset:
				center_point = center_point + cls.offset

			pen.down()
			pen.circle(center_point, radius, color)
			pen.up()

	@classmethod
	def debug_text(cls, point, text):
		"""Write some text."""
		pass
		# if cls.debug_enabled:
		# 	with DebugPen('grey', 1) as pen:
		# 		pen.setpos(point.pixels() * 0.86666666666666666 * 0.86666666666666666)
		# 		pen.write(text)
	
	@classmethod
	def debug_clear(cls):
		"""Clear all debug drawing."""
		if cls.debug_enabled:
			debug_pen.clear()
예제 #16
0
 def set_track(self, radius, angle):
     """The pen's track can be anywhere."""
     self.track = Polar(self.offset, angle)
예제 #17
0
	def motor_step_distance(self):
		"""Return the step size of the motors."""
		return Polar(self.r_motor.step_distance, self.t_motor.step_distance)
예제 #18
0
 def __init__(self):
     super(Koru, self).__init__(Polar(0.0, 0.0))
예제 #19
0
 def __iter__(self):
     """Iterable steps."""
     delta = Polar(self.radius_end - self.radius_start,
                   math.tau * self.turns)
     for blah in self.step_absolute(delta, self.grid_size):
         yield blah
예제 #20
0
 def set_track(self, radius, angle):
     """Save the track."""
     self.track = Polar(radius, angle)