def planes_by_number(self, n, ref_pln=None, d1=None, d2=None, shape1=None, shape2=None): """ Create a specified number of planes along the reference curve. :param int n: Number of points to create (*n* > 0). :param afem.geometry.entities.Plane ref_pln: The normal of this plane will be used to define the normal of all planes along the curve. If no plane is provided, then the first derivative of the curve will define the plane normal. :param float d1: An offset distance for the first point. This is typically a positive number indicating a distance from *u1* towards *u2*. :param float d2: An offset distance for the last point. This is typically a negative number indicating a distance from *u2* towards *u1*. :param afem.topology.entities.Shape shape1: A shape to define the first point. This shape is intersected with the reference curve. :param afem.topology.entities.Shape shape2: A shape to define the last point. This shape is intersected with the reference curve. :return: List of planes along the curve. :rtype: list(afem.geometry.entities.Plane) :raise TypeError: If *shape* if not an edge or wire. :raise RuntimeError: If OCC method fails. """ edge = Edge.by_curve(self._cref) return PlanesAlongShapeByNumber(edge, n, ref_pln, d1, d2, shape1, shape2).planes
def points_by_distance(self, maxd, nmin=0, d1=None, d2=None, shape1=None, shape2=None): """ Create a points along the reference curve by distance. :param float maxd: The maximum allowed spacing between points. The actual spacing will be adjusted to not to exceed this value. :param int nmin: Minimum number of points to create. :param float d1: An offset distance for the first point. This is typically a positive number indicating a distance from *u1* towards *u2*. :param float d2: An offset distance for the last point. This is typically a negative number indicating a distance from *u2* towards *u1*. :param afem.topology.entities.Shape shape1: A shape to define the first point. This shape is intersected with the edge or wire. :param afem.topology.entities.Shape shape2: A shape to define the last point. This shape is intersected with the edge or wire. :return: The points. :rtype: list(afem.geometry.entities.Point) """ edge = Edge.by_curve(self._cref) builder = PointsAlongShapeByDistance(edge, maxd, d1, d2, shape1, shape2, nmin) return builder.points
def build(self, pln=None, scale=None, rotate=None): """ Build a shape in 3-D using the 2-D cross section curves. This method collects the 2-D curves, converts them into 3-D edges on the plane, fuses them together, and attempts to build wires and a face if applicable. :param pln: The plane to build on. If *None*, then the default plane is used. :param float scale: Scale the 3-D curve after construction on the plane. The reference point is the plane origin. :param float rotate: Rotate the 3-D curve after construction on the plane. The reference point is the plane origin. :return: *True* if successful, *False* otherwise. :rtype: bool """ if pln is None: pln = self._pln if pln is None: raise RuntimeError('No plane is defined.') origin = pln.origin axis = pln.axis edges = [] for c2d in self._crvs: c3d = c2d.to_3d(pln) if scale is not None: c3d.scale(origin, scale) if rotate is not None: c3d.rotate(axis, rotate) e = Edge.by_curve(c3d) edges.append(e) if len(edges) == 0: return False if len(edges) == 1: self._shape = edges[0] else: # Fuse the shape fuse = FuseShapes() fuse.set_args(edges[:-1]) fuse.set_tools(edges[-1:]) fuse.build() self._shape = fuse.shape edges = fuse.edges # Try and make wire(s) self._wire_tool = WiresByConnectedEdges(edges) # Try to make a face if one wire was created if self.nwires == 1: self._face = FaceByPlanarWire(self.wires[0]).face return True
def points_by_number(self, n, d1=None, d2=None, shape1=None, shape2=None): """ Create a specified number of points along the reference curve. :param int n: Number of points to create (*n* > 0). :param float d1: An offset distance for the first point. This is typically a positive number indicating a distance from *u1* towards *u2*. :param float d2: An offset distance for the last point. This is typically a negative number indicating a distance from *u2* towards *u1*. :param afem.topology.entities.Shape shape1: A shape to define the first point. This shape is intersected with the edge or wire. :param afem.topology.entities.Shape shape2: A shape to define the last point. This shape is intersected with the edge or wire. :return: The points. :rtype: list(afem.geometry.entities.Point) """ edge = Edge.by_curve(self._cref) builder = PointsAlongShapeByNumber(edge, n, d1, d2, shape1, shape2) return builder.points
def planes_by_distance(self, maxd, ref_pln=None, d1=None, d2=None, shape1=None, shape2=None, nmin=0): """ Create planes along the reference curve by distance between them. :param float maxd: The maximum allowed spacing between planes. The actual spacing will be adjusted to not to exceed this value. :param afem.geometry.entities.Plane ref_pln: The normal of this plane will be used to define the normal of all planes along the curve. If no plane is provided, then the first derivative of the curve will define the plane normal. :param float d1: An offset distance for the first point. This is typically a positive number indicating a distance from *u1* towards *u2*. :param float d2: An offset distance for the last point. This is typically a negative number indicating a distance from *u2* towards *u1*. :param afem.topology.entities.Shape shape1: A shape to define the first point. This shape is intersected with the reference curve. :param afem.topology.entities.Shape shape2: A shape to define the last point. This shape is intersected with the reference curve. :param int nmin: Minimum number of planes to create. :return: List of planes along the curve. :rtype: list(afem.geometry.entities.Plane) :raise TypeError: If *shape* if not an edge or wire. :raise RuntimeError: If OCC method fails. """ edge = Edge.by_curve(self._cref) return PlanesAlongShapeByDistance(edge, maxd, ref_pln, d1, d2, shape1, shape2, nmin).planes
def _process_unsplit_wing(compound, divide_closed, reloft, tol): # Process a wing that was generated without "Split Surfs" option. faces = compound.faces if len(faces) != 1: return None, None face = faces[0] # Get the surface. master_surf = face.surface # master_surf = NurbsSurface(master_surf.object) uknots, vknots = master_surf.uknots, master_surf.vknots vsplit = master_surf.local_to_global_param('v', 0.5) # Segment off the end caps and the trailing edges. u1, u2 = uknots[1], uknots[-2] v1, v2 = vknots[1], vknots[-2] s1 = master_surf.copy() s1.segment(u1, u2, v1, v2) # Reloft the surface by tessellating a curve at each spanwise knot. This # enforces C1 continuity but assumes linear spanwise wing which may not # support blending wing sections in newer versions of OpenVSP. Also, since # the tessellated curves may not match up to the wing end caps making # sewing unreliable, flat end caps are assumed. if reloft: s1 = _reloft_wing_surface(s1, tol) # Generate new flat end caps using isocurves at the root and tip of # this new surface c0 = s1.v_iso(s1.v1) c1 = s1.v_iso(s1.v2) e0 = Edge.by_curve(c0) e1 = Edge.by_curve(c1) w0 = Wire.by_edge(e0) w1 = Wire.by_edge(e1) f0 = Face.by_wire(w0) f1 = Face.by_wire(w1) # Make faces of surfaces f = Face.by_surface(s1) new_faces = [f, f0, f1] else: # Reparamterize knots in spanwise direction to be chord length instead # of uniform. Use isocurve at quarter-chord to determine knot values. # This only works as long as surfaces are linear. c0 = s1.u_iso(s1.u1) c0.segment(vsplit, c0.u2) qc_u = PointFromParameter(c0, vsplit, 0.25 * c0.length).parameter c = s1.v_iso(qc_u) pnts = [c.eval(u) for u in c.knots] new_uknots = geom_utils.chord_parameters(pnts, 0., 1.) s1.set_uknots(new_uknots) # Segment off end caps u1, u2 = uknots[0], uknots[1] v1, v2 = vknots[1], vsplit s2 = master_surf.copy() s2.segment(u1, u2, v1, v2) u1, u2 = uknots[0], uknots[1] v1, v2 = vsplit, vknots[-2] s3 = master_surf.copy() s3.segment(u1, u2, v1, v2) u1, u2 = uknots[-2], uknots[-1] v1, v2 = vknots[1], vsplit s4 = master_surf.copy() s4.segment(u1, u2, v1, v2) u1, u2 = uknots[-2], uknots[-1] v1, v2 = vsplit, vknots[-2] s5 = master_surf.copy() s5.segment(u1, u2, v1, v2) # Make faces of surfaces new_faces = [] for s in [s1, s2, s3, s4, s5]: f = Face.by_surface(s) new_faces.append(f) # Segment off TE. u1, u2 = uknots[0], uknots[-1] v1, v2 = vknots[0], vknots[1] s6 = master_surf.copy() s6.segment(u1, u2, v1, v2) u1, u2 = uknots[0], uknots[-1] v1, v2 = vknots[-2], vknots[-1] s7 = master_surf.copy() s7.segment(u1, u2, v1, v2) # Split the TE surface at each u-knot. usplits = occ_utils.to_tcolstd_hseq_real(uknots[1:-1]) split = ShapeUpgrade_SplitSurface() split.Init(s6.object) split.SetUSplitValues(usplits) split.Perform() comp_surf1 = split.ResSurfaces() split = ShapeUpgrade_SplitSurface() split.Init(s7.object) split.SetUSplitValues(usplits) split.Perform() comp_surf2 = split.ResSurfaces() # For each patch in the composite surfaces create a face. for i in range(1, comp_surf1.NbUPatches() + 1): for j in range(1, comp_surf1.NbVPatches() + 1): hpatch = comp_surf1.Patch(i, j) f = BRepBuilderAPI_MakeFace(hpatch, 0.).Face() new_faces.append(f) for i in range(1, comp_surf2.NbUPatches() + 1): for j in range(1, comp_surf2.NbVPatches() + 1): hpatch = comp_surf2.Patch(i, j) f = BRepBuilderAPI_MakeFace(hpatch, 0.).Face() new_faces.append(f) # Put all faces into a compound a generate solid. new_compound = Compound.by_shapes(new_faces) return _build_solid(new_compound, divide_closed)