Exemple #1
0
    def _NACA5cambercurve(self, MaxCamberLocFracChord, DesignLiftCoefficient):
        # Generates the camber curve of a NACA 5-digit airfoil
        
        xmc = MaxCamberLocFracChord

        # Determine the transition point m that separates the polynomial
        # forward section from the linear aft section
        R = act.cubic(-3, 6*xmc, -3*xmc**2)
        m = R[2].real
    
        # Sampling the chord line
        ChordCoord, NCosPoints = act.coslin(xmc)
        
        # As per equation (A-13) in Bill Mason's Geometry for
        # Aerodynamicists
        QQ = (3*m-7*m**2+8*m**3-4*m**4) / (math.sqrt(m*(1-m))) - 3/2*(1-2*m)*(math.pi/2-math.asin(1-2*m))
        k1 = 6*DesignLiftCoefficient/QQ
    
        # Compute the two sections of the camber curve and its slope
        zcam = []
        dzcamdx = []
        for cc in ChordCoord[0:NCosPoints]:
            list.append(zcam, (1/6)*k1*(cc**3 - 3*m*cc**2 + m**2*(3-m)*cc))
            list.append(dzcamdx, (1/6)*k1*(3*cc**2-6*m*cc+m**2*(3-m)))
        for cc in ChordCoord[NCosPoints:]:
            list.append(zcam, (1/6)*k1*m**3*(1-cc))
            list.append(dzcamdx, -(1/6)*m**3);
        return ChordCoord, zcam, dzcamdx
def CockpitWindowContours(Height=1.620, Depth=5):
    P1 = [0.000, 0.076, Height - 1.620 + 2.194]
    P2 = [0.000, 0.852, Height - 1.620 + 2.290]
    P3 = [0.000, 0.904, Height + 0.037]
    P4 = [0.000, 0.076, Height]
    CWC1 = rs.AddPolyline([P1, P2, P3, P4, P1])
    rs.SelectObject(CWC1)
    rs.Command("_FilletCorners 0.08 ")

    P1 = [0.000, 0.951, Height - 1.620 + 2.289]
    P2 = [0.000, 1.343, Height - 1.620 + 2.224]
    P3 = [0.000, 1.634, Height - 1.620 + 1.773]
    P4 = [0.000, 1.557, Height - 1.620 + 1.588]
    P5 = [0.000, 1.027, Height - 1.620 + 1.671]
    CWC2 = rs.AddPolyline([P1, P2, P3, P4, P5, P1])
    rs.SelectObject(CWC2)
    rs.Command("_FilletCorners 0.08 ")

    CWC3 = act.MirrorObjectXZ(CWC1)
    CWC4 = act.MirrorObjectXZ(CWC2)

    ExtPathId = rs.AddLine([0, 0, 0], [Depth, 0, 0])

    CWC1s = rs.ExtrudeCurve(CWC1, ExtPathId)
    CWC2s = rs.ExtrudeCurve(CWC2, ExtPathId)
    CWC3s = rs.ExtrudeCurve(CWC3, ExtPathId)
    CWC4s = rs.ExtrudeCurve(CWC4, ExtPathId)

    rs.DeleteObjects([CWC1, CWC2, CWC3, CWC4, ExtPathId])

    return CWC1s, CWC2s, CWC3s, CWC4s
    def _NACA5cambercurve(self, MaxCamberLocFracChord, DesignLiftCoefficient):
        # Generates the camber curve of a NACA 5-digit airfoil

        xmc = MaxCamberLocFracChord

        # Determine the transition point m that separates the polynomial
        # forward section from the linear aft section
        R = act.cubic(-3, 6 * xmc, -3 * xmc**2)
        m = R[2].real

        # Sampling the chord line
        ChordCoord, NCosPoints = act.coslin(xmc)

        # As per equation (A-13) in Bill Mason's Geometry for
        # Aerodynamicists
        QQ = (3 * m - 7 * m**2 + 8 * m**3 - 4 * m**4) / (math.sqrt(
            m * (1 - m))) - 3 / 2 * (1 - 2 * m) * (math.pi / 2 -
                                                   math.asin(1 - 2 * m))
        k1 = 6 * DesignLiftCoefficient / QQ

        # Compute the two sections of the camber curve and its slope
        zcam = []
        dzcamdx = []
        for cc in ChordCoord[0:NCosPoints]:
            list.append(zcam, (1 / 6) * k1 * (cc**3 - 3 * m * cc**2 + m**2 *
                                              (3 - m) * cc))
            list.append(dzcamdx, (1 / 6) * k1 *
                        (3 * cc**2 - 6 * m * cc + m**2 * (3 - m)))
        for cc in ChordCoord[NCosPoints:]:
            list.append(zcam, (1 / 6) * k1 * m**3 * (1 - cc))
            list.append(dzcamdx, -(1 / 6) * m**3)
        return ChordCoord, zcam, dzcamdx
    def _NACA4cambercurve(self, MaxCamberLocTenthChord, MaxCamberPercChord):
        """ Generates the camber curve of a NACA 4-digit airfoil
        """

        # Using the original notation of Jacobs et al.(1933)
        xmc = MaxCamberLocTenthChord / 10.0
        zcammax = MaxCamberPercChord / 100.0

        # Protect against division by zero on airfoils like NACA0012
        if xmc == 0:
            xmc = 0.2

        # Sampling the chord line
        ChordCoord, NCosPoints = act.coslin(xmc)

        # Compute the two sections of the camber curve and its slope
        zcam = []
        dzcamdx = []
        for cc in ChordCoord[0:NCosPoints]:
            list.append(zcam, (zcammax / (xmc**2)) * (2 * xmc * cc - cc**2))
            list.append(dzcamdx, (zcammax / xmc**2) * (2 * xmc - 2 * cc))
        for cc in ChordCoord[NCosPoints:]:
            list.append(zcam, (zcammax / ((1 - xmc)**2)) *
                        (1 - 2 * xmc + 2 * xmc * cc - (cc**2)))
            list.append(dzcamdx, (zcammax / (1 - xmc)**2) * (2 * xmc - 2 * cc))
        return ChordCoord, zcam, dzcamdx
Exemple #5
0
    def _NACA4cambercurve(self, MaxCamberLocTenthChord, MaxCamberPercChord):
        """ Generates the camber curve of a NACA 4-digit airfoil
        """
        
        # Using the original notation of Jacobs et al.(1933)
        xmc     = MaxCamberLocTenthChord /10.0;
        zcammax = MaxCamberPercChord    /100.0;
        
        # Protect against division by zero on airfoils like NACA0012
        if xmc==0:
            xmc = 0.2 

        # Sampling the chord line
        ChordCoord, NCosPoints = act.coslin(xmc)
        
        # Compute the two sections of the camber curve and its slope
        zcam = []
        dzcamdx = []
        for cc in ChordCoord[0:NCosPoints]:
            list.append(zcam, (zcammax/(xmc ** 2))*(2*xmc*cc - cc ** 2))
            list.append(dzcamdx, (zcammax/xmc ** 2)*(2*xmc - 2*cc))
        for cc in ChordCoord[NCosPoints:]:
            list.append(zcam, (zcammax/((1-xmc) ** 2))*(1-2*xmc+2*xmc*cc-(cc ** 2)))
            list.append(dzcamdx, (zcammax/(1-xmc) ** 2)*(2*xmc - 2*cc));
        return ChordCoord, zcam, dzcamdx
Exemple #6
0
    def _BuildSurfacePoints(self, ChordFactor, ScaleFactor):
        LEPoints = self._GenerateLeadingEdge()

        SurfacePntsUp = []
        SurfacePntsDown = []
        Sections = []
        #         SurfacePntstoAdd=[]

        Eps = np.linspace(0, 1, self.NPaero_span + 1)
        Sections = [
            self.AirfoilFunct(Eps[i], LEPoints[i], self.ChordFunct,
                              ChordFactor, self.DihedralFunct,
                              self.TwistFunct).Curve
            for i in xrange(self.NPaero_span + 1)
        ]
        numb = 0

        for num in xrange(self.NPaero_span + 1):
            section = Sections[num]
            sectionPnt = act.Uniform_Points_on_Curve(section,
                                                     self.NPaero_chord)
            numb = numb + 1
            for numm in xrange(1, self.NPaero_chord + 1):
                print(sectionPnt[numm - 1].Y())
                print(sectionPnt[numm - 1].X())
                edgePnts = act.make_vertex(sectionPnt[numm - 1])
                if self.ScaleFactor != 1:
                    Origin = gp_Pnt(0., 0., 0.)
                    Pnts = act.scale_uniformal(edgePnts, Origin,
                                               self.ScaleFactor)
                    if numm <= (self.NPaero_chord - 1) / 2 + 1:
                        SurfacePntsUp.append(Pnts)
                        if numm == (self.NPaero_chord - 1) / 2 + 1:
                            SurfacePntsDown.append(Pnts)
                    elif numm > (self.NPaero_chord - 1) / 2 + 1:
                        #                      SurfacePntsDown.append(SurfacePntstoAdd)
                        SurfacePntsDown.append(Pnts)
#                      SurfacePntsDown=SurfacePntsD+SurfacePntstoAdd
#            numbb=numbb+1
#         if self.ScaleFactor!= 1:
#             Origin = gp_Pnt(0., 0., 0.)
#             SurfacePnts=act.scale_uniformal(SurfacePnts, Origin, self.ScaleFactor)

        print(np.shape(SurfacePntsUp))
        print(np.shape(SurfacePntsDown))
        return SurfacePntsUp, SurfacePntsDown
def myChordFunctionJetstream(Epsilon):
    # User-defined function describing the variation of chord as a function of
    # the leading edge coordinate

    ChordLengths = [1, 0.333]
    EpsArray = [0, 1]

    f = act.linear_interpolation(EpsArray, ChordLengths)
    return f(Epsilon)
Exemple #8
0
def mySweepAngleFunctionAirliner(Epsilon):
    # User-defined function describing the variation of sweep angle as a function
    # of the leading edge coordinate

    SweepAngles = [90, 87, 35, 35, 35, 35, 35, 35, 35, 35, 80]

    EpsArray = []
    for i in range(0, 11):
        list.append(EpsArray, float(i)/10)
    f = act.linear_interpolation(EpsArray, SweepAngles)

    return f(Epsilon)
Exemple #9
0
def myChordFunctionAirliner(Epsilon):
    # User-defined function describing the variation of chord as a function of
    # the leading edge coordinate

    ChordLengths = [0.5, 0.3792, 0.2867, 0.232, 0.1763, 0.1393, 0.1155, 0.093,
    0.0713, 0.055, 0.007]

    EpsArray = []
    for i in range(0, 11):
        list.append(EpsArray, float(i)/10)
    f = act.linear_interpolation(EpsArray, ChordLengths)
    return f(Epsilon)
def FuselageOML(NoseLengthRatio=0.182,
                TailLengthRatio=0.293,
                Scaling=[55.902, 55.902, 55.902],
                NoseCoordinates=[0, 0, 0],
                CylindricalMidSection=False,
                SimplificationReqd=False):
    # Instantiates a parametric fuselage outer mould line (OML) geometry for a given
    # set of design variables.
    FuselageOMLSurf, SternPoint = _BuildFuselageOML(NoseLengthRatio,
                                                    TailLengthRatio,
                                                    CylindricalMidSection,
                                                    SimplificationReqd)

    if not (FuselageOMLSurf) or FuselageOMLSurf is None:
        return

    ScalingF = [0, 0, 0]
    ScalingF[0] = Scaling[0] / 55.902
    ScalingF[1] = Scaling[1] / 55.902
    ScalingF[2] = Scaling[2] / 55.902

    # Overall scaling
    FuselageOMLSurf = act.ScaleObjectWorld000(FuselageOMLSurf, ScalingF)

    # A few other ways of performing the scaling...
    # Variant one: this depends on the current CPlane!
    # FuselageOMLSurf = rs.ScaleObject(FuselageOMLSurf, (0,0,0), Scaling)

    # Variant two: define plane in World coordinates
    #P = rs.PlaneFromFrame((0,0,0),(1,0,0),(0,1,0))
    #TransfMatrix = Rhino.Geometry.Transform.Scale(P, Scaling[0], Scaling[1], Scaling[2])
    #FuselageOMLSurf = rs.TransformObjects(FuselageOMLSurf, TransfMatrix)

    # Variant three: World coordinate system based scaling
    #xform = rs.XformScale(Scaling)
    #FuselageOMLSurf = rs.TransformObjects(FuselageOMLSurf, xform)

    SternPoint[0] = SternPoint[0] * ScalingF[0]
    SternPoint[1] = SternPoint[1] * ScalingF[1]
    SternPoint[2] = SternPoint[2] * ScalingF[2]

    # Positioning
    MoveVec = rs.VectorCreate(NoseCoordinates, [0, 0, 0])
    FuselageOMLSurf = rs.MoveObject(FuselageOMLSurf, MoveVec)
    SternPoint[0] = SternPoint[0] + NoseCoordinates[0]
    SternPoint[1] = SternPoint[1] + NoseCoordinates[1]
    SternPoint[2] = SternPoint[2] + NoseCoordinates[2]

    return FuselageOMLSurf, SternPoint
def _FuselageLongitudinalGuideCurves(NoseLengthRatio, TailLengthRatio):
    # Internal function. Defines the four longitudinal curves that outline the
    # fuselage (outer mould line).

    FSVU, FSVL = _AirlinerFuselageSideView(NoseLengthRatio, TailLengthRatio)
    FSVUCurve = rs.AddCurve(FSVU)
    FSVLCurve = rs.AddCurve(FSVL)

    AFPVPort, NoseEndX, TailStartX = _AirlinerFuselagePlanView(
        NoseLengthRatio, TailLengthRatio)

    # Generate plan view
    PlanPortCurve = rs.AddCurve(AFPVPort)

    # How wide is the fuselage?
    (Xmin, Ymin, Zmin, Xmax, Ymax, Zmax) = act.ObjectsExtents(PlanPortCurve)

    # Generate a slightly wider projection surface
    FSVMeanCurve = rs.MeanCurve(FSVUCurve, FSVLCurve)
    RuleLinePort = rs.AddLine((0, 0, 0), (0, -1.1 * abs(Ymax - Ymin), 0))
    FSVMCEP = rs.CurveEndPoint(FSVMeanCurve)
    AftLoftEdgePort = rs.CopyObject(RuleLinePort, FSVMCEP)
    ParallelLoftEdgePort = rs.CopyObject(FSVMeanCurve,
                                         (0, -1.1 * abs(Ymax - Ymin), 0))
    LSPort = rs.AddSweep2((FSVMeanCurve, ParallelLoftEdgePort),
                          (RuleLinePort, AftLoftEdgePort))

    # Project the plan view onto the mean surface
    PortCurve = rs.ProjectCurveToSurface(PlanPortCurve, LSPort, (0, 0, 100))

    # House-keeping
    rs.DeleteObjects([
        LSPort, PlanPortCurve, ParallelLoftEdgePort, RuleLinePort,
        AftLoftEdgePort
    ])

    # Tidy up the mean curve. This is necessary for a smooth result and removing
    # it can render the algorithm unstable. However, FitCurve itself may sometimes
    # be slightly unstable.
    FLength = abs(Xmax - Xmin)  # establish a reference length
    PortCurveSimplified = rs.FitCurve(PortCurve,
                                      distance_tolerance=FLength * 0.001)
    StarboardCurveSimplified = act.MirrorObjectXZ(PortCurveSimplified)

    rs.DeleteObject(PortCurve)

    # Compute the actual end points of the longitudinal curves
    (Xmin, Ymin, Zmin, Xmax1, Ymax,
     Zmax) = act.ObjectsExtents(StarboardCurveSimplified)
    (Xmin, Ymin, Zmin, Xmax2, Ymax,
     Zmax) = act.ObjectsExtents(PortCurveSimplified)
    (Xmin, Ymin, Zmin, Xmax3, Ymax, Zmax) = act.ObjectsExtents(FSVUCurve)
    (Xmin, Ymin, Zmin, Xmax4, Ymax, Zmax) = act.ObjectsExtents(FSVLCurve)
    EndX = min([Xmax1, Xmax2, Xmax3, Xmax4])

    return StarboardCurveSimplified, PortCurveSimplified, FSVUCurve, FSVLCurve, FSVMeanCurve, NoseEndX, TailStartX, EndX
    def GenerateLiftingSurface(self, ChordFactor, ScaleFactor, OptimizeChordScale=0):
        # This is the main method of this class. It builds a lifting surface
        # (wing, tailplane, etc.) with the given ChordFactor and ScaleFactor or 
        # an optimized ChordFactor and ScaleFactor, with the local search started
        # from the two given values.

        x0 = [ChordFactor, ScaleFactor]

        if OptimizeChordScale:
            self._CheckOptParCorrectlySpec()
            self._NormaliseWeightings()
            self._PrintTargetsAndWeights()
            print("Optimizing scale factors...")
            # An iterative local hillclimber type optimizer is needed here. One
            # option might be SciPy's fmin as below:
            # x0, fopt, iter, funcalls, warnflag, allvecs = scipy.optimize.fmin(self._LSObjective, x0, retall=True, xtol=0.025, full_output=True)
            # However, SciPy is not supported on 64-bit Rhino installations, so 
            # so here we use an alternative: a simple evoltionary optimizer
            # included with AirCONICS_tools.
            MaxIter = 50
            xtol = 0.025
            deltax = [x0[0]*0.25,x0[1]*0.25]
            x0, fopt = act.boxevopmin2d(self._LSObjective, x0, deltax, xtol, MaxIter)
            x0[0] = abs(x0[0])
            x0[1] = abs(x0[1])
            print("Optimum chord factor %5.3f, optimum scale factor %5.3f" % (x0[0], x0[1]))

        LS, ActualSemiSpan, LSP_area,  RootChord, AR, WingTip = self._BuildLS(x0[0], x0[1])
        
        self._ClearConstructionGeometry()
        
        # Moving the wing into position
        AP = rs.AddPoint(self.ApexPoint)
        MoveVec = rs.VectorCreate(AP, (0,0,0))
        rs.MoveObject(LS, MoveVec)
        if WingTip:
            rs.MoveObject(WingTip, MoveVec)
        rs.DeleteObject(AP)

        # FINAL REPORT ON THE COMPLETED SURFACE
        SA  = rs.SurfaceArea(LS)
        print("Wing complete. Key features (all related to both wings):")
        print("Proj.area: %5.4f   Wet.area: %5.4f   Span:%5.4f  Aspect ratio:  %5.4f  Root chord: %5.4f" % (2*LSP_area, 2.0*SA[0], 2.0*ActualSemiSpan, AR, RootChord))

        return LS, ActualSemiSpan, LSP_area,  RootChord, AR, WingTip
Exemple #13
0
    def GenerateLiftingSurface(self, ChordFactor, ScaleFactor, OptimizeChordScale=0):
        # This is the main method of this class. It builds a lifting surface
        # (wing, tailplane, etc.) with the given ChordFactor and ScaleFactor or
        # an optimized ChordFactor and ScaleFactor, with the local search started
        # from the two given values.

        x0 = [ChordFactor, ScaleFactor]

        if OptimizeChordScale:
            self._CheckOptParCorrectlySpec()
            self._NormaliseWeightings()
            self._PrintTargetsAndWeights()
            print("Optimizing scale factors...")
            # An iterative local hillclimber type optimizer is needed here. One
            # option might be SciPy's fmin as below:
            # x0, fopt, iter, funcalls, warnflag, allvecs = scipy.optimize.fmin(self._LSObjective, x0, retall=True, xtol=0.025, full_output=True)
            # However, SciPy is not supported on 64-bit Rhino installations, so
            # so here we use an alternative: a simple evoltionary optimizer
            # included with AirCONICS_tools.
            MaxIter = 50
            xtol = 0.025
            deltax = [x0[0]*0.25,x0[1]*0.25]
            x0, fopt = act.boxevopmin2d(self._LSObjective, x0, deltax, xtol, MaxIter)
            x0[0] = abs(x0[0])
            x0[1] = abs(x0[1])
            print("Optimum chord factor %5.3f, optimum scale factor %5.3f" % (x0[0], x0[1]))

        LS, ActualSemiSpan, LSP_area,  RootChord, AR, WingTip = self._BuildLS(x0[0], x0[1])

        self._ClearConstructionGeometry()

        # Moving the wing into position
        AP = rs.AddPoint(self.ApexPoint)
        MoveVec = rs.VectorCreate(AP, (0,0,0))
        rs.MoveObject(LS, MoveVec)
        if WingTip:
            rs.MoveObject(WingTip, MoveVec)
        rs.DeleteObject(AP)

        # FINAL REPORT ON THE COMPLETED SURFACE
        SA  = rs.SurfaceArea(LS)
        print("Wing complete. Key features (all related to both wings):")
        print("Proj.area: %5.4f   Wet.area: %5.4f   Span:%5.4f  Aspect ratio:  %5.4f  Root chord: %5.4f" % (2*LSP_area, 2.0*SA[0], 2.0*ActualSemiSpan, AR, RootChord))

        return LS, ActualSemiSpan, LSP_area,  RootChord, AR, WingTip
Exemple #14
0
    def _BuildLS(self, ChordFactor, ScaleFactor):
        """Generates a tentative lifting surface, given the general,
        nondimensional parameters of the object (variations of chord length,
        dihedral, etc.) and the two scaling factors.

        Parameters
        ----------
        ChordFactor - float
            Factor againt which the standard shape is scaled in the chordwise
            direction
        ScaleFactor - float
            Factor againt which the standard shape is scaled in the world
            coordinates

        Returns
        -------
        LS : TopoDS_Shape
            The generated Lifting surface

        ActualSemiSpan : scalar
            TODO: currently not calculated, None is returned

        LSP_area : scalar
            TODO: currently not calculated, None is returned

        AR : scalar
            TODO: currently not calculated, None is returned

        WingTip : TopoDS face or shape
            TODO: currently not calculated, None is returned
        """
        LEPoints = self._GenerateLeadingEdge()

        Sections = []
        # TODO: These lists are used for when the curve has been smoothed or
        # the loft has failed, neither of which have been implemented yet
        #        ProjectedSections = []
        #        TEPoints_u = []
        #        TEPoints_l = []

        Eps = np.linspace(0, 1, self.SegmentNo + 1)
        Sections = [
            self.AirfoilFunct(Eps[i], LEPoints[i], self.ChordFunct,
                              ChordFactor, self.DihedralFunct,
                              self.TwistFunct).Curve
            for i in xrange(self.SegmentNo + 1)
        ]

        self._Sections = Sections  # I used from debugging - remove it?

        # TODO: Implement chord projection and Curve start/end points
        # to rescale smoothed curves and for secondary loft methods

        LS = act.AddSurfaceLoft(Sections,
                                max_degree=self._max_degree,
                                continuity=self._Cont)

        if LS is None:
            pass

        WingTip = None

        if self.TipRequired:
            pass

        # Scaling
        if self.ScaleFactor != 1:
            Origin = gp_Pnt(0., 0., 0.)
            LS = act.scale_uniformal(LS, Origin, self.ScaleFactor)
            # TODO: Wing tip scaling (TipRequired is not implemented yet)
            if self.TipRequired and WingTip:
                pass

        self.RootChord = (self.ChordFunct(0) * ChordFactor) * ScaleFactor

        # Temporarily set other variables as None until above TODO's are done
        ActualSemiSpan = None
        LSP_area = None
        AR = None

        return LS, ActualSemiSpan, LSP_area, AR, WingTip
    def _TransformAirfoil(self, C):
        # Internal function. Given a normal airfoil, unit chord, nose in origin,
        # chord along x axis, applies scaling, rotations, positioning and smoothing

        # Smoothing
        for i in range(1, self.SmoothingIterations + 1):
            rs.FairCurve(C)

        # Find the actual leading edge point - the airfoil may have stretched as
        # as a result of the smoothing or it may have been incorrectly defined
        # through a series of coordinates
        RefLine = rs.AddLine((-100, 0, -100), (-100, 0, 100))
        ClosestPoints = rs.CurveClosestObject(RefLine, C)
        P = rs.AddPoint(ClosestPoints[1])
        MoveVec = rs.VectorCreate((0, 0, 0), P)
        rs.MoveObject(C, MoveVec)
        # Garbage collection
        rs.DeleteObjects((RefLine, P))
        # Now find the trailing edge points
        PUpper = rs.CurveStartPoint(C)
        PLower = rs.CurveEndPoint(C)
        TECentre = ((PUpper[0] + PLower[0]) / 2, (PUpper[1] + PLower[1]) / 2,
                    (PUpper[2] + PLower[2]) / 2)
        if PUpper[2] < PLower[2]:
            print "Warning: the upper and lower surface intersect at the TE."
        TECentrePoint = rs.AddPoint(TECentre)
        AxisOfRotation = rs.VectorCreate((0, 0, 0), (0, 1, 0))

        L1 = rs.AddLine((0, 0, 0), (1, 0, 0))
        L2 = rs.AddLine((0, 0, 0), TECentrePoint)
        AngRot = rs.Angle2(L1, L2)
        # The angle returned by Angle2 is always positive so:
        if TECentre[2] < 0:
            rs.RotateObject(C, (0, 0, 0), AngRot[0], AxisOfRotation)
        else:
            rs.RotateObject(C, (0, 0, 0), -AngRot[0], AxisOfRotation)
        # Garbage collection
        rs.DeleteObjects((TECentrePoint, L1, L2))

        # Find the trailing edge point again after rotating it onto the x axis
        PUpper = rs.CurveStartPoint(C)
        PLower = rs.CurveEndPoint(C)
        TECentre = [(PUpper[0] + PLower[0]) / 2, (PUpper[1] + PLower[1]) / 2,
                    (PUpper[2] + PLower[2]) / 2]
        ActualChordLength = TECentre[0]

        # Scale the airfoil to unit chord
        #rs.ScaleObject(C, (0,0,0), (1/ActualChordLength, 1, 1/ActualChordLength))
        act.ScaleObjectWorld000(
            C, (1 / ActualChordLength, 1, 1 / ActualChordLength))

        # Now we can assume that airfoil is normalised to the unit chord, with
        # its leading edge in the origin, trailing edge in (1,0,0)
        Chrd = rs.AddLine((0, 0, 0), (1, 0, 0))

        # Scaling
        ScaleFact = (self.ChordLength, self.ChordLength, self.ChordLength)

        # same as rs.ScaleObject(C, (0,0,0), ScaleFact)
        act.ScaleObjectWorld000(C, ScaleFact)

        # same as rs.ScaleObject(Chrd, (0,0,0), ScaleFact)
        act.ScaleObjectWorld000(Chrd, ScaleFact)

        # Twist
        rs.RotateObject(C, (0, 0, 0), self.Twist,
                        rs.VectorCreate((0, 0, 0), (0, 1, 0)))
        rs.RotateObject(Chrd, (0, 0, 0), self.Twist,
                        rs.VectorCreate((0, 0, 0), (0, 1, 0)))
        # Dihedral
        rs.RotateObject(C, (0, 0, 0), -self.Rotation,
                        rs.VectorCreate((0, 0, 0), (1, 0, 0)))
        rs.RotateObject(Chrd, (0, 0, 0), -self.Rotation,
                        rs.VectorCreate((0, 0, 0), (1, 0, 0)))
        # 3d positioning
        MoveVec = rs.VectorCreate(self.LeadingEdgePoint, (0, 0, 0))
        rs.MoveObject(C, MoveVec)
        rs.MoveObject(Chrd, MoveVec)
        return C, Chrd
Exemple #16
0
def TurbofanNacelle(EngineSection,
                    Chord,
                    CentreLocation=[0, 0, 0],
                    ScarfAngle=3,
                    HighlightRadius=1.45,
                    MeanNacelleLength=5.67):
    # The defaults yield a nacelle similar to that of an RR Trent 1000 / GEnx

    HighlightDepth = 0.12 * MeanNacelleLength
    SectionNo = 100

    # Draw the nacelle with the centre of the intake highlight circle in 0,0,0
    rs.EnableRedraw(False)
    Highlight = rs.AddCircle3Pt((0, 0, HighlightRadius),
                                (0, -HighlightRadius, 0),
                                (0, 0, -HighlightRadius))
    HighlightCutterCircle = rs.AddCircle3Pt((0, 0, HighlightRadius * 1.5),
                                            (0, -HighlightRadius * 1.5, 0),
                                            (0, 0, -HighlightRadius * 1.5))

    # Fan disk for CFD boundary conditions
    FanCircle = rs.CopyObject(Highlight, (MeanNacelleLength * 0.25, 0, 0))
    FanDisk = rs.AddPlanarSrf(FanCircle)
    # Aft outflow for CFD boundary conditions
    BypassCircle = rs.CopyObject(Highlight, (MeanNacelleLength * 0.85, 0, 0))
    BypassDisk = rs.AddPlanarSrf(BypassCircle)
    rs.DeleteObjects([FanCircle, BypassCircle])

    # Outflow cone
    TailConeBasePoint = [MeanNacelleLength * 0.84, 0, 0]
    TailConeApex = [MeanNacelleLength * 1.35, 0, 0]
    TailConeRadius = HighlightRadius * 0.782
    TailCone = rs.AddCone(TailConeBasePoint, TailConeApex, TailConeRadius)
    # Spinner cone
    SpinnerConeBasePoint = [MeanNacelleLength * 0.26, 0, 0]
    SpinnerConeApex = [MeanNacelleLength * 0.08, 0, 0]
    SpinnerConeRadius = MeanNacelleLength * 0.09
    Spinner = rs.AddCone(SpinnerConeBasePoint, SpinnerConeApex,
                         SpinnerConeRadius)

    # Tilt the intake
    RotVec = rs.VectorCreate((0, 0, 0), (0, 1, 0))
    Highlight = rs.RotateObject(Highlight, (0, 0, 0), ScarfAngle, axis=RotVec)

    # Set up the disk for separating the intake lip later
    HighlightCutterCircle = rs.RotateObject(HighlightCutterCircle, (0, 0, 0),
                                            ScarfAngle,
                                            axis=RotVec)
    HighlightCutterDisk = rs.AddPlanarSrf(HighlightCutterCircle)
    rs.DeleteObject(HighlightCutterCircle)
    rs.MoveObject(HighlightCutterDisk, (HighlightDepth, 0, 0))

    # Build the actual airfoil sections to define the nacelle
    HighlightPointVector = rs.DivideCurve(Highlight, SectionNo)

    Sections = []
    TailPoints = []
    Rotation = 0
    Twist = 0
    AirfoilSeligName = 'goe613'
    SmoothingPasses = 1

    for HighlightPoint in HighlightPointVector:
        ChordLength = MeanNacelleLength - HighlightPoint.X
        Af = primitives.Airfoil(HighlightPoint, ChordLength, Rotation, Twist,
                                airconics_setup.SeligPath)
        AfCurve, Chrd = primitives.Airfoil.AddAirfoilFromSeligFile(
            Af, AirfoilSeligName, SmoothingPasses)
        rs.DeleteObject(Chrd)
        P = rs.CurveEndPoint(AfCurve)
        list.append(TailPoints, P)
        AfCurve = act.AddTEtoOpenAirfoil(AfCurve)
        list.append(Sections, AfCurve)
        Rotation = Rotation + 360.0 / SectionNo

    list.append(TailPoints, TailPoints[0])

    # Build the actual nacelle OML surface
    EndCircle = rs.AddInterpCurve(TailPoints)
    Nacelle = rs.AddSweep2([Highlight, EndCircle], Sections, closed=True)
    # Separate the lip
    Cowling, HighlightSection = rs.SplitBrep(Nacelle, HighlightCutterDisk,
                                             True)

    # Now build the pylon between the engine and the specified chord on the wing
    CP1 = [
        MeanNacelleLength * 0.26 + CentreLocation[0], CentreLocation[1],
        CentreLocation[2] + HighlightRadius * 0.1
    ]
    CP2 = [
        MeanNacelleLength * 0.4 + CentreLocation[0], CentreLocation[1],
        HighlightRadius * 1.45 + CentreLocation[2]
    ]
    CP3 = rs.CurveEndPoint(Chord)
    rs.ReverseCurve(Chord)
    CP4 = rs.CurveEndPoint(Chord)

    # Move the engine into its actual place on the wing
    rs.MoveObjects(
        [HighlightSection, Cowling, FanDisk, BypassDisk, TailCone, Spinner],
        CentreLocation)

    # Pylon wireframe
    PylonTop = rs.AddInterpCurve([CP1, CP2, CP3, CP4])
    PylonAf = primitives.Airfoil(CP1, MeanNacelleLength * 1.35, 90, 0,
                                 airconics_setup.SeligPath)
    PylonAfCurve, PylonChord = primitives.Airfoil.AddNACA4(
        PylonAf, 0, 0, 12, 3)
    LowerTE = rs.CurveEndPoint(PylonChord)
    PylonTE = rs.AddLine(LowerTE, CP4)

    # Create the actual pylon surface
    PylonLeft = rs.AddNetworkSrf([PylonTop, PylonAfCurve, PylonTE])
    rs.MoveObject(PylonLeft, (0, -CentreLocation[1], 0))
    PylonRight = act.MirrorObjectXZ(PylonLeft)
    rs.MoveObject(PylonLeft, (0, CentreLocation[1], 0))
    rs.MoveObject(PylonRight, (0, CentreLocation[1], 0))
    PylonAfCurve = act.AddTEtoOpenAirfoil(PylonAfCurve)
    PylonAfSrf = rs.AddPlanarSrf(PylonAfCurve)

    # Assigning basic surface properties
    act.AssignMaterial(Cowling, "ShinyBABlueMetal")
    act.AssignMaterial(HighlightSection, "UnpaintedMetal")
    act.AssignMaterial(TailCone, "UnpaintedMetal")
    act.AssignMaterial(FanDisk, "FanDisk")
    act.AssignMaterial(Spinner, "ShinyBlack")
    act.AssignMaterial(BypassDisk, "FanDisk")
    act.AssignMaterial(PylonLeft, "White_composite_external")
    act.AssignMaterial(PylonRight, "White_composite_external")

    # Clean-up
    rs.DeleteObject(HighlightCutterDisk)
    rs.DeleteObjects(Sections)
    rs.DeleteObject(EndCircle)
    rs.DeleteObject(Highlight)
    rs.DeleteObjects([PylonTop, PylonAfCurve, PylonChord, PylonTE])

    rs.Redraw()

    TFEngine = [
        Cowling, HighlightSection, TailCone, FanDisk, Spinner, BypassDisk
    ]
    TFPylon = [PylonLeft, PylonRight, PylonAfSrf]

    return TFEngine, TFPylon
Exemple #17
0
                                         tea.myAirfoilFunctionAirliner,
                                         LooseSurf,
                                         SegmentNo,
                                         TipRequired=True)
    ChordFactor = 1
    ScaleFactor = 50
    rs.EnableRedraw(False)
    WingSurf, ActualSemiSpan, LSP_area, RootChord, AR, WingTip = Wing.GenerateLiftingSurface(
        ChordFactor, ScaleFactor)
    rs.EnableRedraw()

    SpanStation = 0.3  # The engine is to be placed at 30% span
    EngineDia = 2.9
    NacelleLength = 1.95 * EngineDia
    rs.EnableRedraw(False)
    EngineSection, Chord = act.CutSect(WingSurf, SpanStation)
    CEP = rs.CurveEndPoint(Chord)

    # Variables controlling the position of the engine with respect to the wing
    EngineCtrFwdOfLE = 0.98
    EngineCtrBelowLE = 0.35
    Scarf_deg = 4

    #   Now build the engine and its pylon
    EngineStbd, PylonStbd = TurbofanNacelle(
        EngineSection,
        Chord,
        CentreLocation=[
            CEP.X - EngineCtrFwdOfLE * NacelleLength, CEP.Y,
            CEP.Z - EngineCtrBelowLE * NacelleLength
        ],
Exemple #18
0
def _BuildFuselageOML(NoseLengthRatio, TailLengthRatio, CylindricalMidSection, SimplificationReqd):

    MaxFittingAttempts = 6

    FittingAttempts = -1


    NetworkSrfSettings = [
    [35, 20, 15, 5, 20],
    [35, 30, 15, 5, 20],
    [35, 20, 15, 2, 20],
    [30, 30, 15, 2, 20],
    [30, 20, 15, 2, 20],
    [25, 20, 15, 2, 20],
    [20, 20, 15, 2, 20],
    [15, 20, 15, 2, 20]]

    StarboardCurve, PortCurve, FSVUCurve, FSVLCurve, FSVMeanCurve, NoseEndX, TailStartX, EndX = _FuselageLongitudinalGuideCurves(NoseLengthRatio, TailLengthRatio)


    while FittingAttempts <= MaxFittingAttempts:

        FittingAttempts = FittingAttempts + 1 
        
        # Construct array of cross section definition frames
        SX0 = 0
        Step01 = NetworkSrfSettings[FittingAttempts][0]
        SX1 = 0.04*NoseEndX
        Step12 = NetworkSrfSettings[FittingAttempts][1]
        SX2 = SX1 + 0.25*NoseEndX
        Step23 = NetworkSrfSettings[FittingAttempts][2]
        SX3 = NoseEndX
        Step34 = NetworkSrfSettings[FittingAttempts][3]
        SX4 = TailStartX
        Step45 = NetworkSrfSettings[FittingAttempts][4]
        SX5 = EndX
        
        print "Attempting network surface fit with network density setup ", NetworkSrfSettings[FittingAttempts][:]
        
        
        Stations01 = act.pwfrange(SX0,SX1,max([Step01,2]))
        Stations12 = act.pwfrange(SX1,SX2,max([Step12,2]))
        Stations23 = act.pwfrange(SX2,SX3,max([Step23,2]))
        Stations34 = act.pwfrange(SX3,SX4,max([Step34,2]))
        Stations45 = act.pwfrange(SX4,SX5,max([Step45,2]))
    
        StationRange = Stations01[:-1] + Stations12[:-1] + Stations23[:-1] + Stations34[:-1] + Stations45
        C = []
        FirstTime = True
        for XStation in StationRange:
            P = rs.PlaneFromPoints((XStation,0,0),(XStation,1,0),(XStation,0,1))
            IP1 = rs.PlaneCurveIntersection(P,StarboardCurve)
            IP2 = rs.PlaneCurveIntersection(P,FSVUCurve)
            IP3 = rs.PlaneCurveIntersection(P,PortCurve)
            IP4 = rs.PlaneCurveIntersection(P,FSVLCurve)
            IPcentre = rs.PlaneCurveIntersection(P,FSVMeanCurve)
            IPoint1 = rs.AddPoint(IP1[0][1])
            IPoint2 = rs.AddPoint(IP2[0][1])
            IPoint3 = rs.AddPoint(IP3[0][1])
            IPoint4 = rs.AddPoint(IP4[0][1])
            IPointCentre = rs.AddPoint(IPcentre[0][1])
            PseudoDiameter = abs(IP4[0][1].Z-IP2[0][1].Z)
            if CylindricalMidSection and NoseEndX < XStation < TailStartX:
            # Ensure that the parallel section of the fuselage is cylindrical
            # if CylindricalMidSection is True
                print "Enforcing circularity in the central section..."
                if FirstTime:
                    PseudoRadius = PseudoDiameter/2
                    FirstTime = False
                Pc = rs.PointCoordinates(IPointCentre)
                P1 = P2 = P3 = Pc
                P1 = rs.PointAdd(P1,(0,PseudoRadius,0))
                P2 = rs.PointAdd(P2,(0,0,PseudoRadius))
                P3 = rs.PointAdd(P3,(0,-PseudoRadius,0))
                c = rs.AddCircle3Pt(P1, P2, P3)
            else:
                c = rs.AddInterpCurve([IPoint1,IPoint2,IPoint3,IPoint4,IPoint1],knotstyle=3)
                # Once CSec is implemented in Rhino Python, this could be replaced
            rs.DeleteObjects([IPoint1,IPoint2,IPoint3,IPoint4,IPointCentre])
            list.append(C,c)
    
        # Fit fuselage external surface
        CurveNet = []
        for c in C[1:]:
            list.append(CurveNet,c)
        list.append(CurveNet, FSVUCurve)
        list.append(CurveNet, PortCurve)
        list.append(CurveNet, FSVLCurve)
        list.append(CurveNet, StarboardCurve)
        FuselageOMLSurf = rs.AddNetworkSrf(CurveNet)
        rs.DeleteObjects(C)
        
        if not(FuselageOMLSurf==None):
            print "Network surface fit succesful on attempt ", FittingAttempts+1 
            FittingAttempts = MaxFittingAttempts+1 # Force an exit from 'while'

    # If all attempts at fitting a network surface failed, we attempt a Sweep2
    if FuselageOMLSurf==None:
        print "Failed to fit network surface to the external shape of the fuselage"
        print "Attempting alternative fitting method, quality likely to be low..."

        try:
            FuselageOMLSurf = rs.AddSweep2([FSVUCurve,FSVLCurve],C[:])
        except:
            FuselageOMLSurf = False

        SimplificationReqd = True # Enforce simplification
        if not(FuselageOMLSurf):
            print "Alternative fitting method failed too. Out of ideas."

    if FuselageOMLSurf and SimplificationReqd:
        rs.UnselectAllObjects()
        rs.SelectObject(FuselageOMLSurf)
        ToleranceStr = str(0.0005*EndX)
        print "Smoothing..."
        rs.Command("FitSrf " + ToleranceStr)
        rs.UnselectAllObjects()

    # Compute the stern point coordinates of the fuselage
    Pu = rs.CurveEndPoint(FSVUCurve)
    Pl = rs.CurveEndPoint(FSVLCurve)
    SternPoint = [Pu.X, Pu.Y, 0.5*(Pu.Z+Pl.Z)]

    rs.DeleteObjects([FSVUCurve,FSVLCurve,PortCurve,StarboardCurve,FSVMeanCurve])

    return FuselageOMLSurf, SternPoint
def _BuildFuselageOML(NoseLengthRatio, TailLengthRatio, CylindricalMidSection,
                      SimplificationReqd):

    MaxFittingAttempts = 6

    FittingAttempts = -1

    NetworkSrfSettings = [[35, 20, 15, 5, 20], [35, 30, 15, 5, 20],
                          [35, 20, 15, 2, 20], [30, 30, 15, 2, 20],
                          [30, 20, 15, 2, 20], [25, 20, 15, 2, 20],
                          [20, 20, 15, 2, 20], [15, 20, 15, 2, 20]]

    StarboardCurve, PortCurve, FSVUCurve, FSVLCurve, FSVMeanCurve, NoseEndX, TailStartX, EndX = _FuselageLongitudinalGuideCurves(
        NoseLengthRatio, TailLengthRatio)

    while FittingAttempts <= MaxFittingAttempts:

        FittingAttempts = FittingAttempts + 1

        # Construct array of cross section definition frames
        SX0 = 0
        Step01 = NetworkSrfSettings[FittingAttempts][0]
        SX1 = 0.04 * NoseEndX
        Step12 = NetworkSrfSettings[FittingAttempts][1]
        SX2 = SX1 + 0.25 * NoseEndX
        Step23 = NetworkSrfSettings[FittingAttempts][2]
        SX3 = NoseEndX
        Step34 = NetworkSrfSettings[FittingAttempts][3]
        SX4 = TailStartX
        Step45 = NetworkSrfSettings[FittingAttempts][4]
        SX5 = EndX

        print "Attempting network surface fit with network density setup ", NetworkSrfSettings[
            FittingAttempts][:]

        Stations01 = act.pwfrange(SX0, SX1, max([Step01, 2]))
        Stations12 = act.pwfrange(SX1, SX2, max([Step12, 2]))
        Stations23 = act.pwfrange(SX2, SX3, max([Step23, 2]))
        Stations34 = act.pwfrange(SX3, SX4, max([Step34, 2]))
        Stations45 = act.pwfrange(SX4, SX5, max([Step45, 2]))

        StationRange = Stations01[:
                                  -1] + Stations12[:
                                                   -1] + Stations23[:
                                                                    -1] + Stations34[:
                                                                                     -1] + Stations45
        C = []
        FirstTime = True
        for XStation in StationRange:
            P = rs.PlaneFromPoints((XStation, 0, 0), (XStation, 1, 0),
                                   (XStation, 0, 1))
            IP1 = rs.PlaneCurveIntersection(P, StarboardCurve)
            IP2 = rs.PlaneCurveIntersection(P, FSVUCurve)
            IP3 = rs.PlaneCurveIntersection(P, PortCurve)
            IP4 = rs.PlaneCurveIntersection(P, FSVLCurve)
            IPcentre = rs.PlaneCurveIntersection(P, FSVMeanCurve)
            IPoint1 = rs.AddPoint(IP1[0][1])
            IPoint2 = rs.AddPoint(IP2[0][1])
            IPoint3 = rs.AddPoint(IP3[0][1])
            IPoint4 = rs.AddPoint(IP4[0][1])
            IPointCentre = rs.AddPoint(IPcentre[0][1])
            PseudoDiameter = abs(IP4[0][1].Z - IP2[0][1].Z)
            if CylindricalMidSection and NoseEndX < XStation < TailStartX:
                # Ensure that the parallel section of the fuselage is cylindrical
                # if CylindricalMidSection is True
                print "Enforcing circularity in the central section..."
                if FirstTime:
                    PseudoRadius = PseudoDiameter / 2
                    FirstTime = False
                Pc = rs.PointCoordinates(IPointCentre)
                P1 = P2 = P3 = Pc
                P1 = rs.PointAdd(P1, (0, PseudoRadius, 0))
                P2 = rs.PointAdd(P2, (0, 0, PseudoRadius))
                P3 = rs.PointAdd(P3, (0, -PseudoRadius, 0))
                c = rs.AddCircle3Pt(P1, P2, P3)
            else:
                c = rs.AddInterpCurve(
                    [IPoint1, IPoint2, IPoint3, IPoint4, IPoint1], knotstyle=3)
                # Once CSec is implemented in Rhino Python, this could be replaced
            rs.DeleteObjects(
                [IPoint1, IPoint2, IPoint3, IPoint4, IPointCentre])
            list.append(C, c)

        # Fit fuselage external surface
        CurveNet = []
        for c in C[1:]:
            list.append(CurveNet, c)
        list.append(CurveNet, FSVUCurve)
        list.append(CurveNet, PortCurve)
        list.append(CurveNet, FSVLCurve)
        list.append(CurveNet, StarboardCurve)
        FuselageOMLSurf = rs.AddNetworkSrf(CurveNet)
        rs.DeleteObjects(C)

        if not (FuselageOMLSurf == None):
            print "Network surface fit succesful on attempt ", FittingAttempts + 1
            FittingAttempts = MaxFittingAttempts + 1  # Force an exit from 'while'

    # If all attempts at fitting a network surface failed, we attempt a Sweep2
    if FuselageOMLSurf == None:
        print "Failed to fit network surface to the external shape of the fuselage"
        print "Attempting alternative fitting method, quality likely to be low..."

        try:
            FuselageOMLSurf = rs.AddSweep2([FSVUCurve, FSVLCurve], C[:])
        except:
            FuselageOMLSurf = False

        SimplificationReqd = True  # Enforce simplification
        if not (FuselageOMLSurf):
            print "Alternative fitting method failed too. Out of ideas."

    if FuselageOMLSurf and SimplificationReqd:
        rs.UnselectAllObjects()
        rs.SelectObject(FuselageOMLSurf)
        ToleranceStr = str(0.0005 * EndX)
        print "Smoothing..."
        rs.Command("FitSrf " + ToleranceStr)
        rs.UnselectAllObjects()

    # Compute the stern point coordinates of the fuselage
    Pu = rs.CurveEndPoint(FSVUCurve)
    Pl = rs.CurveEndPoint(FSVLCurve)
    SternPoint = [Pu.X, Pu.Y, 0.5 * (Pu.Z + Pl.Z)]

    rs.DeleteObjects(
        [FSVUCurve, FSVLCurve, PortCurve, StarboardCurve, FSVMeanCurve])

    return FuselageOMLSurf, SternPoint
def transonic_airliner(
    Propulsion=1,  # 1 - twin, 2 - quad 
    EngineDia=2.9,  # Diameter of engine intake highlight 
    FuselageScaling=[55.902, 55.902, 55.902],  # [x,y,z] scale factors
    NoseLengthRatio=0.182,  # Proportion of forward tapering section of the fuselage 
    TailLengthRatio=0.293,  # Proportion of aft tapering section of the fuselage
    WingScaleFactor=44.56,
    WingChordFactor=1.0,
    Topology=1,  # Topology = 2 will yield a box wing airliner - use with caution, this is just for demo purposes.
    SpanStation1=0.31,  # Inboard engine at this span station
    SpanStation2=0.625,  # Outboard engine at this span station (ignored if Propulsion=1)
    EngineCtrBelowLE=0.3558,  # Engine below leading edge, normalised by the length of the nacelle - range: [0.35,0.5]
    EngineCtrFwdOfLE=0.9837,  # Engine forward of leading edge, normalised by the length of the nacelle - range: [0.85,1.5]
    Scarf_deg=3):  # Engine scarf angle

    # Build fuselage geometry
    rs.EnableRedraw(False)
    try:
        FuselageOMLSurf, SternPoint = fuselage_oml.FuselageOML(
            NoseLengthRatio,
            TailLengthRatio,
            Scaling=FuselageScaling,
            NoseCoordinates=[0, 0, 0],
            CylindricalMidSection=False,
            SimplificationReqd=False)
    except:
        print "Fuselage fitting failed - stopping."
        return

    FuselageHeight = FuselageScaling[2] * 0.105
    FuselageLength = FuselageScaling[0]
    FuselageWidth = FuselageScaling[1] * 0.106
    rs.Redraw()

    if FuselageOMLSurf is None:
        print "Failed to fit fuselage surface, stopping."
        return

    FSurf = rs.CopyObject(FuselageOMLSurf)

    # Position of the apex of the wing
    if FuselageHeight < 8.0:
        WingApex = [0.1748 * FuselageLength, 0,
                    -0.0523 * FuselageHeight]  #787:[9.77,0,-0.307]
    else:
        WingApex = [0.1748 * FuselageLength, 0,
                    -0.1 * FuselageHeight]  #787:[9.77,0,-0.307]

    # Set up the wing object, including the list of user-defined functions that
    # describe the spanwise variations of sweep, dihedral, etc.
    LooseSurf = 1
    if Topology == 1:
        SegmentNo = 10
        Wing = liftingsurface.LiftingSurface(WingApex,
                                             ta.mySweepAngleFunctionAirliner,
                                             ta.myDihedralFunctionAirliner,
                                             ta.myTwistFunctionAirliner,
                                             ta.myChordFunctionAirliner,
                                             ta.myAirfoilFunctionAirliner,
                                             LooseSurf,
                                             SegmentNo,
                                             TipRequired=True)
    elif Topology == 2:
        SegmentNo = 101
        Wing = liftingsurface.LiftingSurface(WingApex,
                                             ta.mySweepAngleFunctionAirliner,
                                             bw.myDihedralFunctionBoxWing,
                                             ta.myTwistFunctionAirliner,
                                             ta.myChordFunctionAirliner,
                                             ta.myAirfoilFunctionAirliner,
                                             LooseSurf,
                                             SegmentNo,
                                             TipRequired=True)

    # Instantiate the wing object and add it to the document
    rs.EnableRedraw(False)
    WingSurf, ActualSemiSpan, LSP_area, RootChord, AR, WingTip = Wing.GenerateLiftingSurface(
        WingChordFactor, WingScaleFactor)
    rs.Redraw()

    if Topology == 1:
        # Add wing to body fairing
        WTBFXCentre = WingApex[
            0] + RootChord / 2.0 + RootChord * 0.1297  # 787: 23.8
        if FuselageHeight < 8.0:
            WTBFZ = RootChord * 0.009  #787: 0.2
            WTBFheight = 0.1212 * RootChord  #787:2.7
            WTBFwidth = 1.08 * FuselageWidth
        else:
            WTBFZ = WingApex[2] + 0.005 * RootChord
            WTBFheight = 0.09 * RootChord
            WTBFwidth = 1.15 * FuselageWidth

        WTBFlength = 1.167 * RootChord  #787:26

        WTBFXStern = WTBFXCentre + WTBFlength / 2.0

        CommS = "_Ellipsoid %3.2f,0,%3.2f %3.2f,0,%3.2f %3.2f,%3.2f,%3.2f %3.2f,0,%3.2f " % (
            WTBFXCentre, WTBFZ, WTBFXStern, WTBFZ, 0.5 *
            (WTBFXCentre + WTBFXStern), 0.5 * WTBFwidth, WTBFZ, 0.5 *
            (WTBFXCentre + WTBFXStern), WTBFheight)

        rs.EnableRedraw(False)

        rs.CurrentView("Perspective")
        rs.Command(CommS)
        LO = rs.LastCreatedObjects()
        WTBF = LO[0]
        rs.Redraw()

        # Trim wing inboard section
        CutCirc = rs.AddCircle3Pt((0, WTBFwidth / 4, -45),
                                  (0, WTBFwidth / 4, 45),
                                  (90, WTBFwidth / 4, 0))
        CutCircDisk = rs.AddPlanarSrf(CutCirc)
        CutDisk = CutCircDisk[0]
        rs.ReverseSurface(CutDisk, 1)
        rs.TrimBrep(WingSurf, CutDisk)
    elif Topology == 2:
        # Overlapping wing tips
        CutCirc = rs.AddCircle3Pt((0, 0, -45), (0, 0, 45), (90, 0, 0))
        CutCircDisk = rs.AddPlanarSrf(CutCirc)
        CutDisk = CutCircDisk[0]
        rs.ReverseSurface(CutDisk, 1)
        rs.TrimBrep(WingSurf, CutDisk)

    # Engine installation (nacelle and pylon)

    if Propulsion == 1:
        # Twin, wing mounted
        SpanStation = SpanStation1
        NacelleLength = 1.95 * EngineDia
        rs.EnableRedraw(False)
        EngineSection, Chord = act.CutSect(WingSurf, SpanStation)
        CEP = rs.CurveEndPoint(Chord)
        EngineStbd, PylonStbd = engine.TurbofanNacelle(
            EngineSection,
            Chord,
            CentreLocation=[
                CEP.X - EngineCtrFwdOfLE * NacelleLength, CEP.Y,
                CEP.Z - EngineCtrBelowLE * NacelleLength
            ],
            ScarfAngle=Scarf_deg,
            HighlightRadius=EngineDia / 2.0,
            MeanNacelleLength=NacelleLength)
        rs.Redraw()
    elif Propulsion == 2:
        # Quad, wing-mounted
        NacelleLength = 1.95 * EngineDia

        rs.EnableRedraw(False)
        EngineSection, Chord = act.CutSect(WingSurf, SpanStation1)
        CEP = rs.CurveEndPoint(Chord)

        EngineStbd1, PylonStbd1 = engine.TurbofanNacelle(
            EngineSection,
            Chord,
            CentreLocation=[
                CEP.X - EngineCtrFwdOfLE * NacelleLength, CEP.Y,
                CEP.Z - EngineCtrBelowLE * NacelleLength
            ],
            ScarfAngle=Scarf_deg,
            HighlightRadius=EngineDia / 2.0,
            MeanNacelleLength=NacelleLength)

        rs.DeleteObjects([EngineSection, Chord])

        EngineSection, Chord = act.CutSect(WingSurf, SpanStation2)
        CEP = rs.CurveEndPoint(Chord)

        EngineStbd2, PylonStbd2 = engine.TurbofanNacelle(
            EngineSection,
            Chord,
            CentreLocation=[
                CEP.X - EngineCtrFwdOfLE * NacelleLength, CEP.Y,
                CEP.Z - EngineCtrBelowLE * NacelleLength
            ],
            ScarfAngle=Scarf_deg,
            HighlightRadius=EngineDia / 2.0,
            MeanNacelleLength=NacelleLength)
        rs.Redraw()

    # Script for generating and positioning the fin
    rs.EnableRedraw(False)
    # Position of the apex of the fin
    P = [0.6524 * FuselageLength, 0.003, FuselageHeight * 0.384]
    #P = [36.47,0.003,2.254]55.902
    RotVec = rs.VectorCreate([1, 0, 0], [0, 0, 0])
    LooseSurf = 1
    SegmentNo = 200
    Fin = liftingsurface.LiftingSurface(P, tail.mySweepAngleFunctionFin,
                                        tail.myDihedralFunctionFin,
                                        tail.myTwistFunctionFin,
                                        tail.myChordFunctionFin,
                                        tail.myAirfoilFunctionFin, LooseSurf,
                                        SegmentNo)
    ChordFactor = 1.01  #787:1.01
    if Topology == 1:
        ScaleFactor = WingScaleFactor / 2.032  #787:21.93
    elif Topology == 2:
        ScaleFactor = WingScaleFactor / 3.5
    FinSurf, FinActualSemiSpan, FinArea, FinRootChord, FinAR, FinTip = Fin.GenerateLiftingSurface(
        ChordFactor, ScaleFactor)
    FinSurf = rs.RotateObject(FinSurf, P, 90, axis=RotVec)
    FinTip = rs.RotateObject(FinTip, P, 90, axis=RotVec)

    if Topology == 1:
        # Tailplane
        P = [0.7692 * FuselageLength, 0.000, FuselageHeight * 0.29]
        RotVec = rs.VectorCreate([1, 0, 0], [0, 0, 0])
        LooseSurf = 1
        SegmentNo = 100
        TP = liftingsurface.LiftingSurface(P, tail.mySweepAngleFunctionTP,
                                           tail.myDihedralFunctionTP,
                                           tail.myTwistFunctionTP,
                                           tail.myChordFunctionTP,
                                           tail.myAirfoilFunctionTP, LooseSurf,
                                           SegmentNo)
        ChordFactor = 1.01
        ScaleFactor = 0.388 * WingScaleFactor  #787:17.3
        TPSurf, TPActualSemiSpan, TPArea, TPRootChord, TPAR, TPTip = TP.GenerateLiftingSurface(
            ChordFactor, ScaleFactor)

    rs.EnableRedraw(True)

    rs.DeleteObjects([EngineSection, Chord])
    try:
        rs.DeleteObjects([CutCirc])
    except:
        pass

    try:
        rs.DeleteObjects([CutCircDisk])
    except:
        pass

    # Windows

    # Cockpit windows:
    rs.EnableRedraw(False)

    CockpitWindowTop = 0.305 * FuselageHeight

    CWC1s, CWC2s, CWC3s, CWC4s = fuselage_oml.CockpitWindowContours(
        Height=CockpitWindowTop, Depth=6)

    FuselageOMLSurf, Win1 = rs.SplitBrep(FuselageOMLSurf,
                                         CWC1s,
                                         delete_input=True)
    FuselageOMLSurf, Win2 = rs.SplitBrep(FuselageOMLSurf,
                                         CWC2s,
                                         delete_input=True)
    FuselageOMLSurf, Win3 = rs.SplitBrep(FuselageOMLSurf,
                                         CWC3s,
                                         delete_input=True)
    FuselageOMLSurf, Win4 = rs.SplitBrep(FuselageOMLSurf,
                                         CWC4s,
                                         delete_input=True)

    rs.DeleteObjects([CWC1s, CWC2s, CWC3s, CWC4s])

    (Xmin, Ymin, Zmin, Xmax, Ymax,
     Zmax) = act.ObjectsExtents([Win1, Win2, Win3, Win4])
    CockpitBulkheadX = Xmax

    CockpitWallPlane = rs.PlaneFromPoints([CockpitBulkheadX, -15, -15],
                                          [CockpitBulkheadX, 15, -15],
                                          [CockpitBulkheadX, -15, 15])

    CockpitWall = rs.AddPlaneSurface(CockpitWallPlane, 30, 30)

    if 'WTBF' in locals():
        rs.TrimBrep(WTBF, CockpitWall)

    rs.DeleteObject(CockpitWall)

    # Window lines
    WIN = [1]
    NOWIN = [0]

    # A typical window pattern (including emergency exit windows)
    WinVec = WIN + 2 * NOWIN + 9 * WIN + 3 * NOWIN + WIN + NOWIN + 24 * WIN + 2 * NOWIN + WIN + NOWIN + 14 * WIN + 2 * NOWIN + WIN + 20 * WIN + 2 * NOWIN + WIN + NOWIN + 20 * WIN

    if FuselageHeight < 8.0:
        # Single deck
        WindowLineHeight = 0.3555 * FuselageHeight
        WinX = 0.1157 * FuselageLength
        WindowPitch = 0.609
        WinInd = -1
        while WinX < 0.75 * FuselageLength:
            WinInd = WinInd + 1
            if WinVec[WinInd] == 1 and WinX > CockpitBulkheadX:
                WinStbd, WinPort, FuselageOMLSurf = fuselage_oml.MakeWindow(
                    FuselageOMLSurf, WinX, WindowLineHeight)
                act.AssignMaterial(WinStbd, "Plexiglass")
                act.AssignMaterial(WinPort, "Plexiglass")
            WinX = WinX + WindowPitch
    else:
        # Fuselage big enough to accommodate two decks
        # Lower deck
        WindowLineHeight = 0.17 * FuselageHeight  #0.166
        WinX = 0.1 * FuselageLength  #0.112
        WindowPitch = 0.609
        WinInd = 0
        while WinX < 0.757 * FuselageLength:
            WinInd = WinInd + 1
            if WinVec[WinInd] == 1 and WinX > CockpitBulkheadX:
                WinStbd, WinPort, FuselageOMLSurf = fuselage_oml.MakeWindow(
                    FuselageOMLSurf, WinX, WindowLineHeight)
                act.AssignMaterial(WinStbd, "Plexiglass")
                act.AssignMaterial(WinPort, "Plexiglass")
            WinX = WinX + WindowPitch
        # Upper deck
        WindowLineHeight = 0.49 * FuselageHeight
        WinX = 0.174 * FuselageLength  #0.184
        WinInd = 0
        while WinX < 0.757 * FuselageLength:
            WinInd = WinInd + 1
            if WinVec[WinInd] == 1 and WinX > CockpitBulkheadX:
                WinStbd, WinPort, FuselageOMLSurf = fuselage_oml.MakeWindow(
                    FuselageOMLSurf, WinX, WindowLineHeight)
                act.AssignMaterial(WinStbd, "Plexiglass")
                act.AssignMaterial(WinPort, "Plexiglass")
            WinX = WinX + WindowPitch

    rs.Redraw()

    act.AssignMaterial(FuselageOMLSurf, "White_composite_external")
    act.AssignMaterial(WingSurf, "White_composite_external")
    try:
        act.AssignMaterial(TPSurf, "ShinyBARedMetal")
    except:
        pass
    act.AssignMaterial(FinSurf, "ShinyBARedMetal")
    act.AssignMaterial(Win1, "Plexiglass")
    act.AssignMaterial(Win2, "Plexiglass")
    act.AssignMaterial(Win3, "Plexiglass")
    act.AssignMaterial(Win4, "Plexiglass")

    # Mirror the geometry as required
    act.MirrorObjectXZ(WingSurf)
    act.MirrorObjectXZ(WingTip)
    try:
        act.MirrorObjectXZ(TPSurf)
        act.MirrorObjectXZ(TPTip)
    except:
        pass
    if Propulsion == 1:
        for ObjId in EngineStbd:
            act.MirrorObjectXZ(ObjId)
        act.MirrorObjectXZ(PylonStbd)
    elif Propulsion == 2:
        for ObjId in EngineStbd1:
            act.MirrorObjectXZ(ObjId)
        act.MirrorObjectXZ(PylonStbd1)
        for ObjId in EngineStbd2:
            act.MirrorObjectXZ(ObjId)
        act.MirrorObjectXZ(PylonStbd2)

    rs.DeleteObject(FSurf)
    rs.Redraw()
Exemple #21
0
    def _BuildLS(self, ChordFactor, ScaleFactor):
        # Generates a tentative lifting surface, given the general, nondimensio-
        # nal parameters of the object (variations of chord length, dihedral, etc.)
        # and the two scaling factors.

        LEPoints = self._GenerateLeadingEdge()

        Sections = []
        ProjectedSections = []
        TEPoints_u = []
        TEPoints_l = []

        for i, LEP in enumerate(LEPoints):
            Eps = float(i)/self.SegmentNo
            Airfoil, Chrd = self.AirfoilFunct(Eps, LEP, self.ChordFunct, ChordFactor, self.DihedralFunct, self.TwistFunct)
            list.append(Sections, Airfoil)

            Pr = rs.ProjectCurveToSurface(Chrd,self.XoY_Plane,self.ProjVectorZ)
            list.append(ProjectedSections, Pr)

            list.append(TEPoints_l, rs.CurveEndPoint(Airfoil))
            list.append(TEPoints_u, rs.CurveStartPoint(Airfoil))

            rs.DeleteObjects(Chrd)

        LS = rs.AddLoftSrf(Sections,loft_type=self.LooseSurf)

        if LS==None:
            # Failed to fit loft surface. Try another fitting algorithm
            TECurve_u = rs.AddInterpCurve(TEPoints_u)
            TECurve_l = rs.AddInterpCurve(TEPoints_l)

            rails = []
            list.append(rails, TECurve_u)
            list.append(rails, TECurve_l)

            # Are the first and last curves identical?
            # AddSweep fails if they are, so if that is the case, one is skipped
            CDev = rs.CurveDeviation(Sections[0],Sections[-1])
            if CDev==None:
                shapes = Sections
                LS = rs.AddSweep2(rails, shapes, False)
            else:
                shapes = Sections[:-1]
                LS = rs.AddSweep2(rails, shapes, True)

            rs.DeleteObjects(rails)
            rs.DeleteObjects([TECurve_u, TECurve_l])

        WingTip = None

        if self.TipRequired:
            TipCurve = Sections[-1]
            TipCurve = act.AddTEtoOpenAirfoil(TipCurve)
            WingTip = rs.AddPlanarSrf(TipCurve)
            rs.DeleteObject(TipCurve)

        # Calculate projected area
        # In some cases the projected sections cannot all be lofted in one go
        # (it happens when parts of the wing fold back onto themselves), so
        # we loft them section by section and we compute the area as a sum.
        LSP_area = 0
        # Attempt to compute a projected area
        try:
            for i, LEP in enumerate(ProjectedSections):
                if i < len(ProjectedSections)-1:
                    LSPsegment = rs.AddLoftSrf(ProjectedSections[i:i+2])
                    SA = rs.SurfaceArea(LSPsegment)
                    rs.DeleteObject(LSPsegment)
                    LSP_area = LSP_area + SA[0]
        except:
            print "Failed to compute projected area. Using half of surface area instead."
            LS_area = rs.SurfaceArea(LS)
            LSP_area = 0.5*LS_area[0]

        BB = rs.BoundingBox(LS)
        if BB:
            ActualSemiSpan = BB[2].Y - BB[0].Y
        else:
            ActualSemiSpan = 0.0

        # Garbage collection
        rs.DeleteObjects(Sections)
        try:
            rs.DeleteObjects(ProjectedSections)
        except:
            print "Cleanup: no projected sections to delete"
        rs.DeleteObjects(LEPoints)


        # Scaling
        Origin = rs.AddPoint([0,0,0])
        ScaleXYZ = (ScaleFactor, ScaleFactor, ScaleFactor)
        LS = rs.ScaleObject(LS, Origin, ScaleXYZ)
        if self.TipRequired and WingTip:
            WingTip = rs.ScaleObject(WingTip, Origin, ScaleXYZ)

        rs.DeleteObject(Origin)

        ActualSemiSpan = ActualSemiSpan*ScaleFactor
        LSP_area = LSP_area*ScaleFactor**2.0
        RootChord = (self.ChordFunct(0)*ChordFactor)*ScaleFactor
        AR = ((2.0*ActualSemiSpan)**2.0)/(2*LSP_area)

        return LS, ActualSemiSpan, LSP_area, RootChord, AR, WingTip