def deconstruct(outer, bore, top_fractions, bottom_fractions, bit_diameter, dilation, block_zsize): """ Object must be large enough to include end padding """ xsize, ysize, zsize = outer.size() radius = max(xsize, ysize) * 2 length = zsize outers = make_segments(outer, length, radius, top_fractions, bottom_fractions) bores = make_segments(bore, length, radius, top_fractions, bottom_fractions, False) result = [] for outer, bore in zip(outers, bores): extent = outer.extent() b = bit_diameter clipper = shape.block(extent.xmin - b, extent.xmax + b, extent.ymin - b, extent.ymax + b, extent.zmin, extent.zmax + b) bore.clip(clipper) n = 1 while extent.zmax > block_zsize * n: n += 1 #thickness = extent.zmax/n thickness = block_zsize block = shape.block(extent.xmin - 1, extent.xmax + 1, extent.ymin - 1, extent.ymax + 1, 0, thickness) for i in xrange(n): temp_outer = outer.copy() temp_bore = bore.copy() temp_outer.move(0, 0, -i * thickness) temp_bore.move(0, 0, -i * thickness) temp_outer.clip(block) #temp_bore.clip(block) result.append([ Packable([temp_outer, temp_bore], 0, dilation), Packable([temp_outer, temp_bore], 180, dilation), ]) return result
def deconstruct(outer, bore, top_fractions, bottom_fractions, bit_diameter, dilation, block_zsize): """ Object must be large enough to include end padding """ xsize,ysize,zsize = outer.size() radius = max(xsize,ysize)*2 length = zsize outers = make_segments(outer, length, radius, top_fractions, bottom_fractions) bores = make_segments(bore, length, radius, top_fractions, bottom_fractions, False) result = [ ] for outer, bore in zip(outers, bores): extent = outer.extent() b = bit_diameter clipper = shape.block(extent.xmin-b,extent.xmax+b, extent.ymin-b,extent.ymax+b, extent.zmin,extent.zmax+b) bore.clip(clipper) n = 1 while extent.zmax > block_zsize*n: n += 1 #thickness = extent.zmax/n thickness = block_zsize block = shape.block(extent.xmin-1,extent.xmax+1,extent.ymin-1,extent.ymax+1,0,thickness) for i in xrange(n): temp_outer = outer.copy() temp_bore = bore.copy() temp_outer.move(0,0,-i*thickness) temp_bore.move(0,0,-i*thickness) temp_outer.clip(block) #temp_bore.clip(block) result.append([ Packable([temp_outer,temp_bore], 0, dilation), Packable([temp_outer,temp_bore], 180, dilation), ]) return result
def mill_template(xsize, ysize, zsize, dilation): template = Pack(xsize, ysize, zsize) peg_diameter = 6.0 block_radius = 4.0 hole = shape.prism(min(zsize,peg_diameter*2.0), peg_diameter) # *3 is too deep hole_block = shape.block(-block_radius,block_radius,-block_radius,block_radius,0,zsize) hole_packable = Packable([hole_block,hole], 0, 0.0, use_upper=False) shift = 4 template.put(shift, block_radius,hole_packable) template.put(xsize-block_radius*2-shift, block_radius,hole_packable) template.put(0,ysize-block_radius*3,hole_packable) template.put(xsize-block_radius*2,ysize-block_radius*3,hole_packable) return template
def mill_template(xsize, ysize, zsize, dilation): template = Pack(xsize, ysize, zsize) peg_diameter = 6.0 block_radius = 4.0 hole = shape.prism(min(zsize, peg_diameter * 1.5), peg_diameter) # *3 is too deep hole_block = shape.block(-block_radius, block_radius, -block_radius, block_radius, 0, zsize) hole_packable = Packable([hole_block, hole], 0, 0.0, use_upper=False) shift = 4 template.put(shift, block_radius, hole_packable) template.put(xsize - block_radius * 2 - shift, block_radius, hole_packable) #template.put(0,ysize-block_radius*3,hole_packable) #template.put(xsize-block_radius*2,ysize-block_radius*3,hole_packable) return template
def make_segment(instrument, top, low, high, radius, clip=True): #if not clip_half: # y1,y2 = -radius,radius segment = instrument.copy() if clip: if top: y1,y2 = 0,radius else: y1,y2 = -radius,0 clipper = shape.block(-radius,radius, y1,y2, low,high) segment.clip(clipper) #Closed flute is meant to be like this #assert abs(segment.size()[2] - (high-low+pad*2)) < 1e-3, 'Need more padding for construction' segment.move(0,0,-low) if top: segment.rotate(0,0,1, 180) segment.rotate(1,0,0,-90) segment.rotate(0,0,1,90) segment.move(high-low,0,0) return segment
def make_segment(instrument, top, low, high, radius, clip=True): #if not clip_half: # y1,y2 = -radius,radius segment = instrument.copy() if clip: if top: y1, y2 = 0, radius else: y1, y2 = -radius, 0 clipper = shape.block(-radius, radius, y1, y2, low, high) segment.clip(clipper) #Closed flute is meant to be like this #assert abs(segment.size()[2] - (high-low+pad*2)) < 1e-3, 'Need more padding for construction' segment.move(0, 0, -low) if top: segment.rotate(0, 0, 1, 180) segment.rotate(1, 0, 0, -90) segment.rotate(0, 0, 1, 90) segment.move(high - low, 0, 0) return segment
def render(self, bit_diameter, bit_pad): xsize = self.xsize ysize = self.ysize a = bit_pad b = bit_pad + self.zsize/10.0 pad_cone = shape.extrude_profile(profile.Profile([0,self.zsize],[a*2,b*2],[a*2,b*2]), cross_section=lambda d: shape.circle(d,16)) pad_cylinder = shape.extrude_profile(profile.Profile([0,self.zsize+bit_diameter],[a*2,a*2],[a*2,a*2]), cross_section=lambda d: shape.circle(d,16)) pad = 0.5 + self.zsize/10.0 upper = shape.block(-pad,xsize+pad,-pad,ysize+pad,0,self.zsize) print 'Cut holes' for i,(x,y,packable) in enumerate(self.items): if packable.use_upper: flat = packable.mask.to_3() flat.move(x,y,0) minsum = flat.minkowski_sum(pad_cone) upper.remove( minsum ) print 'Put things in them' for x,y,packable in self.items: if packable.use_upper: temp = packable.shapes[0].copy() temp.move(x,y,0) upper.add(temp) bol = int(self.xsize / 10.0) bol_width = 1.0 # 0.5 seemed to allow shifting on a sop flute bol_height = 1.0 # 0.5 was too low, middle piece tore loose in final pass of # contour finishing (x-scan of horizontal-like surfaces) xmins = [ x for x,y,packable in self.items ] xmaxs = [ x+packable.extent.xmax for x,y,packable in self.items ] margin = bol_width+bit_diameter+0.25 potential_bols = [ ((i+0.5)*xsize/bol, 0,ysize) for i in xrange(bol) ] bols = [ ] while potential_bols: pos, y_low, y_high = potential_bols.pop() for i, (x,y,packable) in enumerate(self.items): if pos-margin <= xmins[i] <= pos+margin or \ pos-margin <= xmaxs[i] <= pos+margin: low = y-bit_diameter high = y+packable.extent.ymax+bit_diameter if low <= y_low and y_high <= high: break elif y_low < low and high < y_high: potential_bols.append((pos, y_low, low)) potential_bols.append((pos, high, y_high)) break elif y_low < low < y_high <= high: potential_bols.append((pos, y_low, low)) break elif low < y_low < high <= y_high: potential_bols.append((pos, high, y_high)) break else: bols.append((pos,y_low,y_high)) for pos, y_low, y_high in bols: upper.add(shape.block( pos-bol_width*0.5, pos+bol_width*0.5, y_low, y_high, #0,ysize, #-bit_diameter*0.6, bol_height, 0,bol_height, )) print 'Underside' # Cut the bottom of upper with lower, to depth bit_diameter lower = shape.block(-pad,xsize+pad,-pad,ysize+pad,bit_diameter,self.zsize) lower.add(upper) print 'Remove bores' for x,y,packable in self.items: temp = packable.shapes[1].copy() temp.move(x,y,0) flat = packable.mask.to_3() flat.move(x,y,0) minsum = flat.minkowski_sum(pad_cylinder) temp.clip(minsum) lower.remove(temp) lower.rotate(0,1,0, 180) return lower, upper
def run(self): zsize = self.thickness pad = self.wall diameter = zsize - pad*2 self.log.log('Thickness: %.1fmm\n' % zsize) self.log.log('Min wall thickness: %.1fmm\n' % pad) self.log.log('Hole diameter: %.1fmm\n' % diameter) negatives = [ ] lengths = [ ] xs = [ ] for i, note in enumerate(SCALE): print 'Make hole %d / %d' % (i+1,len(SCALE)) length = design.wavelength(note,self.transpose)*0.25 + LENGTH_CORRECTION*diameter x = i*(diameter+pad) lengths.append(length) xs.append(x) hole = make_hole(diameter, length) hole.move(x,0,0) negatives.append(hole) string_hole_diameter = diameter*1.5 string_hole_loop = shape.circle(string_hole_diameter) string_hole = shape.extrusion([-zsize,zsize],[string_hole_loop,string_hole_loop]) string_hole.rotate(1,0,0, 90) xlow = xs[0]-zsize #xmid = xs[-1]*0.5 xhigh = xs[-1]+zsize zhigh = lengths[0]+zsize*0.5 #zmid = max(lengths[-1]+zsize*0.5, zhigh-(xhigh-xmid)) trim = min(xhigh-xlow,zhigh) * 0.5 #string_x = (xmid+xhigh)*0.5 - diameter #string_z = (zmid+zhigh)*0.5 - diameter #string_z = lengths[3] + diameter*2 #string_x = xhigh-trim*0.5-diameter #string_z = zhigh-trim*0.5-diameter a = math.pi*-5/8 d = diameter * 1.5 string_x = xhigh-trim + math.cos(a)*d string_z = zhigh + math.sin(a)*d string_hole.move(string_x,0,string_z) #p = pad*0.5 #loop = shape.Loop([(0,p),(p*2,-p),(-p*2,p)]) #r = diameter-pad #stick = shape.extrusion([-r,r],[loop,loop]) # #for i in xrange(-1,len(SCALE)+2): # for j in xrange(int(zhigh / (diameter+pad))+1): # x = (i-0.5)*(diameter+pad) # z = r + j*(diameter+pad) # c = stick.copy() # if (i^j)&1: # c.rotate(0,1,0,90) # c.move(x,-diameter*0.5-pad,z) # negatives.append(c) loop = shape.Loop([ (xlow,0), (xhigh,0), (xhigh,zhigh-trim), (xhigh-trim,zhigh), (xlow,zhigh) ]) bev = zsize / 4.0 loop_bevel = shape.Loop([ (xlow,bev), (xhigh,bev), (xhigh,zhigh-trim), (xhigh-trim,zhigh), (xlow,zhigh) ]) #mask = loop.mask(RES) #amount = diameter * 0.5 #op = shape.circle(amount).mask(RES) #mask = mask.open(op) #loop = mask.trace(RES)[0] #sloop = mask.erode(op).trace(RES)[0] #z1 = zsize*0.5-amount z2 = zsize*0.5 #positive = shape.extrusion([-z2,z2],[loop,loop]) positive = shape.extrusion([-z2,-z2+bev,z2-bev,z2],[loop_bevel,loop,loop,loop_bevel]) positive.rotate(1,0,0,90) negative = string_hole.copy() for i, item in enumerate(negatives): print 'Merge %d / %d' % (i+1,len(negatives)) negative.add(item) del negatives instrument = positive.copy() print 'Remove holes from instrument' instrument.remove(negative) del positive del negative instrument.rotate(1,0,0,90) extent = instrument.extent() copy = instrument.copy() copy.rotate(0,0,1,-45) cextent = copy.extent() copy.move(-(cextent.xmin+cextent.xmax)*0.5, -(cextent.ymin+cextent.ymax)*0.5, -cextent.zmin) self.save(copy,'instrument') del copy top = shape.block( extent.xmin-1,extent.xmax+1, extent.ymin-1,extent.ymax+1, 0,extent.zmax+1 ) bottom = shape.block( extent.xmin-1,extent.xmax+1, extent.ymin-1,extent.ymax+1, extent.zmin-1,0 ) top.clip(instrument) bottom.clip(instrument) top.rotate(1,0,0,180) top.move(0,4,0) bottom.add(top) pattern = bottom del top del bottom pattern.move(0,0,z2) pattern.rotate(0,0,1, -90) bit_pad = 4.0 extra_depth = 3.0 a = bit_pad b = bit_pad + z2/10.0 pad_cone = shape.extrude_profile(profile.Profile( [-extra_depth,0,z2],[a*2,a*2,b*2] ), cross_section=lambda d: shape.circle(d,16)) extra = b + 0.5 extent = pattern.extent() mill = shape.block( extent.xmin-extra, extent.xmax+extra, extent.ymin-extra, extent.ymax+extra, -extra_depth, z2, ) mill.remove( pattern.polygon_mask().to_3().minkowski_sum(pad_cone) ) mill.add( pattern ) del pad_cone del pattern self.save(mill, 'mill')
def run(self): zsize = self.thickness pad = self.wall diameter = zsize - pad * 2 self.log.log('Thickness: %.1fmm\n' % zsize) self.log.log('Min wall thickness: %.1fmm\n' % pad) self.log.log('Hole diameter: %.1fmm\n' % diameter) negatives = [] lengths = [] xs = [] for i, note in enumerate(SCALE): print 'Make hole %d / %d' % (i + 1, len(SCALE)) length = design.wavelength( note, self.transpose) * 0.25 + LENGTH_CORRECTION * diameter x = i * (diameter + pad) lengths.append(length) xs.append(x) hole = make_hole(diameter, length) hole.move(x, 0, 0) negatives.append(hole) string_hole_diameter = diameter * 1.5 string_hole_loop = shape.circle(string_hole_diameter) string_hole = shape.extrusion([-zsize, zsize], [string_hole_loop, string_hole_loop]) string_hole.rotate(1, 0, 0, 90) xlow = xs[0] - zsize #xmid = xs[-1]*0.5 xhigh = xs[-1] + zsize zhigh = lengths[0] + zsize * 0.5 #zmid = max(lengths[-1]+zsize*0.5, zhigh-(xhigh-xmid)) trim = min(xhigh - xlow, zhigh) * 0.5 #string_x = (xmid+xhigh)*0.5 - diameter #string_z = (zmid+zhigh)*0.5 - diameter #string_z = lengths[3] + diameter*2 #string_x = xhigh-trim*0.5-diameter #string_z = zhigh-trim*0.5-diameter a = math.pi * -5 / 8 d = diameter * 1.5 string_x = xhigh - trim + math.cos(a) * d string_z = zhigh + math.sin(a) * d string_hole.move(string_x, 0, string_z) #p = pad*0.5 #loop = shape.Loop([(0,p),(p*2,-p),(-p*2,p)]) #r = diameter-pad #stick = shape.extrusion([-r,r],[loop,loop]) # #for i in xrange(-1,len(SCALE)+2): # for j in xrange(int(zhigh / (diameter+pad))+1): # x = (i-0.5)*(diameter+pad) # z = r + j*(diameter+pad) # c = stick.copy() # if (i^j)&1: # c.rotate(0,1,0,90) # c.move(x,-diameter*0.5-pad,z) # negatives.append(c) loop = shape.Loop([(xlow, 0), (xhigh, 0), (xhigh, zhigh - trim), (xhigh - trim, zhigh), (xlow, zhigh)]) bev = zsize / 4.0 loop_bevel = shape.Loop([(xlow, bev), (xhigh, bev), (xhigh, zhigh - trim), (xhigh - trim, zhigh), (xlow, zhigh)]) #mask = loop.mask(RES) #amount = diameter * 0.5 #op = shape.circle(amount).mask(RES) #mask = mask.open(op) #loop = mask.trace(RES)[0] #sloop = mask.erode(op).trace(RES)[0] #z1 = zsize*0.5-amount z2 = zsize * 0.5 #positive = shape.extrusion([-z2,z2],[loop,loop]) positive = shape.extrusion([-z2, -z2 + bev, z2 - bev, z2], [loop_bevel, loop, loop, loop_bevel]) positive.rotate(1, 0, 0, 90) negative = string_hole.copy() for i, item in enumerate(negatives): print 'Merge %d / %d' % (i + 1, len(negatives)) negative.add(item) del negatives instrument = positive.copy() print 'Remove holes from instrument' instrument.remove(negative) del positive del negative instrument.rotate(1, 0, 0, 90) extent = instrument.extent() copy = instrument.copy() copy.rotate(0, 0, 1, -45) cextent = copy.extent() copy.move(-(cextent.xmin + cextent.xmax) * 0.5, -(cextent.ymin + cextent.ymax) * 0.5, -cextent.zmin) self.save(copy, 'instrument') del copy top = shape.block(extent.xmin - 1, extent.xmax + 1, extent.ymin - 1, extent.ymax + 1, 0, extent.zmax + 1) bottom = shape.block(extent.xmin - 1, extent.xmax + 1, extent.ymin - 1, extent.ymax + 1, extent.zmin - 1, 0) top.clip(instrument) bottom.clip(instrument) top.rotate(1, 0, 0, 180) top.move(0, 4, 0) bottom.add(top) pattern = bottom del top del bottom pattern.move(0, 0, z2) pattern.rotate(0, 0, 1, -90) bit_pad = 4.0 extra_depth = 3.0 a = bit_pad b = bit_pad + z2 / 10.0 pad_cone = shape.extrude_profile( profile.Profile([-extra_depth, 0, z2], [a * 2, a * 2, b * 2]), cross_section=lambda d: shape.circle(d, 16)) extra = b + 0.5 extent = pattern.extent() mill = shape.block( extent.xmin - extra, extent.xmax + extra, extent.ymin - extra, extent.ymax + extra, -extra_depth, z2, ) mill.remove(pattern.polygon_mask().to_3().minkowski_sum(pad_cone)) mill.add(pattern) del pad_cone del pattern self.save(mill, 'mill')
def render(self, bit_diameter, bit_pad): xsize = self.xsize ysize = self.ysize a = bit_pad b = bit_pad + self.zsize / 10.0 pad_cone = shape.extrude_profile( profile.Profile([0, self.zsize], [a * 2, b * 2], [a * 2, b * 2]), cross_section=lambda d: shape.circle(d, 16)) pad_cylinder = shape.extrude_profile( profile.Profile([0, self.zsize + bit_diameter], [a * 2, a * 2], [a * 2, a * 2]), cross_section=lambda d: shape.circle(d, 16)) pad = 0.5 + self.zsize / 10.0 upper = shape.block(-pad, xsize + pad, -pad, ysize + pad, 0, self.zsize) print 'Cut holes' for i, (x, y, packable) in enumerate(self.items): if packable.use_upper: flat = packable.mask.to_3() flat.move(x, y, 0) minsum = flat.minkowski_sum(pad_cone) upper.remove(minsum) print 'Put things in them' for x, y, packable in self.items: if packable.use_upper: temp = packable.shapes[0].copy() temp.move(x, y, 0) upper.add(temp) bol = int(self.xsize / 10.0) bol_width = 1.0 # 0.5 seemed to allow shifting on a sop flute bol_height = 1.0 # 0.5 was too low, middle piece tore loose in final pass of # contour finishing (x-scan of horizontal-like surfaces) xmins = [x for x, y, packable in self.items] xmaxs = [x + packable.extent.xmax for x, y, packable in self.items] margin = bol_width + bit_diameter + 0.25 potential_bols = [((i + 0.5) * xsize / bol, 0, ysize) for i in xrange(bol)] bols = [] while potential_bols: pos, y_low, y_high = potential_bols.pop() for i, (x, y, packable) in enumerate(self.items): if pos-margin <= xmins[i] <= pos+margin or \ pos-margin <= xmaxs[i] <= pos+margin: low = y - bit_diameter high = y + packable.extent.ymax + bit_diameter if low <= y_low and y_high <= high: break elif y_low < low and high < y_high: potential_bols.append((pos, y_low, low)) potential_bols.append((pos, high, y_high)) break elif y_low < low < y_high <= high: potential_bols.append((pos, y_low, low)) break elif low < y_low < high <= y_high: potential_bols.append((pos, high, y_high)) break else: bols.append((pos, y_low, y_high)) for pos, y_low, y_high in bols: upper.add( shape.block( pos - bol_width * 0.5, pos + bol_width * 0.5, y_low, y_high, #0,ysize, #-bit_diameter*0.6, bol_height, 0, bol_height, )) print 'Underside' # Cut the bottom of upper with lower, to depth bit_diameter lower = shape.block(-pad, xsize + pad, -pad, ysize + pad, bit_diameter, self.zsize) lower.add(upper) print 'Remove bores' for x, y, packable in self.items: temp = packable.shapes[1].copy() temp.move(x, y, 0) flat = packable.mask.to_3() flat.move(x, y, 0) minsum = flat.minkowski_sum(pad_cylinder) temp.clip(minsum) lower.remove(temp) lower.rotate(0, 1, 0, 180) return lower, upper