def generate_spokes(self, root_radius, spoke_width, spokes, mount_radius, mount_hole, unit_factor, unit_label): """ given a set of constraints - generate the svg path for the gear spokes - lies between mount_radius (inner hole) and root_radius (bottom of the teeth) - spoke width also defines the spacing at the root_radius - mount_radius is adjusted so that spokes fit if there is room - if no room (collision) then spokes not drawn """ if not spokes: return [] # Spokes collision = False # assume we draw spokes messages = [] # messages to send back about changes. spoke_holes = [] r_outer = root_radius - spoke_width try: spoke_count = spokes spokes = [i*2*pi/spokes for i in range(spoke_count)] except TypeError: spoke_count = len(spokes) spokes = [radians(a) for a in spokes] spokes.append(spokes[0]+two_pi) # checks for collision with spokes # check for mount hole collision with inner spokes if mount_radius <= mount_hole/2: adj_factor = (r_outer - mount_hole/2) / 5 if adj_factor < 0.1: # not enough reasonable room collision = True else: mount_radius = mount_hole/2 + adj_factor # small fix messages.append("Mount support too small. Auto increased to %2.2f%s." % (mount_radius/unit_factor*2, unit_label)) # then check to see if cross-over on spoke width for i in range(spoke_count): angle = spokes[i]-spokes[i-1] if spoke_width >= angle * mount_radius: adj_factor = 1.2 # wrong value. its probably one of the points distances calculated below mount_radius += adj_factor messages.append("Too many spokes. Increased Mount support by %2.3f%s" % (adj_factor/unit_factor, unit_label)) # check for collision with outer rim if r_outer <= mount_radius: # not enough room to draw spokes so cancel collision = True if collision: # don't draw spokes if no room. messages.append("Not enough room for Spokes. Decrease Spoke width.") else: # draw spokes for i in range(spoke_count): self.boxes.ctx.save() start_a, end_a = spokes[i], spokes[i+1] # inner circle around mount asin_factor = spoke_width/mount_radius/2 # check if need to clamp radius asin_factor = max(-1.0, min(1.0, asin_factor)) # no longer needed - resized above a = asin(asin_factor) # is inner circle too small asin_factor = spoke_width/r_outer/2 # check if need to clamp radius asin_factor = max(-1.0, min(1.0, asin_factor)) # no longer needed - resized above a2 = asin(asin_factor) l = vlength(vdiff(point_on_circle(mount_radius, start_a + a), point_on_circle(r_outer, start_a + a2))) self.boxes.moveTo(*point_on_circle(mount_radius, start_a + a), degrees=degrees(start_a)) self.boxes.polyline( l, +90+degrees(a2), 0, (degrees(end_a-start_a-2*a2), r_outer), 0, +90+degrees(a2), l, 90-degrees(a), 0, (-degrees(end_a-start_a-2*a), mount_radius), 0, 90+degrees(a2), 0 ) self.boxes.ctx.restore() return messages