Ejemplo n.º 1
0
bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
{
    // This is for python:
    if( aFileSet.size() != 1 )
    {
        UTF8 msg = StrPrintf( "Pcbnew:%s() takes only a single filename", __func__ );
        DisplayError( this, msg );
        return false;
    }

    wxString fullFileName( aFileSet[0] );

    // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
    wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "Path is not absolute!" ) );

    std::unique_ptr<wxSingleInstanceChecker> lockFile = ::LockFile( fullFileName );

    if( !lockFile )
    {
        wxString msg = wxString::Format( _( "PCB file \"%s\" is already open." ), fullFileName );
        DisplayError( this, msg );
        return false;
    }

    if( GetScreen()->IsModify() && !GetBoard()->IsEmpty() )
    {
        if( !HandleUnsavedChanges( this, _( "The current PCB has been modified.  Save changes?" ),
            [&]()->bool { return SavePcbFile( GetBoard()->GetFileName(), CREATE_BACKUP_FILE ); } ) )
        {
            return false;
        }
    }

    // Release the lock file, until the new file is actually loaded
    ReleaseFile();

    wxFileName pro = fullFileName;
    pro.SetExt( ProjectFileExtension );

    bool is_new = !wxFileName::IsFileReadable( fullFileName );

    // If its a non-existent schematic and caller thinks it exists
    if( is_new && !( aCtl & KICTL_CREATE ) )
    {
        // notify user that fullFileName does not exist, ask if user wants to create it.
        wxString ask = wxString::Format( _( "PCB \"%s\" does not exist.  Do you wish to create it?" ),
                                         fullFileName );
        if( !IsOK( this, ask ) )
            return false;
    }

    Clear_Pcb( false );     // pass false since we prompted above for a modified board

    IO_MGR::PCB_FILE_T  pluginType = plugin_type( fullFileName, aCtl );

    bool converted =  pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD_SEXP;

    if( !converted )
    {
        // PROJECT::SetProjectFullName() is an impactful function.  It should only be
        // called under carefully considered circumstances.

        // The calling code should know not to ask me here to change projects unless
        // it knows what consequences that will have on other KIFACEs running and using
        // this same PROJECT.  It can be very harmful if that calling code is stupid.
        Prj().SetProjectFullName( pro.GetFullPath() );

        // load project settings before BOARD
        LoadProjectSettings();
    }

    if( is_new )
    {
        OnModify();
    }
    else
    {
        BOARD* loadedBoard = 0;   // it will be set to non-NULL if loaded OK

        PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );

        // This will rename the file if there is an autosave and the user want to recover
		CheckForAutoSaveFile( fullFileName );

        try
        {
            PROPERTIES  props;
            char        xbuf[30];
            char        ybuf[30];

            // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
            sprintf( xbuf, "%d", GetPageSizeIU().x );
            sprintf( ybuf, "%d", GetPageSizeIU().y );

            props["page_width"]  = xbuf;
            props["page_height"] = ybuf;

#if USE_INSTRUMENTATION
            // measure the time to load a BOARD.
            unsigned startTime = GetRunningMicroSecs();
#endif

            loadedBoard = pi->Load( fullFileName, NULL, &props );

#if USE_INSTRUMENTATION
            unsigned stopTime = GetRunningMicroSecs();
            printf( "PLUGIN::Load(): %u usecs\n", stopTime - startTime );
#endif
        }
        catch( const IO_ERROR& ioe )
        {
            if( ioe.Problem() != wxT( "CANCEL" ) )
            {
                wxString msg = wxString::Format( _( "Error loading board file:\n%s" ), fullFileName );
                DisplayErrorMessage( this, msg, ioe.What() );
            }

            return false;
        }


        // 6.0 TODO: some settings didn't make it into the board file in 5.1 so as not to
        // change the file format.  For 5.1 we must copy them across from the config-initialized
        // board.
        BOARD_DESIGN_SETTINGS& bds = loadedBoard->m_designSettings;
        BOARD_DESIGN_SETTINGS& configBds = GetBoard()->GetDesignSettings();

        bds.m_RequireCourtyards                 = configBds.m_RequireCourtyards;
        bds.m_ProhibitOverlappingCourtyards     = configBds.m_ProhibitOverlappingCourtyards;
        bds.m_HoleToHoleMin                     = configBds.m_HoleToHoleMin;
        bds.m_LineThickness[LAYER_CLASS_OTHERS] = configBds.m_LineThickness[LAYER_CLASS_OTHERS];
        bds.m_TextSize[LAYER_CLASS_OTHERS]      = configBds.m_TextSize[LAYER_CLASS_OTHERS];
        bds.m_TextThickness[LAYER_CLASS_OTHERS] = configBds.m_TextThickness[LAYER_CLASS_OTHERS];
        std::copy( configBds.m_TextItalic,  configBds.m_TextItalic + 4,  bds.m_TextItalic );
        std::copy( configBds.m_TextUpright, configBds.m_TextUpright + 4, bds.m_TextUpright );
        bds.m_DiffPairDimensionsList            = configBds.m_DiffPairDimensionsList;
        bds.m_CopperEdgeClearance               = configBds.m_CopperEdgeClearance;

        SetBoard( loadedBoard );

        // we should not ask PLUGINs to do these items:
        loadedBoard->BuildListOfNets();
        loadedBoard->SynchronizeNetsAndNetClasses();

        // If this is a legacy board then we set the copper edge clearance to 1/2 the edge-cut
        // line width (which was a legacy kludge for implementing edge clearances).
        if( bds.m_CopperEdgeClearance == Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ) )
            bds.SetCopperEdgeClearance( inferLegacyEdgeClearance( loadedBoard ) );

        if( loadedBoard->IsModified() )
            OnModify();
        else
            GetScreen()->ClrModify();

        if( pluginType == IO_MGR::LEGACY &&
            loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION )
        {
            DisplayInfoMessage( this,
                _(  "This file was created by an older version of Pcbnew.\n"
                    "It will be stored in the new file format when you save this file again." ) );
        }
    }

    {
        wxFileName fn = fullFileName;

        if( converted )
            fn.SetExt( PcbFileExtension );

        wxString fname = fn.GetFullPath();

        fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );

        GetBoard()->SetFileName( fname );
    }

    // Lock the file newly opened:
    m_file_checker.reset( lockFile.release() );

    if( !converted )
        UpdateFileHistory( GetBoard()->GetFileName() );

    // Rebuild the new pad list (for drc and ratsnet control ...)
    GetBoard()->m_Status_Pcb = 0;

    // Select netclass Default as current netclass (it always exists)
    SetCurrentNetClass( NETCLASS::Default );

    // Rebuild list of nets (full ratsnest rebuild)
    Compile_Ratsnest( NULL, true );
    GetBoard()->BuildConnectivity();

    onBoardLoaded();

    // Refresh the 3D view, if any
    EDA_3D_VIEWER* draw3DFrame = Get3DViewerFrame();

    if( draw3DFrame )
        draw3DFrame->NewDisplay();

#if 0 && defined(DEBUG)
    // Output the board object tree to stdout, but please run from command prompt:
    GetBoard()->Show( 0, std::cout );
#endif

    // from EDA_APPL which was first loaded BOARD only:
    {
        /* For an obscure reason the focus is lost after loading a board file
         * when starting up the process.
         * (seems due to the recreation of the layer manager after loading the file)
         * Give focus to main window and Drawpanel
         * must be done for these 2 windows (for an obscure reason ...)
         * Linux specific
         * This is more a workaround than a fix.
         */
        SetFocus();
        GetCanvas()->SetFocus();
    }

    return true;
}
void C3D_RENDER_OGL_LEGACY::reload( REPORTER *aStatusTextReporter )
{
    m_reloadRequested = false;

    ogl_free_all_display_lists();

    COBJECT2D_STATS::Instance().ResetStats();

#ifdef PRINT_STATISTICS_3D_VIEWER
    printf("InitSettings...\n");
#endif

    unsigned stats_startReloadTime = GetRunningMicroSecs();

    m_settings.InitSettings( aStatusTextReporter );

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_endReloadTime = GetRunningMicroSecs();
#endif

    SFVEC3F camera_pos = m_settings.GetBoardCenter3DU();
    m_settings.CameraGet().SetBoardLookAtPos( camera_pos );

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_start_OpenGL_Load_Time = GetRunningMicroSecs();
#endif

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Load OpenGL: board" ) );

    // Create Board
    // /////////////////////////////////////////////////////////////////////////

    CCONTAINER2D boardContainer;
    Convert_shape_line_polygon_to_triangles( m_settings.GetBoardPoly(),
                                             boardContainer,
                                             m_settings.BiuTo3Dunits(),
                                             (const BOARD_ITEM &)*m_settings.GetBoard() );

    const LIST_OBJECT2D &listBoardObject2d = boardContainer.GetList();

    if( listBoardObject2d.size() > 0 )
    {
        // We will set a unitary Z so it will in future used with transformations
        // since the board poly will be used not only to draw itself but also the
        // solder mask layers.
        const float layer_z_top = 1.0f;
        const float layer_z_bot = 0.0f;

        CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() );

        // Convert the list of objects(triangles) to triangle layer structure
        for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
             itemOnLayer != listBoardObject2d.end();
             ++itemOnLayer )
        {
            const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

            wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );

            const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;

            const SFVEC2F &v1 = tri->GetP1();
            const SFVEC2F &v2 = tri->GetP2();
            const SFVEC2F &v3 = tri->GetP3();

            add_triangle_top_bot( layerTriangles,
                                  v1,
                                  v2,
                                  v3,
                                  layer_z_top,
                                  layer_z_bot );
        }

        const SHAPE_POLY_SET &boardPoly = m_settings.GetBoardPoly();

        wxASSERT( boardPoly.OutlineCount() > 0 );

        if( boardPoly.OutlineCount() > 0 )
        {
            layerTriangles->AddToMiddleContourns( boardPoly,
                                                  layer_z_bot,
                                                  layer_z_top,
                                                  m_settings.BiuTo3Dunits(),
                                                  false );

            m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
                                                                m_ogl_circle_texture,
                                                                layer_z_top,
                                                                layer_z_top );
        }

        delete layerTriangles;
    }

    // Create Through Holes and vias
    // /////////////////////////////////////////////////////////////////////////

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Load OpenGL: holes and vias" ) );

    m_ogl_disp_list_through_holes_outer = generate_holes_display_list(
                m_settings.GetThroughHole_Outer().GetList(),
                m_settings.GetThroughHole_Outer_poly(),
                1.0f,
                0.0f,
                false );

    SHAPE_POLY_SET bodyHoles = m_settings.GetThroughHole_Outer_poly();

    bodyHoles.BooleanAdd( m_settings.GetThroughHole_Outer_poly_NPTH(),
                          SHAPE_POLY_SET::PM_FAST );

    m_ogl_disp_list_through_holes_outer_with_npth = generate_holes_display_list(
                m_settings.GetThroughHole_Outer().GetList(),
                bodyHoles,
                1.0f,
                0.0f,
                false );

    m_ogl_disp_list_through_holes_inner = generate_holes_display_list(
                m_settings.GetThroughHole_Inner().GetList(),
                m_settings.GetThroughHole_Inner_poly(),
                1.0f,
                0.0f,
                true );


    m_ogl_disp_list_through_holes_vias_outer = generate_holes_display_list(
                m_settings.GetThroughHole_Vias_Outer().GetList(),
                m_settings.GetThroughHole_Vias_Outer_poly(),
                1.0f,
                0.0f,
                false );

    // Not in use
    //m_ogl_disp_list_through_holes_vias_inner = generate_holes_display_list(
    //      m_settings.GetThroughHole_Vias_Inner().GetList(),
    //      m_settings.GetThroughHole_Vias_Inner_poly(),
    //      1.0f, 0.0f,
    //      false );

    const MAP_POLY & innerMapHoles = m_settings.GetPolyMapHoles_Inner();
    const MAP_POLY & outerMapHoles = m_settings.GetPolyMapHoles_Outer();

    wxASSERT( innerMapHoles.size() == outerMapHoles.size() );

    const MAP_CONTAINER_2D &map_holes = m_settings.GetMapLayersHoles();

    if( outerMapHoles.size() > 0 )
    {
        float layer_z_bot = 0.0f;
        float layer_z_top = 0.0f;

        for( MAP_POLY::const_iterator ii = outerMapHoles.begin();
             ii != outerMapHoles.end();
             ++ii )
        {
            LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);
            const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
            const CBVHCONTAINER2D *container = map_holes.at( layer_id );

            get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );

            m_ogl_disp_lists_layers_holes_outer[layer_id] = generate_holes_display_list(
                        container->GetList(),
                        *poly,
                        layer_z_top,
                        layer_z_bot,
                        false );
        }

        for( MAP_POLY::const_iterator ii = innerMapHoles.begin();
             ii != innerMapHoles.end();
             ++ii )
        {
            LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);
            const SHAPE_POLY_SET *poly = static_cast<const SHAPE_POLY_SET *>(ii->second);
            const CBVHCONTAINER2D *container = map_holes.at( layer_id );

            get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );

            m_ogl_disp_lists_layers_holes_inner[layer_id] = generate_holes_display_list(
                        container->GetList(),
                        *poly,
                        layer_z_top,
                        layer_z_bot,
                        false );
        }
    }

    // Generate vertical cylinders of vias and pads (copper)
    generate_3D_Vias_and_Pads();

    // Add layers maps
    // /////////////////////////////////////////////////////////////////////////

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Load OpenGL: layers" ) );

    for( MAP_CONTAINER_2D::const_iterator ii = m_settings.GetMapLayers().begin();
         ii != m_settings.GetMapLayers().end();
         ++ii )
    {
        LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);

        if( !m_settings.Is3DLayerEnabled( layer_id ) )
            continue;

        const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(ii->second);
        const LIST_OBJECT2D &listObject2d = container2d->GetList();

        if( listObject2d.size() == 0 )
            continue;

        float layer_z_bot = 0.0f;
        float layer_z_top = 0.0f;

        get_layer_z_pos( layer_id, layer_z_top, layer_z_bot );

        // Calculate an estimation for the nr of triangles based on the nr of objects
        unsigned int nrTrianglesEstimation = listObject2d.size() * 8;

        CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation );

        m_triangles[layer_id] = layerTriangles;

        for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
             itemOnLayer != listObject2d.end();
             ++itemOnLayer )
        {
            const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);

            switch( object2d_A->GetObjectType() )
            {
                case OBJ2D_FILLED_CIRCLE:
                    add_object_to_triangle_layer( (const CFILLEDCIRCLE2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_POLYGON4PT:
                    add_object_to_triangle_layer( (const CPOLYGON4PTS2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_RING:
                    add_object_to_triangle_layer( (const CRING2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_TRIANGLE:
                    add_object_to_triangle_layer( (const CTRIANGLE2D *)object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                case OBJ2D_ROUNDSEG:
                    add_object_to_triangle_layer( (const CROUNDSEGMENT2D *) object2d_A,
                                                  layerTriangles,
                                                  layer_z_top, layer_z_bot );
                break;

                default:
                    wxFAIL_MSG("C3D_RENDER_OGL_LEGACY: Object type is not implemented");
                break;
            }
        }

        const MAP_POLY &map_poly = m_settings.GetPolyMap();

        if( map_poly.find( layer_id ) != map_poly.end() )
        {
            const SHAPE_POLY_SET *polyList = map_poly.at( layer_id );

            layerTriangles->AddToMiddleContourns( *polyList,
                                                  layer_z_bot,
                                                  layer_z_top,
                                                  m_settings.BiuTo3Dunits(),
                                                  false );
        }

        // Create display list
        // /////////////////////////////////////////////////////////////////////
        m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
                                                                        m_ogl_circle_texture,
                                                                        layer_z_bot,
                                                                        layer_z_top );
    }// for each layer on map

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_end_OpenGL_Load_Time = GetRunningMicroSecs();
#endif

    // Load 3D models
    // /////////////////////////////////////////////////////////////////////////
#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_start_models_Load_Time = GetRunningMicroSecs();
#endif

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Loading 3D models" ) );

    load_3D_models();

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_end_models_Load_Time = GetRunningMicroSecs();


    printf( "C3D_RENDER_OGL_LEGACY::reload times:\n" );
    printf( "  Reload board:             %.3f ms\n",
            (float)( stats_endReloadTime        - stats_startReloadTime        ) / 1000.0f );
    printf( "  Loading to openGL:        %.3f ms\n",
            (float)( stats_end_OpenGL_Load_Time - stats_start_OpenGL_Load_Time ) / 1000.0f );
    printf( "  Loading 3D models:        %.3f ms\n",
            (float)( stats_end_models_Load_Time - stats_start_models_Load_Time ) / 1000.0f );
    COBJECT2D_STATS::Instance().PrintStats();
#endif

    if( aStatusTextReporter )
    {
        // Calculation time in seconds
        const double calculation_time = (double)( GetRunningMicroSecs() -
                                                  stats_startReloadTime) / 1e6;

        aStatusTextReporter->Report( wxString::Format( _( "Reload time %.3f s" ),
                                                       calculation_time ) );
    }
}
void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch )
{
    if( m_tree == NULL )
        return;
//#define SHOW_CALC_TIME      // uncomment this to show calculation time

#ifdef SHOW_CALC_TIME
    unsigned starttime =  GetRunningMicroSecs();
#endif

    // We score the list by going through it several time, essentially with a complexity
    // of O(n). For the default library of 2000+ items, this typically takes less than 5ms
    // on an i5. Good enough, no index needed.

    // Initial AND condition: Leaf nodes are considered to match initially.
    for( TREE_NODE* node : m_nodes )
    {
        node->PreviousScore = node->MatchScore;
        node->MatchScore = ( node->Type == TREE_NODE::TYPE_LIB ) ? 0 : kLowestDefaultScore;
    }

    // Create match scores for each node for all the terms, that come space-separated.
    // Scoring adds up values for each term according to importance of the match. If a term does
    // not match at all, the result is thrown out of the results (AND semantics).
    // From high to low
    //   - Exact match for a ccmponent name gives the highest score, trumping all.
    //   - A positional score depending of where a term is found as substring; prefix-match: high.
    //   - substring-match in library name.
    //   - substring match in keywords and descriptions with positional score. Keywords come
    //     first so contribute more to the score.
    //
    // This is of course subject to tweaking.
    wxStringTokenizer tokenizer( aSearch );

    while ( tokenizer.HasMoreTokens() )
    {
        const wxString term = tokenizer.GetNextToken().Lower();
        EDA_COMBINED_MATCHER matcher( term );

        for( TREE_NODE* node : m_nodes )
        {
            if( node->Type != TREE_NODE::TYPE_ALIAS )
                continue;      // Only aliases are actually scored here.

            if( node->MatchScore == 0)
                continue;   // Leaf node without score are out of the game.

            // Keywords and description we only count if the match string is at
            // least two characters long. That avoids spurious, low quality
            // matches. Most abbreviations are at three characters long.
            int found_pos;
            int matcher_fired = 0;

            if( term == node->MatchName )
                node->MatchScore += 1000;  // exact match. High score :)
            else if( (found_pos = matcher.Find( node->MatchName, &matcher_fired ) ) != EDA_PATTERN_NOT_FOUND )
            {
                // Substring match. The earlier in the string the better.  score += 20..40
                node->MatchScore += matchPosScore( found_pos, 20 ) + 20;
            }
            else if( matcher.Find( node->Parent->MatchName, &matcher_fired ) != EDA_PATTERN_NOT_FOUND )
                node->MatchScore += 19;   // parent name matches.         score += 19
            else if( ( found_pos = matcher.Find( node->SearchText, &matcher_fired ) ) != EDA_PATTERN_NOT_FOUND )
            {
                // If we have a very short search term (like one or two letters), we don't want
                // to accumulate scores if they just happen to be in keywords or description as
                // almost any one or two-letter combination shows up in there.
                // For longer terms, we add scores 1..18 for positional match (higher in the
                // front, where the keywords are).                        score += 0..18
                node->MatchScore += ( ( term.length() >= 2 )
                                       ? matchPosScore( found_pos, 17 ) + 1
                                       : 0 );
            }
            else
                node->MatchScore = 0;    // No match. That's it for this item.

            node->MatchScore += 2 * matcher_fired;
        }
    }

    // Library nodes have the maximum score seen in any of their children.
    // Alias nodes have the score of their parents.
    unsigned highest_score_seen = 0;
    bool any_change = false;

    for( TREE_NODE* node : m_nodes )
    {
        switch( node->Type )
        {
        case TREE_NODE::TYPE_ALIAS:
            {
                any_change |= (node->PreviousScore != node->MatchScore);
                // Update library score.
                node->Parent->MatchScore = std::max( node->Parent->MatchScore, node->MatchScore );
                highest_score_seen = std::max( highest_score_seen, node->MatchScore );
            }
            break;

        case TREE_NODE::TYPE_UNIT:
            node->MatchScore = node->Parent->MatchScore;
            break;

        default:
            break;
        }
    }

    // The tree update might be slow, so we want to bail out if there is no change.
    if( !any_change )
        return;

    // Now: sort all items according to match score, libraries first.
    std::sort( m_nodes.begin(), m_nodes.end(), scoreComparator );

#ifdef SHOW_CALC_TIME
    unsigned sorttime = GetRunningMicroSecs();
#endif

    // Fill the tree with all items that have a match. Re-arranging, adding and removing changed
    // items is pretty complex, so we just re-build the whole tree.
    m_tree->Freeze();
    m_tree->DeleteAllItems();
    const wxTreeItemId root_id = m_tree->AddRoot( wxEmptyString );
    const TREE_NODE* first_match = NULL;
    const TREE_NODE* preselected_node = NULL;

    for( TREE_NODE* node : m_nodes )
    {
        if( node->MatchScore == 0 )
            continue;

        // If we have nodes that go beyond the default score, suppress nodes that
        // have the default score. That can happen if they have an honary += 0 score due to
        // some one-letter match in the keyword or description. In this case, we prefer matches
        // that just have higher scores. Improves relevancy and performance as the tree has to
        // display less items.
        if( highest_score_seen > kLowestDefaultScore && node->MatchScore == kLowestDefaultScore )
            continue;

        wxString node_text;
#if 0
        // Node text with scoring information for debugging
        node_text.Printf( wxT("%s (s=%u)%s"), GetChars(node->DisplayName),
                          node->MatchScore, GetChars( node->DisplayInfo ));
#else
        node_text = node->DisplayName + node->DisplayInfo;
#endif
        node->TreeId = m_tree->AppendItem( node->Parent ? node->Parent->TreeId : root_id,
                                           node_text );

        // If we are a nicely scored alias, we want to have it visible. Also, if there
        // is only a single library in this container, we want to have it unfolded
        // (example: power library).
        if( node->Type == TREE_NODE::TYPE_ALIAS
             && ( node->MatchScore > kLowestDefaultScore || m_libraries_added == 1 ) )
        {
            m_tree->Expand( node->TreeId );

            if( first_match == NULL )
                first_match = node;   // First, highest scoring: the "I am feeling lucky" element.
        }

        // The first node that matches our pre-select criteria is choosen. 'First node'
        // means, it shows up in the history, as the history node is displayed very first
        // (by virtue of alphabetical ordering)
        if( preselected_node == NULL
             && node->Type == TREE_NODE::TYPE_ALIAS
             && node->MatchName == m_preselect_node_name )
            preselected_node = node;

        // Refinement in case we come accross a matching unit node.
        if( preselected_node != NULL && preselected_node->Type == TREE_NODE::TYPE_ALIAS
             && node->Parent == preselected_node
             && m_preselect_unit_number >= 1 && node->Unit == m_preselect_unit_number )
            preselected_node = node;
    }

    if( first_match )                      // Highest score search match pre-selected.
    {
        m_tree->SelectItem( first_match->TreeId );
        m_tree->EnsureVisible( first_match->TreeId );
    }
    else if( preselected_node )            // No search, so history item preselected.
    {
        m_tree->SelectItem( preselected_node->TreeId );
        m_tree->EnsureVisible( preselected_node->TreeId );
    }

    m_tree->Thaw();

#ifdef SHOW_CALC_TIME
    unsigned endtime = GetRunningMicroSecs();
    wxLogMessage( wxT("sort components %.1f ms,  rebuild tree %.1f ms"),
                  double(sorttime-starttime)/1000.0, double(endtime-sorttime)/1000.0 );
#endif
}
Ejemplo n.º 4
0
bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
{
    // This is for python:
    if( aFileSet.size() != 1 )
    {
        UTF8 msg = StrPrintf( "Pcbnew:%s() takes only a single filename", __func__ );
        DisplayError( this, msg );
        return false;
    }

    wxString fullFileName( aFileSet[0] );

    // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
    wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(),
        wxT( "bug in single_top.cpp or project manager." ) );

    if( !LockFile( fullFileName ) )
    {
        wxString msg = wxString::Format( _(
                "PCB file '%s' is already open." ),
                GetChars( fullFileName )
                );
        DisplayError( this, msg );
        return false;
    }

    if( GetScreen()->IsModify() )
    {
        int response = YesNoCancelDialog( this, _(
            "The current board has been modified.  Do you wish to save the changes?" ),
            wxEmptyString,
            _( "Save and Load" ),
            _( "Load Without Saving" )
            );

        if( response == wxID_CANCEL )
            return false;
        else if( response == wxID_YES )
            SavePcbFile( GetBoard()->GetFileName(), CREATE_BACKUP_FILE );
        else
        {
            // response == wxID_NO, fall thru
        }
    }

    wxFileName pro = fullFileName;
    pro.SetExt( ProjectFileExtension );

    bool is_new = !wxFileName::IsFileReadable( fullFileName );

    // If its a non-existent schematic and caller thinks it exists
    if( is_new && !( aCtl & KICTL_CREATE ) )
    {
        // notify user that fullFileName does not exist, ask if user wants to create it.
        wxString ask = wxString::Format( _(
                "Board '%s' does not exist.  Do you wish to create it?" ),
                GetChars( fullFileName )
                );
        if( !IsOK( this, ask ) )
            return false;
    }

    Clear_Pcb( false );     // pass false since we prompted above for a modified board

    IO_MGR::PCB_FILE_T  pluginType = plugin_type( fullFileName, aCtl );

    bool converted =  pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD;

    if( !converted )
    {
        // PROJECT::SetProjectFullName() is an impactful function.  It should only be
        // called under carefully considered circumstances.

        // The calling code should know not to ask me here to change projects unless
        // it knows what consequences that will have on other KIFACEs running and using
        // this same PROJECT.  It can be very harmful if that calling code is stupid.
        Prj().SetProjectFullName( pro.GetFullPath() );

        // load project settings before BOARD
        LoadProjectSettings();
    }

    if( is_new )
    {
        OnModify();
    }
    else
    {
        BOARD* loadedBoard = 0;   // it will be set to non-NULL if loaded OK

        PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );

        try
        {
            PROPERTIES  props;
            char        xbuf[30];
            char        ybuf[30];

            // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
            sprintf( xbuf, "%d", GetPageSizeIU().x );
            sprintf( ybuf, "%d", GetPageSizeIU().y );

            props["page_width"]  = xbuf;
            props["page_height"] = ybuf;

#if USE_INSTRUMENTATION
            // measure the time to load a BOARD.
            unsigned startTime = GetRunningMicroSecs();
#endif

            loadedBoard = pi->Load( fullFileName, NULL, &props );

#if USE_INSTRUMENTATION
            unsigned stopTime = GetRunningMicroSecs();
            printf( "PLUGIN::Load(): %u usecs\n", stopTime - startTime );
#endif
        }
        catch( const IO_ERROR& ioe )
        {
            wxString msg = wxString::Format( _(
                    "Error loading board.\n%s" ),
                    GetChars( ioe.errorText )
                    );
            DisplayError( this, msg );

            return false;
        }

        SetBoard( loadedBoard );

        // we should not ask PLUGINs to do these items:
        loadedBoard->BuildListOfNets();
        loadedBoard->SynchronizeNetsAndNetClasses();

        SetStatusText( wxEmptyString );
        BestZoom();

        // update the layer names in the listbox
        ReCreateLayerBox( false );

        GetScreen()->ClrModify();

        {
            wxFileName fn = fullFileName;
            CheckForAutoSaveFile( fullFileName, fn.GetExt() );
        }

        if( pluginType == IO_MGR::LEGACY &&
            loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION )
        {
            DisplayInfoMessage( this,
                _(  "This file was created by an older version of Pcbnew.\n"
                    "It will be stored in the new file format when you save this file again." ) );
        }
    }

    {
        wxFileName fn = fullFileName;

        if( converted )
            fn.SetExt( PcbFileExtension );

        wxString fname = fn.GetFullPath();

        fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );

        GetBoard()->SetFileName( fname );
    }

    UpdateTitle();

    if( !converted )
        UpdateFileHistory( GetBoard()->GetFileName() );

    // Rebuild the new pad list (for drc and ratsnet control ...)
    GetBoard()->m_Status_Pcb = 0;

    // Update info shown by the horizontal toolbars
    SetCurrentNetClass( NETCLASS::Default );
    ReFillLayerWidget();
    ReCreateLayerBox();

    // upate the layer widget to match board visibility states, both layers and render columns.
    syncLayerVisibilities();
    syncLayerWidgetLayer();
    syncRenderStates();

    // Update the tracks / vias available sizes list:
    ReCreateAuxiliaryToolbar();

    // Update the RATSNEST items, which were not loaded at the time
    // BOARD::SetVisibleElements() was called from within any PLUGIN.
    // See case RATSNEST_VISIBLE: in BOARD::SetElementVisibility()
    GetBoard()->SetVisibleElements( GetBoard()->GetVisibleElements() );

    // Display the loaded board:
    Zoom_Automatique( false );

    // Compile ratsnest and displays net info
    {
        wxBusyCursor dummy;    // Displays an Hourglass while building connectivity
        Compile_Ratsnest( NULL, true );
        GetBoard()->GetRatsnest()->ProcessBoard();
    }

    SetMsgPanel( GetBoard() );

    // Refresh the 3D view, if any
    if( m_Draw3DFrame )
        m_Draw3DFrame->NewDisplay();

#if 0 && defined(DEBUG)
    // Output the board object tree to stdout, but please run from command prompt:
    GetBoard()->Show( 0, std::cout );
#endif

    // from EDA_APPL which was first loaded BOARD only:
    {
        /* For an obscure reason the focus is lost after loading a board file
         * when starting up the process.
         * (seems due to the recreation of the layer manager after loading the file)
         * Give focus to main window and Drawpanel
         * must be done for these 2 windows (for an obscure reason ...)
         * Linux specific
         * This is more a workaround than a fix.
         */
        SetFocus();
        GetCanvas()->SetFocus();
    }

    return true;
}
Ejemplo n.º 5
0
void EDA_3D_CANVAS::buildFootprintShape3DList( GLuint aOpaqueList,
                                               GLuint aTransparentList,
                                               REPORTER* aErrorMessages,
                                               REPORTER* aActivity )
{
    DBG( unsigned strtime = GetRunningMicroSecs() );

    if( aActivity )
        aActivity->Report( _( "Load 3D Shapes" ) );

    // clean the parser list if it have any already loaded files
    m_model_parsers_list.clear();
    m_model_filename_list.clear();

    BOARD* pcb = GetBoard();

    for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
        read3DComponentShape( module );

    DBG( printf( "  read3DComponentShape total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );

    DBG( strtime = GetRunningMicroSecs() );

    bool useMaterial = g_Parm_3D_Visu.GetFlag( FL_RENDER_MATERIAL );

    if( useMaterial )
    {
        // aOpaqueList is the gl list for non transparent items
        // aTransparentList is the gl list for non transparent items,
        // which need to be drawn after all other items

        glNewList( aOpaqueList, GL_COMPILE );
        bool loadOpaqueObjects = true;

        for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
            render3DComponentShape( module,  loadOpaqueObjects,
                                             !loadOpaqueObjects );

        glEndList();


        glNewList( aTransparentList, GL_COMPILE );
        bool loadTransparentObjects = true;

        for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
            render3DComponentShape( module, !loadTransparentObjects,
                                            loadTransparentObjects );

        glEndList();
    }
    else
    {
        // Just create one list
        glNewList( aOpaqueList, GL_COMPILE );

        for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
            render3DComponentShape( module, false, false );
        glEndList();
    }

    DBG( printf( "  render3DComponentShape total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
}
Ejemplo n.º 6
0
void EDA_3D_CANVAS::CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    BOARD* pcb = GetBoard();

    wxBusyCursor    dummy;

    // Build 3D board parameters:
    GetPrm3DVisu().InitSettings( pcb );

    glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );

    // Create axis gl list (if it is not shown, the list will be not called
    draw3DAxis();

    // Create Board full gl lists:

    if( ! m_glLists[GL_ID_BOARD] )
    {
        DBG( unsigned strtime = GetRunningMicroSecs() );

        m_glLists[GL_ID_BOARD] = glGenLists( 1 );
        m_glLists[GL_ID_BODY] = glGenLists( 1 );
        buildBoard3DView(m_glLists[GL_ID_BOARD], m_glLists[GL_ID_BODY], aErrorMessages, aActivity );
        CheckGLError( __FILE__, __LINE__ );

        DBG( printf( "  buildBoard3DView total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
    }

    if( ! m_glLists[GL_ID_TECH_LAYERS] )
    {
        DBG( unsigned strtime = GetRunningMicroSecs() );

        m_glLists[GL_ID_TECH_LAYERS] = glGenLists( 1 );
        glNewList( m_glLists[GL_ID_TECH_LAYERS], GL_COMPILE );
        // when calling BuildTechLayers3DView,
        // do not show warnings, which are the same as buildBoard3DView
        buildTechLayers3DView( aErrorMessages, aActivity );
        glEndList();
        CheckGLError( __FILE__, __LINE__ );

        DBG( printf( "  buildTechLayers3DView total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
    }

    if( ! m_glLists[GL_ID_AUX_LAYERS] )
    {
        DBG( unsigned strtime = GetRunningMicroSecs() );

        m_glLists[GL_ID_AUX_LAYERS] = glGenLists( 1 );
        glNewList( m_glLists[GL_ID_AUX_LAYERS], GL_COMPILE );
        buildBoard3DAuxLayers( aErrorMessages, aActivity );
        glEndList();
        CheckGLError( __FILE__, __LINE__ );

        DBG( printf( "  buildBoard3DAuxLayers total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
    }

    // draw modules 3D shapes
    if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] && isEnabled( FL_MODULE ) )
    {
        m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] = glGenLists( 1 );

        // GL_ID_3DSHAPES_TRANSP_FRONT is an auxiliary list for 3D shapes;
        // Ensure it is cleared before rebuilding it
        if( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
            glDeleteLists( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT], 1 );

        bool useMaterial = g_Parm_3D_Visu.GetFlag( FL_RENDER_MATERIAL );

        if( useMaterial )
            m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] = glGenLists( 1 );
        else
            m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] = 0;

        buildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT],
                                   m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT],
                                   aErrorMessages, aActivity );

        CheckGLError( __FILE__, __LINE__ );
    }

    calcBBox();

    // Create grid gl list
    if( ! m_glLists[GL_ID_GRID] )
    {
        m_glLists[GL_ID_GRID] = glGenLists( 1 );
        glNewList( m_glLists[GL_ID_GRID], GL_COMPILE );

        draw3DGrid( GetPrm3DVisu().m_3D_Grid );

        glEndList();
    }

    if( !m_glLists[GL_ID_SHADOW_FRONT] )
        m_glLists[GL_ID_SHADOW_FRONT] = glGenLists( 1 );

    if( !m_glLists[GL_ID_SHADOW_BACK] )
        m_glLists[GL_ID_SHADOW_BACK]  = glGenLists( 1 );

    if( !m_glLists[GL_ID_SHADOW_BOARD] )
        m_glLists[GL_ID_SHADOW_BOARD] = glGenLists( 1 );

    buildShadowList( m_glLists[GL_ID_SHADOW_FRONT],
                     m_glLists[GL_ID_SHADOW_BACK],
                     m_glLists[GL_ID_SHADOW_BOARD] );

    CheckGLError( __FILE__, __LINE__ );
}
Ejemplo n.º 7
0
void EDA_3D_CANVAS::Redraw()
{
    // SwapBuffer requires the window to be shown before calling
    if( !IsShownOnScreen() )
        return;

    wxString err_messages;
    WX_STRING_REPORTER errorReporter( &err_messages );
    STATUS_TEXT_REPORTER activityReporter( Parent(), 0 );

    // Display build time at the end of build
    unsigned strtime = GetRunningMicroSecs();

    GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );

    // Set the OpenGL viewport according to the client size of this canvas.
    // This is done here rather than in a wxSizeEvent handler because our
    // OpenGL rendering context (and thus viewport setting) is used with
    // multiple canvases: If we updated the viewport in the wxSizeEvent
    // handler, changing the size of one canvas causes a viewport setting that
    // is wrong when next another canvas is repainted.
    wxSize size = GetClientSize();

    InitGL();

    if( isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) )
    {
        generateFakeShadowsTextures( &errorReporter, &activityReporter );
    }

    // *MUST* be called *after* GL_CONTEXT_MANAGER::LockCtx():
    glViewport( 0, 0, size.x, size.y );

    // clear color and depth buffers
    glClearColor( 0.95, 0.95, 1.0, 1.0 );
    glClearStencil( 0 );
    glClearDepth( 1.0 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

    glShadeModel( GL_SMOOTH );

    // Draw background
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glDisable( GL_LIGHTING );
    glDisable( GL_COLOR_MATERIAL );
    glDisable( GL_DEPTH_TEST );
    glDisable( GL_TEXTURE_2D );

    // Draw the background ( rectangle with color gradient)
    glBegin( GL_QUADS );
    SetGLColor( GetPrm3DVisu().m_BgColor_Top, 1.0 );
    glVertex2f( -1.0, 1.0 );    // Top left corner

    SetGLColor( GetPrm3DVisu().m_BgColor, 1.0 );
    glVertex2f( -1.0,-1.0 );    // bottom left corner
    glVertex2f( 1.0,-1.0 );     // bottom right corner

    SetGLColor( GetPrm3DVisu().m_BgColor_Top, 1.0 );
    glVertex2f( 1.0, 1.0 );     // top right corner

    glEnd();
    glEnable( GL_DEPTH_TEST );


    // set viewing projection
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

#define MAX_VIEW_ANGLE 160.0 / 45.0

    if( GetPrm3DVisu().m_Zoom > MAX_VIEW_ANGLE )
        GetPrm3DVisu().m_Zoom = MAX_VIEW_ANGLE;

     if( Parent()->ModeIsOrtho() )
     {
         // OrthoReductionFactor is chosen to provide roughly the same size as
         // Perspective View
         const double orthoReductionFactor = 400 / GetPrm3DVisu().m_Zoom;

         // Initialize Projection Matrix for Ortographic View
         glOrtho( -size.x / orthoReductionFactor, size.x / orthoReductionFactor,
                  -size.y / orthoReductionFactor, size.y / orthoReductionFactor, 1, 100 );
     }
     else
     {
         // Ratio width / height of the window display
         double ratio_HV = (double) size.x / size.y;

         // Initialize Projection Matrix for Perspective View
         gluPerspective( 45.0f * GetPrm3DVisu().m_Zoom, ratio_HV, 1, 100 );
     }

    // position viewer
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glTranslatef( 0.0f, 0.0f, -(m_ZBottom + m_ZTop) / 2.0f );

    // Setup light sources:
    SetLights();

    CheckGLError( __FILE__, __LINE__ );

    glMatrixMode( GL_MODELVIEW );    // position viewer

    // transformations
    GLfloat mat[4][4];

    // Translate motion first, so rotations don't mess up the orientation...
    glTranslatef( m_draw3dOffset.x, m_draw3dOffset.y, 0.0F );

    build_rotmatrix( mat, GetPrm3DVisu().m_Quat );
    glMultMatrixf( &mat[0][0] );

    glRotatef( GetPrm3DVisu().m_Rot[0], 1.0, 0.0, 0.0 );
    glRotatef( GetPrm3DVisu().m_Rot[1], 0.0, 1.0, 0.0 );
    glRotatef( GetPrm3DVisu().m_Rot[2], 0.0, 0.0, 1.0 );


    if( ! m_glLists[GL_ID_BOARD] || ! m_glLists[GL_ID_TECH_LAYERS] )
        CreateDrawGL_List( &errorReporter, &activityReporter );

    if( isEnabled( FL_AXIS ) && m_glLists[GL_ID_AXIS] )
        glCallList( m_glLists[GL_ID_AXIS] );

    // move the board in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                  0.0f );

    if( isEnabled( FL_MODULE ) )
    {
        if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] )
            CreateDrawGL_List( &errorReporter, &activityReporter );
    }

    glEnable( GL_LIGHTING );

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    if( isRealisticMode() && isEnabled( FL_RENDER_TEXTURES ) )
        glEnable( GL_TEXTURE_2D );
    else
        glDisable( GL_TEXTURE_2D );

    // Set material for the board
    glEnable( GL_COLOR_MATERIAL );
    SetOpenGlDefaultMaterial();

    //glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, FALSE );

    // Board Body

    GLint shininess_value = 32;
    glMateriali( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );

    if( isEnabled( FL_SHOW_BOARD_BODY ) )
    {
        if( m_glLists[GL_ID_BODY] )
        {
            glCallList( m_glLists[GL_ID_BODY] );
        }
    }


    // Board

    // specify material parameters for the lighting model.
    shininess_value = 52;
    glMateriali( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );

    glm::vec4 specular( GetPrm3DVisu().m_CopperColor.m_Red   * 0.20f,
                        GetPrm3DVisu().m_CopperColor.m_Green * 0.20f,
                        GetPrm3DVisu().m_CopperColor.m_Blue  * 0.20f, 1.0f );
    glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x );

    if( m_glLists[GL_ID_BOARD] )
    {
        glCallList( m_glLists[GL_ID_BOARD] );
    }


    // Tech layers

    shininess_value = 32;
    glMateriali( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value );

    glm::vec4 specularTech( 0.0f, 0.0f, 0.0f, 1.0f );
    glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specularTech.x );

    if( m_glLists[GL_ID_TECH_LAYERS] )
    {
        glCallList( m_glLists[GL_ID_TECH_LAYERS] );
    }

    if( isEnabled( FL_COMMENTS ) || isEnabled( FL_ECO )  )
    {
        if( ! m_glLists[GL_ID_AUX_LAYERS] )
            CreateDrawGL_List( &errorReporter, &activityReporter );

        glCallList( m_glLists[GL_ID_AUX_LAYERS] );
    }

    //glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, TRUE );

    // Draw Component Shadow

    if( isEnabled( FL_MODULE )  && isRealisticMode() &&
        isEnabled( FL_RENDER_SHADOWS ) )
    {
        glEnable( GL_CULL_FACE );
        glDisable( GL_DEPTH_TEST );

        glEnable( GL_COLOR_MATERIAL ) ;
        SetOpenGlDefaultMaterial();
        glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

        glEnable( GL_TEXTURE_2D );

        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

        if( m_glLists[GL_ID_SHADOW_FRONT] )
        {
            glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_front );
            glCallList( m_glLists[GL_ID_SHADOW_FRONT] );
        }

        if( m_glLists[GL_ID_SHADOW_BACK] )
        {
            glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_back );
            glCallList( m_glLists[GL_ID_SHADOW_BACK] );
        }
        glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

        glEnable( GL_DEPTH_TEST );
        glDisable( GL_TEXTURE_2D );
        glDisable( GL_CULL_FACE );
    }

    glEnable( GL_COLOR_MATERIAL );
    SetOpenGlDefaultMaterial();

    glDisable( GL_BLEND );


    // Draw Solid Shapes

    if( isEnabled( FL_MODULE ) )
    {
        if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] )
            CreateDrawGL_List( &errorReporter, &activityReporter );

        glCallList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] );
    }

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );


    // Grid uses transparency: draw it after all objects

    if( isEnabled( FL_GRID ) )
    {
        if( ! m_glLists[GL_ID_GRID] )
            CreateDrawGL_List( &errorReporter, &activityReporter );

        glCallList( m_glLists[GL_ID_GRID] );
    }


    // Draw Board Shadow

    if( isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) )
    {
        if( m_glLists[GL_ID_SHADOW_BOARD] )
        {
            glEnable( GL_BLEND );
            glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
            glColor4f( 1.0, 1.0, 1.0, 0.75f );
            glEnable( GL_CULL_FACE );
            glDisable( GL_COLOR_MATERIAL );
            glEnable( GL_TEXTURE_2D );
            glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_board );
            glCallList( m_glLists[GL_ID_SHADOW_BOARD] );
            glDisable( GL_CULL_FACE );
            glDisable( GL_TEXTURE_2D );
        }
    }

    // This list must be drawn last, because it contains the
    // transparent gl objects, which should be drawn after all
    // non transparent objects
    if(  isEnabled( FL_MODULE ) && m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] )
    {
        glEnable( GL_COLOR_MATERIAL );
        SetOpenGlDefaultMaterial();
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
        glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] );
    }

    // Debug bounding boxes
    /*
    glDisable( GL_BLEND );
    glDisable( GL_COLOR_MATERIAL );
    glDisable( GL_LIGHTING );
    glColor4f( 1.0f, 0.0f, 1.0f, 1.0f );
    m_fastAABBox_Shadow.GLdebug();

    glColor4f( 0.0f, 1.0f, 1.0f, 1.0f );
    m_boardAABBox.GLdebug();
    */

    SwapBuffers();
    GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );

    // Show calculation time if some activity was reported
    if( activityReporter.HasMessage() )
    {
        // Calculation time in seconds
        double calculation_time = (double)( GetRunningMicroSecs() - strtime) / 1e6;

        activityReporter.Report( wxString::Format( _( "Build time %.3f s" ),
                                 calculation_time ) );
    }
    else
        activityReporter.Report( wxEmptyString );

    if( !err_messages.IsEmpty() )
        wxLogMessage( err_messages );

}
Ejemplo n.º 8
0
void EDA_3D_CANVAS::generateFakeShadowsTextures( REPORTER* aErrorMessages, REPORTER* aActivity )
{
    if( m_shadow_init == true )
    {
        return;
    }

    // Init info 3d parameters and create gl lists:
    CreateDrawGL_List( aErrorMessages, aActivity );

    DBG( unsigned strtime = GetRunningMicroSecs() );

    m_shadow_init = true;

    glClearColor( 0, 0, 0, 1 );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    const float zDistMax = Millimeter2iu( 3.5 ) * GetPrm3DVisu().m_BiuTo3Dunits;

    glOrtho( -GetPrm3DVisu().m_BoardSize.x * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             GetPrm3DVisu().m_BoardSize.x * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             -GetPrm3DVisu().m_BoardSize.y * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             GetPrm3DVisu().m_BoardSize.y * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f,
             0.0, zDistMax );

    float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;

    // Render FRONT shadow
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glTranslatef( 0.0f, 0.0f, zpos );
    glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );

    // move the board in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                  0.0f );

    create_and_render_shadow_buffer( &m_text_fake_shadow_front, 512, false, 1 );

    zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;

    // Render BACK shadow
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glTranslatef( 0.0f, 0.0f, fabs( zpos ) );


    // move the board in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits,
                  -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits,
                  0.0f );

    create_and_render_shadow_buffer( &m_text_fake_shadow_back, 512, false, 1 );


    // Render ALL BOARD shadow
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    // Normalization scale to convert bouding box
    // to normalize 3D units between -1.0 and +1.0

    S3D_VERTEX v = m_fastAABBox_Shadow.Max() - m_fastAABBox_Shadow.Min();
    float BoundingBoxBoardiuTo3Dunits = 2.0f / glm::max( v.x, v.y );

    //float zDistance = (m_lightPos.z * zDistMax) / sqrt( (m_lightPos.z - m_fastAABBox_Shadow.Min().z) );
    float zDistance = (m_lightPos.z - m_fastAABBox_Shadow.Min().z) / 3.0f;

    glOrtho( -v.x * BoundingBoxBoardiuTo3Dunits / 2.0f,
              v.x * BoundingBoxBoardiuTo3Dunits / 2.0f,
             -v.y * BoundingBoxBoardiuTo3Dunits / 2.0f,
              v.y * BoundingBoxBoardiuTo3Dunits / 2.0f,
             0.0f, zDistance );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    // fits the bouding box to scale this size
    glScalef( BoundingBoxBoardiuTo3Dunits, BoundingBoxBoardiuTo3Dunits, 1.0f );

    // Place the eye in the lowerpoint of boudingbox and turn arround and look up to the model
    glTranslatef( 0.0f, 0.0f, m_fastAABBox_Shadow.Min().z );
    glRotatef( 180.0, 0.0f, 1.0f, 0.0f );

    // move the bouding box in order to draw it with its center at 0,0 3D coordinates
    glTranslatef( -(m_fastAABBox_Shadow.Min().x + v.x / 2.0f), -(m_fastAABBox_Shadow.Min().y + v.y / 2.0f), 0.0f );

    create_and_render_shadow_buffer( &m_text_fake_shadow_board, 512, true, 10 );

    DBG( printf( "  generateFakeShadowsTextures total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) );
}
Ejemplo n.º 9
0
void CINFO3D_VISU::InitSettings( REPORTER *aStatusTextReporter )
{
    wxLogTrace( m_logTrace, wxT( "CINFO3D_VISU::InitSettings" ) );

    // Calculates the board bounding box
    // First, use only the board outlines
    EDA_RECT bbbox = m_board->ComputeBoundingBox( true );

    // If no outlines, use the board with items
    if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
        bbbox = m_board->ComputeBoundingBox( false );

    // Gives a non null size to avoid issues in zoom / scale calculations
    if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
        bbbox.Inflate( Millimeter2iu( 10 ) );

    m_boardSize = bbbox.GetSize();
    m_boardPos  = bbbox.Centre();

    wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );

    m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer

    m_copperLayersCount = m_board->GetCopperLayerCount();

    // Ensure the board has 2 sides for 3D views, because it is hard to find
    // a *really* single side board in the true life...
    if( m_copperLayersCount < 2 )
        m_copperLayersCount = 2;

    // Calculate the convertion to apply to all positions.
    m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );

    // Calculate factors for cicle segment approximation
    m_calc_seg_min_factor3DU = (float)( SEG_MIN_FACTOR_BIU * m_biuTo3Dunits );
    m_calc_seg_max_factor3DU = (float)( SEG_MAX_FACTOR_BIU * m_biuTo3Dunits );

    m_epoxyThickness3DU = m_board->GetDesignSettings().GetBoardThickness() *
                          m_biuTo3Dunits;

    // !TODO: use value defined by user (currently use default values by ctor
    m_copperThickness3DU         = COPPER_THICKNESS     * m_biuTo3Dunits;
    m_nonCopperLayerThickness3DU = TECH_LAYER_THICKNESS * m_biuTo3Dunits;

    // Init  Z position of each layer
    // calculate z position for each copper layer
    // Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = 31)
    // Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = 0)
    // all unused copper layer z position are set to 0

    //  ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
    // |                                  |   Top = Bottom + m_copperThickness
    // |__________________________________|
    //   ==         ==         ==     ==   <- Bottom = -m_epoxyThickness / 2.0,
    //                                        Top = Bottom - m_copperThickness

    unsigned int layer;

    for( layer = 0; layer < m_copperLayersCount; ++layer )
    {
        m_layerZcoordBottom[layer] = m_epoxyThickness3DU / 2.0f -
                                     (m_epoxyThickness3DU * layer / (m_copperLayersCount - 1) );

        if( layer < (m_copperLayersCount / 2) )
            m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] + m_copperThickness3DU;
        else
            m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] - m_copperThickness3DU;
    }

    #define layerThicknessMargin 1.1
    const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;

    // Fill remaining unused copper layers and back layer zpos
    // with -m_epoxyThickness / 2.0
    for( ; layer < MAX_CU_LAYERS; layer++ )
    {
        m_layerZcoordBottom[layer] = -(m_epoxyThickness3DU / 2.0f);
        m_layerZcoordTop[layer]    = -(m_epoxyThickness3DU / 2.0f) - m_copperThickness3DU;
    }

    // This is the top of the copper layer thickness.
    const float zpos_copperTop_back  = m_layerZcoordTop[B_Cu];
    const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];

    // calculate z position for each non copper layer
    // Solder mask and Solder paste have the same Z position
    for( int layer_id = MAX_CU_LAYERS; layer_id < LAYER_ID_COUNT; ++layer_id )
    {
        float zposTop;
        float zposBottom;

        switch( layer_id )
        {
        case B_Adhes:
            zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
            zposTop    = zposBottom - m_nonCopperLayerThickness3DU;
            break;

        case F_Adhes:
            zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
            zposTop    = zposBottom + m_nonCopperLayerThickness3DU;
            break;

        case B_Mask:
        case B_Paste:
            zposBottom = zpos_copperTop_back;
            zposTop    = zpos_copperTop_back - m_nonCopperLayerThickness3DU;
            break;

        case F_Mask:
        case F_Paste:
            zposTop    = zpos_copperTop_front + m_nonCopperLayerThickness3DU;
            zposBottom = zpos_copperTop_front;
            break;

        case B_SilkS:
            zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
            zposTop    = zposBottom - m_nonCopperLayerThickness3DU;
            break;

        case F_SilkS:
            zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
            zposTop    = zposBottom + m_nonCopperLayerThickness3DU;
            break;

        // !TODO: review
        default:
            zposTop = zpos_copperTop_front + (layer_id - MAX_CU_LAYERS + 3.0f) * zpos_offset;
            zposBottom = zposTop - m_nonCopperLayerThickness3DU;
            break;
        }

        m_layerZcoordTop[layer_id]    = zposTop;
        m_layerZcoordBottom[layer_id] = zposBottom;
    }

    m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits,
                             m_boardPos.y * m_biuTo3Dunits,
                             0.0f );

    SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits,
                                 m_boardSize.y * m_biuTo3Dunits,
                                 0.0f );
            boardSize /= 2.0f;

    SFVEC3F boardMin = (m_boardCenter - boardSize);
    SFVEC3F boardMax = (m_boardCenter + boardSize);

    boardMin.z = m_layerZcoordTop[B_Adhes];
    boardMax.z = m_layerZcoordTop[F_Adhes];

    m_boardBoudingBox = CBBOX( boardMin, boardMax );

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_startCreateBoardPolyTime = GetRunningMicroSecs();
#endif

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Build board body" ) );

    createBoardPolygon();

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_stopCreateBoardPolyTime = GetRunningMicroSecs();
    unsigned stats_startCreateLayersTime = stats_stopCreateBoardPolyTime;
#endif

    if( aStatusTextReporter )
        aStatusTextReporter->Report( _( "Create layers" ) );

    createLayers( aStatusTextReporter );

#ifdef PRINT_STATISTICS_3D_VIEWER
    unsigned stats_stopCreateLayersTime = GetRunningMicroSecs();

    printf( "CINFO3D_VISU::InitSettings times\n" );
    printf( "  CreateBoardPoly:          %.3f ms\n",
            (float)( stats_stopCreateBoardPolyTime  - stats_startCreateBoardPolyTime  ) / 1e3 );
    printf( "  CreateLayers and holes:   %.3f ms\n",
            (float)( stats_stopCreateLayersTime     - stats_startCreateLayersTime     ) / 1e3 );
    printf( "\n" );
#endif
}