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 loft_profiles_aux(profiles, rails, is_ruled, is_closed): profiles_refs = list([profile.realize()._ref for profile in profiles]) rails_refs = list([rail.realize()._ref for rail in rails]) if len(rails_refs) == 0: return singleton( rh.AddLoftSrf(profiles_refs, None, None, 2 if is_ruled else 0, 0, 0, is_closed)) elif len(rails_refs) == 1: return singleton(rh.AddSweep1(rails_refs[0], profiles_refs)) elif len(rails_refs) == 2: return singleton(rh.AddSweep2(rails_refs, profiles_refs)) elif len(rails_refs) > 2: print('Warning: Rhino only supports two rails but were passed {0}'. format(len(rails))) return singleton(rh.AddSweep2(rails_refs[:2], profiles_refs)) else: #Remove? raise RuntimeError( 'Rhino only supports two rails but were passed {0}'.format( len(rails)))
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
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 _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
def RunCommand(is_interactive): global params center = rs.GetPoint(message="Select center point") n = rs.GetInteger(message="Number of teeth", number=params["n"], minimum=4) m = rs.GetReal(message="Gear module", number=params["m"]) pa = rs.GetReal(message="Pressure angle", number=params["pa"], minimum=0, maximum=45) ha = rs.GetReal(message="Helix angle", number=params["ha"], minimum=-45, maximum=45) t = rs.GetReal(message="Thickness", number=params["t"], minimum=0) bool_opts = rs.GetBoolean(message="Output options", items=(("PitchCylinder", "No", "Yes"),), defaults=(params["pc"],)) if None in [center, n, m, pa, ha, t, bool_opts]: return 1 # Cancel pc = bool_opts[0] params["n"] = n params["m"] = m params["pa"] = pa params["ha"] = ha params["t"] = t params["pc"] = pc cplane = rs.ViewCPlane() # Get current CPlane cplane = rs.MovePlane(cplane, center) xform = rs.XformChangeBasis(cplane, rs.WorldXYPlane()) rs.EnableRedraw(False) old_plane = rs.ViewCPlane(plane=rs.WorldXYPlane()) gear = generate_gear_crv(teeth=params["n"], module=params["m"], pressure_angle=params["pa"]) pitch = abs((n * m * pi) / tan(radians(ha))) turns = t / pitch if ha < 0: # Left handed helix turns = -turns centerline = rs.AddLine([0, 0, 0], [0, 0, t]) helix = rs.AddSpiral([0, 0, 0], [0, 0, t], pitch=pitch, turns=turns, radius0=(m * n) / 2) helical_gear_srf = rs.AddSweep2(rails=[centerline, helix], shapes=[gear]) rs.DeleteObjects([centerline, helix, gear]) rs.ViewCPlane(plane=old_plane) rs.TransformObjects(helical_gear_srf, xform) if pc: circle = generate_pitch_circle_crv(teeth=params["n"], module=params["m"]) pitch_cyl_srf = rs.ExtrudeCurveStraight(circle, start_point=[0, 0, 0], end_point=[0, 0, t]) rs.TransformObjects(pitch_cyl_srf, xform) rs.DeleteObject(circle) rs.SelectObjects([helical_gear_srf, pitch_cyl_srf]) else: rs.SelectObjects(helical_gear_srf) rs.EnableRedraw(True) return 0 # Success