Beispiel #1
0
vector< vec3d > PropXSec::GetDrawLines( Matrix4d &transMat  )
{
    vector< vec3d > lines;

    VspCurve curve = GetCurve();

    curve.Scale( 1.0 / m_PropPos.m_Chord );

    vec3d v = curve.CompPnt( 0 );
    curve.OffsetZ( -v.z() );

    m_PropPos.SetCurve( curve );
    m_PropPos.Update();
    curve = m_PropPos.GetCurve();

    curve.Transform( transMat );
    curve.TessAdapt( lines, 1e-2, 10 );

    return lines;
}
Beispiel #2
0
//==== Update Fuselage And Cross Section Placement ====//
void PropGeom::UpdateSurf()
{
    int nxsec = m_XSecSurf.NumXSec();

    double radius = m_Diameter() / 2.0;

    double rfirst = 0.0;
    double rlast = 1.0;

    vector < double > uvec( nxsec );
    vector < double > rvec( nxsec );

    double rev = 1.0;
    if ( m_ReverseFlag() )
    {
        rev = -1.0;
    }

    //==== Update XSec Location/Rotation ====//
    for ( int i = 0 ; i < nxsec ; i++ )
    {
        PropXSec* xs = ( PropXSec* ) m_XSecSurf.FindXSec( i );

        if ( xs )
        {
            if ( xs->GetXSecCurve()->GetType() == XS_POINT )
            {
                printf( "Warning: XS_POINT type not valid for propellers\n" );
                // Propellers are constructed in two phases.  The first phase stacks
                // all the XSecs with unit chord.  Intermediate curves are extracted
                // from that surface and are scaled to match the required chord.
                // Since XS_POINT XSecs already have zero chord, they mess up this
                // process.
            }

            //==== Reset Group Names ====//
            xs->SetGroupDisplaySuffix( i );

            //==== Set X Limits ====//
            EnforceOrder( xs, i );

            xs->SetRefLength( radius );

            bool first = false;
            bool last = false;

            if( i == 0 ) first = true;
            else if( i == (nxsec-1) ) last = true;

            if ( first )
            {
                rfirst = xs->m_RadiusFrac();
            }
            if ( last )
            {
                rlast = xs->m_RadiusFrac();
            }

            uvec[i] = i;
            rvec[i] = xs->m_RadiusFrac();
        }
    }

    m_rtou = Vsp1DCurve();
    m_rtou.InterpolateLinear( uvec, rvec, false );

    EnforcePCurveOrder( rfirst, rlast );

    // Set lower limit for activity factor integration limit
    m_AFLimit.SetLowerLimit( rfirst );
    // Integrate activity factor.
    m_AF.Set( m_ChordCurve.IntegrateAF( m_AFLimit() ) );
    m_AF.Deactivate();

    if ( m_UseBeta34Flag() == 1 )
    {
        if ( rfirst <= 0.75 )
        {
            double theta34 = m_TwistCurve.Comp( 0.75 );
            m_Feather = m_Beta34() - theta34;
        }
        else
        {
            m_Feather = m_Beta34();
        }
        m_Beta34.Activate();
        m_Feather.Deactivate();
    }
    else
    {
        if ( rfirst <= 0.75 )
        {
            double theta34 = m_TwistCurve.Comp( 0.75 );
            m_Beta34 = m_Feather() + theta34;
        }
        else
        {
            m_Beta34 = m_Feather();
        }
        m_Beta34.Deactivate();
        m_Feather.Activate();
    }

    // Set up fold axis & store for visualization.
    Matrix4d fold, foldrot;
    fold.loadIdentity();
    fold.rotateY( m_AzimuthFoldDir() );
    fold.rotateX( m_ElevationFoldDir() );
    m_FoldAxDirection = fold.xform( vec3d( 0, 0, 1 ) );
    m_FoldAxOrigin = vec3d( m_AxialFoldAxis() * radius, m_RadFoldAxis() * radius, m_OffsetFoldAxis() * radius );

    //==== Cross Section Curves & joint info ====//
    vector< VspCurve > crv_vec;
    crv_vec.resize( nxsec );

    //==== Update XSec Location/Rotation ====//
    for ( int i = 0 ; i < nxsec ; i++ )
    {
        PropXSec* xs = ( PropXSec* ) m_XSecSurf.FindXSec( i );

        if ( xs )
        {
            XSecCurve* xsc = xs->GetXSecCurve();

            double r = xs->m_RadiusFrac();
            double w = m_ChordCurve.Comp( r ) * radius;

            if ( xsc )
            {
                //==== Find Width Parm ====//
                string width_id = xsc->GetWidthParmID();
                Parm* width_parm = ParmMgr.FindParm( width_id );

                piecewise_curve_type pwc;

                if ( width_parm )
                {
                    width_parm->Deactivate();

                    Airfoil* af = dynamic_cast < Airfoil* > ( xsc );
                    if ( af )
                    {
                        width_parm->Set( 1.0 );
                        xs->GetXSecCurve()->SetFakeWidth( w );
                        xs->GetXSecCurve()->SetUseFakeWidth( true );
                        pwc = xs->GetCurve().GetCurve();
                        xs->GetXSecCurve()->SetUseFakeWidth( false );
                        width_parm->Set( w );
                    }
                    else
                    {
                        CircleXSec* cir = dynamic_cast < CircleXSec* > ( xsc );
                        if ( cir )
                        {
                            width_parm->Set( 1.0 );
                            pwc = xs->GetCurve().GetCurve();
                            width_parm->Set( w );
                        }
                        else
                        {
                            double h = xs->GetXSecCurve()->GetHeight();
                            xsc->SetWidthHeight( 1.0, h/w );
                            pwc = xs->GetCurve().GetCurve();
                            xsc->SetWidthHeight( w, h );
                        }
                    }

                }
                else
                {
                    pwc = xs->GetCurve().GetCurve();
                }

                // Set up prop positioner for highlight curves - not lofting.
                xs->m_PropPos.m_ParentProp = GetXSecSurf( 0 );
                xs->m_PropPos.m_Radius = r * radius;
                xs->m_PropPos.m_Chord = w;
                xs->m_PropPos.m_Twist = m_TwistCurve.Comp( r );
                xs->m_PropPos.m_XRotate = 0.0;
                xs->m_PropPos.m_ZRotate = atan( -m_RakeCurve.Compdt( r ) ) * 180.0 / PI;

                xs->m_PropPos.m_Rake = m_RakeCurve.Comp( r ) * radius;
                xs->m_PropPos.m_Skew = m_SkewCurve.Comp( r ) * radius;
                xs->m_PropPos.m_PropRot = m_Rotate();
                xs->m_PropPos.m_Feather = m_Feather();

                xs->m_PropPos.m_FoldOrigin = m_FoldAxOrigin;
                xs->m_PropPos.m_FoldDirection = m_FoldAxDirection;
                xs->m_PropPos.m_FoldAngle = m_FoldAngle();

                xs->m_PropPos.m_Reverse = rev;

                crv_vec[i].SetCurve( pwc );
            }
        }
    }

    // This surface linearly interpolates the airfoil sections without
    // any other transformations.
    // These sections can be extracted (as u-const curves) and then
    // transformed to their final position before skinning.
    m_FoilSurf = VspSurf();
    m_FoilSurf.SkinC0( crv_vec, false );

    // Find the union of stations required to approximate the blade parameters
    // with cubic functions.
    vector < double > tmap = rvec;  // Initialize with specified XSecs.
    vector < double > tdisc;
    tdisc.push_back( rfirst );
    tdisc.push_back( rlast );
    for ( int i = 0; i < m_pcurve_vec.size(); i++ )
    {
        vector < double > tm;
        vector < double > tmout;
        vector < double > td;
        m_pcurve_vec[i]->GetTMap( tm, td );

        std::set_union( tmap.begin(), tmap.end(), tm.begin(), tm.end(), std::back_inserter(tmout), &aboutcomp );
        std::swap( tmout, tmap );
    }

    // Not sure why above set_union leaves duplicate entries, but
    // sort and force unique just to be sure.
    std::sort( tmap.begin(), tmap.end() );
    auto tmit = std::unique( tmap.begin(), tmap.end(), &abouteq );
    tmap.erase( tmit, tmap.end() );

    // Treat all control points as possible discontinuities.
    tdisc = tmap;

    // Refine by adding two intermediate points to each cubic section
    // this is needed because the adaptive algorithm above uses derivatives
    // while our later reconstruction does not.
    vector < double > tref( ( tmap.size() - 1 ) * 3 + 1 );
    for ( int i = 0; i < tmap.size() - 1; i++ )
    {
        int iref = 3*i;
        double t = tmap[i];
        double tnxt = tmap[i+1];
        double dt = (tnxt-t)/3.0;

        tref[iref] = t;
        tref[iref+1] = t + dt;
        tref[iref+2] = t + 2 * dt;
    }
    tref.back() = tmap.back();
    std::swap( tmap, tref );

    // Convert tdisc to final parameterization.
    for ( int i = 0; i < tdisc.size(); i++ )
    {
        tdisc[i] = ( tdisc[i] - rfirst ) / ( rlast - rfirst );
    }

    // Pseudo cross sections
    // Not directly user-controlled, but an intermediate step in lofting the
    // surface.
    int npseudo = tmap.size();

    vector < rib_data_type > rib_vec( npseudo );
    vector < double > u_pseudo( npseudo );
    for ( int i = 0; i < npseudo; i++ )
    {
        // Assume linear interpolation means linear u/r relationship.
        double r = tmap[i];
        double u = m_rtou.CompPnt( r );

        VspCurve c;
        m_FoilSurf.GetUConstCurve( c, u );
        vec3d v = c.CompPnt( 0 );
        c.OffsetZ( -v.z() );

        PropPositioner pp;

        pp.m_ParentProp = this->GetXSecSurf( 0 );
        pp.m_Radius = r * radius;

        pp.m_Chord = m_ChordCurve.Comp( r ) * radius;
        pp.m_Twist = m_TwistCurve.Comp( r );

        pp.m_XRotate = 0.0;
        pp.m_ZRotate = atan( -m_RakeCurve.Compdt( r ) ) * 180.0 / PI;

        pp.m_Rake = m_RakeCurve.Comp( r ) * radius;
        pp.m_Skew = m_SkewCurve.Comp( r ) * radius;

        pp.m_PropRot = m_Rotate();
        pp.m_Feather = m_Feather();

        pp.m_FoldOrigin = m_FoldAxOrigin;
        pp.m_FoldDirection = m_FoldAxDirection;
        pp.m_FoldAngle = m_FoldAngle();

        pp.m_Reverse = rev;

        // Set a bunch of other pp variables.
        pp.SetCurve( c );
        pp.Update();

        rib_vec[i].set_f( pp.GetCurve().GetCurve() );
        u_pseudo[i] = ( r - rfirst ) / ( rlast - rfirst );
    }

    m_MainSurfVec.resize( 1 );
    m_MainSurfVec.reserve( m_Nblade() );

    m_MainSurfVec[0].SetMagicVParm( false );
    m_MainSurfVec[0].SkinCubicSpline( rib_vec, u_pseudo, tdisc, false );

    m_MainSurfVec[0].SetMagicVParm( true );
    m_MainSurfVec[0].SetSurfType( PROP_SURF );
    m_MainSurfVec[0].SetClustering( m_LECluster(), m_TECluster() );
    m_MainSurfVec[0].SetFoilSurf( &m_FoilSurf );

    if ( m_XSecSurf.GetFlipUD() )
    {
        m_MainSurfVec[0].FlipNormal();
    }

    if ( this->m_ReverseFlag() )
    {
        m_MainSurfVec[0].FlipNormal();
    }

    // UpdateEndCaps here so we only have to cap one blade.
    UpdateEndCaps();

    m_MainSurfVec.resize( m_Nblade(), m_MainSurfVec[0] );

    // Duplicate capping variables
    m_CapUMinSuccess.resize( m_Nblade(), m_CapUMinSuccess[0] );
    m_CapUMaxSuccess.resize( m_Nblade(), m_CapUMaxSuccess[0] );
    m_CapWMinSuccess.resize( m_Nblade(), m_CapWMinSuccess[0] );
    m_CapWMaxSuccess.resize( m_Nblade(), m_CapWMaxSuccess[0] );

    Matrix4d rot;
    for ( int i = 1; i < m_Nblade(); i++ )
    {
        double theta = 360.0 * i / ( double )m_Nblade();
        rot.loadIdentity();
        rot.rotateX( theta );

        m_MainSurfVec[i].Transform( rot );
    }

    CalculateMeshMetrics( u_pseudo );
}
Beispiel #3
0
string PropGeom::BuildBEMResults()
{
    // Calculate prop center and normal vector
    vec3d cen = m_ModelMatrix.xform( vec3d( 0, 0, 0 ) );
    vec3d norm = m_ModelMatrix.xform( vec3d( -1.0, 0, 0 ) ) - cen;

    int n = m_TessU();

    //==== Create Results ====//
    Results* res = ResultsMgr.CreateResults( "PropBEM" );
    res->Add( NameValData( "Num_Sections", n ) );
    res->Add( NameValData( "Num_Blade", m_Nblade() ) );
    res->Add( NameValData( "Diameter", m_Diameter() ) );
    res->Add( NameValData( "Beta34", m_Beta34() ) );
    res->Add( NameValData( "Feather", m_Feather() ) );
    res->Add( NameValData( "Center", cen ) );
    res->Add( NameValData( "Normal", norm ) );

    double rfirst = m_ChordCurve.GetRFirst();
    double rlast = m_ChordCurve.GetRLast();

    // Establish points to evaluate sections at.
    vector < double > vtess;
    m_MainSurfVec[0].MakeVTess( m_TessW(), vtess, m_CapUMinTess(), false );

    vector < double > r_vec(n);
    vector < double > chord_vec(n);
    vector < double > twist_vec(n);
    vector < double > rake_vec(n);
    vector < double > skew_vec(n);

    double rspan = rlast - rfirst;
    for ( int i = 0; i < n; i++ )
    {
        double t = static_cast < double > ( i ) / ( n - 1 );
        double r = rfirst + rspan * Cluster( t, m_RootCluster(), m_TipCluster() );
        double u = m_rtou.CompPnt( r );

        VspCurve c;
        m_FoilSurf.GetUConstCurve( c, u );
        vec3d v = c.CompPnt( 0 );
        c.OffsetZ( -v.z() );

        vector < vec3d > pts;
        c.Tesselate( vtess, pts );

        vector < double > xpts( pts.size() );
        vector < double > ypts( pts.size() );

        for ( int j = 0; j < pts.size(); j++ )
        {
            xpts[j] = pts[j].x();
            ypts[j] = pts[j].y();
        }

        char str[255];
        sprintf( str, "%03d", i );
        res->Add( NameValData( "XSection_" + string( str ), xpts ) );
        res->Add( NameValData( "YSection_" + string( str ), ypts ) );

        r_vec[i] = r;
        chord_vec[i] = m_ChordCurve.Comp( r );
        twist_vec[i] = m_TwistCurve.Comp( r );
        rake_vec[i] = m_RakeCurve.Comp( r );
        skew_vec[i] = m_SkewCurve.Comp( r );
    }

    res->Add( NameValData( "Radius", r_vec ) );
    res->Add( NameValData( "Chord", chord_vec ) );
    res->Add( NameValData( "Twist", twist_vec ) );
    res->Add( NameValData( "Rake", rake_vec ) );
    res->Add( NameValData( "Skew", skew_vec ) );

    return res->GetID();
}