def duplicate(self, name, features, quantity, distance, squantity, primary, secondary, body): if not primary or not primary.isValid: raise PrimaryAxisMissing entities = ObjectCollection.create() for feature in features: entities.add(feature) patterns = body.parentComponent.features.rectangularPatternFeatures quantity = vi.createByReal(quantity) distance = vi.createByReal(distance) input_ = patterns.createInput(entities, primary, quantity, distance, EDT) # input_.patternComputeOption = pco.IdenticalPatternCompute input_.patternComputeOption = pco.AdjustPatternCompute self.configure_secondary_axis(input_, secondary, squantity) pattern = patterns.add(input_) if pattern.healthState > 0: pattern.patternComputeOption = pco.AdjustPatternCompute pattern.name = name return pattern
def extrude(self, profiles, body, extrudes, name, edge_offset): selection = ObjectCollection.create() for profile in profiles: selection.add(profile) dist = vi.createByReal(-self.properties.adjusted_depth.value) cut_input = extrudes.createInput(selection, CFO) cut_input.setDistanceExtent(False, dist) cut_input.participantBodies = [body] if edge_offset: offset = OffsetStartDefinition.create( vi.createByReal(-abs(edge_offset))) cut_input.startExtent = offset cut = extrudes.add(cut_input) cut.name = name return cut
def create_rib_body(component, comp_occurrence, wing_body, root_plane, dist_from_root, thickness): """ Creates 2 construction planes and a solid rib body using a boundary fill between the 2 planes and the wing body """ # Create 2 construction planes: # 1) offset from root sketch plane # 2) offset from the first planes = component.constructionPlanes plane1_input = planes.createInput() plane1_input.setByOffset(root_plane, ValueInput.createByReal(dist_from_root)) plane1 = planes.add(plane1_input) plane2_input = planes.createInput() plane2_input.setByOffset(plane1, ValueInput.createByReal(thickness)) plane2 = planes.add(plane2_input) rib_body = boundary_fill_between_planes(component, comp_occurrence, wing_body, plane1, plane2) # hide the construction planes plane1.isLightBulbOn = False plane2.isLightBulbOn = False return rib_body, plane1, plane2
def create_rib(self, dist_from_root, rib_thickness, rib_inset, rib_name, rib_post_relative_positions, rib_post_width, rib_post_triangle_len): root_plane = self.root_sketch.referencePlane # Create rib body and return it and the 2 construction planes along each fact rib_body, plane1, plane2 = create_rib_body(self.component, self.component_occurrence, self.wing_body, root_plane, dist_from_root, rib_thickness) rib_body.name = rib_name # find the chordwise extremities of the wing body start_coord = chordwise_coord(rib_body.boundingBox.minPoint) end_coord = chordwise_coord(rib_body.boundingBox.maxPoint) rib_post_locs = [relative_location(start_coord, end_coord, frac) for frac in rib_post_relative_positions] for i, rib_post_loc in enumerate(rib_post_locs): post = create_rib_vertical_post(self.component, self.component_occurrence, self.wing_body, rib_body, rib_post_loc, rib_post_width, rib_post_triangle_len) post.name = '{}_post_{}'.format(rib_name, i + 1) # find the faces aligned with the construction planes plane1_face = find_coplanar_face(rib_body, plane1) plane2_face = find_coplanar_face(rib_body, plane2) assert plane1_face is not None, 'plane1' assert plane2_face is not None, 'plane2' # use shell tool to remove center of rib, and the 2 faces # Create a collection of entities for shell entities1 = ObjectCollection.create() entities1.add(plane1_face) entities1.add(plane2_face) # Create a shell feature shell_feats = self.component.features.shellFeatures is_tangent_chain = False shell_feature_input = shell_feats.createInput(entities1, is_tangent_chain) rib_thickness = ValueInput.createByReal(rib_inset) shell_feature_input.insideThickness = rib_thickness shell_feats.add(shell_feature_input)
def extrude(self, thickness: Dim, operation, name_body=False): """Extrudes the sketch a specified distance in a specified way. This should not be used on sketches with multiple profiles unless care is taken to ensure the last profile is the desired one. Profiles are not well-labeled and so inferring the correct profile is application dependent. Args: thickness (Dim): distance to extrude operation (FeatureOperations): type of extrusion (e.g., cut or new component) name_body (bool): if true, assign current sketch name to the new body. """ profiles = self.sketch.profiles # Take the last profile (arbitrary) profile = profiles.item(profiles.count - 1) extrudes = self.root_comp.features.extrudeFeatures extrude_distance = ValueInput.createByReal( thickness.dist * self.conv_factor) ext = extrudes.addSimple(profile, extrude_distance, operation) if name_body: ext.bodies.item(0).name = self.name
def create_spar_from_line(component, component_occurrence, wing_body, spar_lines_sketch, line, spar_width): log(line) start_point = spar_lines_sketch.sketchToModelSpace( line.startSketchPoint.geometry) end_point = spar_lines_sketch.sketchToModelSpace( line.endSketchPoint.geometry) log(start_point, end_point) # create construction plane, centered on line, at 90 degrees to horizontal plan planes = component.constructionPlanes plane_input = planes.createInput() angle = ValueInput.createByString('90.0 deg') plane_input.setByAngle(line, angle, horizontal_plane(component)) center_plane = planes.add(plane_input) # create offset planes one either side of the center plane plane_input = planes.createInput() offset = ValueInput.createByReal(spar_width / 2) plane_input.setByOffset(center_plane, offset) plane1 = planes.add(plane_input) plane_input = planes.createInput() offset = ValueInput.createByReal(-1 * spar_width / 2) plane_input.setByOffset(center_plane, offset) plane2 = planes.add(plane_input) for p in [center_plane, plane1, plane2]: p.isLightBulbOn = False # now use boundary fill to create spar between construction planes and wing body spar = boundary_fill_between_planes(component, component_occurrence, wing_body, plane1, plane2) # now get bounding box of spar and find min an max spanwise dimensions min_point = spar.boundingBox.minPoint max_point = spar.boundingBox.maxPoint sw1 = project_coord(min_point.asArray(), SPANWISE_DIRECTION.asArray()) sw2 = project_coord(max_point.asArray(), SPANWISE_DIRECTION.asArray()) min_spanwise = min(sw1, sw2) max_spanwise = max(sw1, sw2) v1 = project_coord(min_point.asArray(), VERTICAL_UP_DIRECTION.asArray()) v2 = project_coord(max_point.asArray(), VERTICAL_UP_DIRECTION.asArray()) min_vertical = min(v1, v2) max_vertical = max(v1, v2) log("Spanwise range = {} to {}".format(min_spanwise, max_spanwise)) log("Vertical range = {} to {}".format(min_vertical, max_vertical)) # create sketch and draw circles in a row spanwise spar_face_sketch = component.sketches.add(center_plane) circle_locs = [] loc = min_spanwise + settings.SPAR_CIRCLE_SPACING_CM while loc + settings.SPAR_CIRCLE_DIAMETER_CM / 2 < max_spanwise: circle_locs.append(loc) loc = loc + settings.SPAR_CIRCLE_SPACING_CM log('Circle locs:', circle_locs) vertical_center = 0 # sketch origin seems to be centered on the body. x seems to be spanwise # TODO: formalise this, for different part orientations. Need a way to deduce sketch orientation x_offset = (max_spanwise - min_spanwise) / 2 # create circles for loc in circle_locs: spar_face_sketch.sketchCurves.sketchCircles.addByCenterRadius( Point3D.create(loc - x_offset, vertical_center, 0), settings.SPAR_CIRCLE_DIAMETER_CM / 2) profiles = ObjectCollection.create() for c in spar_face_sketch.profiles: profiles.add(c) # now extrude the circles to cut the spar extrudes = component.features.extrudeFeatures extrude_input = extrudes.createInput(profiles, FeatureOperations.CutFeatureOperation) # extrude_input.setAllExtent(ExtentDirections.SymmetricExtentDirection) distanceForCut = ValueInput.createByString( '2 cm') # some distance > we need. extrude_input.setSymmetricExtent(distanceForCut, True) extrude_input.participantBodies = [spar] extrudes.add(extrude_input) return spar
def set_normal_value(i, v, node): i.value = v SettingType = namedtuple('SettingType', ['to_input', 'from_input', 'to_str', 'from_str', 'set_value']) setting_types = { 'bool': SettingType( to_input=lambda k, desc, inp, v: inp.addBoolValueInput(k, desc['label'], True, '', bool(v)), to_str=lambda v: str(v).lower(), from_str=bool, from_input=(lambda i, node: i.value), set_value=set_normal_value), 'float': SettingType( to_input=lambda k, desc, inp, v: inp.addValueInput(k, desc['label'], '', ValueInput.createByReal(float(v) if v else 0), ), to_str=str, from_str=float, from_input=lambda i, node: i.value, set_value=set_normal_value), 'int': SettingType( to_input=lambda k, desc, inp, v: inp.addIntegerSpinnerCommandInput(k, desc['label'], 0, 300000, 1, int(v) if v else 0), to_str=str, from_str=int, from_input=lambda i, node: i.value, set_value=set_normal_value), 'str': SettingType( to_input=lambda k, desc, inp, v: inp.addStringValueInput(k, desc['label'], v if v else ''), to_str=lambda v: v, from_str=lambda v: v, from_input=lambda i, node: i.value, set_value=set_normal_value), 'enum': SettingType(to_input=add_enum_input, to_str=str, from_str=str, from_input=lambda i, node: [k for (k, v) in node['options'].items() if v == i.selectedItem.name][0], set_value=set_enum_value), 'optional_extruder': SettingType( to_input=lambda k, desc, inp, v: inp.addIntegerSpinnerCommandInput(k, desc['label'], -1, 16, 1, int(v) if v else 0),
def create_rib_vertical_post(component, comp_occurrence, wing_body, rib_body, rib_post_loc, rib_post_width, rib_post_triangle_len): """ create a vertical rib post """ # log('creating rib post of width', rib_post_width, ' at ', rib_post_loc) # create 2 planes, rib_post_width apart, centered on rib_post_loc p1loc = rib_post_loc - (rib_post_width / 2) p2loc = rib_post_loc + (rib_post_width / 2) planes = component.constructionPlanes plane1_input = planes.createInput() plane1_input.setByOffset(vert_spanwise_plane(component), ValueInput.createByReal(p1loc)) plane1 = planes.add(plane1_input) plane2_input = planes.createInput() plane2_input.setByOffset(vert_spanwise_plane(component), ValueInput.createByReal(p2loc)) plane2 = planes.add(plane2_input) post = boundary_fill_between_planes(component, comp_occurrence, rib_body, plane1, plane2) # hide the construction planes plane1.isLightBulbOn = False plane2.isLightBulbOn = False # get dimensions of post bounding_box = post.boundingBox top = project_coord(bounding_box.maxPoint.asArray(), VERTICAL_UP_DIRECTION.asArray()) bottom = project_coord(bounding_box.minPoint.asArray(), VERTICAL_UP_DIRECTION.asArray()) spanwise_mid = project_coord(centroid_of_bounding_box(bounding_box).asArray(), SPANWISE_DIRECTION.asArray()) assert plane1.isValid sketch = component.sketches.add(plane2, comp_occurrence) lines = sketch.sketchCurves.sketchLines tri_side = rib_post_triangle_len # only create triangles if the section is tall enough if top - bottom > 2 * tri_side: p1 = sketch.modelToSketchSpace(point(chordwise=p1loc, spanwise=spanwise_mid, vertical=top - tri_side)) p2 = sketch.modelToSketchSpace(point(chordwise=p1loc, spanwise=spanwise_mid + tri_side, vertical=top)) p3 = sketch.modelToSketchSpace(point(chordwise=p1loc, spanwise=spanwise_mid - tri_side, vertical=top)) lines.addByTwoPoints(p1, p2) lines.addByTwoPoints(p2, p3) lines.addByTwoPoints(p3, p1) p1 = sketch.modelToSketchSpace(point(chordwise=p1loc, spanwise=spanwise_mid, vertical=bottom + tri_side)) p2 = sketch.modelToSketchSpace(point(chordwise=p1loc, spanwise=spanwise_mid + tri_side, vertical=bottom)) p3 = sketch.modelToSketchSpace(point(chordwise=p1loc, spanwise=spanwise_mid - tri_side, vertical=bottom)) lines.addByTwoPoints(p1, p2) lines.addByTwoPoints(p2, p3) lines.addByTwoPoints(p3, p1) # extrude the 2 triangular profiles just created assert sketch.profiles.count == 2, "expected 2 triangle profiles in the sketch just created" profile = sketch.profiles.item(0) extrudes = component.features.extrudeFeatures top_triangle_extrusion = extrudes.addSimple(profile, ValueInput.createByReal(rib_post_width), FeatureOperations.NewBodyFeatureOperation) top_triangle = top_triangle_extrusion.bodies.item(0) top_triangle.name = 'top_triangle' profile = sketch.profiles.item(1) extrudes = component.features.extrudeFeatures bottom_triangle_extrusion = extrudes.addSimple(profile, ValueInput.createByReal(rib_post_width), FeatureOperations.NewBodyFeatureOperation) bottom_triangle = bottom_triangle_extrusion.bodies.item(0) bottom_triangle.name = 'bottom_triangle' # now trim the triangles to the intersection with the wing body tool_bodies = ObjectCollection.create() tool_bodies.add(wing_body) combines = component.features.combineFeatures combine_input = combines.createInput(top_triangle, tool_bodies) combine_input.isKeepToolBodies = True combine_input.isNewComponent = False combine_input.operation = FeatureOperations.IntersectFeatureOperation combines.add(combine_input) combine_input = combines.createInput(bottom_triangle, tool_bodies) combine_input.isKeepToolBodies = True combine_input.isNewComponent = False combine_input.operation = FeatureOperations.IntersectFeatureOperation combines.add(combine_input) return post
def configure_secondary_axis(self, input_, secondary, squantity): if self.properties.distance_two.value and secondary and secondary.isValid: value = abs(self.properties.distance_two.value) second_distance = vi.createByReal(value) input_.setDirectionTwo(secondary, vi.createByReal(squantity), second_distance)