def __init__(self, wire, shape1, shape2=None): if wire.closed: raise TypeError('Closed wires are not supported.') shape1 = Shape.to_shape(shape1) shape2 = Shape.to_shape(shape2) # Split wire with shapes other_shape = Compound.by_shapes([shape1, shape2]) split = SplitShapes(wire, other_shape) split_wire = split.shape.wires[0] # Get new vertices old_verts = ExploreWire(wire).ordered_vertices wire_exp = ExploreWire(split_wire) all_verts = wire_exp.ordered_vertices new_verts = [v for v in all_verts if v not in old_verts] # Find index of new vertices and use that to extract edges n = len(new_verts) if n == 2: i1 = all_verts.index(new_verts[0]) i2 = all_verts.index(new_verts[1]) ordered_edges = wire_exp.edges first_edges = ordered_edges[:i1] trimmed_edges = ordered_edges[i1:i2] last_edges = ordered_edges[i2:] elif n == 1: i1 = all_verts.index(new_verts[0]) ordered_edges = wire_exp.edges first_edges = ordered_edges[:i1] trimmed_edges = [] last_edges = ordered_edges[i1:] else: msg = 'Only one or two split locations are supported.' raise RuntimeError(msg) # Avoid circular imports from afem.topology.create import WireByEdges # Collect data and build trimmed wires self._first_wire = None self._trimmed_wire = None self._last_wire = None self._split_wire = split_wire if len(first_edges) > 0: self._first_wire = WireByEdges(*first_edges).wire if len(trimmed_edges) > 0: self._trimmed_wire = WireByEdges(*trimmed_edges).wire if len(last_edges) > 0: self._last_wire = WireByEdges(*last_edges).wire self._new_verts = new_verts self._verts = all_verts
def __init__(self, shapes): topods_compound = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(topods_compound) for shape in shapes: shape = Shape.to_shape(shape) if isinstance(shape, Shape): builder.Add(topods_compound, shape.object) self._cp = Compound(topods_compound)
def __init__(self, shapes): results = [] for shape in shapes: shape = Shape.to_shape(shape) ls = LinearProps(shape).length results.append((ls, shape)) results.sort(key=lambda tup: tup[0]) self._lengths = [data[0] for data in results] self._shapes = [data[1] for data in results]
def __init__(self, shapes): results = [] for shape in shapes: shape = Shape.to_shape(shape) a = SurfaceProps(shape).area results.append((a, shape)) results.sort(key=lambda tup: tup[0]) self._areas = [data[0] for data in results] self._shapes = [data[1] for data in results]
def __init__(self, parts, shape): parts = list(parts) shape2 = Shape.to_shape(shape) # Loop through each since since that seems to be more robust self._status = {} for part in parts: status = part.cut(shape2) self._status[part] = status
def __init__(self, spine, profile): if isinstance(spine, Curve): spine = Wire.by_curve(spine) elif spine.is_edge: spine = Wire.by_edge(spine) if not spine.is_wire: raise TypeError('Spine is not a wire.') profile = Shape.to_shape(profile) self._tool = BRepOffsetAPI_MakePipe(spine.object, profile.object) self._tool.Build()
def trim_u2(self, entity): """ Trim the last parameter of the reference curve by interesting it with the entity. :param entity: The entity. :type entity: afem.geometry.entities.Geometry or afem.topology.entities.Shape :return: None. :raise RuntimeError: If an intersection with the reference curve cannot be found. """ shape1 = Shape.to_shape(self.cref) shape2 = Shape.to_shape(entity) bop = IntersectShapes(shape1, shape2) if not bop.is_done: raise RuntimeError('Failed to intersect reference curve.') pnts = [v.point for v in bop.vertices] p = CheckGeom.nearest_point(self.cref.p2, pnts) self.set_p2(p)
def shape_of_entity(entity): """ Get the shape of the entity. This method is useful if method inputs can either be a part or a shape. If the entity is already a shape it will be returned. If the entity is part the shape of the part will be returned. If the entity is a curve or surface then it will be converted to a shape. :param entity: The entity. :type entity: afem.geometry.entities.Geometry or afem.topology.entities.Shape or afem.base.entities.ShapeHolder :return: The shape. :rtype: afem.topology.entities.Shape """ if isinstance(entity, ShapeHolder): return entity.shape else: return Shape.to_shape(entity)
def transfer(self, *shapes): """ Transfer and add the shapes to the exported entities. :param afem.topology.entities.Shape shapes: The shape(s). :return: *True* if shape was transferred, *False* if not. :rtype: bool """ added_shape = False for shape in shapes: shape = Shape.to_shape(shape) if not shape: continue status = self._writer.Transfer(shape.object, STEPControl_AsIs) if int(status) < int(IFSelect_RetError): added_shape = True return added_shape
def discard_by_dmin(self, entity, dmin): """ Discard shapes of the part using a shape and a distance. If the distance between a shape of the part and the given shape is less than *dmin*, then the shape is removed. Edges are checked for curve parts and faces are checked for surface parts. :param entity: The shape. :type entity: afem.topology.entities.Shape or afem.geometry.entities.Geometry :param float dmin: The minimum distance. :return: *True* if shapes were discarded, *False* if not. :rtype: bool :raise TypeError: If this part is not a curve or surface part. """ entity = Shape.to_shape(entity) if isinstance(self, CurvePart): shapes = self.shape.edges elif isinstance(self, SurfacePart): shapes = self.shape.faces else: msg = 'Invalid part type in discard operation.' raise TypeError(msg) rebuild = RebuildShapeWithShapes(self._shape) modified = False for part_shape in shapes: dmin_ = DistanceShapeToShape(entity, part_shape).dmin if dmin > dmin_: rebuild.remove(part_shape) modified = True if not modified: return False new_shape = rebuild.apply() self.set_shape(new_shape) return True
def __init__(self, shape1, shape2, deflection=1.0e-7): shape1 = Shape.to_shape(shape1) shape2 = Shape.to_shape(shape2) self._tool = BRepExtrema_DistShapeShape(shape1.object, shape2.object, deflection, Extrema_ExtFlag_MIN)
def extract_curve(self, u1, v1, u2, v2, basis_shape=None): """ Extract a trimmed curve within the reference surface between the parameters. :param float u1: First u-parameter. :param float v1: First v-parameter. :param float u2: Second u-parameter. :param float v2: Second v-parameter. :param basis_shape: The shape that will be used to intersect with the reference shape. If not provided a plane will be created using the *extract_plane()* method. The parameters should create points that are on or very near the intersection between these two shapes. If they are not they will be projected to the intersection which could yield unanticipated results. :type basis_shape: afem.geometry.entities.Surface or afem.topology.entities.Shape :return: The curve. :rtype: afem.geometry.entities.TrimmedCurve :raise RuntimeError: If method fails. """ p1 = self.eval(u1, v1) p2 = self.eval(u2, v2) if basis_shape is None: basis_shape = self.extract_plane(u1, v1, u2, v2) basis_shape = Shape.to_shape(basis_shape) bop = IntersectShapes(basis_shape, self.sref_shape, approximate=True) shape = bop.shape edges = shape.edges builder = WiresByConnectedEdges(edges) if builder.nwires == 0: msg = 'Failed to extract any curves.' raise RuntimeError(msg) if builder.nwires == 1: wire = builder.wires[0] else: dist = DistancePointToShapes(p1, builder.wires) wire = dist.nearest_shape crv = wire.curve proj = ProjectPointToCurve(p1, crv) if not proj.success: msg = 'Failed to project point to reference curve.' raise RuntimeError(msg) u1c = proj.nearest_param proj = ProjectPointToCurve(p2, crv) if not proj.success: msg = 'Failed to project point to reference curve.' raise RuntimeError(msg) u2c = proj.nearest_param if u1c > u2c: crv.reverse() u1c, u2c = crv.reversed_u(u1c), crv.reversed_u(u2c) return TrimmedCurve.by_parameters(crv, u1c, u2c)