Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
    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
Esempio n. 6
0
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)