def gen_geoms(self, joint_def, layerdef, design, split_buffer): print('Generating geometry') hinge_gap = joint_def.width * popupcad.csg_processing_scaling # split_buffer = .1 * hinge_gap sublaminate_layers = [ layerdef.getlayer(item) for item in joint_def.sublaminate_layers ] hingelayer = layerdef.getlayer(joint_def.joint_layer) operationgeom = design.sketches[joint_def.sketch].output_csg() sketch_result = Laminate(design.return_layer_definition()) sketch_result.replacelayergeoms(hingelayer, operationgeom) hingelines = sketch_result.to_generic_laminate().geoms[hingelayer] hingelines = [item for item in hingelines if item.is_valid_bool()] buffered_split = sketch_result.buffer(split_buffer, resolution=self.resolution) allgeoms4 = [] for geom in hingelines: geom = geom.to_shapely(scaling=popupcad.csg_processing_scaling) laminate = Laminate(layerdef) for layer in sublaminate_layers: laminate.replacelayergeoms(layer, [geom]) allgeoms4.append( laminate.buffer(hinge_gap, resolution=self.resolution)) return allgeoms4, buffered_split, hingelines
def gen_geoms(self, joint_def, layerdef, design): hinge_gap = joint_def.width *popupcad.csg_processing_scaling split_buffer = .1 * hinge_gap stiffness = joint_def.stiffness damping = joint_def.damping preload_angle = joint_def.preload_angle sublaminate_layers = [ layerdef.getlayer(item) for item in joint_def.sublaminate_layers] hingelayer = layerdef.getlayer(joint_def.joint_layer) operationgeom = design.sketches[joint_def.sketch].output_csg() sketch_result = Laminate(design.return_layer_definition()) sketch_result.replacelayergeoms(hingelayer, operationgeom) hingelines = sketch_result.to_generic_laminate().geoms[hingelayer] hingelines = [item for item in hingelines if item.is_valid_bool()] buffered_split = sketch_result.buffer(split_buffer,resolution=self.resolution) allgeoms4 = [] for geom in hingelines: geom = geom.to_shapely() laminate = Laminate(layerdef) for layer in sublaminate_layers: laminate.replacelayergeoms(layer, [geom]) allgeoms4.append(laminate.buffer(hinge_gap,resolution=self.resolution)) joint_props = [(stiffness, damping, preload_angle) for item in hingelines] return allgeoms4, buffered_split, hingelines, joint_props
def cross_section(layerdef, sketch, parent, scale_value): from popupcad.filetypes.laminate import Laminate from popupcad.filetypes.genericshapes import GenericLine import shapely.affinity as aff import popupcad.algorithms.points as points import shapely.geometry as sg import numpy laminate = Laminate(layerdef) for item in sketch.operationgeometry: if isinstance(item, GenericLine): line = item b = line.exteriorpoints(scaling=popupcad.csg_processing_scaling)[0] c = numpy.array(b) + numpy.array([1, 0]) a = points.calctransformfrom2lines( line.exteriorpoints(scaling=popupcad.csg_processing_scaling), [b, c.tolist()], scale_x=1, scale_y=1) sketch_csg = sketch.output_csg() for layer in layerdef.layers: laminate.replacelayergeoms(layer, sketch_csg) result = parent.intersection(laminate) laminate2 = Laminate(layerdef) for ii, layerid in enumerate(layerdef.layers): yshift = layerdef.z_values[ layerid] * popupcad.csg_processing_scaling * scale_value layer = result.layer_sequence[layerid] thickness = layerid.thickness * popupcad.csg_processing_scaling * scale_value newgeoms = [item for item in layer.geoms] newgeoms = [aff.affine_transform(item, a) for item in newgeoms] newgeoms2 = [] for geom in newgeoms: newgeom = sg.box(geom.coords[0][0], geom.coords[0][1], geom.coords[-1][0], geom.coords[-1][1] + thickness) newgeoms2.append(newgeom) newgeoms = newgeoms2 newgeoms = [ aff.translate(item, yoff=yshift) for item in newgeoms ] newgeoms = popupcad.algorithms.csg_shapely.condition_shapely_entities( *newgeoms) laminate2[ii] = newgeoms return laminate2 return laminate
def find(generic_laminate): generic = generic_laminate.geoms layerdef = generic_laminate.layerdef from popupcad.filetypes.laminate import Laminate layer_dict = dict([(geom.id, layer) for layer, geoms in generic.items() for geom in geoms]) geom_dict = dict([(geom.id, geom) for layer, geoms in generic.items() for geom in geoms]) geom_dict_whole = geom_dict.copy() laminates = [] values = [] while len(geom_dict) > 0: laminate = Laminate(layerdef) key = list(geom_dict.keys())[0] gs = findallconnectedneighborgeoms(key, generic_laminate, geom_dict, layerdef) geom_mins = numpy.array( [find_minimum_xy(geom_dict_whole[geom_id]) for geom_id in gs]) values.append(tuple(geom_mins.min(0))) for item_id in gs: geom = geom_dict_whole[item_id] if geom.is_valid_bool(): laminate.insertlayergeoms(layer_dict[item_id], [geom.to_shapely()]) laminates.append(laminate) laminates = sort_lams(laminates, values) return laminates
def to_csg(self): from popupcad.filetypes.laminate import Laminate new = Laminate(self.layerdef) for ii, layer in enumerate(self.layerdef.layers): geoms = [item.to_shapely() for item in self.geoms[layer]] new.replacelayergeoms(layer, geoms) return new
def shift_flip_rotate(ls1, shift, flip, rotate): from popupcad.filetypes.laminate import Laminate lsout = Laminate(ls1.layerdef) layers = ls1.layerdef.layers step = 1 if flip: step = -1 if rotate: for layerout, layerin in zip( layers[shift:] + layers[:shift], layers[::step]): lsout.replacelayergeoms( layerout, ls1.layer_sequence[layerin].geoms) else: if shift > 0: outshift = shift inshift = 0 elif shift < 0: outshift = 0 inshift = -shift else: outshift = 0 inshift = 0 for layerout, layerin in zip(layers[outshift:], layers[::step][inshift:]): lsout.replacelayergeoms(layerout,ls1.layer_sequence[layerin].geoms) return lsout
def transform_csg(layerdef_from, layerdef_to, inshift, outshift, step, geom_from, geoms_to, csg_laminate, scale_x, scale_y): from popupcad.filetypes.laminate import Laminate import shapely.affinity as aff from popupcad.algorithms.points import calctransformfrom2lines lsout = Laminate(layerdef_to) for layer_from, layer_to in zip(layerdef_from.layers[::step][inshift:], layerdef_to.layers[outshift:]): newgeoms = [] for geom in geoms_to: for designgeom in csg_laminate.layer_sequence[layer_from].geoms: try: from_line = geom_from.exteriorpoints( scaling=popupcad.csg_processing_scaling) to_line = geom.exteriorpoints( scaling=popupcad.csg_processing_scaling) transform = calctransformfrom2lines(from_line, to_line, scale_x=scale_x, scale_y=scale_y) transformed_geom = aff.affine_transform( designgeom, transform) newgeoms.append(transformed_geom) except IndexError: pass result1 = popupcad.algorithms.csg_shapely.unary_union_safe(newgeoms) results2 = popupcad.algorithms.csg_shapely.condition_shapely_entities( result1) lsout.replacelayergeoms(layer_to, results2) return lsout
def sketch_operation(sketch, layerdef, layers): from popupcad.filetypes.laminate import Laminate operationgeom = sketch.output_csg() laminate = Laminate(layerdef) for layer in layers: laminate.replacelayergeoms(layer, operationgeom) return laminate
def one_way_up(laminatein): l = Layer([]) laminateout = Laminate(laminatein.layerdef) for ii, geoms in enumerate(laminatein): l = l.union(geoms) laminateout[ii] = l laminateout = modify_up(laminateout) return laminateout
def millkeepout(laminatein): '''calculate the keepout for an input laminate assuming milling''' l = Layer([]) laminateout = Laminate(laminatein.layerdef) for ii, geoms in enumerate(laminatein[::-1]): l = l.union(geoms) laminateout[-1 - ii] = l return laminateout
def to_foldable_robotics(self, scaling=1): from foldable_robotics.laminate import Laminate from foldable_robotics.layer import Layer layers = [] for layer in self.layers(): geoms = [item.to_shapely(scaling) for item in self.geoms[layer]] layers.append(Layer(*geoms)) lam = Laminate(*layers) return lam
def find_outer(ls, minpoint): import popupcad.algorithms.points as points lsouter = Laminate(ls.layerdef) lsinner = Laminate(ls.layerdef) for layer, layer_geometry in ls.layer_sequence.items(): outergeoms = [] innergeoms = [] for geom in layer_geometry.geoms: if points.pointinpoints( minpoint, popupcad.algorithms.csg_shapely.to_generic(geom). exteriorpoints(scaling=popupcad.csg_processing_scaling), popupcad.distinguishable_number_difference): outergeoms.append(geom) else: innergeoms.append(geom) lsouter.replacelayergeoms(layer, outergeoms) lsinner.replacelayergeoms(layer, innergeoms) return lsouter, lsinner
def operate(self, design): layerdef = design.return_layer_definition() csg = Laminate(layerdef) for layer in layerdef.layers: shapelygeoms = [ geom.to_shapely(scaling=popupcad.csg_processing_scaling) for geom in self.generic.geoms[layer] if geom.is_valid_bool() ] csg.insertlayergeoms(layer, shapelygeoms) return csg
def operate(self, design): sketchid = self.sketch_links['sketch'][0] sketch = design.sketches[sketchid] operationgeom = popupcad.algorithms.csg_shapely.unary_union_safe( [item.to_shapely() for item in sketch.operationgeometry]) lsout = Laminate(design.return_layer_definition()) for layer in design.return_layer_definition().layers: lsout.replacelayergeoms( layer, popupcad.algorithms.csg_shapely.condition_shapely_entities( operationgeom)) return lsout
def operate(self, design): if len(self.operation_links['unary']) > 0: laminates1 = [ design.op_from_ref(link).output[ii].csg for link, ii in self.operation_links['unary'] ] else: laminates1 = [Laminate(design.return_layer_definition())] if len(self.operation_links['binary']) > 0: laminates2 = [ design.op_from_ref(link).output[ii].csg for link, ii in self.operation_links['binary'] ] else: laminates2 = [Laminate(design.return_layer_definition())] if self.function in self.unaryoperationtypes: return Laminate.unaryoperation(laminates1, self.function) elif self.function in self.pairoperationtypes: laminate1 = Laminate.unaryoperation(laminates1, 'union') laminate2 = Laminate.unaryoperation(laminates2, 'union') return laminate1.binaryoperation(laminate2, self.function)
def supportsheet(layerdef, lsin, value): allext = [] for layer, layer_geometry in lsin.layer_sequence.items(): for geom in layer_geometry.geoms: geom2 = popupcad.algorithms.csg_shapely.to_generic(geom) allext.extend( geom2.exteriorpoints(scaling=popupcad.csg_processing_scaling)) allext = numpy.array(allext) minx = allext[:, 0].min() - value miny = allext[:, 1].min() - value maxx = allext[:, 0].max() + value maxy = allext[:, 1].max() + value exterior = [[minx, miny], [maxx, miny], [maxx, maxy], [minx, maxy]] exterior_scaled = (numpy.array(exterior) / popupcad.csg_processing_scaling).tolist() geom = GenericPoly.gen_from_point_lists(exterior_scaled, []) geom = geom.to_shapely(scaling=popupcad.csg_processing_scaling) ls = Laminate(layerdef) [ls.replacelayergeoms(layer, [geom]) for layer in layerdef.layers] return ls, exterior[0]
def find_rigid(generic, layerdef): csg1 = generic.to_csg() laminate_results = [] for ii,layer in enumerate(layerdef.layers): if layer.is_rigid: rigid_layer_csg = csg1.layer_sequence[layer] laminate_result = Laminate(layerdef) laminate_result.replacelayergeoms(layer,rigid_layer_csg.geoms) lower_layers = layerdef.layers[ii::-1] upper_layers = layerdef.layers[ii:] for list1 in [lower_layers,upper_layers]: a = list1[:-1] b = list1[1:] c = zip(a,b) for aa,bb in c: if aa.is_adhesive or bb.is_adhesive: if bb.is_rigid: break csga = laminate_result.layer_sequence[aa] csgb = csg1.layer_sequence[bb] layer_result = csga.intersection(csgb) laminate_result.replacelayergeoms(bb,layer_result.geoms) else: break laminate_results.append(laminate_result) laminate_results = [item for item in laminate_results if not item.isEmpty()] result = Laminate.unaryoperation(laminate_results,'union') return result
def promote(self, layerdef): from popupcad.filetypes.laminate import Laminate lsout = Laminate(layerdef) for layer in layerdef.layers: lsout.replacelayergeoms(layer, self.geoms) return lsout
def find_rigid(generic, layerdef): layer_dict = dict([(geom.id, layer) for layer, geoms in generic.geoms.items() for geom in geoms]) rigid_geoms = [] connections = [] source_geoms = [{'id': None, 'csg': sg.Polygon()}] for layer in layerdef.layers: if layer.is_rigid: rigid_geoms.extend(generic.geoms[layer]) while not not source_geoms: source_geom = source_geoms.pop() new_geoms = [ dict([('csg', geom.to_shapely()), ('id', geom.id)]) for geom in generic.geoms[layer] ] for new_geom in new_geoms: connection = source_geom['csg'].intersection( new_geom['csg']) if not (connection.is_empty): connections.append((source_geom['id'], new_geom['id'])) source_geoms = new_geoms else: new_source_geoms = [] while not not source_geoms: source_geom = source_geoms.pop() layer_geoms = [ geom.to_shapely() for geom in generic.geoms[layer] ] for layer_geom in layer_geoms: new_geom = source_geom['csg'].intersection(layer_geom) if not (new_geom.is_empty): new_source_geoms.append({ 'id': source_geom['id'], 'csg': new_geom }) source_geoms = new_source_geoms ids = [geom.id for geom in rigid_geoms] m = len(ids) C = numpy.zeros((m, m), dtype=bool) for id1, id2 in connections: ii = ids.index(id1) jj = ids.index(id2) C[ii, jj] = True C[jj, ii] = True done = False D_last = C.copy() while not done: D = D_last.dot(C) + C done = (D == D_last).all() D_last = D rigid_bodies = [] rigid_geoms_set = set(rigid_geoms[:]) while not not rigid_geoms_set: geom = list(rigid_geoms_set)[0] ii = ids.index(geom.id) a = list(set((D[ii, :] == True).nonzero()[0].tolist() + [ii])) b = set(numpy.array(rigid_geoms)[a]) rigid_geoms_set -= b rigid_bodies.append(list(b)) values = [ tuple((numpy.array([ popupcad.algorithms.body_detection.find_minimum_xy(geom) for geom in body ])).min(0)) for body in rigid_bodies ] rigid_bodies = popupcad.algorithms.body_detection.sort_lams( rigid_bodies, values) new_csgs = [] for rigid_body in rigid_bodies: new_csg = Laminate(layerdef) for geom in rigid_body: new_csg.insertlayergeoms(layer_dict[geom.id], [geom.to_shapely()]) new_csgs.append(new_csg) return new_csgs
def operate(self, design): design_copy = design # design_copy.reprocessoperations() part_to_insert = design_copy.operations[design_copy.operation_index(self.part_opref)] sheet_to_insert_into = design_copy.operations[design_copy.operation_index(self.sheet_opref)] release_to_insert_into = design_copy.operations[design_copy.operation_index(self.release_opref)] # build the op_links, then auto make the operation op = part_to_insert op_ref = op.id op_links = {'parent': [(op_ref, op.getoutputref())]} new_web = AutoWeb4(op_links,[self.support_offset,0],MultiValueOperation3.keepout_types.laser_keepout) new_web.setcustomname(op.name) # support = OperationOutput(new_web.output[1], "support", self) design_copy.addoperation(new_web) new_web.generate(design_copy) ######################## generate the same size construction line somewhere in the sheet file # get geom for line parts_bounding_box = new_web.output[1].generic_laminate().getBoundingBox() # parts_bounding_box = support.generic_laminate().getBoundingBox() # make the sketch construction_geom_hinge = Sketch.new() tmp_geom = [(parts_bounding_box[0],parts_bounding_box[1]), (parts_bounding_box[0],parts_bounding_box[3])] construction_line = GenericLine.gen_from_point_lists(tmp_geom,[],construction=False) construction_geom_hinge.addoperationgeometries([construction_line]) # add sketch to sketch list design_copy.sketches[construction_geom_hinge.id] = construction_geom_hinge ######################## generate the external transform geometry in the sheet # center the locate line top left as origin position_hinge = (-tmp_geom[0][0],-tmp_geom[0][1]) locate_lines = [(x + position_hinge[0], y + position_hinge[1]) for (x,y) in tmp_geom] # lets make 4x4 width = (parts_bounding_box[2] - parts_bounding_box[0])*self.sc + self.x_gap height = (parts_bounding_box[3] - parts_bounding_box[1])*self.sc + self.y_gap # check if will all fit in one window, if not fill first and check if remainder will fit in second window max_num_cols = divmod(self.sketch_bounding_box[2] - self.sketch_bounding_box[0], width)[0] max_num_rows = divmod(self.sketch_bounding_box[3] - self.sketch_bounding_box[1], height)[0] if max_num_cols == 0 or max_num_rows == 0: print('Cannot tile into this area') design.remove_operation(new_web) return Laminate() # check if can fit in one # if N <= max_num_rows*max_num_cols: rows = math.ceil(self.N / max_num_cols) cols = math.ceil(self.N / rows) # spread across the two windows upper_right_origin_bounding_box = (self.sketch_bounding_box[0], self.sketch_bounding_box[3]) n_count = 0 arrayed_reference_lines = [] for row in range(rows): for col in range(cols): if n_count >= self.N or n_count >= max_num_rows*max_num_cols*2: break newx = upper_right_origin_bounding_box[0] + locate_lines[0][0] + col*width newy = upper_right_origin_bounding_box[1] - locate_lines[1][1] - row*height arrayed_reference_lines.append([(newx, newy), (newx, newy + height)]) n_count = n_count + 1 construction_geom_sheet = Sketch.new() construction_line = [GenericLine.gen_from_point_lists(line,[],construction=False) for line in arrayed_reference_lines] construction_geom_sheet.addoperationgeometries(construction_line) # add sketch to sketch list design_copy.sketches[construction_geom_sheet.id] = construction_geom_sheet ######################## External transform the hinge onto the sheet construction line # # insert hinge into sheet as subdesign # sheet.subdesigns[hinge.id] = hinge # # make design links operation_links = {} operation_links['from'] = [(part_to_insert.id,0)] sketch_links = {} sketch_links['sketch_to'] = [construction_geom_sheet.id] sketch_links['sketch_from'] = [construction_geom_hinge.id] insert_part = TransformInternal(sketch_links, operation_links, 'scale', 'scale', 0, False, 1., 1.) insert_part.customname = 'Inserted part' design_copy.addoperation(insert_part) insert_part.generate(design_copy) insert_part_id = design_copy.operations[-1].id # save for later ######################## External transform the web.sheet to the construction line # # make design links operation_links = {} operation_links['from'] = [(new_web.id,1)] sketch_links = {} sketch_links['sketch_to'] = [construction_geom_sheet.id] sketch_links['sketch_from'] = [construction_geom_hinge.id] insert_webs = TransformInternal(sketch_links, operation_links, 'scale', 'scale', 0, False, 1., 1.) insert_webs.customname = 'Inserted part webs' design_copy.addoperation(insert_webs) insert_webs.generate(design_copy) ######################## Remove web.sheet from sheet, union external transform + generateed sheet with hole + web # first the difference # link 1 is the sheet sheet_with_hole = LaminateOperation2({'unary': [(sheet_to_insert_into.id,0)], 'binary': [(insert_webs.id,0)]},'difference') sheet_with_hole.customname = 'Sheet with hole' design_copy.addoperation(sheet_with_hole) sheet_with_hole.generate(design_copy) sheet_with_part = LaminateOperation2({'unary': [(sheet_with_hole.id,0), (insert_part_id,0)], 'binary':[]},'union') sheet_with_part.customname = 'First pass cuts' design_copy.addoperation(sheet_with_part) sheet_with_part.generate(design_copy) # ######################## Make release cut laminate operation operation_links = {} operation_links['from'] = [(release_to_insert_into.id,0)] sketch_links = {} sketch_links['sketch_to'] = [construction_geom_sheet.id] sketch_links['sketch_from'] = [construction_geom_hinge.id] insert_release = TransformInternal(sketch_links, operation_links, 'scale', 'scale', 0, False, 1., 1.) design.addoperation(insert_release) insert_release.generate(design) ######################################### prepare outputs # delete the intermediate layers design.remove_operation(sheet_with_hole) design.remove_operation(insert_webs) design.remove_operation(insert_part) design.remove_operation(new_web) design.remove_operation(sheet_with_part) design.remove_operation(insert_release) self.output = [OperationOutput(sheet_with_part.output[0].csg, 'FirstCuts', self), OperationOutput(sheet_with_part.output[0].csg, 'FirstCuts', self), OperationOutput(insert_release.output[0].csg, 'Release', self)] return sheet_with_part.output[0].csg
def operate(self, design): laminate = Laminate(design.return_layer_definition()) return laminate