108 const std::vector<T*>& aNew )
110 struct MATCH_CANDIDATE
117 std::vector<MATCH_CANDIDATE> candidates;
119 for(
T* existing : aExisting )
121 for(
T* updated : aNew )
123 if( existing->Type() != updated->Type() )
126 double similarity = existing->Similarity( *updated );
128 if constexpr( std::is_same_v<T, PAD> )
130 if( existing->GetNumber() == updated->GetNumber() )
134 if( similarity <= 0.0 )
137 candidates.push_back( { existing, updated, similarity } );
141 std::sort( candidates.begin(), candidates.end(),
142 [](
const MATCH_CANDIDATE& a,
const MATCH_CANDIDATE& b )
144 if( a.score != b.score )
145 return a.score > b.score;
147 if( a.existing != b.existing )
148 return a.existing < b.existing;
150 return a.updated < b.updated;
153 std::vector<std::pair<T*, T*>> matches;
154 matches.reserve( candidates.size() );
156 std::unordered_set<T*> matchedExisting;
157 std::unordered_set<T*> matchedNew;
159 for(
const MATCH_CANDIDATE& candidate : candidates )
161 if( matchedExisting.find( candidate.existing ) != matchedExisting.end() )
164 if( matchedNew.find( candidate.updated ) != matchedNew.end() )
167 matchedExisting.insert( candidate.existing );
168 matchedNew.insert( candidate.updated );
169 matches.emplace_back( candidate.existing, candidate.updated );
177 bool matchPadPositions,
178 bool deleteExtraTexts,
179 bool resetTextLayers,
180 bool resetTextEffects,
181 bool resetTextPositions,
182 bool resetTextContent,
183 bool resetFabricationAttrs,
184 bool resetClearanceOverrides,
190 bool dummyBool =
false;
193 aUpdated = &dummyBool;
212 if( matchPadPositions )
216 position += posShift;
217 orientation += angleShift;
229 if( !resetTransform )
247 std::vector<PAD*> oldPads;
248 oldPads.reserve( aExisting->
Pads().size() );
251 oldPads.push_back(
pad );
253 std::vector<PAD*> newPads;
254 newPads.reserve( aNew->
Pads().size() );
257 newPads.push_back(
pad );
260 std::unordered_set<PAD*> matchedNewPads;
262 for(
const auto& match : padMatches )
264 PAD* oldPad = match.first;
265 PAD* newPad = match.second;
267 matchedNewPads.insert( newPad );
279 for(
PAD* newPad : aNew->
Pads() )
281 if( matchedNewPads.find( newPad ) != matchedNewPads.end() )
288 std::vector<BOARD_ITEM*> oldDrawings;
292 oldDrawings.push_back( item );
294 std::vector<BOARD_ITEM*> newDrawings;
298 newDrawings.push_back( item );
301 std::unordered_map<BOARD_ITEM*, BOARD_ITEM*> oldToNewDrawings;
302 std::unordered_set<BOARD_ITEM*> matchedNewDrawings;
304 for(
const auto& match : drawingMatches )
309 oldToNewDrawings[ oldItem ] = newItem;
310 matchedNewDrawings.insert( newItem );
316 if( matchedNewDrawings.find( newItem ) == matchedNewDrawings.end() )
317 newItem->ResetUuid();
320 std::vector<ZONE*> oldZones;
321 oldZones.reserve( aExisting->
Zones().size() );
324 oldZones.push_back( zone );
326 std::vector<ZONE*> newZones;
327 newZones.reserve( aNew->
Zones().size() );
330 newZones.push_back( zone );
333 std::unordered_set<ZONE*> matchedNewZones;
335 for(
const auto& match : zoneMatches )
337 ZONE* oldZone = match.first;
338 ZONE* newZone = match.second;
340 matchedNewZones.insert( newZone );
344 for(
ZONE* newZone : newZones )
346 if( matchedNewZones.find( newZone ) == matchedNewZones.end() )
347 newZone->ResetUuid();
350 std::vector<PCB_POINT*> oldPoints;
351 oldPoints.reserve( aExisting->
Points().size() );
354 oldPoints.push_back( point );
356 std::vector<PCB_POINT*> newPoints;
357 newPoints.reserve( aNew->
Points().size() );
360 newPoints.push_back( point );
363 std::unordered_set<PCB_POINT*> matchedNewPoints;
365 for(
const auto& match : pointMatches )
370 matchedNewPoints.insert( newPoint );
376 if( matchedNewPoints.find( newPoint ) == matchedNewPoints.end() )
377 newPoint->ResetUuid();
380 std::vector<PCB_GROUP*> oldGroups;
381 oldGroups.reserve( aExisting->
Groups().size() );
384 oldGroups.push_back(
group );
386 std::vector<PCB_GROUP*> newGroups;
387 newGroups.reserve( aNew->
Groups().size() );
390 newGroups.push_back(
group );
393 std::unordered_set<PCB_GROUP*> matchedNewGroups;
395 for(
const auto& match : groupMatches )
400 matchedNewGroups.insert( newGroup );
406 if( matchedNewGroups.find( newGroup ) == matchedNewGroups.end() )
407 newGroup->ResetUuid();
410 std::vector<PCB_FIELD*> oldFieldsVec;
411 std::vector<PCB_FIELD*> newFieldsVec;
413 oldFieldsVec.reserve( aExisting->
GetFields().size() );
417 wxCHECK2( field,
continue );
419 if( field->IsReference() || field->IsValue() )
422 oldFieldsVec.push_back( field );
425 newFieldsVec.reserve( aNew->
GetFields().size() );
429 wxCHECK2( field,
continue );
431 if( field->IsReference() || field->IsValue() )
434 newFieldsVec.push_back( field );
438 std::unordered_map<PCB_FIELD*, PCB_FIELD*> oldToNewFields;
439 std::unordered_set<PCB_FIELD*> matchedNewFields;
441 for(
const auto& match : fieldMatches )
446 oldToNewFields[ oldField ] = newField;
447 matchedNewFields.insert( newField );
451 for(
PCB_FIELD* newField : newFieldsVec )
453 if( matchedNewFields.find( newField ) == matchedNewFields.end() )
454 newField->ResetUuid();
457 std::unordered_map<PCB_TEXT*, PCB_TEXT*> oldToNewTexts;
459 for(
const auto& match : drawingMatches )
464 if( oldText && newText )
465 oldToNewTexts[ oldText ] = newText;
468 std::set<PCB_TEXT*> handledTextItems;
482 auto textMatchIt = oldToNewTexts.find( oldTextItem );
484 if( textMatchIt != oldToNewTexts.end() )
485 newTextItem = textMatchIt->second;
489 handledTextItems.insert( newTextItem );
490 processTextItem( *oldTextItem, *newTextItem, posShift, angleShift, resetTextContent, resetTextLayers,
491 resetTextEffects, resetTextPositions, aUpdated );
493 else if( deleteExtraTexts )
499 newTextItem =
static_cast<PCB_TEXT*
>( oldTextItem->
Clone() );
500 handledTextItems.insert( newTextItem );
501 aNew->
Add( newTextItem );
517 if( !handledTextItems.contains( newTextItem ) )
527 resetTextEffects, resetTextPositions, aUpdated );
534 resetTextLayers, resetTextEffects, resetTextPositions, aUpdated );
536 std::set<PCB_FIELD*> handledFields;
541 wxCHECK2( oldField,
continue );
544 if( oldField->IsReference() || oldField->IsValue() )
549 auto fieldMatchIt = oldToNewFields.find( oldField );
551 if( fieldMatchIt != oldToNewFields.end() )
552 newField = fieldMatchIt->second;
556 handledFields.insert( newField );
557 processTextItem( *oldField, *newField, posShift, angleShift, resetTextContent, resetTextLayers,
558 resetTextEffects, resetTextPositions, aUpdated );
560 else if( deleteExtraTexts )
567 handledFields.insert( newField );
568 aNew->
Add( newField );
575 wxCHECK2( newField,
continue );
578 if( newField->IsReference() || newField->IsValue() )
581 if( !handledFields.contains( newField ) )
588 if( resetFabricationAttrs )
600 if( resetClearanceOverrides )
628 if( aNew->
Models().size() != aExisting->
Models().size() )
634 for(
size_t ii = 0; ii < aNew->
Models().size(); ++ii )
672 if( *aUpdated ==
false )
679 aCommit.
Remove( aExisting );
virtual const wxString & GetText() const
Return the string associated with the text object.
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.