bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName,
        double aMMtoWRMLunit, bool aExport3DFiles,
        const wxString& a3D_Subdir )
{
    wxString        msg;
    BOARD*          pcb = GetBoard();
    bool            ok  = true;

    MODEL_VRML model3d;

    model_vrml = &model3d;
    std::ofstream output_file;

    try
    {
        output_file.exceptions( std::ofstream::failbit );
        output_file.open( TO_UTF8( aFullFileName ), std::ios_base::out );

        // Switch the locale to standard C (needed to print floating point numbers like 1.3)
        SetLocaleTo_C_standard();

        // Begin with the usual VRML boilerplate
        wxString name = aFullFileName;

        name.Replace( wxT( "\\" ), wxT( "/" ) );
        ChangeIllegalCharacters( name, false );

        output_file << "#VRML V2.0 utf8\n";
        output_file << "WorldInfo {\n";
        output_file << "  title \"" << TO_UTF8( name ) << " - Generated by Pcbnew\"\n";
        output_file << "}\n";

        // Set the VRML world scale factor
        model3d.SetScale( aMMtoWRMLunit );

        output_file << "Transform {\n";

        // compute the offset to center the board on (0, 0, 0)
        // XXX - NOTE: we should allow the user a GUI option to specify the offset
        EDA_RECT bbbox = pcb->ComputeBoundingBox();

        model3d.SetOffset( -model3d.scale * bbbox.Centre().x,
                           model3d.scale * bbbox.Centre().y );

        output_file << "  children [\n";

        // Preliminary computation: the z value for each layer
        compute_layer_Zs( model3d, pcb );

        // board edges and cutouts
        export_vrml_board( model3d, pcb );

        // Drawing and text on the board
        export_vrml_drawings( model3d, pcb );

        // Export vias and trackage
        export_vrml_tracks( model3d, pcb );

        // Export zone fills
        export_vrml_zones( model3d, pcb);

        /* scaling factor to convert 3D models to board units (decimils)
         * Usually we use Wings3D to create thems.
         * One can consider the 3D units is 0.1 inch (2.54 mm)
         * So the scaling factor from 0.1 inch to board units
         * is 2.54 * aMMtoWRMLunit
         */
        double wrml_3D_models_scaling_factor = 2.54 * aMMtoWRMLunit;

        // Export footprints
        for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
            export_vrml_module( model3d, pcb, module, output_file,
                                wrml_3D_models_scaling_factor,
                                aExport3DFiles, a3D_Subdir );

            // write out the board and all layers
            write_layers( model3d, output_file, pcb );

        // Close the outer 'transform' node
        output_file << "]\n}\n";
    }
    catch( const std::exception& e )
    {
        wxString msg;
        msg << _( "IDF Export Failed:\n" ) << FROM_UTF8( e.what() );
        wxMessageBox( msg );

        ok = false;
    }

    // End of work
    output_file.exceptions( std::ios_base::goodbit );
    output_file.close();
    SetLocaleTo_Default();       // revert to the current  locale

    return ok;
}
Beispiel #2
0
/* Note1:
 * When copying 3D shapes files, the new filename is build from
 * the full path name, changing the separators by underscore.
 * this is needed because files with the same shortname can exist in different directories
 * Note 2:
 * ExportVRML_File generates coordinates in board units (BIU) inside the file.
 * (TODO: use mm inside the file)
 * A general scale transform is applied to the whole file
 * (1.0 to have the actual WRML unit im mm, 0.001 to have the actual WRML unit im meter
 * Note 3:
 * For 3D models built by a 3D modeler, the unit is 0,1 inch
 * A specfic scale is applied to 3D models to convert them to BIU
 *
 */
bool PCB_EDIT_FRAME::ExportVRML_File( const wxString & aFullFileName,
                                      double aMMtoWRMLunit, bool aExport3DFiles,
                                      const wxString & a3D_Subdir )
{
    wxString   msg;
    FILE*      output_file;
    BOARD*     pcb = GetBoard();

    output_file = wxFopen( aFullFileName, wxT( "wt" ) );
    if( output_file == NULL )
        return false;

    // Switch the locale to standard C (needed to print floating point numbers like 1.3)
    SetLocaleTo_C_standard();

    // Begin with the usual VRML boilerplate
    wxString name = aFullFileName;

    name.Replace(wxT("\\"), wxT("/" ) );
    ChangeIllegalCharacters( name, false );
    fprintf( output_file, "#VRML V2.0 utf8\n"
                          "WorldInfo {\n"
                          "  title \"%s - Generated by Pcbnew\"\n"
                          "}\n", TO_UTF8( name ) );

    /* The would be in BIU and not in meters, as the standard wants.
     * It is trivial to embed everything in a transform node to
     * fix it. For example here we build the world in inches...
    */

    // Global VRML scale to export to a different scale.
    // (aMMtoWRMLScale = 1.0 to export in mm)
    double boardIU2WRML = aMMtoWRMLunit / MM_PER_IU;
    fprintf( output_file, "Transform {\n" );

    /* Define the translation to have the board centre to the 2D axis origin
     * more easy for rotations...
     */
    EDA_RECT bbbox = pcb->ComputeBoundingBox();

    double dx = boardIU2WRML * bbbox.Centre().x;
    double dy = boardIU2WRML * bbbox.Centre().y;

    fprintf( output_file, "  translation %g %g 0.0\n", -dx, dy );
    fprintf( output_file, "  children [\n" );

    // Preliminary computation: the z value for each layer
    compute_layer_Zs( pcb );

    // Drawing and text on the board, and edges which are special
    export_vrml_drawings( pcb );

    // Export vias and trackage
    export_vrml_tracks( pcb );

    // Export zone fills
/* TODO    export_vrml_zones(pcb);
*/

    /* scaling factor to convert 3D models to board units (decimils)
     * Usually we use Wings3D to create thems.
     * One can consider the 3D units is 0.1 inch (2.54 mm)
     * So the scaling factor from 0.1 inch to board units
     * is 2.54 * aMMtoWRMLunit
     */
    double wrml_3D_models_scaling_factor = 2.54 * aMMtoWRMLunit;
    // Export footprints
    for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
        export_vrml_module( pcb, module, output_file,
                            wrml_3D_models_scaling_factor,
                            aExport3DFiles, a3D_Subdir,
                            boardIU2WRML );

    /* Output the bagged triangles for each layer
     * Each layer will be a separate shape */
    for( int layer = 0; layer < LAYER_COUNT; layer++ )
        write_and_empty_triangle_bag( output_file,
                                      layer_triangles[layer],
                                      pcb->GetLayerColor(layer),
                                      boardIU2WRML );

    // Same thing for the via layers
    for( int i = 0; i < 4; i++ )
        write_and_empty_triangle_bag( output_file,
                                      via_triangles[i],
                                      pcb->GetVisibleElementColor( VIAS_VISIBLE + i ),
                                      boardIU2WRML );

    // Close the outer 'transform' node
    fputs( "]\n}\n", output_file );

    // End of work
    fclose( output_file );
    SetLocaleTo_Default();       // revert to the current  locale

    return true;
}
static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule,
        std::ofstream& aOutputFile,
        double aVRMLModelsToBiu,
        bool aExport3DFiles, const wxString& a3D_Subdir )
{
    // Reference and value
    if( aModule->Reference().IsVisible() )
        export_vrml_text_module( &aModule->Reference() );

    if( aModule->Value().IsVisible() )
        export_vrml_text_module( &aModule->Value() );

    // Export module edges
    for( EDA_ITEM* item = aModule->GraphicalItems(); item; item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
            export_vrml_text_module( static_cast<TEXTE_MODULE*>( item ) );
            break;

        case PCB_MODULE_EDGE_T:
            export_vrml_edge_module( aModel, static_cast<EDGE_MODULE*>( item ),
                                     aModule->GetOrientation() );
            break;

        default:
            break;
        }
    }

    // Export pads
    for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
        export_vrml_pad( aModel, aPcb, pad );

    bool isFlipped = aModule->GetLayer() == B_Cu;

    // Export the object VRML model(s)
    for( S3D_MASTER* vrmlm = aModule->Models();  vrmlm;  vrmlm = vrmlm->Next() )
    {
        if( !vrmlm->Is3DType( S3D_MASTER::FILE3D_VRML ) )
            continue;

        wxString fname = vrmlm->GetShape3DFullFilename();

        fname.Replace( wxT( "\\" ), wxT( "/" ) );
        wxString source_fname = fname;

        if( aExport3DFiles )
        {
            // Change illegal characters in filenames
            ChangeIllegalCharacters( fname, true );
            fname = a3D_Subdir + wxT( "/" ) + fname;

            if( !wxFileExists( fname ) )
                wxCopyFile( source_fname, fname );
        }

        /* Calculate 3D shape rotation:
         * this is the rotation parameters, with an additional 180 deg rotation
         * for footprints that are flipped
         * When flipped, axis rotation is the horizontal axis (X axis)
         */
        double rotx = -vrmlm->m_MatRotation.x;
        double roty = -vrmlm->m_MatRotation.y;
        double rotz = -vrmlm->m_MatRotation.z;

        if( isFlipped )
        {
            rotx += 180.0;
            NEGATE( roty );
            NEGATE( rotz );
        }

        // Do some quaternion munching
        double q1[4], q2[4], rot[4];
        build_quat( 1, 0, 0, DEG2RAD( rotx ), q1 );
        build_quat( 0, 1, 0, DEG2RAD( roty ), q2 );
        compose_quat( q1, q2, q1 );
        build_quat( 0, 0, 1, DEG2RAD( rotz ), q2 );
        compose_quat( q1, q2, q1 );

        // Note here aModule->GetOrientation() is in 0.1 degrees,
        // so module rotation has to be converted to radians
        build_quat( 0, 0, 1, DECIDEG2RAD( aModule->GetOrientation() ), q2 );
        compose_quat( q1, q2, q1 );
        from_quat( q1, rot );

        aOutputFile << "Transform {\n";

        // A null rotation would fail the acos!
        if( rot[3] != 0.0 )
        {
            aOutputFile << "  rotation " << std::setprecision( 3 );
            aOutputFile << rot[0] << " " << rot[1] << " " << rot[2] << " " << rot[3] << "\n";
        }

        // adjust 3D shape local offset position
        // they are given in inch, so they are converted in board IU.
        double offsetx = vrmlm->m_MatPosition.x * IU_PER_MILS * 1000.0;
        double offsety = vrmlm->m_MatPosition.y * IU_PER_MILS * 1000.0;
        double offsetz = vrmlm->m_MatPosition.z * IU_PER_MILS * 1000.0;

        if( isFlipped )
            NEGATE( offsetz );
        else // In normal mode, Y axis is reversed in Pcbnew.
            NEGATE( offsety );

        RotatePoint( &offsetx, &offsety, aModule->GetOrientation() );

        aOutputFile << "  translation " << std::setprecision( aModel.precision );
        aOutputFile << (( offsetx + aModule->GetPosition().x) * aModel.scale + aModel.tx ) << " ";
        aOutputFile << ( -(offsety + aModule->GetPosition().y) * aModel.scale - aModel.ty ) << " ";
        aOutputFile << ( (offsetz * aModel.scale ) + aModel.GetLayerZ( aModule->GetLayer() ) ) << "\n";

        aOutputFile << "  scale ";
        aOutputFile << ( vrmlm->m_MatScale.x * aVRMLModelsToBiu ) << " ";
        aOutputFile << ( vrmlm->m_MatScale.y * aVRMLModelsToBiu ) << " ";
        aOutputFile << ( vrmlm->m_MatScale.z * aVRMLModelsToBiu ) << "\n";

        if( fname.EndsWith( wxT( "x3d" ) ) )
        {
            X3D_MODEL_PARSER* parser = new X3D_MODEL_PARSER( vrmlm );

            if( parser )
            {
                // embed x3d model in vrml format
                double vrml_to_x3d = aVRMLModelsToBiu;
                parser->Load( fname, vrml_to_x3d );

                try
                {
                    aOutputFile << "  children [\n ";
                    aOutputFile << TO_UTF8( parser->VRML2_representation() ) << " ]\n";
                    aOutputFile << "  }\n";
                }
                catch( const std::exception& e )
                {
                    delete parser;
                    throw;
                }
            }
        }
        else
        {
            aOutputFile << "  children [\n    Inline {\n      url \"";
            aOutputFile << TO_UTF8( fname ) << "\"\n    } ]\n";
            aOutputFile << "  }\n";
        }
    }
}
Beispiel #4
0
static void export_vrml_module( BOARD* aPcb, MODULE* aModule,
                                FILE* aOutputFile,
                                double aVRMLModelsToBiu,
                                bool aExport3DFiles, const wxString & a3D_Subdir,
                                double boardIU2WRML )
{
    // Reference and value
    export_vrml_text_module( aModule->m_Reference );
    export_vrml_text_module( aModule->m_Value );

    // Export module edges
    for( EDA_ITEM* item = aModule->m_Drawings;  item != NULL;  item = item->Next() )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
            export_vrml_text_module( dynamic_cast<TEXTE_MODULE*>(item) );
            break;

        case PCB_MODULE_EDGE_T:
            export_vrml_edge_module( dynamic_cast<EDGE_MODULE*>(item) );
            break;

        default:
            break;
        }
    }

    // Export pads
    for( D_PAD* pad = aModule->m_Pads;  pad; pad = pad->Next() )
        export_vrml_pad( aPcb, pad );

    bool isFlipped = aModule->GetLayer() == LAYER_N_BACK;

    // Export the object VRML model(s)
    for( S3D_MASTER* vrmlm = aModule->m_3D_Drawings; vrmlm != 0; vrmlm = vrmlm->Next() )
    {
        wxString fname = vrmlm->m_Shape3DName;

        if( fname.IsEmpty() )
            continue;

        if( ! wxFileName::FileExists( fname ) )
        {
            wxFileName fn = fname;
            fname = wxGetApp().FindLibraryPath( fn );

            if( fname.IsEmpty() )   // keep "short" name if full filemane not found
                fname = vrmlm->m_Shape3DName;
        }

        fname.Replace(wxT("\\"), wxT("/" ) );
        wxString source_fname = fname;

        if( aExport3DFiles )    // Change illegal characters in short filename
        {
            ChangeIllegalCharacters( fname, true );
            fname = a3D_Subdir + wxT("/") + fname;

            if( !wxFileExists( fname ) )
                wxCopyFile( source_fname, fname );
        }

        /* Calculate 3D shape rotation:
         * this is the rotation parameters, with an additional 180 deg rotation
         * for footprints that are flipped
         * When flipped, axis rotation is the horizontal axis (X axis)
         */
        double rotx = - vrmlm->m_MatRotation.x;
        double roty = - vrmlm->m_MatRotation.y;
        double rotz = - vrmlm->m_MatRotation.z;

        if ( isFlipped )
        {
            rotx += 180.0;
            NEGATE(roty);
            NEGATE(rotz);
        }

        // Do some quaternion munching
        double q1[4], q2[4], rot[4];
        build_quat( 1, 0, 0, rotx / 180.0 * M_PI, q1 );
        build_quat( 0, 1, 0, roty / 180.0 * M_PI, q2 );
        compose_quat( q1, q2, q1 );
        build_quat( 0, 0, 1, rotz / 180.0 * M_PI, q2 );
        compose_quat( q1, q2, q1 );
        // Note here aModule->GetOrientation() is in 0.1 degrees,
        // so module rotation is aModule->GetOrientation() / 1800.0
        build_quat( 0, 0, 1, aModule->GetOrientation() / 1800.0 * M_PI, q2 );
        compose_quat( q1, q2, q1 );
        from_quat( q1, rot );

        fprintf( aOutputFile, "Transform {\n" );
        // A null rotation would fail the acos!
        if( rot[3] != 0.0 )
        {
            fprintf( aOutputFile, "  rotation %g %g %g %g\n", rot[0], rot[1], rot[2], rot[3] );
        }

        // adjust 3D shape offset position
        int offsetx = vrmlm->m_MatPosition.x;
        int offsety = vrmlm->m_MatPosition.y;
        double offsetz = vrmlm->m_MatPosition.z;

        if ( isFlipped )
            NEGATE(offsetz);
        else    // In normal mode, Y axis is reversed in Pcbnew.
            NEGATE(offsety);

        RotatePoint(&offsetx, &offsety, aModule->GetOrientation());

        fprintf( aOutputFile, "  translation %g %g %g\n",
                 (double) (offsetx + aModule->m_Pos.x) * boardIU2WRML,
                 - (double)(offsety + aModule->m_Pos.y) * boardIU2WRML,    // Y axis is reversed in Pcbnew
                 offsetz + layer_z[aModule->GetLayer()] * boardIU2WRML);

        fprintf( aOutputFile, "  scale %g %g %g\n",
                 vrmlm->m_MatScale.x * aVRMLModelsToBiu,
                 vrmlm->m_MatScale.y * aVRMLModelsToBiu,
                 vrmlm->m_MatScale.z * aVRMLModelsToBiu );

        fprintf( aOutputFile,
//                 "  children [\n    Inline {\n      url \"file://%s\"\n    } ]\n",
                 "  children [\n    Inline {\n      url \"%s\"\n    } ]\n",
                 TO_UTF8( fname ) );
        fprintf( aOutputFile, "  }\n" );
    }
}