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 }
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; }
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 ) ); }
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__ ); }
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 ); }
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 ) ); }
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 }