コード例 #1
0
ファイル: airfoil.py プロジェクト: sunstarchan/Genair
    def sharpen(self, l=0.05, show=True):
        ''' Sharpen the Airfoil's TE by (1) extending its extremities
        with curvature-continuous B-spline Curves and (2) finding where
        they intersect.  Upon success an intersection Point is created
        and set on the Airfoil.intersection attribute.  This Point will
        be automatically included when the Airfoil is refitted with any
        of the available fitting techniques, after which point the
        Airfoil should be sharp.  Should you later desire to discard the
        intersection Point, simply reset Airfoil.intersection equal to
        None.

        Parameters
        ----------
        l = the length of the two extensions (for phase 1)
        show = whether or not to draw the new set of data Points

        Returns
        -------
        fig = a Figure

        '''
        def dist(us):
            try:
                return distance(n0.eval_point(us[0]), n1.eval_point(us[1]))
            except KnotOutsideKnotVectorRange:
                return np.inf

        n = self.nurbs
        if not n:
            raise UnfitAirfoil()
        if self.issharp:
            raise AlreadySharpAirfoil()
        u = arc_length_to_param(n, l)
        n0, n1 = [n.extend(u, end=end) for end in (False, True)]
        U0, = n0.U
        n0.colorize()
        U1, = n1.U
        n1.colorize()
        bnds = [(U0[0], U0[-1]), (U1[0], U1[-1])]
        us = brute(dist, bnds, finish=None)
        u0, u1 = fmin(dist, us, xtol=0.0, ftol=0.0, disp=False)
        x0, x1 = (n0.eval_point(u0), n1.eval_point(u1))
        l2n = distance(x1, x0)
        if l2n > 1e-8:
            draw(n, n0, n1, stride=0.1)
            raise NoIntersectionFoundAirfoil(l2n)
        i = np.average([x0, x1], axis=0)
        if self.issymmetric:
            i[2] = 0.0
        i = Point(*i)
        i.colorize()
        print('geom.airfoil.Airfoil.sharpen :: '
              'intersection Point found ({})'.format(i.xyz))
        self.intersection = i
        if show:
            d = [n, n0, n1, i]
            d += self.data['lo'] + self.data['up']
            fig = draw(*d, stride=0.1)
            fig.c.setup_preset('xz')
            return fig
コード例 #2
0
ファイル: junction.py プロジェクト: sunstarchan/Genair
    def trim(self, show=True):

        '''

        '''

        if not any(self.ICs):
            raise Exception

        for half, h, IC in zip((0, 1), self.wing.halves, self.ICs):
            if not self.half in (2, half):
                continue
            U, V = h.U
            if not self.tip:
                jnc1 = self.wing.junctions[1]
                if (not jnc1) or (jnc1 and not jnc1.ICs[half]):
                    P0 = IC.cobj.cpts[ 0]
                    P1 = IC.cobj.cpts[-1]
                    P2 = Point(U[-1], V[-1])
                    P3 = Point(U[ 0], V[-1])
                    C0 = IC
                    C1 = make_linear_curve(P1, P2)
                    C2 = make_linear_curve(P2, P3)
                    C3 = make_linear_curve(P3, P0)
                else:
                    IC1 = jnc1.ICs[half]
                    P0 = IC.cobj.cpts[ 0]
                    P1 = IC.cobj.cpts[-1]
                    P2 = IC1.cobj.cpts[-1]
                    P3 = IC1.cobj.cpts[ 0]
                    C0 = IC
                    C1 = make_linear_curve(P1, P2)
                    C2 = IC1.reverse()
                    C3 = make_linear_curve(P3, P0)
            else:
                jnc0 = self.wing.junctions[0]
                if (not jnc0) or (jnc0 and not jnc0.ICs[half]):
                    P0 = Point(U[ 0], V[0])
                    P1 = Point(U[-1], V[0])
                    P2 = IC.cobj.cpts[-1]
                    P3 = IC.cobj.cpts[ 0]
                    C0 = make_linear_curve(P0, P1)
                    C1 = make_linear_curve(P1, P2)
                    C2 = IC
                    C3 = make_linear_curve(P3, P0)
                else:
                    IC0 = jnc0.ICs[half]
                    P0 = IC0.cobj.cpts[ 0]
                    P1 = IC0.cobj.cpts[-1]
                    P2 = IC.cobj.cpts[-1]
                    P3 = IC.cobj.cpts[ 0]
                    C0 = IC0
                    C1 = make_linear_curve(P1, P2)
                    C2 = IC.reverse()
                    C3 = make_linear_curve(P3, P0)
            IC = make_composite_curve([C0, C1, C2, C3], remove=False)
            h.trim(IC)

        if show:
            return draw(self.S, self.wing)
コード例 #3
0
ファイル: fuselage.py プロジェクト: sunstarchan/Genair
    def setup(self, nlcpt=50, cap=True, show=True):
        ''' Setup the NURBS representation of the initial bullet head
        cylinder.  Analogous to modelling clay, it is this NURBS Surface
        that will be successively shaped by molders.

        Parameters
        ----------
        nlcpt = the number of longitudinal control points used to
                represent the cylinder with
        cap = whether or not to close the rear-end gap with a rounded
              Surface; for geometries destined for inviscid flow
              simulations this flag should be set to False
        show = whether or not to draw the newly setup cylinder

        Returns
        -------
        fig = a Figure

        '''

        R, BL, NL = self.R, self.BL, self.NL

        O, X, Y = [0, 0, 0], [-1, 0, 0], [0, 0, -1]
        args = (O, X, Y, NL, R, 0, np.pi / 2.0)
        P0, P1 = Point(0, 0, -R), Point(BL, 0, -R)

        nose = make_ellipse(*args)
        body = make_linear_curve(P0, P1)
        for c in nose, body:
            reparam_arc_length_curve(c)

        n = make_composite_curve([nose, body])
        n = refit_curve(n, nlcpt, num=50000)
        n2, = n.cobj.n
        for i in xrange(n2 + 1):
            Pw = n.cobj.Pw[i]
            if Pw[0] > 0 or Pw[2] < -R:
                Pw[2] = -R

        if cap:
            P2 = Point(BL, 0, 0)
            rear = make_linear_curve(P1, P2)
            reparam_arc_length_curve(rear)
            n = make_composite_curve([n, rear])

        n = make_revolved_surface_nrat(n, O, [1, 0, 0], 180)

        if not cap:
            n.cobj.Pw[:, -1, 1] = 0.0

        self.nurbs = n
        self.molders = []
        self.clamp()
        if show:
            return draw(self)
コード例 #4
0
ファイル: grid.py プロジェクト: sunstarchan/Genair
    def read_grid(self, plot3d_file='grid.g', endian='big_endian', show=False):

        ''' Pre: None '''

        self.blk = []

        try:
            open_file(plot3d_file, endian)
            nblk = read_nblk()
            jkmmax = np.zeros((3, nblk), dtype='i', order='F')
            read_header(jkmmax, nblk)
            for ib in xrange(nblk):
                nxyz = np.append(jkmmax[:,ib], 3)
                xyz = np.zeros(nxyz, order='F')
                read_one_block(jkmmax[:,ib], 3, xyz)
                P0 = Point(*xyz[ 0, 0, 0])
                P1 = Point(*xyz[ 0, 0,-1])
                P2 = Point(*xyz[ 0,-1, 0])
                P3 = Point(*xyz[ 0,-1,-1])
                P4 = Point(*xyz[-1, 0, 0])
                P5 = Point(*xyz[-1, 0,-1])
                P6 = Point(*xyz[-1,-1, 0])
                P7 = Point(*xyz[-1,-1,-1])
                cvol = ControlVolume([[[P0, P1], [P2, P3]],
                                      [[P4, P5], [P6, P7]]])
                blk = Block(cvol, (1,1,1))
                blk.indx, blk.xyz = ib + 1, xyz
                self.blk.append(blk)
            nnode = sum([blk.xyz.size for blk in self.blk]) / 3
            print('{} has {} nonunique nodes.'.format(plot3d_file, nnode))
        finally:
            close_file()

        if show:
            return draw(self)
コード例 #5
0
ファイル: fuselage.py プロジェクト: sunstarchan/Genair
 def _setup_control_volume(self, R, zs):
     C = make_linear_curve(Point(), Point(z=R))
     C = C.elevate(2)
     args = C, (0, 0, 0), (-1, 0, 0), 180, 3, 1e-4
     S = make_revolved_surface_nrat(*args)
     Ps = [S.cobj.Pw[:, :, :-1][:, :, np.newaxis, :]]
     for z in zs[1:]:
         P = Ps[0].copy()
         P[..., 0] += z
         Ps.append(P)
     P = np.concatenate(Ps, axis=2)
     Pw = obj_mat_to_4D(P)
     Pw[0, ..., 1] = Pw[-1, ..., 1] = 0.0
     return ControlVolume(Pw=Pw)
コード例 #6
0
ファイル: airfoil.py プロジェクト: sunstarchan/Genair
 def read(si, npt):
     nr = 0
     while True:
         xz = fh.readline().strip()
         if not xz:
             continue
         nr += 1
         x, z = xz.split()
         x, z = float(x), float(z)
         pt = Point(x=x, z=z)
         self.data[si].append(pt)
         if nr == npt:
             break
コード例 #7
0
ファイル: fuselage.py プロジェクト: sunstarchan/Genair
    def _setup(self):
        def transform_ffd(R):
            O, D, S, Pw = R._O, R._D, R._S, R._Pw
            D_new = distance(O, R.xyz)
            sf = D_new / D
            if np.allclose(sf, 1.0):
                return
            scale(Pw, sf, R.line[0], R.line[1])
            R._D = D_new
            if S and not np.allclose(S.xyz[2], R.xyz[2]):
                args = S.line[0], S.line[1], R.xyz, [0, 1, 0]
                xyz = intersect_3D_lines(*args)
                S._xyzw[1:3] = xyz[1:3]
                S.transform_ffd(S)

        super(FairingMolder, self)._setup()
        Ps = []
        for i in xrange(self.cobj.n[0] + 1):
            Pw = self.cobj.Pw[i, :, 1]

            R = Pw[-1].copy()
            O = Pw[0, :3]
            L = Pw[-1, :3] - O
            scale(R, 1.3, O, L)  # knob
            R = Point(*R)
            Ps.append(R)

            R._O = O
            R._D = distance(O, R.xyz)
            R._S = None
            R._Pw = Pw
            R.line = O, L

            R.transform_ffd = transform_ffd
            R.ffd = self

        Ps[0]._S = Ps[1]
        Ps[1]._S = Ps[0]
        Ps[-2]._S = Ps[-1]
        Ps[-1]._S = Ps[-2]

        self.pilot_points = Ps
        self.glued = Ps + [self]
コード例 #8
0
ファイル: filler.py プロジェクト: sunstarchan/Genair
    def _split(self, Bk, Gk):
        ''' Split all boundary Curves at their parametric midpoint. '''

        for BG in zip(Bk, Gk):
            CD = make_curves_compatible1(BG)[3]
            C, D = CD
            self.Ck.append(C)
            self.Dk.append(D)

        self.CLRk, self.DLRk, Mk, self.DMk = split_nsided_region(
            self.Ck, self.Dk)

        CLRk0 = None if not len(self.Ck) == 2 else self.CLRk[0]
        C = find_central_point_nsided_region(Mk, self.DMk)
        CN = find_normal_vec_nsided_region(C, Mk, self.DMk, CLRk0)

        self.C = Point(*C)
        self.C.originate = self._originate

        self.CN = Point(*CN)
        self.CN.innerize = self._innerize

        self.Mk = [Point(*mk) for mk in Mk]
コード例 #9
0
ファイル: filler.py プロジェクト: sunstarchan/Genair
    def __init__(self, Bk, Gk):
        ''' Form a Filler from a set of N boundary curves and associated
        cross-derivative fields.  These are usually picked interactively
        whilst in plot.mode.ExtractCrossBoundariesMode.

        There are many subtleties involved in designing a Filler.  Some
        of them are pointed out nurbs.surface.make_nsided_region and
        many more in the reference cited therein.  For best results,
        all the boundary Curves should be about the same arc length.

        Parameters
        ----------
        Bk = the boundary Curves
        Gk = the cross-derivative Curves

        '''

        self.C = Point()
        self.CN = Point()

        self.Mk = []
        self.DMk = np.array([[]])

        self.Ck = []
        self.Dk = []

        self.CLRk = []
        self.DLRk = []

        self.CIk = []
        self.BLRk = []

        self.nurbs = []

        self.O = None  # originating and deoriginating

        self._split(Bk, Gk)
コード例 #10
0
ファイル: filler.py プロジェクト: sunstarchan/Genair
class Filler(Part):
    ''' Create a generic Filler.  As its name suggests, a Filler
    attempts to fill an N-sided hole with as many NURBS patches.

    Presently, the Filler is used by other higher-level objects such as
    the Wingtip (N = 2) and the Fuselage (2 x (N = 2)).

    Intended usage
    --------------
    >>> fi = Filler(Bk, Gk)
    >>> fi.design()
    >>> fi.blend() # Not satisfied?
    >>> fi.design()
    >>> fi.blend()

    The Filler should not be transformed between calls to Filler.design
    and Filler.deoriginate.

    After deoriginating, the design cycle can restart from either
    Filler.pre_split (if new split points are desired) immediately
    followed by Filler.split, or directly from Filler.design.

    Source
    ------
    Piegl & Tiller, Filling n-sided regions with NURBS patches, The
    Visual Computer, 1999.

    '''
    def __init__(self, Bk, Gk):
        ''' Form a Filler from a set of N boundary curves and associated
        cross-derivative fields.  These are usually picked interactively
        whilst in plot.mode.ExtractCrossBoundariesMode.

        There are many subtleties involved in designing a Filler.  Some
        of them are pointed out nurbs.surface.make_nsided_region and
        many more in the reference cited therein.  For best results,
        all the boundary Curves should be about the same arc length.

        Parameters
        ----------
        Bk = the boundary Curves
        Gk = the cross-derivative Curves

        '''

        self.C = Point()
        self.CN = Point()

        self.Mk = []
        self.DMk = np.array([[]])

        self.Ck = []
        self.Dk = []

        self.CLRk = []
        self.DLRk = []

        self.CIk = []
        self.BLRk = []

        self.nurbs = []

        self.O = None  # originating and deoriginating

        self._split(Bk, Gk)

    def __setstate__(self, d):
        ''' Unpickling. '''
        if d['C']:
            d['C'].originate = self._originate
        if d['CN']:
            d['CN'].innerize = self._innerize
        self.__dict__.update(d)

    def _innerize(self):
        ''' Generate the Filler's inner Curves. '''
        Mk = np.array([mk.xyz for mk in self.Mk])
        CIkn = generate_inner_curves_nsided_region(self.C.xyz, self.CN.xyz, Mk,
                                                   self.DMk)
        if not self.CIk:
            self.CIk = CIkn
        else:
            for ci, cin in zip(self.CIk, CIkn):
                ci.cobj.Pw.setflags(write=True)
                ci.cobj.Pw[:] = cin.cobj.Pw
                ci._construct_GL_arrays()
                ci._fill_batch()
            for clr in self.CLRk:
                for c in clr:
                    c._fill_batch()

    def _originate(self):
        ''' Originate the whole Filler IN-PLACE, so that the Filler's
        central Point lies on the origin.  This considerably eases
        interactive manipulations. '''

        O = self.C.xyz
        if (O != 0.0).any():
            self.O = O if self.O is None else self.O + O
            os = [self.C] + self.Ck + self.Mk + \
                    [c for clr in self.CLRk for c in clr]
            for o in os:
                if isinstance(o, Point):
                    translate(o._xyzw, -O)
                elif isinstance(o, NURBSObject):
                    if o._figs:
                        o.cobj.Pw.setflags(write=True)
                        translate(o.cobj.Pw, -O)
                        o.cobj.Pw.setflags(write=False)
                        translate(o.cobj._Pwf, -O)
                        o._fill_batch()
                    else:
                        translate(o.cobj.Pw, -O)
        self._innerize()

    def _split(self, Bk, Gk):
        ''' Split all boundary Curves at their parametric midpoint. '''

        for BG in zip(Bk, Gk):
            CD = make_curves_compatible1(BG)[3]
            C, D = CD
            self.Ck.append(C)
            self.Dk.append(D)

        self.CLRk, self.DLRk, Mk, self.DMk = split_nsided_region(
            self.Ck, self.Dk)

        CLRk0 = None if not len(self.Ck) == 2 else self.CLRk[0]
        C = find_central_point_nsided_region(Mk, self.DMk)
        CN = find_normal_vec_nsided_region(C, Mk, self.DMk, CLRk0)

        self.C = Point(*C)
        self.C.originate = self._originate

        self.CN = Point(*CN)
        self.CN.innerize = self._innerize

        self.Mk = [Point(*mk) for mk in Mk]

    def design(self, show=True):
        ''' Design the Filler's default entities, i.e. its inner Curves,
        its central Point and/or normal vector.  All of these will have
        a direct impact on the shape of the resultant blended NURBS
        patches.  Choose them wisely!

        Parameters
        ----------
        show = whether or not to interactively design the Filler

        Returns
        -------
        fig = a Figure

        '''

        self.nurbs = []
        self.unglue()
        self._originate()
        if show:
            return draw(self, self.C, self.CN, *self.CIk)

    def blend(self, eps=1.0, show=True):
        ''' Blend all boundary and inner Curves to produce N smooth
        Surfaces.

        Parameters
        ----------
        eps = the tolerance on geometric continuity (in degrees)
        show = whether or not to draw the blended Surfaces

        Returns
        -------
        fig = a Figure

        '''

        if not self.CIk:
            raise UndesignedFiller(self)
        self.BLRk = generate_inner_cross_deriv_nsided_region(
            self.CN.xyz, self.CIk, self.CLRk)
        self.nurbs = make_nsided_region(self.CLRk, self.DLRk, self.CIk,
                                        self.BLRk, eps)

        self.glue()
        O = self.O
        self.O = None
        if O is not None:
            self.C.translate(O)
        self.unglue()

        self.colorize()
        if show:
            return draw(self)

    def _glue(self, parent=None):
        ''' See Part._glue. '''
        super(Filler, self)._glue(parent)
        g = [self.C] + self.Ck + self.Mk + self.CIk + self.nurbs + \
                [c for clr in self.CLRk for c in clr]
        return g

    def _draw(self):
        ''' See Part._draw. '''
        return (self.nurbs or [c for clr in self.CLRk for c in clr] or self.Ck)
コード例 #11
0
ファイル: fuselage.py プロジェクト: sunstarchan/Genair
    def _setup(self):
        def transform_ffd0(O):
            R, D, Pw = O._R, O._D, O._Pw
            sf = O.xyz[1] / D
            if not np.allclose(sf, 1.0):
                scale(Pw, sf, L=[0, 1, 0])
            dz = O.xyz[2] - Pw[0, 0, 2]
            if not np.allclose(dz, 0.0):
                Om = [r._xyzw for r in R] + [Pw]
                for o in Om:
                    translate(o, [0, 0, dz])
            O._D = O.xyz[1]

        def transform_ffd1(R):
            O, D, Pw = R._O, R._D, R._Pw
            z0 = O.xyz[2]
            sf = (R.xyz[2] - z0) / D
            if not np.allclose(sf, 1.0):
                x = R.xyz[0]
                scale(Pw, sf, [x, 0, z0], [0, 0, 1])
            R._D = R.xyz[2] - z0

        super(FuselageMolder, self)._setup()
        n, dummy, l = self.cobj.n
        Ps = []
        for k in xrange(l + 1):
            Pw = self.cobj.Pw[:, :, k]

            O = Pw[n / 2, 0, :3]
            R = Pw[n / 2, -1].copy()
            R[2] = O[2]
            L = R[:3] - O
            scale(R, 1.3, O, L)  # knob
            R = Point(*R)
            Ps.append(R)
            R._D = R.xyz[1]
            R._Pw = Pw
            R.plane = O, [1, 0, 0]
            R.transform_ffd = transform_ffd0

            O = Pw[-1, 0, :3]
            R = Pw[-1, -1].copy()
            L = R[:3] - O
            scale(R, 1.3, O, L)  # knob
            R = Point(*R)
            Ps.append(R)
            R._D = R.xyz[2] - O[2]
            R._Pw = Pw[n / 2:]
            R.line = O, [0, 0, 1]
            R.transform_ffd = transform_ffd1

            O = Pw[0, 0, :3]
            R = Pw[0, -1].copy()
            L = R[:3] - O
            scale(R, 1.3, O, L)  # knob
            R = Point(*R)
            Ps.append(R)
            R._D = R.xyz[2] - O[2]
            R._Pw = Pw[:n / 2]
            R.line = O, [0, 0, 1]
            R.transform_ffd = transform_ffd1

            O, R0, R1 = Ps[-3:]
            O._R = (R0, R1)
            R0._O = O
            R1._O = O

        for p in Ps:
            p.ffd = self

        self.pilot_points = Ps
        self.glued = Ps + [self]