/** * Do the actual autoplacement. * @param aManual - if true, use extra heuristics for smarter placement when manually * called up. */ void DoAutoplace( bool aManual ) { bool force_wire_spacing = false; SIDE field_side = choose_side_for_fields( aManual ); wxPoint fbox_pos = field_box_placement( field_side ); EDA_RECT field_box( fbox_pos, m_fbox_size ); if( aManual ) force_wire_spacing = fit_fields_between_wires( &field_box, field_side ); // Move the fields int last_y_coord = field_box.GetTop(); for( unsigned field_idx = 0; field_idx < m_fields.size(); ++field_idx ) { SCH_FIELD* field = m_fields[field_idx]; if( m_allow_rejustify ) justify_field( field, field_side ); wxPoint pos( field_horiz_placement( field, field_box ), field_vert_placement( field, field_box, &last_y_coord, !force_wire_spacing ) ); if( m_align_to_grid ) { pos.x = round_n( pos.x, 50, field_side.x >= 0 ); pos.y = round_n( pos.y, 50, field_side.y == 1 ); } field->SetPosition( pos ); } }
/** * If any changes have been made to this component, * they are now applied to the schematic component */ void BOM_TABLE_COMPONENT::ApplyFieldChanges() { for( auto& unit : Units ) { auto cmp = unit.GetComp(); if( !cmp ) continue; // Iterate over each column SCH_FIELD* field; for( auto& column : m_columnList->Columns ) { if( column && HasValueChanged( column ) ) { wxString value = GetFieldValue( column->Id() ); switch( column->Id() ) { // Ignore read-only fields case BOM_COL_ID_REFERENCE: case BOM_COL_ID_QUANTITY: continue; // Special field considerations case BOM_COL_ID_FOOTPRINT: field = cmp->GetField( FOOTPRINT ); break; case BOM_COL_ID_VALUE: field = cmp->GetField( VALUE ); break; case BOM_COL_ID_DATASHEET: field = cmp->GetField( DATASHEET ); break; default: // Find the field by name (but ignore default fields) field = cmp->FindField( column->Title(), false ); break; } // New field needs to be added? if( !field && !value.IsEmpty() ) { SCH_FIELD newField( wxPoint( 0, 0 ), -1, cmp, column->Title() ); field = cmp->AddField( newField ); } if( field ) { field->SetText( value ); } } } } }
/** * Extract field data from all components * Compiles an inclusive list of all field names from all components */ void BOM_TABLE_MODEL::AddComponentFields( SCH_COMPONENT* aCmp ) { std::vector< SCH_FIELD* > fields; SCH_FIELD* field; wxString fieldName; if( nullptr == aCmp ) return; // Extract custom columns from component fields.clear(); aCmp->GetFields( fields, false ); // Iterate over custom field datas for( unsigned int i=MANDATORY_FIELDS; i<fields.size(); i++ ) { field = fields[i]; if( nullptr == field ) continue; fieldName = field->GetName(); bool userMatchFound = false; // Search for the column within the existing columns for( auto col : ColumnList.Columns ) { if( !col ) { continue; } if( col->Title().Cmp( fieldName ) == 0 ) { if( col->Id() >= BOM_COL_ID_USER ) { userMatchFound = true; break; } } } // If a user-made column already exists with the same name, abort if( userMatchFound ) { continue; } ColumnList.AddColumn( new BOM_COLUMN( ColumnList.NextFieldId(), BOM_COL_TYPE_USER, field->GetName(), true, false ) ); } }
SCH_ITEM* SCH_SCREEN::GetItem( const wxPoint& aPosition, int aAccuracy, KICAD_T aType ) const { for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( item->HitTest( aPosition, aAccuracy ) && (aType == NOT_USED) ) return item; if( (aType == SCH_FIELD_T) && (item->Type() == SCH_COMPONENT_T) ) { SCH_COMPONENT* component = (SCH_COMPONENT*) item; for( int i = REFERENCE; i < component->GetFieldCount(); i++ ) { SCH_FIELD* field = component->GetField( i ); if( field->HitTest( aPosition, aAccuracy ) ) return (SCH_ITEM*) field; } } else if( (aType == SCH_SHEET_PIN_T) && (item->Type() == SCH_SHEET_T) ) { SCH_SHEET* sheet = (SCH_SHEET*)item; SCH_SHEET_PIN* label = sheet->GetPin( aPosition ); if( label ) return (SCH_ITEM*) label; } else if( (item->Type() == aType) && item->HitTest( aPosition, aAccuracy ) ) { return item; } } return NULL; }
bool SCH_EDIT_FRAME::ProcessCmpToFootprintLinkFile( wxString& aFullFilename, bool aForceFieldsVisibleAttribute, bool aFieldsVisibleAttributeState ) { // Build a flat list of components in schematic: SCH_REFERENCE_LIST referencesList; SCH_SHEET_LIST SheetList; SheetList.GetComponents( referencesList, false ); FILE* cmpFile = wxFopen( aFullFilename, wxT( "rt" ) ); if( cmpFile == NULL ) return false; // cmpFileReader dtor will close cmpFile FILE_LINE_READER cmpFileReader( cmpFile, aFullFilename ); // Now, for each component found in file, // replace footprint field value by the new value: wxString reference; wxString footprint; wxString buffer; wxString value; while( cmpFileReader.ReadLine() ) { buffer = FROM_UTF8( cmpFileReader.Line() ); if( ! buffer.StartsWith( wxT("BeginCmp") ) ) continue; // Begin component description. reference.Empty(); footprint.Empty(); while( cmpFileReader.ReadLine() ) { buffer = FROM_UTF8( cmpFileReader.Line() ); if( buffer.StartsWith( wxT("EndCmp") ) ) break; // store string value, stored between '=' and ';' delimiters. value = buffer.AfterFirst( '=' ); value = value.BeforeLast( ';'); value.Trim(true); value.Trim(false); if( buffer.StartsWith( wxT("Reference") ) ) { reference = value; continue; } if( buffer.StartsWith( wxT("IdModule =" ) ) ) { footprint = value; continue; } } // A block is read: initialize the footprint field of the correponding component // if the footprint name is not empty if( reference.IsEmpty() ) continue; // Search the component in the flat list for( unsigned ii = 0; ii < referencesList.GetCount(); ii++ ) { if( reference.CmpNoCase( referencesList[ii].GetRef() ) == 0 ) { // We have found a candidate. // Note: it can be not unique (multiple parts per package) // So we *do not* stop the search here SCH_COMPONENT* component = referencesList[ii].GetComponent(); SCH_FIELD * fpfield = component->GetField( FOOTPRINT ); fpfield->SetText( footprint ); if( aForceFieldsVisibleAttribute ) { component->GetField( FOOTPRINT ) ->SetVisible( aFieldsVisibleAttributeState ); } } } } return true; }
XNODE* NETLIST_EXPORTER_GENERIC::makeComponents() { XNODE* xcomps = node( wxT( "components" ) ); wxString timeStamp; // some strings we need many times, but don't want to construct more // than once for performance. These are used within loops so the // enclosing wxString constructor would fire on each loop iteration if // they were in a nested scope. // these are actually constructor invocations, not assignments as it appears: wxString sFields = wxT( "fields" ); wxString sField = wxT( "field" ); wxString sComponent = wxT( "comp" ); // use "part" ? wxString sName = wxT( "name" ); wxString sRef = wxT( "ref" ); wxString sPins = wxT( "pins" ); wxString sPin = wxT( "pin" ); wxString sValue = wxT( "value" ); wxString sSheetPath = wxT( "sheetpath" ); wxString sFootprint = wxT( "footprint" ); wxString sDatasheet = wxT( "datasheet" ); wxString sTStamp = wxT( "tstamp" ); wxString sTStamps = wxT( "tstamps" ); wxString sTSFmt = wxT( "%8.8lX" ); // comp->m_TimeStamp wxString sLibSource = wxT( "libsource" ); wxString sLibPart = wxT( "libpart" ); wxString sLib = wxT( "lib" ); wxString sPart = wxT( "part" ); wxString sNames = wxT( "names" ); m_ReferencesAlreadyFound.Clear(); SCH_SHEET_LIST sheetList( g_RootSheet ); // Output is xml, so there is no reason to remove spaces from the field values. // And XML element names need not be translated to various languages. for( unsigned i = 0; i < sheetList.size(); i++ ) { for( EDA_ITEM* schItem = sheetList[i].LastDrawList(); schItem; schItem = schItem->Next() ) { SCH_COMPONENT* comp = findNextComponentAndCreatePinList( schItem, &sheetList[i] ); if( !comp ) break; // No component left schItem = comp; XNODE* xcomp; // current component being constructed // Output the component's elements in order of expected access frequency. // This may not always look best, but it will allow faster execution // under XSL processing systems which do sequential searching within // an element. xcomps->AddChild( xcomp = node( sComponent ) ); xcomp->AddAttribute( sRef, comp->GetRef( &sheetList[i] ) ); xcomp->AddChild( node( sValue, comp->GetField( VALUE )->GetText() ) ); if( !comp->GetField( FOOTPRINT )->IsVoid() ) xcomp->AddChild( node( sFootprint, comp->GetField( FOOTPRINT )->GetText() ) ); if( !comp->GetField( DATASHEET )->IsVoid() ) xcomp->AddChild( node( sDatasheet, comp->GetField( DATASHEET )->GetText() ) ); // Export all user defined fields within the component, // which start at field index MANDATORY_FIELDS. Only output the <fields> // container element if there are any <field>s. if( comp->GetFieldCount() > MANDATORY_FIELDS ) { XNODE* xfields; xcomp->AddChild( xfields = node( sFields ) ); for( int fldNdx = MANDATORY_FIELDS; fldNdx < comp->GetFieldCount(); ++fldNdx ) { SCH_FIELD* f = comp->GetField( fldNdx ); // only output a field if non empty and not just "~" if( !f->IsVoid() ) { XNODE* xfield; xfields->AddChild( xfield = node( sField, f->GetText() ) ); xfield->AddAttribute( sName, f->GetName() ); } } } XNODE* xlibsource; xcomp->AddChild( xlibsource = node( sLibSource ) ); // "logical" library name, which is in anticipation of a better search // algorithm for parts based on "logical_lib.part" and where logical_lib // is merely the library name minus path and extension. LIB_PART* part = m_libs->FindLibPart( comp->GetLibId() ); if( part ) xlibsource->AddAttribute( sLib, part->GetLib()->GetLogicalName() ); // We only want the symbol name, not the full LIB_ID. xlibsource->AddAttribute( sPart, comp->GetLibId().GetLibItemName() ); XNODE* xsheetpath; xcomp->AddChild( xsheetpath = node( sSheetPath ) ); xsheetpath->AddAttribute( sNames, sheetList[i].PathHumanReadable() ); xsheetpath->AddAttribute( sTStamps, sheetList[i].Path() ); timeStamp.Printf( sTSFmt, (unsigned long)comp->GetTimeStamp() ); xcomp->AddChild( node( sTStamp, timeStamp ) ); } } return xcomps; }
bool SCH_SCREEN::SetComponentFootprint( SCH_SHEET_PATH* aSheetPath, const wxString& aReference, const wxString& aFootPrint, bool aSetVisible ) { SCH_COMPONENT* component; bool found = false; for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { if( item->Type() != SCH_COMPONENT_T ) continue; component = (SCH_COMPONENT*) item; if( aReference.CmpNoCase( component->GetRef( aSheetPath ) ) == 0 ) { // Found: Init Footprint Field /* Give a reasonable value to the field position and * orientation, if the text is empty at position 0, because * it is probably not yet initialized */ SCH_FIELD * fpfield = component->GetField( FOOTPRINT ); if( fpfield->GetText().IsEmpty() && ( fpfield->GetTextPosition() == component->GetPosition() ) ) { fpfield->SetOrientation( component->GetField( VALUE )->GetOrientation() ); fpfield->SetTextPosition( component->GetField( VALUE )->GetTextPosition() ); fpfield->SetSize( component->GetField( VALUE )->GetSize() ); if( fpfield->GetOrientation() == 0 ) fpfield->Offset( wxPoint( 0, 100 ) ); else fpfield->Offset( wxPoint( 100, 0 ) ); } fpfield->SetText( aFootPrint ); fpfield->SetVisible( aSetVisible ); found = true; } } return found; }
void SCH_EDIT_FRAME::backAnnotateFootprints( const std::string& aChangedSetOfReferences ) throw( IO_ERROR, boost::bad_pointer ) { // Build a flat list of components in schematic: SCH_REFERENCE_LIST refs; SCH_SHEET_LIST sheets( g_RootSheet ); bool isChanged = false; sheets.GetComponents( Prj().SchLibs(), refs, false ); DSNLEXER lexer( aChangedSetOfReferences, FROM_UTF8( __func__ ) ); PTREE doc; try { Scan( &doc, &lexer ); #if defined(DEBUG) && 0 STRING_FORMATTER sf; Format( &sf, 0, 0, doc ); printf( "%s: '%s'\n", __func__, sf.GetString().c_str() ); #endif CPTREE& back_anno = doc.get_child( "back_annotation" ); wxString footprint; for( PTREE::const_iterator ref = back_anno.begin(); ref != back_anno.end(); ++ref ) { wxASSERT( ref->first == "ref" ); wxString reference = (UTF8&) ref->second.front().first; // Ensure the "fpid" node contains a footprint name, // and get it if exists if( ref->second.get_child( "fpid" ).size() ) { wxString tmp = (UTF8&) ref->second.get_child( "fpid" ).front().first; footprint = tmp; } else footprint.Empty(); // DBG( printf( "%s: ref:%s fpid:%s\n", __func__, TO_UTF8( reference ), TO_UTF8( footprint ) ); ) // Search the component in the flat list for( unsigned ii = 0; ii < refs.GetCount(); ++ii ) { if( reference == refs[ii].GetRef() ) { // We have found a candidate. // Note: it can be not unique (multiple parts per package) // So we *do not* stop the search here SCH_COMPONENT* component = refs[ii].GetComp(); SCH_FIELD* fpfield = component->GetField( FOOTPRINT ); const wxString& oldfp = fpfield->GetText(); if( !oldfp && fpfield->IsVisible() ) { fpfield->SetVisible( false ); } // DBG( printf("%s: ref:%s fpid:%s\n", __func__, TO_UTF8( refs[ii].GetRef() ), TO_UTF8( footprint ) );) if( oldfp != footprint ) isChanged = true; fpfield->SetText( footprint ); } } } } catch( const PTREE_ERROR& ex ) { // remap the exception to something the caller is likely to understand. THROW_IO_ERROR( ex.what() ); } if( isChanged ) OnModify(); }
bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl ) { const wxString delimiters( "{:,; }" ); SCH_SHEET_LIST sheetList( g_RootSheet ); // Set of reference names, to check for duplications std::set<wxString> refNames; // Prepare list of nets generation (not used here, but... for( unsigned ii = 0; ii < m_masterList->size(); ii++ ) m_masterList->GetItem( ii )->m_Flag = 0; m_netMap.clear(); m_netMap["GND"] = 0; // 0 is reserved for "GND" int netIdx = 1; m_libraries.clear(); m_ReferencesAlreadyFound.Clear(); UpdateDirectives( aCtl ); for( unsigned sheet_idx = 0; sheet_idx < sheetList.size(); sheet_idx++ ) { // Process component attributes to find Spice directives for( EDA_ITEM* item = sheetList[sheet_idx].LastDrawList(); item; item = item->Next() ) { SCH_COMPONENT* comp = findNextComponentAndCreatePinList( item, &sheetList[sheet_idx] ); if( !comp ) break; item = comp; SPICE_ITEM spiceItem; spiceItem.m_parent = comp; // Obtain Spice fields SCH_FIELD* fieldLibFile = comp->FindField( GetSpiceFieldName( SF_LIB_FILE ) ); SCH_FIELD* fieldSeq = comp->FindField( GetSpiceFieldName( SF_NODE_SEQUENCE ) ); spiceItem.m_primitive = GetSpiceField( SF_PRIMITIVE, comp, aCtl )[0]; spiceItem.m_model = GetSpiceField( SF_MODEL, comp, aCtl ); spiceItem.m_refName = comp->GetRef( &sheetList[sheet_idx] ); // Duplicate references will result in simulation errors if( refNames.count( spiceItem.m_refName ) ) { DisplayError( NULL, wxT( "There are duplicate components. " "You need to annotate schematics first." ) ); return false; } refNames.insert( spiceItem.m_refName ); // Check to see if component should be removed from Spice netlist spiceItem.m_enabled = StringToBool( GetSpiceField( SF_ENABLED, comp, aCtl ) ); if( fieldLibFile && !fieldLibFile->GetText().IsEmpty() ) m_libraries.insert( fieldLibFile->GetText() ); wxArrayString pinNames; // Store pin information for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ ) { NETLIST_OBJECT* pin = m_SortedComponentPinList[ii]; // NETLIST_EXPORTER marks removed pins by setting them to NULL if( !pin ) continue; spiceItem.m_pins.push_back( pin ); pinNames.Add( pin->GetPinNumText() ); // Create net mapping const wxString& netName = pin->GetNetName(); if( m_netMap.count( netName ) == 0 ) m_netMap[netName] = netIdx++; } // Check if an alternative pin sequence is available: if( fieldSeq ) { // Get the string containing the sequence of nodes: wxString nodeSeqIndexLineStr = fieldSeq->GetText(); // Verify field exists and is not empty: if( !nodeSeqIndexLineStr.IsEmpty() ) { // Get Alt Pin Name Array From User: wxStringTokenizer tkz( nodeSeqIndexLineStr, delimiters ); while( tkz.HasMoreTokens() ) { wxString pinIndex = tkz.GetNextToken(); int seq; // Find PinName In Standard List assign Standard List Index to Name: seq = pinNames.Index( pinIndex ); if( seq != wxNOT_FOUND ) spiceItem.m_pinSequence.push_back( seq ); } } } m_spiceItems.push_back( spiceItem ); } } return true; }
wxString NETLIST_EXPORTER_PSPICE::GetSpiceField( SPICE_FIELD aField, SCH_COMPONENT* aComponent, unsigned aCtl ) { SCH_FIELD* field = aComponent->FindField( GetSpiceFieldName( aField ) ); return field ? field->GetText() : GetSpiceFieldDefVal( aField, aComponent, aCtl ); }