Example #1
0
void PropPositioner::Update()
{
    m_NeedsUpdate = false;

    m_TransformedCurve = m_Curve;

    Matrix4d mat;
    mat.scale( m_Chord );

    if ( m_Reverse < 0 )
    {
        mat.translatef( 1.0, 0.0, 0.0 );
        mat.flipx();
    }

    m_TransformedCurve.Transform( mat );

    if ( !m_ParentProp )
    {
        return;
    }

    // Basic transformation orients curve before other transformations.
    m_ParentProp->GetBasicTransformation( m_Chord, mat );
    m_TransformedCurve.Transform( mat );

    mat.loadIdentity();

    // Propeller rotation first because order is reversed.
    mat.rotateX( -m_Reverse * m_PropRot );

    mat.translatef( m_FoldOrigin.x(), m_FoldOrigin.y(), m_FoldOrigin.z() );
    mat.rotate( m_FoldAngle * PI / 180.0, m_FoldDirection );
    mat.translatef( -m_FoldOrigin.x(), -m_FoldOrigin.y(), -m_FoldOrigin.z() );

    mat.rotateY( m_Reverse * m_Feather );

    mat.translatef( 0, m_Radius, 0 );

    mat.rotateY( m_Reverse * m_Twist );

    mat.rotateX( m_XRotate ); // About rake direction

    mat.translatef( m_Rake, 0, m_Reverse * m_Skew );

    mat.rotateZ( m_ZRotate ); // About chord

    m_TransformedCurve.Transform( mat );
}
Example #2
0
void PropGeom::UpdateDrawObj()
{
    GeomXSec::UpdateDrawObj();

    double axlen = 1.0;

    Vehicle *veh = VehicleMgr.GetVehicle();
    if ( veh )
    {
        axlen = veh->m_AxisLength();
    }

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

    double data[16];
    m_ModelMatrix.getMat( data );

    vec3d cen( 0, 0, 0 );
    vec3d rotdir( -1, 0, 0 );
    vec3d thrustdir( -1, 0, 0 );
    rotdir = rotdir * rev;

    cen = m_ModelMatrix.xform( cen );
    rotdir = m_ModelMatrix.xform( rotdir ) - cen;
    thrustdir = m_ModelMatrix.xform( thrustdir ) - cen;

    Matrix4d mat;
    mat.loadIdentity();
    mat.rotateX( -rev * m_Rotate() );
    mat.postMult( data );

    vec3d pmid = mat.xform( m_FoldAxOrigin );
    vec3d ptstart = mat.xform( m_FoldAxOrigin + m_FoldAxDirection * axlen / 2.0 );
    vec3d ptend = mat.xform( m_FoldAxOrigin - m_FoldAxDirection * axlen / 2.0 );


    vec3d dir = ptend - ptstart;
    dir.normalize();

    m_ArrowLinesDO.m_PntVec.clear();
    m_ArrowHeadDO.m_PntVec.clear();

    m_ArrowLinesDO.m_PntVec.push_back( ptstart );
    m_ArrowLinesDO.m_PntVec.push_back( ptend );
    m_ArrowLinesDO.m_PntVec.push_back( cen );
    m_ArrowLinesDO.m_PntVec.push_back( cen + thrustdir * axlen );

    MakeArrowhead( cen + thrustdir * axlen, thrustdir, 0.25 * axlen, m_ArrowHeadDO.m_PntVec );
    MakeCircleArrow( pmid, dir, 0.5 * axlen, m_ArrowLinesDO, m_ArrowHeadDO );
    MakeCircleArrow( cen, rotdir, 0.5 * axlen, m_ArrowLinesDO, m_ArrowHeadDO );

}
Example #3
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 );
}