bool TRACKS_CLEANER::remove_duplicates_of_track( const TRACK *aTrack ) { bool modified = false; TRACK *nextsegment; for( TRACK *other = aTrack->Next(); other; other = nextsegment ) { nextsegment = other->Next(); // New netcode, break out (can't be there any other) if( aTrack->GetNetCode() != other->GetNetCode() ) break; // Must be of the same type, on the same layer and the endpoints // must be the same (maybe swapped) if( (aTrack->Type() != other->Type()) && (aTrack->GetLayer() != other->GetLayer()) ) { if( ((aTrack->GetStart() == other->GetStart()) && (aTrack->GetEnd() == other->GetEnd())) || ((aTrack->GetStart() == other->GetEnd()) && (aTrack->GetEnd() == other->GetStart()))) { m_Brd->GetRatsnest()->Remove( other ); other->ViewRelease(); other->DeleteStructure(); modified = true; } } } return modified; }
static void export_vrml_tracks( BOARD* pcb ) //{{{ { for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) export_vrml_via( pcb, (SEGVIA*) track ); else export_vrml_line( track->GetLayer(), track->GetStart().x, track->GetStart().y, track->GetEnd().x, track->GetEnd().y, track->GetWidth(), 4 ); } }
void ROUTER_TOOL::NeighboringSegmentFilter( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector ) { /* * If the collection contains a trivial line corner (two connected segments) * or a non-fanout-via (a via with no more than two connected segments), then * trim the collection down to a single item (which one won't matter since * they're all connected). */ // First make sure we've got something that *might* match. int vias = aCollector.CountType( PCB_VIA_T ); int traces = aCollector.CountType( PCB_TRACE_T ); if( vias > 1 || traces > 2 || vias + traces < 1 ) return; // Fetch first TRACK (via or trace) as our reference TRACK* reference = nullptr; for( int i = 0; !reference && i < aCollector.GetCount(); i++ ) reference = dynamic_cast<TRACK*>( aCollector[i] ); int refNet = reference->GetNetCode(); wxPoint refPoint( aPt.x, aPt.y ); STATUS_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 ); if( flags & STARTPOINT ) refPoint = reference->GetStart(); else if( flags & ENDPOINT ) refPoint = reference->GetEnd(); // Check all items to ensure that any TRACKs are co-terminus with the reference and on // the same net. for( int i = 0; i < aCollector.GetCount(); i++ ) { TRACK* neighbor = dynamic_cast<TRACK*>( aCollector[i] ); if( neighbor && neighbor != reference ) { if( neighbor->GetNetCode() != refNet ) return; if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint ) return; } } // Selection meets criteria; trim it to the reference item. aCollector.Empty(); aCollector.Append( reference ); }
TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace, const wxPoint& aPosition, LAYER_MSK aLayerMask ) { for( TRACK *PtSegm = aStartTrace; PtSegm != NULL; PtSegm = PtSegm->Next() ) { if( PtSegm->GetState( IS_DELETED | BUSY ) == 0 ) { if( aPosition == PtSegm->GetStart() ) { if( aLayerMask & PtSegm->GetLayerMask() ) return PtSegm; } if( aPosition == PtSegm->GetEnd() ) { if( aLayerMask & PtSegm->GetLayerMask() ) return PtSegm; } } if( PtSegm == aEndTrace ) break; } return NULL; }
TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace, const wxPoint& aPosition, LSET aLayerMask ) { for( TRACK* seg = aStartTrace; seg; seg = seg->Next() ) { if( seg->GetState( IS_DELETED | BUSY ) == 0 ) { if( aPosition == seg->GetStart() ) { if( ( aLayerMask & seg->GetLayerSet() ).any() ) return seg; } if( aPosition == seg->GetEnd() ) { if( ( aLayerMask & seg->GetLayerSet() ).any() ) return seg; } } if( seg == aEndTrace ) break; } return NULL; }
// Redraw the moved node according to the mouse cursor position static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { auto displ_opts = (PCB_DISPLAY_OPTIONS*) aPanel->GetDisplayOptions(); wxPoint moveVector; int tmp = displ_opts->m_DisplayPcbTrackFill; GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT; displ_opts->m_DisplayPcbTrackFill = false; #ifndef USE_WX_OVERLAY aErase = true; #else aErase = false; #endif // set the new track coordinates wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition(); moveVector = Pos - s_LastPos; s_LastPos = Pos; TRACK *track = NULL; for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ ) { track = g_DragSegmentList[ii].m_Track; if( aErase ) track->Draw( aPanel, aDC, draw_mode ); if( track->GetFlags() & STARTPOINT ) track->SetStart( track->GetStart() + moveVector ); if( track->GetFlags() & ENDPOINT ) track->SetEnd( track->GetEnd() + moveVector ); if( track->Type() == PCB_VIA_T ) track->SetEnd( track->GetStart() ); track->Draw( aPanel, aDC, draw_mode ); } displ_opts->m_DisplayPcbTrackFill = tmp; // Display track length if( track ) { PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent(); frame->SetMsgPanel( track ); } }
void DRC::testKeepoutAreas() { // Test keepout areas for vias, tracks and pads inside keepout areas for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) { ZONE_CONTAINER* area = m_pcb->GetArea( ii ); if( !area->GetIsKeepout() ) continue; for( TRACK* segm = m_pcb->m_Track; segm != NULL; segm = segm->Next() ) { if( segm->Type() == PCB_TRACE_T ) { if( ! area->GetDoNotAllowTracks() ) continue; if( segm->GetLayer() != area->GetLayer() ) continue; if( area->Outline()->Distance( segm->GetStart(), segm->GetEnd(), segm->GetWidth() ) == 0 ) { m_currentMarker = fillMarker( segm, NULL, DRCE_TRACK_INSIDE_KEEPOUT, m_currentMarker ); m_pcb->Add( m_currentMarker ); m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } else if( segm->Type() == PCB_VIA_T ) { if( ! area->GetDoNotAllowVias() ) continue; if( ! ((VIA*)segm)->IsOnLayer( area->GetLayer() ) ) continue; if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 ) { m_currentMarker = fillMarker( segm, NULL, DRCE_VIA_INSIDE_KEEPOUT, m_currentMarker ); m_pcb->Add( m_currentMarker ); m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker ); m_currentMarker = 0; } } } // Test pads: TODO } }
static void export_vrml_tracks( MODEL_VRML& aModel, BOARD* pcb ) { for( TRACK* track = pcb->m_Track; track; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) { export_vrml_via( aModel, pcb, (const VIA*) track ); } else if( track->GetLayer() == B_Cu || track->GetLayer() == F_Cu ) export_vrml_line( aModel, track->GetLayer(), track->GetStart().x * aModel.scale, track->GetStart().y * aModel.scale, track->GetEnd().x * aModel.scale, track->GetEnd().y * aModel.scale, track->GetWidth() * aModel.scale ); } }
void CONNECTIONS::BuildTracksCandidatesList( TRACK* aBegin, TRACK* aEnd) { m_candidates.clear(); m_firstTrack = m_lastTrack = aBegin; unsigned ii = 0; // Count candidates ( i.e. end points ) for( const TRACK* track = aBegin; track; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) ii++; else ii += 2; m_lastTrack = track; if( track == aEnd ) break; } // Build candidate list m_candidates.reserve( ii ); for( TRACK* track = aBegin; track; track = track->Next() ) { CONNECTED_POINT candidate( track, track->GetStart() ); m_candidates.push_back( candidate ); if( track->Type() != PCB_VIA_T ) { CONNECTED_POINT candidate2( track, track->GetEnd()); m_candidates.push_back( candidate2 ); } if( track == aEnd ) break; } // Sort list by increasing X coordinate, // and for increasing Y coordinate when items have the same X coordinate // So candidates to the same location are consecutive in list. sort( m_candidates.begin(), m_candidates.end(), sortConnectedPointByXthenYCoordinates ); }
void TRACKS_CLEANER::buildTrackConnectionInfo() { BuildTracksCandidatesList( m_Brd->m_Track, NULL); // clear flags and variables used in cleanup for( TRACK * track = m_Brd->m_Track; track; track = track->Next() ) { track->start = NULL; track->end = NULL; track->m_PadsConnected.clear(); track->SetState( START_ON_PAD|END_ON_PAD|BUSY, false ); } // Build connections info tracks to pads SearchTracksConnectedToPads(); for( TRACK * track = m_Brd->m_Track; track; track = track->Next() ) { // Mark track if connected to pads for( unsigned jj = 0; jj < track->m_PadsConnected.size(); jj++ ) { D_PAD * pad = track->m_PadsConnected[jj]; if( pad->HitTest( track->GetStart() ) ) { track->start = pad; track->SetState( START_ON_PAD, true ); } if( pad->HitTest( track->GetEnd() ) ) { track->end = pad; track->SetState( END_ON_PAD, true ); } } } }
void DRC::testTexts() { std::vector<wxPoint> textShape; // a buffer to store the text shape (set of segments) std::vector<D_PAD*> padList = m_pcb->GetPads(); // Test text areas for vias, tracks and pads inside text areas for( BOARD_ITEM* item = m_pcb->m_Drawings; item; item = item->Next() ) { // Drc test only items on copper layers if( ! IsCopperLayer( item->GetLayer() ) ) continue; // only texts on copper layers are tested if( item->Type() != PCB_TEXT_T ) continue; textShape.clear(); // So far the bounding box makes up the text-area TEXTE_PCB* text = (TEXTE_PCB*) item; text->TransformTextShapeToSegmentList( textShape ); if( textShape.size() == 0 ) // Should not happen (empty text?) continue; for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() ) { if( ! track->IsOnLayer( item->GetLayer() ) ) continue; // Test the distance between each segment and the current track/via int min_dist = ( track->GetWidth() + text->GetThickness() ) /2 + track->GetClearance(NULL); if( track->Type() == PCB_TRACE_T ) { SEG segref( track->GetStart(), track->GetEnd() ); // Error condition: Distance between text segment and track segment is // smaller than the clearance of the segment for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) { SEG segtest( textShape[jj], textShape[jj+1] ); int dist = segref.Distance( segtest ); if( dist < min_dist ) { addMarkerToPcb( fillMarker( track, text, DRCE_TRACK_INSIDE_TEXT, m_currentMarker ) ); m_currentMarker = nullptr; break; } } } else if( track->Type() == PCB_VIA_T ) { // Error condition: Distance between text segment and via is // smaller than the clearance of the via for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) { SEG segtest( textShape[jj], textShape[jj+1] ); if( segtest.PointCloserThan( track->GetPosition(), min_dist ) ) { addMarkerToPcb( fillMarker( track, text, DRCE_VIA_INSIDE_TEXT, m_currentMarker ) ); m_currentMarker = nullptr; break; } } } } // Test pads for( unsigned ii = 0; ii < padList.size(); ii++ ) { D_PAD* pad = padList[ii]; if( ! pad->IsOnLayer( item->GetLayer() ) ) continue; wxPoint shape_pos = pad->ShapePos(); for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) { /* In order to make some calculations more easier or faster, * pads and tracks coordinates will be made relative * to the segment origin */ wxPoint origin = textShape[jj]; // origin will be the origin of other coordinates m_segmEnd = textShape[jj+1] - origin; wxPoint delta = m_segmEnd; m_segmAngle = 0; // for a non horizontal or vertical segment Compute the segment angle // in tenths of degrees and its length if( delta.x || delta.y ) // delta.x == delta.y == 0 for vias { // Compute the segment angle in 0,1 degrees m_segmAngle = ArcTangente( delta.y, delta.x ); // Compute the segment length: we build an equivalent rotated segment, // this segment is horizontal, therefore dx = length RotatePoint( &delta, m_segmAngle ); // delta.x = length, delta.y = 0 } m_segmLength = delta.x; m_padToTestPos = shape_pos - origin; if( !checkClearanceSegmToPad( pad, text->GetThickness(), pad->GetClearance(NULL) ) ) { addMarkerToPcb( fillMarker( pad, text, DRCE_PAD_INSIDE_TEXT, m_currentMarker ) ); m_currentMarker = nullptr; break; } } } } }
/* Function BuildAirWiresTargetsList * Build a list of candidates that can be a coonection point * when a track is started. * This functions prepares data to show airwires to nearest connecting points (pads) * from the current new track to candidates during track creation */ void PCB_BASE_FRAME::BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef, const wxPoint& aPosition, bool aInit ) { if( ( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 ) || ( ( m_Pcb->m_Status_Pcb & LISTE_PAD_OK ) == 0 ) || ( ( m_Pcb->m_Status_Pcb & NET_CODES_OK ) == 0 ) ) { s_TargetsLocations.clear(); return; } s_CursorPos = aPosition; // needed for sort_by_distance if( aInit ) { s_TargetsLocations.clear(); if( aItemRef == NULL ) return; int net_code = aItemRef->GetNet(); int subnet = aItemRef->GetSubNet(); if( net_code <= 0 ) return; NETINFO_ITEM* net = m_Pcb->FindNet( net_code ); if( net == NULL ) // Should not occur { wxMessageBox( wxT( "BuildAirWiresTargetsList() error: net not found" ) ); return; } // Create a list of pads candidates ( pads not already connected to the // current track ): for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ ) { D_PAD* pad = net->m_PadInNetList[ii]; if( pad == aItemRef ) continue; if( !pad->GetSubNet() || (pad->GetSubNet() != subnet) ) s_TargetsLocations.push_back( pad->GetPosition() ); } // Create a list of tracks ends candidates, not already connected to the // current track: for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() ) { if( track->GetNet() < net_code ) continue; if( track->GetNet() > net_code ) break;; if( !track->GetSubNet() || (track->GetSubNet() != subnet) ) { if( aPosition != track->GetStart() ) s_TargetsLocations.push_back( track->GetStart() ); if( aPosition != track->GetEnd() && track->GetStart() != track->GetEnd() ) s_TargetsLocations.push_back( track->GetEnd() ); } } // Remove duplicate targets, using the C++ unique algorithm sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_point ); std::vector< wxPoint >::iterator it = unique( s_TargetsLocations.begin(), s_TargetsLocations.end() ); // Using the C++ unique algorithm only moves the duplicate entries to the end of // of the array. This removes the duplicate entries from the array. s_TargetsLocations.resize( it - s_TargetsLocations.begin() ); } // end if Init // in all cases, sort by distances: sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_distance ); }
bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) { TRACK* track; wxPoint delta; // length on X and Y axis of segments LSET layerMask; int net_code_ref; wxPoint shape_pos; NETCLASSPTR netclass = aRefSeg->GetNetClass(); BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings(); /* In order to make some calculations more easier or faster, * pads and tracks coordinates will be made relative to the reference segment origin */ wxPoint origin = aRefSeg->GetStart(); // origin will be the origin of other coordinates m_segmEnd = delta = aRefSeg->GetEnd() - origin; m_segmAngle = 0; layerMask = aRefSeg->GetLayerSet(); net_code_ref = aRefSeg->GetNetCode(); // Phase 0 : Test vias if( aRefSeg->Type() == PCB_VIA_T ) { const VIA *refvia = static_cast<const VIA*>( aRefSeg ); // test if the via size is smaller than minimum if( refvia->GetViaType() == VIA_MICROVIA ) { if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_TOO_SMALL_MICROVIA, m_currentMarker ); return false; } if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_TOO_SMALL_MICROVIA_DRILL, m_currentMarker ); return false; } } else { if( refvia->GetWidth() < dsnSettings.m_ViasMinSize ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_TOO_SMALL_VIA, m_currentMarker ); return false; } if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_TOO_SMALL_VIA_DRILL, m_currentMarker ); return false; } } // test if via's hole is bigger than its diameter // This test is necessary since the via hole size and width can be modified // and a default via hole can be bigger than some vias sizes if( refvia->GetDrillValue() > refvia->GetWidth() ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_VIA_HOLE_BIGGER, m_currentMarker ); return false; } // For microvias: test if they are blind vias and only between 2 layers // because they are used for very small drill size and are drill by laser // and **only one layer** can be drilled if( refvia->GetViaType() == VIA_MICROVIA ) { LAYER_ID layer1, layer2; bool err = true; refvia->LayerPair( &layer1, &layer2 ); if( layer1 > layer2 ) std::swap( layer1, layer2 ); if( layer2 == B_Cu && layer1 == m_pcb->GetDesignSettings().GetCopperLayerCount() - 2 ) err = false; else if( layer1 == F_Cu && layer2 == In1_Cu ) err = false; if( err ) { m_currentMarker = fillMarker( refvia, NULL, DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, m_currentMarker ); return false; } } } else // This is a track segment { if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_TOO_SMALL_TRACK_WIDTH, m_currentMarker ); return false; } } // for a non horizontal or vertical segment Compute the segment angle // in tenths of degrees and its length if( delta.x || delta.y ) { // Compute the segment angle in 0,1 degrees m_segmAngle = ArcTangente( delta.y, delta.x ); // Compute the segment length: we build an equivalent rotated segment, // this segment is horizontal, therefore dx = length RotatePoint( &delta, m_segmAngle ); // delta.x = length, delta.y = 0 } m_segmLength = delta.x; /******************************************/ /* Phase 1 : test DRC track to pads : */ /******************************************/ /* Use a dummy pad to test DRC tracks versus holes, for pads not on all copper layers * but having a hole * This dummy pad has the size and shape of the hole * to test tracks to pad hole DRC, using checkClearanceSegmToPad test function. * Therefore, this dummy pad is a circle or an oval. * A pad must have a parent because some functions expect a non null parent * to find the parent board, and some other data */ MODULE dummymodule( m_pcb ); // Creates a dummy parent D_PAD dummypad( &dummymodule ); dummypad.SetLayerSet( LSET::AllCuMask() ); // Ensure the hole is on all layers // Compute the min distance to pads if( testPads ) { unsigned pad_count = m_pcb->GetPadCount(); for( unsigned ii = 0; ii<pad_count; ++ii ) { D_PAD* pad = m_pcb->GetPad( ii ); /* No problem if pads are on an other layer, * But if a drill hole exists (a pad on a single layer can have a hole!) * we must test the hole */ if( !( pad->GetLayerSet() & layerMask ).any() ) { /* We must test the pad hole. In order to use the function * checkClearanceSegmToPad(),a pseudo pad is used, with a shape and a * size like the hole */ if( pad->GetDrillSize().x == 0 ) continue; dummypad.SetSize( pad->GetDrillSize() ); dummypad.SetPosition( pad->GetPosition() ); dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ? PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE ); dummypad.SetOrientation( pad->GetOrientation() ); m_padToTestPos = dummypad.GetPosition() - origin; if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(), netclass->GetClearance() ) ) { m_currentMarker = fillMarker( aRefSeg, pad, DRCE_TRACK_NEAR_THROUGH_HOLE, m_currentMarker ); return false; } continue; } // The pad must be in a net (i.e pt_pad->GetNet() != 0 ) // but no problem if the pad netcode is the current netcode (same net) if( pad->GetNetCode() // the pad must be connected && net_code_ref == pad->GetNetCode() ) // the pad net is the same as current net -> Ok continue; // DRC for the pad shape_pos = pad->ShapePos(); m_padToTestPos = shape_pos - origin; if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) ) { m_currentMarker = fillMarker( aRefSeg, pad, DRCE_TRACK_NEAR_PAD, m_currentMarker ); return false; } } } /***********************************************/ /* Phase 2: test DRC with other track segments */ /***********************************************/ // At this point the reference segment is the X axis // Test the reference segment with other track segments wxPoint segStartPoint; wxPoint segEndPoint; for( track = aStart; track; track = track->Next() ) { // No problem if segments have the same net code: if( net_code_ref == track->GetNetCode() ) continue; // No problem if segment are on different layers : if( !( layerMask & track->GetLayerSet() ).any() ) continue; // the minimum distance = clearance plus half the reference track // width plus half the other track's width int w_dist = aRefSeg->GetClearance( track ); w_dist += (aRefSeg->GetWidth() + track->GetWidth()) / 2; // Due to many double to int conversions during calculations, which // create rounding issues, // the exact clearance margin cannot be really known. // To avoid false bad DRC detection due to these rounding issues, // slightly decrease the w_dist (remove one nanometer is enough !) w_dist -= 1; // If the reference segment is a via, we test it here if( aRefSeg->Type() == PCB_VIA_T ) { delta = track->GetEnd() - track->GetStart(); segStartPoint = aRefSeg->GetStart() - track->GetStart(); if( track->Type() == PCB_VIA_T ) { // Test distance between two vias, i.e. two circles, trivial case if( EuclideanNorm( segStartPoint ) < w_dist ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_VIA_NEAR_VIA, m_currentMarker ); return false; } } else // test via to segment { // Compute l'angle du segment a tester; double angle = ArcTangente( delta.y, delta.x ); // Compute new coordinates ( the segment become horizontal) RotatePoint( &delta, angle ); RotatePoint( &segStartPoint, angle ); if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) ) { m_currentMarker = fillMarker( track, aRefSeg, DRCE_VIA_NEAR_TRACK, m_currentMarker ); return false; } } continue; } /* We compute segStartPoint, segEndPoint = starting and ending point coordinates for * the segment to test in the new axis : the new X axis is the * reference segment. We must translate and rotate the segment to test */ segStartPoint = track->GetStart() - origin; segEndPoint = track->GetEnd() - origin; RotatePoint( &segStartPoint, m_segmAngle ); RotatePoint( &segEndPoint, m_segmAngle ); if( track->Type() == PCB_VIA_T ) { if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) continue; m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_NEAR_VIA, m_currentMarker ); return false; } /* We have changed axis: * the reference segment is Horizontal. * 3 cases : the segment to test can be parallel, perpendicular or have an other direction */ if( segStartPoint.y == segEndPoint.y ) // parallel segments { if( abs( segStartPoint.y ) >= w_dist ) continue; // Ensure segStartPoint.x <= segEndPoint.x if( segStartPoint.x > segEndPoint.x ) std::swap( segStartPoint.x, segEndPoint.x ); if( segStartPoint.x > (-w_dist) && segStartPoint.x < (m_segmLength + w_dist) ) /* possible error drc */ { // the start point is inside the reference range // X........ // O--REF--+ // Fine test : we consider the rounded shape of each end of the track segment: if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_ENDS1, m_currentMarker ); return false; } if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_ENDS2, m_currentMarker ); return false; } } if( segEndPoint.x > (-w_dist) && segEndPoint.x < (m_segmLength + w_dist) ) { // the end point is inside the reference range // .....X // O--REF--+ // Fine test : we consider the rounded shape of the ends if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_ENDS3, m_currentMarker ); return false; } if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_ENDS4, m_currentMarker ); return false; } } if( segStartPoint.x <=0 && segEndPoint.x >= 0 ) { // the segment straddles the reference range (this actually only // checks if it straddles the origin, because the other cases where already // handled) // X.............X // O--REF--+ m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_SEGMENTS_TOO_CLOSE, m_currentMarker ); return false; } } else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments { if( ( segStartPoint.x <= (-w_dist) ) || ( segStartPoint.x >= (m_segmLength + w_dist) ) ) continue; // Test if segments are crossing if( segStartPoint.y > segEndPoint.y ) std::swap( segStartPoint.y, segEndPoint.y ); if( (segStartPoint.y < 0) && (segEndPoint.y > 0) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACKS_CROSSING, m_currentMarker ); return false; } // At this point the drc error is due to an end near a reference segm end if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_ENDS_PROBLEM1, m_currentMarker ); return false; } if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_ENDS_PROBLEM2, m_currentMarker ); return false; } } else // segments quelconques entre eux { // calcul de la "surface de securite du segment de reference // First rought 'and fast) test : the track segment is like a rectangle m_xcliplo = m_ycliplo = -w_dist; m_xcliphi = m_segmLength + w_dist; m_ycliphi = w_dist; // A fine test is needed because a serment is not exactly a // rectangle, it has rounded ends if( !checkLine( segStartPoint, segEndPoint ) ) { /* 2eme passe : the track has rounded ends. * we must a fine test for each rounded end and the * rectangular zone */ m_xcliplo = 0; m_xcliphi = m_segmLength; if( !checkLine( segStartPoint, segEndPoint ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_ENDS_PROBLEM3, m_currentMarker ); return false; } else // The drc error is due to the starting or the ending point of the reference segment { // Test the starting and the ending point segStartPoint = track->GetStart(); segEndPoint = track->GetEnd(); delta = segEndPoint - segStartPoint; // Compute the segment orientation (angle) en 0,1 degre double angle = ArcTangente( delta.y, delta.x ); // Compute the segment length: delta.x = length after rotation RotatePoint( &delta, angle ); /* Comute the reference segment coordinates relatives to a * X axis = current tested segment */ wxPoint relStartPos = aRefSeg->GetStart() - segStartPoint; wxPoint relEndPos = aRefSeg->GetEnd() - segStartPoint; RotatePoint( &relStartPos, angle ); RotatePoint( &relEndPos, angle ); if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_ENDS_PROBLEM4, m_currentMarker ); return false; } if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_ENDS_PROBLEM5, m_currentMarker ); return false; } } } } } return true; }
/** * Function Magnetize * tests to see if there are any magnetic items within near reach of the given * "curpos". If yes, then curpos is adjusted appropriately according to that * near magnetic item and true is returned. * @param frame = the current frame * @param aCurrentTool = the current tool id (from vertical right toolbar) * @param aGridSize = the current grid size * @param on_grid = the on grid position near initial position ( often on_grid = curpos) * @param curpos The initial position, and what to adjust if a change is needed. * @return bool - true if the position was adjusted magnetically, else false. */ bool Magnetize( PCB_EDIT_FRAME* frame, int aCurrentTool, wxSize aGridSize, wxPoint on_grid, wxPoint* curpos ) { bool doCheckNet = g_MagneticPadOption != capture_always && g_Drc_On; bool doTrack = false; bool doPad = false; bool amMovingVia = false; BOARD* m_Pcb = frame->GetBoard(); TRACK* currTrack = g_CurrentTrackSegment; BOARD_ITEM* currItem = frame->GetCurItem(); PCB_SCREEN* screen = frame->GetScreen(); wxPoint pos = frame->RefPos( true ); // D( printf( "currTrack=%p currItem=%p currTrack->Type()=%d currItem->Type()=%d\n", currTrack, currItem, currTrack ? currTrack->Type() : 0, currItem ? currItem->Type() : 0 ); ) if( !currTrack && currItem && currItem->Type()==PCB_VIA_T && currItem->GetFlags() ) { // moving a VIA currTrack = (TRACK*) currItem; amMovingVia = true; return false; // comment this return out and play with it. } else if( currItem != currTrack ) { currTrack = NULL; } if( g_MagneticPadOption == capture_always ) doPad = true; if( g_MagneticTrackOption == capture_always ) doTrack = true; if( aCurrentTool == ID_TRACK_BUTT || amMovingVia ) { int q = capture_cursor_in_track_tool; if( g_MagneticPadOption == q ) doPad = true; if( g_MagneticTrackOption == q ) doTrack = true; } // D(printf("doPad=%d doTrack=%d aCurrentTool=%d amMovingVia=%d\n", doPad, doTrack, aCurrentTool, amMovingVia );) // The search precedence order is pads, then tracks/vias if( doPad ) { LSET layer_mask( screen->m_Active_Layer ); D_PAD* pad = m_Pcb->GetPad( pos, layer_mask ); if( pad ) { if( doCheckNet && currTrack && currTrack->GetNetCode() != pad->GetNetCode() ) return false; *curpos = pad->GetPosition(); return true; } } // after pads, only track & via tests remain, skip them if not desired if( doTrack ) { LAYER_ID layer = screen->m_Active_Layer; for( TRACK* via = m_Pcb->m_Track; via && (via = via->GetVia( *curpos, layer )) != NULL; via = via->Next() ) { if( via != currTrack ) // a via cannot influence itself { if( !doCheckNet || !currTrack || currTrack->GetNetCode() == via->GetNetCode() ) { *curpos = via->GetStart(); // D(printf("via hit\n");) return true; } } } if( !currTrack ) { LSET layers( layer ); TRACK* track = m_Pcb->GetVisibleTrack( m_Pcb->m_Track, pos, layers ); if( !track || track->Type() != PCB_TRACE_T ) { // D(printf("!currTrack and track=%p not found, layer_mask=0x%X\n", track, layer_mask );) return false; } // D( printf( "Project\n" ); ) return Project( curpos, on_grid, track ); } /* * In two segment mode, ignore the final segment if it's inside a grid square. */ if( !amMovingVia && currTrack && g_TwoSegmentTrackBuild && currTrack->Back() && currTrack->GetStart().x - aGridSize.x < currTrack->GetEnd().x && currTrack->GetStart().x + aGridSize.x > currTrack->GetEnd().x && currTrack->GetStart().y - aGridSize.y < currTrack->GetEnd().y && currTrack->GetStart().y + aGridSize.y > currTrack->GetEnd().y ) { currTrack = currTrack->Back(); } for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() ) { if( track->Type() != PCB_TRACE_T ) continue; if( doCheckNet && currTrack && currTrack->GetNetCode() != track->GetNetCode() ) continue; if( m_Pcb->IsLayerVisible( track->GetLayer() ) == false ) continue; // omit the layer check if moving a via if( !amMovingVia && !track->IsOnLayer( layer ) ) continue; if( !track->HitTest( *curpos ) ) continue; // D(printf( "have track prospect\n");) if( Join( curpos, track->GetStart(), track->GetEnd(), currTrack->GetStart(), currTrack->GetEnd() ) ) { // D(printf( "join currTrack->Type()=%d\n", currTrack->Type() );) return true; } if( aCurrentTool == ID_TRACK_BUTT || amMovingVia ) { // At this point we have a drawing mouse on a track, we are drawing // a new track and that new track is parallel to the track the // mouse is on. Find the nearest end point of the track under mouse // to the mouse and return that. double distStart = GetLineLength( *curpos, track->GetStart() ); double distEnd = GetLineLength( *curpos, track->GetEnd() ); // if track not via, or if its a via dragging but not with its adjacent track if( currTrack->Type() != PCB_VIA_T || ( currTrack->GetStart() != track->GetStart() && currTrack->GetStart() != track->GetEnd() )) { double max_dist = currTrack->GetWidth() / 2.0f; if( distStart <= max_dist ) { // D(printf("nearest end is start\n");) *curpos = track->GetStart(); return true; } if( distEnd <= max_dist ) { // D(printf("nearest end is end\n");) *curpos = track->GetEnd(); return true; } // @todo otherwise confine curpos such that it stays centered within "track" } } } } return false; }
// Delete null length segments, and intermediate points .. bool TRACKS_CLEANER::clean_segments() { bool modified = false; TRACK* segment, * nextsegment; TRACK* other; int flag, no_inc; // Delete null segments for( segment = m_Brd->m_Track; segment; segment = nextsegment ) { nextsegment = segment->Next(); if( segment->IsNull() ) // Length segment = 0; delete it segment->DeleteStructure(); } // Delete redundant segments, i.e. segments having the same end points // and layers for( segment = m_Brd->m_Track; segment; segment = segment->Next() ) { for( other = segment->Next(); other; other = nextsegment ) { nextsegment = other->Next(); bool erase = false; if( segment->Type() != other->Type() ) continue; if( segment->GetLayer() != other->GetLayer() ) continue; if( segment->GetNetCode() != other->GetNetCode() ) break; if( ( segment->GetStart() == other->GetStart() ) && ( segment->GetEnd() == other->GetEnd() ) ) erase = true; if( ( segment->GetStart() == other->GetEnd() ) && ( segment->GetEnd() == other->GetStart() ) ) erase = true; // Delete redundant point if( erase ) { other->DeleteStructure(); modified = true; } } } // merge collinear segments: for( segment = m_Brd->m_Track; segment; segment = nextsegment ) { TRACK* segStart; TRACK* segEnd; TRACK* segDelete; nextsegment = segment->Next(); if( segment->Type() != PCB_TRACE_T ) continue; flag = no_inc = 0; // search for a possible point connected to the START point of the current segment for( segStart = segment->Next(); ; ) { segStart = segment->GetTrace( segStart, NULL, FLG_START ); if( segStart ) { // the two segments must have the same width if( segment->GetWidth() != segStart->GetWidth() ) break; // it cannot be a via if( segStart->Type() != PCB_TRACE_T ) break; // We must have only one segment connected segStart->SetState( BUSY, true ); other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_START ); segStart->SetState( BUSY, false ); if( other == NULL ) flag = 1; // OK break; } break; } if( flag ) // We have the starting point of the segment is connected to an other segment { segDelete = mergeCollinearSegmentIfPossible( segment, segStart, FLG_START ); if( segDelete ) { no_inc = 1; segDelete->DeleteStructure(); modified = true; } } // search for a possible point connected to the END point of the current segment: for( segEnd = segment->Next(); ; ) { segEnd = segment->GetTrace( segEnd, NULL, FLG_END ); if( segEnd ) { if( segment->GetWidth() != segEnd->GetWidth() ) break; if( segEnd->Type() != PCB_TRACE_T ) break; // We must have only one segment connected segEnd->SetState( BUSY, true ); other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_END ); segEnd->SetState( BUSY, false ); if( other == NULL ) flag |= 2; // Ok break; } else { break; } } if( flag & 2 ) // We have the ending point of the segment is connected to an other segment { segDelete = mergeCollinearSegmentIfPossible( segment, segEnd, FLG_END ); if( segDelete ) { no_inc = 1; segDelete->DeleteStructure(); modified = true; } } if( no_inc ) // The current segment was modified, retry to merge it nextsegment = segment->Next(); } return modified; }
/** * Function SwapData * Used in undo / redo command: * swap data between Item and a copy * swapped data is data modified by edition, mainly sizes and texts * so ONLY FEW values are swapped * @param aItem = the item * @param aImage = a copy of the item */ void SwapData( BOARD_ITEM* aItem, BOARD_ITEM* aImage ) { if( aItem == NULL || aImage == NULL ) { wxMessageBox( wxT( "SwapData error: NULL pointer" ) ); return; } // Swap layers: if( aItem->Type() != PCB_MODULE_T && aItem->Type() != PCB_ZONE_AREA_T ) { // These items have a global swap function. int layer, layerimg; layer = aItem->GetLayer(); layerimg = aImage->GetLayer(); aItem->SetLayer( layerimg ); aImage->SetLayer( layer ); } switch( aItem->Type() ) { case PCB_MODULE_T: { MODULE* tmp = (MODULE*) aImage->Clone(); ( (MODULE*) aImage )->Copy( (MODULE*) aItem ); ( (MODULE*) aItem )->Copy( tmp ); delete tmp; } break; case PCB_ZONE_AREA_T: { ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone(); ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) aItem ); ( (ZONE_CONTAINER*) aItem )->Copy( tmp ); delete tmp; } break; case PCB_LINE_T: #if 0 EXCHG( ( (DRAWSEGMENT*) aItem )->m_Start, ( (DRAWSEGMENT*) aImage )->m_Start ); EXCHG( ( (DRAWSEGMENT*) aItem )->m_End, ( (DRAWSEGMENT*) aImage )->m_End ); EXCHG( ( (DRAWSEGMENT*) aItem )->m_Width, ( (DRAWSEGMENT*) aImage )->m_Width ); EXCHG( ( (DRAWSEGMENT*) aItem )->m_Shape, ( (DRAWSEGMENT*) aImage )->m_Shape ); #else { DRAWSEGMENT tmp = *(DRAWSEGMENT*) aImage; *aImage = *aItem; *aItem = tmp; } #endif break; case PCB_TRACE_T: case PCB_VIA_T: { TRACK* track = (TRACK*) aItem; TRACK* image = (TRACK*) aImage; // swap start, end, width and shape for track and image. wxPoint exchp = track->GetStart(); track->SetStart( image->GetStart() ); image->SetStart( exchp ); exchp = track->GetEnd(); track->SetEnd( image->GetEnd() ); image->SetEnd( exchp ); int atmp = track->GetWidth(); track->SetWidth( image->GetWidth() ); image->SetWidth( atmp ); atmp = track->GetShape(); track->SetShape( image->GetShape() ); image->SetShape( atmp ); atmp = track->GetDrillValue(); if( track->IsDrillDefault() ) atmp = -1; int itmp = image->GetDrillValue(); if( image->IsDrillDefault() ) itmp = -1; EXCHG(itmp, atmp ); if( atmp > 0 ) track->SetDrill( atmp ); else track->SetDrillDefault(); if( itmp > 0 ) image->SetDrill( itmp ); else image->SetDrillDefault(); } break; case PCB_TEXT_T: EXCHG( ( (TEXTE_PCB*) aItem )->m_Mirror, ( (TEXTE_PCB*) aImage )->m_Mirror ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Size, ( (TEXTE_PCB*) aImage )->m_Size ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Pos, ( (TEXTE_PCB*) aImage )->m_Pos ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Thickness, ( (TEXTE_PCB*) aImage )->m_Thickness ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Orient, ( (TEXTE_PCB*) aImage )->m_Orient ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Text, ( (TEXTE_PCB*) aImage )->m_Text ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Italic, ( (TEXTE_PCB*) aImage )->m_Italic ); EXCHG( ( (TEXTE_PCB*) aItem )->m_Bold, ( (TEXTE_PCB*) aImage )->m_Bold ); EXCHG( ( (TEXTE_PCB*) aItem )->m_HJustify, ( (TEXTE_PCB*) aImage )->m_HJustify ); EXCHG( ( (TEXTE_PCB*) aItem )->m_VJustify, ( (TEXTE_PCB*) aImage )->m_VJustify ); break; case PCB_TARGET_T: ( (PCB_TARGET*) aItem )->Exchg( (PCB_TARGET*) aImage ); break; case PCB_DIMENSION_T: { wxString txt = ( (DIMENSION*) aItem )->GetText(); ( (DIMENSION*) aItem )->SetText( ( (DIMENSION*) aImage )->GetText() ); ( (DIMENSION*) aImage )->SetText( txt ); EXCHG( ( (DIMENSION*) aItem )->m_Width, ( (DIMENSION*) aImage )->m_Width ); EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Size, ( (DIMENSION*) aImage )->m_Text.m_Size ); EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Pos, ( (DIMENSION*) aImage )->m_Text.m_Pos ); EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Thickness, ( (DIMENSION*) aImage )->m_Text.m_Thickness ); EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Mirror, ( (DIMENSION*) aImage )->m_Text.m_Mirror ); } break; case PCB_ZONE_T: default: wxMessageBox( wxT( "SwapData() error: unexpected type" ) ); break; } }
MARKER_PCB* DRC::fillMarker( const TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe ) { wxString textA = aTrack->GetSelectMenuText(); wxString textB; wxPoint position; wxPoint posB; if( aItem ) // aItem might be NULL { textB = aItem->GetSelectMenuText(); if( aItem->Type() == PCB_PAD_T ) { posB = position = ((D_PAD*)aItem)->GetPosition(); } else if( aItem->Type() == PCB_VIA_T ) { posB = position = ((VIA*)aItem)->GetPosition(); } else if( aItem->Type() == PCB_TRACE_T ) { TRACK* track = (TRACK*) aItem; posB = track->GetPosition(); wxPoint endPos = track->GetEnd(); // either of aItem's start or end will be used for the marker position // first assume start, then switch at end if needed. decision made on // distance from end of aTrack. position = track->GetStart(); double dToEnd = GetLineLength( endPos, aTrack->GetEnd() ); double dToStart = GetLineLength( position, aTrack->GetEnd() ); if( dToEnd < dToStart ) position = endPos; } } else position = aTrack->GetPosition(); if( fillMe ) { if( aItem ) fillMe->SetData( aErrorCode, position, textA, aTrack->GetPosition(), textB, posB ); else fillMe->SetData( aErrorCode, position, textA, aTrack->GetPosition() ); } else { if( aItem ) fillMe = new MARKER_PCB( aErrorCode, position, textA, aTrack->GetPosition(), textB, posB ); else fillMe = new MARKER_PCB( aErrorCode, position, textA, aTrack->GetPosition() ); } return fillMe; }
bool DIALOG_TRACK_VIA_PROPERTIES::Apply() { if( !check() ) return false; for( int i = 0; i < m_items.Size(); ++i ) { BOARD_ITEM* item = m_items.Item<BOARD_ITEM>( i ); switch( item->Type() ) { case PCB_TRACE_T: { assert( m_tracks ); TRACK* t = static_cast<TRACK*>( item ); if( m_trackStartX.Valid() || m_trackStartY.Valid() ) { wxPoint start = t->GetStart(); if( m_trackStartX.Valid() ) start.x = m_trackStartX.GetValue(); if( m_trackStartY.Valid() ) start.y = m_trackStartY.GetValue(); t->SetStart( start ); } if( m_trackEndX.Valid() || m_trackEndY.Valid() ) { wxPoint end = t->GetEnd(); if( m_trackEndX.Valid() ) end.x = m_trackEndX.GetValue(); if( m_trackEndY.Valid() ) end.y = m_trackEndY.GetValue(); t->SetEnd( end ); } if( m_trackNetclass->IsChecked() ) { t->SetWidth( t->GetNetClass()->GetTrackWidth() ); } else if( m_trackWidth.Valid() ) { t->SetWidth( m_trackWidth.GetValue() ); } LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection(); if( layer != UNDEFINED_LAYER ) t->SetLayer( (LAYER_ID) layer ); break; } case PCB_VIA_T: { assert( m_vias ); VIA* v = static_cast<VIA*>( item ); if( m_viaX.Valid() || m_viaY.Valid() ) { wxPoint pos = v->GetPosition(); if( m_viaX.Valid() ) pos.x = m_viaX.GetValue(); if( m_viaY.Valid() ) pos.y = m_viaY.GetValue(); v->SetPosition( pos ); } if( m_viaNetclass->IsChecked() ) { v->SetWidth( v->GetNetClass()->GetViaDiameter() ); v->SetDrill( v->GetNetClass()->GetViaDrill() ); } else { if( m_viaDiameter.Valid() ) v->SetWidth( m_viaDiameter.GetValue() ); if( m_viaDrill.Valid() ) v->SetDrill( m_viaDrill.GetValue() ); } break; } default: assert( false ); break; } } return true; }
/* drawing the track segment movement * > s_MovingSegmentSlope slope = moving track segment slope * > s_StartSegmentSlope slope = slope of the segment connected to the start * point of the moving segment * > s_EndSegmentSlope slope = slope of the segment connected to the end point * of the moving segment * * moved segment function : * yt=s_MovingSegmentSlope * x + s_MovingSegment_Yorg * * segment connected to moved segment's start: * y1 = s_StartSegmentSlope * x + s_StartSegment_Yorg * * segment connected to moved segment's end: * y2=s_EndSegmentSlope * x + s_EndSegment_Yorg * * first intersection point will be located at * y1=yt -> * * xi1=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_StartSegmentSlope-s_MovingSegmentSlope) * yi1=s_MovingSegmentSlope*xi1+s_MovingSegment_Yorg * or yi1=s_StartSegmentSlope*xi1+s_MovingSegment_Yorg * * second intersection point * y2=yt -> * * xi2=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_MovingSegmentSlope-s_MovingSegmentSlope) * yi2=s_MovingSegmentSlope*xi2+s_MovingSegment_Yorg * or yi1=s_EndSegmentSlope*xi2+s_MovingSegment_Yorg * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !!!!! special attention to vertical segments because * !!!!! their slope=infinite * !!!!! intersection point will be calculated using the * !!!!! segment intersecting it * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * * Slope parameters are computed once, because they can become undetermined * when moving segments * (i.e. when a segment length is 0) and we want keep them constant */ static void Show_Drag_Track_Segment_With_Cte_Slope( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { double xi1 = 0, yi1 = 0, xi2 = 0, yi2 = 0; // calculated intersection points double tx1, tx2, ty1, ty2; // temporary storage of points int dx, dy; bool update = true; TRACK* Track; TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL; if( g_DragSegmentList.size() == 0 ) return; /* get the segments : * from last to first in list are: * the segment to move * the segment connected to its end point (if exists) * the segment connected to its start point (if exists) */ int ii = g_DragSegmentList.size() - 1; Track = g_DragSegmentList[ii].m_Track; if( Track == NULL ) return; ii--; if( ii >= 0) { if( s_EndSegmentPresent ) { // Get the segment connected to the end point tSegmentToEnd = g_DragSegmentList[ii].m_Track; ii--; } if( s_StartSegmentPresent ) { // Get the segment connected to the start point if( ii >= 0 ) tSegmentToStart = g_DragSegmentList[ii].m_Track; } } GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT; // Undraw the current moved track segments before modification #ifndef USE_WX_OVERLAY // if( erase ) { Track->Draw( aPanel, aDC, draw_mode ); if( tSegmentToStart ) tSegmentToStart->Draw( aPanel, aDC, draw_mode ); if( tSegmentToEnd ) tSegmentToEnd->Draw( aPanel, aDC, draw_mode ); } #endif // Compute the new track segment position wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition(); dx = Pos.x - s_LastPos.x; dy = Pos.y - s_LastPos.y; // move the line by dx and dy tx1 = (double) ( Track->GetStart().x + dx ); ty1 = (double) ( Track->GetStart().y + dy ); tx2 = (double) ( Track->GetEnd().x + dx ); ty2 = (double) ( Track->GetEnd().y + dy ); // recalculate the segments new parameters and intersection points // only the intercept will change, segment slopes does not change // because we are moving parallel with is initial state if( !s_MovingSegmentVertical ) { s_MovingSegment_Yorg = ty1 - ( s_MovingSegmentSlope * tx1 ); } if( ( !s_EndPointVertical ) && ( !s_MovingSegmentVertical ) ) { xi2 = ( s_MovingSegment_Yorg - s_EndSegment_Yorg ) / ( s_EndSegmentSlope - s_MovingSegmentSlope ); } else { if( !s_EndPointVertical ) { xi2 = tx2; } else { //P1=P2 if( !s_EndPointHorizontal ) { xi2 = tx2 - dx; } else { update = false; } } } if( !s_MovingSegmentVertical ) { yi2 = s_MovingSegmentSlope * ( xi2 ) + s_MovingSegment_Yorg; } else { if( !s_EndPointVertical ) { yi2 = s_EndSegmentSlope * ( xi2 ) + s_EndSegment_Yorg; } else { if( !s_EndPointHorizontal ) { update = false; } else { yi2 = s_MovingSegmentSlope * ( xi2 ) + s_MovingSegment_Yorg; } } } if( ( !s_StartPointVertical ) && ( !s_MovingSegmentVertical ) ) { xi1 = ( s_MovingSegment_Yorg - s_StartSegment_Yorg ) / ( s_StartSegmentSlope - s_MovingSegmentSlope ); } else { if( !s_StartPointVertical ) { xi1 = tx1; } else { //P1=P2 if( !s_StartPointHorizontal ) { xi1 = tx1 - dx; } else { if( !s_StartPointHorizontal ) { update = false; } } } } if( !s_MovingSegmentVertical ) { yi1 = s_MovingSegmentSlope * ( xi1 ) + s_MovingSegment_Yorg; } else { if( !s_StartPointVertical ) { yi1 = s_StartSegmentSlope * ( xi1 ) + s_StartSegment_Yorg; } else { if( !s_StartPointHorizontal ) { update = false; } else { yi2 = s_MovingSegmentSlope * ( xi1 ) + s_MovingSegment_Yorg; } } } // update the segment coordinates (if possible) if( tSegmentToStart == NULL ) { xi1 = tx1; yi1 = ty1; } if( tSegmentToEnd == NULL ) { xi2 = tx2; yi2 = ty2; } if( update ) { s_LastPos = Pos; Track->SetStart( wxPoint( KiROUND( xi1 ), KiROUND( yi1 ) ) ); Track->SetEnd( wxPoint( KiROUND( xi2 ), KiROUND( yi2 ) ) ); if( tSegmentToEnd ) { if( tSegmentToEnd->GetFlags() & STARTPOINT ) tSegmentToEnd->SetStart( Track->GetEnd() ); else tSegmentToEnd->SetEnd( Track->GetEnd() ); } if( tSegmentToStart ) { if( tSegmentToStart->GetFlags() & STARTPOINT ) tSegmentToStart->SetStart( Track->GetStart() ); else tSegmentToStart->SetEnd( Track->GetStart() ); } } Track->Draw( aPanel, aDC, draw_mode ); if( tSegmentToStart ) tSegmentToStart->Draw( aPanel, aDC, draw_mode ); if( tSegmentToEnd ) tSegmentToEnd->Draw( aPanel, aDC, draw_mode ); // Display track length PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent(); frame->SetMsgPanel( Track ); }
void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) { if( aImage == NULL ) return; // Remark: to create images of edited items to undo, we are using Clone method // which can duplication of items foe copy, but does not clone all members // mainly pointers in chain and time stamp, which is set to new, unique value. // So we have to use the current values of these parameters. EDA_ITEM * pnext = Next(); EDA_ITEM * pback = Back(); DHEAD* mylist = m_List; time_t timestamp = GetTimeStamp(); switch( Type() ) { case PCB_MODULE_T: { MODULE* tmp = (MODULE*) aImage->Clone(); ( (MODULE*) aImage )->Copy( (MODULE*) this ); ( (MODULE*) this )->Copy( tmp ); delete tmp; } break; case PCB_ZONE_AREA_T: { ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone(); ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) this ); ( (ZONE_CONTAINER*) this )->Copy( tmp ); delete tmp; } break; case PCB_LINE_T: std::swap( *((DRAWSEGMENT*)this), *((DRAWSEGMENT*)aImage) ); break; case PCB_TRACE_T: case PCB_VIA_T: { TRACK* track = (TRACK*) this; TRACK* image = (TRACK*) aImage; std::swap(track->m_Layer, image->m_Layer ); // swap start, end, width and shape for track and image. wxPoint exchp = track->GetStart(); track->SetStart( image->GetStart() ); image->SetStart( exchp ); exchp = track->GetEnd(); track->SetEnd( image->GetEnd() ); image->SetEnd( exchp ); int atmp = track->GetWidth(); track->SetWidth( image->GetWidth() ); image->SetWidth( atmp ); if( Type() == PCB_VIA_T ) { VIA *via = static_cast<VIA*>( this ); VIA *viaimage = static_cast<VIA*>( aImage ); VIATYPE_T viatmp = via->GetViaType(); via->SetViaType( viaimage->GetViaType() ); viaimage->SetViaType( viatmp ); int drilltmp = via->GetDrillValue(); if( via->IsDrillDefault() ) drilltmp = -1; int itmp = viaimage->GetDrillValue(); if( viaimage->IsDrillDefault() ) itmp = -1; std::swap(itmp, drilltmp ); if( drilltmp > 0 ) via->SetDrill( drilltmp ); else via->SetDrillDefault(); if( itmp > 0 ) viaimage->SetDrill( itmp ); else viaimage->SetDrillDefault(); } } break; case PCB_TEXT_T: std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) ); break; case PCB_TARGET_T: std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) ); break; case PCB_DIMENSION_T: std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) ); break; case PCB_ZONE_T: default: wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() ); break; } // Restore pointers and time stamp, to be sure they are not broken Pnext = pnext; Pback = pback; m_List = mylist; SetTimeStamp( timestamp ); }
/* Plot a copper layer or mask. * Silk screen layers are not plotted here. */ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt ) { BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); itemplotter.SetLayerMask( aLayerMask ); EDA_DRAW_MODE_T plotMode = aPlotOpt.GetMode(); // Plot edge layer and graphic items itemplotter.PlotBoardGraphicItems(); // Draw footprint shapes without pads (pads will plotted later) // We plot here module texts, but they are usually on silkscreen layer, // so they are not plot here but plot by PlotSilkScreen() // Plot footprints fields (ref, value ...) for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { if( ! itemplotter.PlotAllTextsModule( module ) ) { wxLogMessage( _( "Your BOARD has a bad layer number for module %s" ), GetChars( module->GetReference() ) ); } } for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() ) { if( ! (aLayerMask & GetLayerMask( item->GetLayer() ) ) ) continue; switch( item->Type() ) { case PCB_MODULE_EDGE_T: itemplotter.Plot_1_EdgeModule( (EDGE_MODULE*) item ); break; default: break; } } } // Plot footprint pads for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { if( (pad->GetLayerMask() & aLayerMask) == 0 ) continue; wxSize margin; double width_adj = 0; if( aLayerMask & ALL_CU_LAYERS ) width_adj = itemplotter.getFineWidthAdj(); switch( aLayerMask & ( SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT | SOLDERPASTE_LAYER_BACK | SOLDERPASTE_LAYER_FRONT ) ) { case SOLDERMASK_LAYER_FRONT: case SOLDERMASK_LAYER_BACK: margin.x = margin.y = pad->GetSolderMaskMargin(); break; case SOLDERPASTE_LAYER_FRONT: case SOLDERPASTE_LAYER_BACK: margin = pad->GetSolderPasteMargin(); break; default: break; } wxSize padPlotsSize; padPlotsSize.x = pad->GetSize().x + ( 2 * margin.x ) + width_adj; padPlotsSize.y = pad->GetSize().y + ( 2 * margin.y ) + width_adj; // Don't draw a null size item : if( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) continue; EDA_COLOR_T color = BLACK; if( (pad->GetLayerMask() & LAYER_BACK) ) color = aBoard->GetVisibleElementColor( PAD_BK_VISIBLE ); if((pad->GetLayerMask() & LAYER_FRONT ) ) color = ColorFromInt( color | aBoard->GetVisibleElementColor( PAD_FR_VISIBLE ) ); // Temporary set the pad size to the required plot size: wxSize tmppadsize = pad->GetSize(); pad->SetSize( padPlotsSize ); switch( pad->GetShape() ) { case PAD_CIRCLE: case PAD_OVAL: if( aPlotOpt.GetSkipPlotNPTH_Pads() && (pad->GetSize() == pad->GetDrillSize()) && (pad->GetAttribute() == PAD_HOLE_NOT_PLATED) ) break; // Fall through: case PAD_TRAPEZOID: case PAD_RECT: default: itemplotter.PlotPad( pad, color, plotMode ); break; } pad->SetSize( tmppadsize ); // Restore the pad size } } // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true, // plot them on solder mask for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) { const VIA* Via = dynamic_cast<const VIA*>( track ); if( !Via ) continue; // vias are not plotted if not on selected layer, but if layer // is SOLDERMASK_LAYER_BACK or SOLDERMASK_LAYER_FRONT,vias are drawn, // only if they are on the corresponding external copper layer int via_mask_layer = Via->GetLayerMask(); if( aPlotOpt.GetPlotViaOnMaskLayer() ) { if( via_mask_layer & LAYER_BACK ) via_mask_layer |= SOLDERMASK_LAYER_BACK; if( via_mask_layer & LAYER_FRONT ) via_mask_layer |= SOLDERMASK_LAYER_FRONT; } if( ( via_mask_layer & aLayerMask ) == 0 ) continue; int via_margin = 0; double width_adj = 0; // If the current layer is a solder mask, use the global mask // clearance for vias if( ( aLayerMask & ( SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT ) ) ) via_margin = aBoard->GetDesignSettings().m_SolderMaskMargin; if( aLayerMask & ALL_CU_LAYERS ) width_adj = itemplotter.getFineWidthAdj(); int diameter = Via->GetWidth() + 2 * via_margin + width_adj; // Don't draw a null size item : if( diameter <= 0 ) continue; EDA_COLOR_T color = aBoard->GetVisibleElementColor(VIAS_VISIBLE + Via->GetViaType()); // Set plot color (change WHITE to LIGHTGRAY because // the white items are not seen on a white paper or screen aPlotter->SetColor( color != WHITE ? color : LIGHTGRAY); aPlotter->FlashPadCircle( Via->GetStart(), diameter, plotMode ); } // Plot tracks (not vias) : for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) { if( track->Type() == PCB_VIA_T ) continue; if( (GetLayerMask( track->GetLayer() ) & aLayerMask) == 0 ) continue; int width = track->GetWidth() + itemplotter.getFineWidthAdj(); aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) ); aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode ); } // Plot zones (outdated, for old boards compatibility): for( TRACK* track = aBoard->m_Zone; track; track = track->Next() ) { if( (GetLayerMask( track->GetLayer() ) & aLayerMask) == 0 ) continue; int width = track->GetWidth() + itemplotter.getFineWidthAdj(); aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) ); aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode ); } // Plot filled ares for( int ii = 0; ii < aBoard->GetAreaCount(); ii++ ) { ZONE_CONTAINER* zone = aBoard->GetArea( ii ); if( ( GetLayerMask(zone->GetLayer() ) & aLayerMask ) == 0 ) continue; itemplotter.PlotFilledAreas( zone ); } // Adding drill marks, if required and if the plotter is able to plot them: if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE ) itemplotter.PlotDrillMarks(); }
void ZONE_CONTAINER::TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb ) { if( m_FilledPolysList.GetCornersCount() == 0 ) return; // Build a list of points connected to the net: // list of coordinates of pads and vias on this layer and on this net. std::vector <wxPoint> listPointsCandidates; for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() ) { if( !pad->IsOnLayer( GetLayer() ) ) continue; if( pad->GetNet() != GetNet() ) continue; listPointsCandidates.push_back( pad->GetPosition() ); } } for( TRACK* track = aPcb->m_Track; track; track = track->Next() ) { if( !track->IsOnLayer( GetLayer() ) ) continue; if( track->GetNet() != GetNet() ) continue; listPointsCandidates.push_back( track->GetStart() ); if( track->Type() != PCB_VIA_T ) listPointsCandidates.push_back( track->GetEnd() ); } // test if a point is inside unsigned indexstart = 0, indexend; bool connected = false; for( indexend = 0; indexend < m_FilledPolysList.GetCornersCount(); indexend++ ) { if( m_FilledPolysList[indexend].end_contour ) // end of a filled sub-area found { EDA_RECT bbox = CalculateSubAreaBoundaryBox( indexstart, indexend ); for( unsigned ic = 0; ic < listPointsCandidates.size(); ic++ ) { // test if this area is connected to a board item: wxPoint pos = listPointsCandidates[ic]; if( !bbox.Contains( pos ) ) continue; if( TestPointInsidePolygon( m_FilledPolysList, indexstart, indexend, pos.x, pos.y ) ) { connected = true; break; } } if( connected ) // this polygon is connected: analyse next polygon { indexstart = indexend + 1; // indexstart points the first point of the next polygon connected = false; } else // Not connected: remove this polygon { m_FilledPolysList.DeleteCorners( indexstart, indexend ); indexend = indexstart; /* indexstart points the first point of the next polygon * because the current poly is removed */ } } } }
bool TRACKS_CLEANER::clean_vias() { TRACK* next_track; bool modified = false; for( TRACK* track = m_Brd->m_Track; track; track = track->Next() ) { // Correct via m_End defects (if any) if( track->Type() == PCB_VIA_T ) { if( track->GetStart() != track->GetEnd() ) track->SetEnd( track->GetStart() ); } if( track->GetShape() != VIA_THROUGH ) continue; // Search and delete others vias at same location TRACK* alt_track = track->Next(); for( ; alt_track != NULL; alt_track = next_track ) { next_track = alt_track->Next(); if( alt_track->GetShape() != VIA_THROUGH ) continue; if( alt_track->GetStart() != track->GetStart() ) continue; // delete via alt_track->UnLink(); delete alt_track; modified = true; } } // Delete Via on pads at same location for( TRACK* track = m_Brd->m_Track; track != NULL; track = next_track ) { next_track = track->Next(); if( track->GetShape() != VIA_THROUGH ) continue; // Examine the list of connected pads: // if one pad through is found, the via can be removed for( unsigned ii = 0; ii < track->m_PadsConnected.size(); ii++ ) { D_PAD * pad = track->m_PadsConnected[ii]; if( (pad->GetLayerMask() & ALL_CU_LAYERS) == ALL_CU_LAYERS ) { // redundant: via delete it track->UnLink(); delete track; modified = true; break; } } } return modified; }
/* This function is used by Retrace and read the autorouting matrix data cells to create * the real track on the physical board */ static void OrCell_Trace( BOARD* pcb, int col, int row, int side, int orient, int current_net_code ) { if( orient == HOLE ) // placement of a via { VIA *newVia = new VIA( pcb ); g_CurrentTrackList.PushBack( newVia ); g_CurrentTrackSegment->SetState( TRACK_AR, true ); g_CurrentTrackSegment->SetLayer( F_Cu ); g_CurrentTrackSegment->SetStart(wxPoint( pcb->GetBoundingBox().GetX() + ( RoutingMatrix.m_GridRouting * row ), pcb->GetBoundingBox().GetY() + ( RoutingMatrix.m_GridRouting * col ))); g_CurrentTrackSegment->SetEnd( g_CurrentTrackSegment->GetStart() ); g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentViaSize() ); newVia->SetViaType( pcb->GetDesignSettings().m_CurrentViaType ); g_CurrentTrackSegment->SetNetCode( current_net_code ); } else // placement of a standard segment { TRACK *newTrack = new TRACK( pcb ); int dx0, dy0, dx1, dy1; g_CurrentTrackList.PushBack( newTrack ); g_CurrentTrackSegment->SetLayer( g_Route_Layer_BOTTOM ); if( side == TOP ) g_CurrentTrackSegment->SetLayer( g_Route_Layer_TOP ); g_CurrentTrackSegment->SetState( TRACK_AR, true ); g_CurrentTrackSegment->SetEnd( wxPoint( pcb->GetBoundingBox().GetX() + ( RoutingMatrix.m_GridRouting * row ), pcb->GetBoundingBox().GetY() + ( RoutingMatrix.m_GridRouting * col ))); g_CurrentTrackSegment->SetNetCode( current_net_code ); if( g_CurrentTrackSegment->Back() == NULL ) // Start trace. { g_CurrentTrackSegment->SetStart( wxPoint( segm_fX, segm_fY ) ); // Placement on the center of the pad if outside grid. dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x; dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y; dx0 = pt_cur_ch->m_PadEnd->GetPosition().x - g_CurrentTrackSegment->GetStart().x; dy0 = pt_cur_ch->m_PadEnd->GetPosition().y - g_CurrentTrackSegment->GetStart().y; // If aligned, change the origin point. if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) { g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() ); } else // Creation of a supplemental segment { g_CurrentTrackSegment->SetStart( pt_cur_ch->m_PadEnd->GetPosition() ); newTrack = (TRACK*)g_CurrentTrackSegment->Clone(); newTrack->SetStart( g_CurrentTrackSegment->GetEnd()); g_CurrentTrackList.PushBack( newTrack ); } } else { if( g_CurrentTrackSegment->Back() ) { g_CurrentTrackSegment->SetStart( g_CurrentTrackSegment->Back()->GetEnd() ); } } g_CurrentTrackSegment->SetWidth( pcb->GetDesignSettings().GetCurrentTrackWidth() ); if( g_CurrentTrackSegment->GetStart() != g_CurrentTrackSegment->GetEnd() ) { // Reduce aligned segments by one. TRACK* oldTrack = g_CurrentTrackSegment->Back(); if( oldTrack && oldTrack->Type() != PCB_VIA_T ) { dx1 = g_CurrentTrackSegment->GetEnd().x - g_CurrentTrackSegment->GetStart().x; dy1 = g_CurrentTrackSegment->GetEnd().y - g_CurrentTrackSegment->GetStart().y; dx0 = oldTrack->GetEnd().x - oldTrack->GetStart().x; dy0 = oldTrack->GetEnd().y - oldTrack->GetStart().y; if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) { oldTrack->SetEnd( g_CurrentTrackSegment->GetEnd() ); delete g_CurrentTrackList.PopBack(); } } } } }
/* * Delete dangling tracks * Vias: * If a via is only connected to a dangling track, it also will be removed */ bool TRACKS_CLEANER::deleteUnconnectedTracks() { if( m_Brd->m_Track == NULL ) return false; bool modified = false; bool item_erased = true; while( item_erased ) // Iterate when at least one track is deleted { item_erased = false; TRACK* next_track; for( TRACK * track = m_Brd->m_Track; track ; track = next_track ) { next_track = track->Next(); int flag_erase = 0; //Not connected indicator int type_end = 0; if( track->GetState( START_ON_PAD ) ) type_end |= START_ON_PAD; if( track->GetState( END_ON_PAD ) ) type_end |= END_ON_PAD; // if the track start point is not connected to a pad, // test if this track start point is connected to another track // For via test, an enhancement could be to test if connected // to 2 items on different layers. // Currently a via must be connected to 2 items, that can be on the same layer LAYER_NUM top_layer, bottom_layer; ZONE_CONTAINER* zone; if( (type_end & START_ON_PAD ) == 0 ) { TRACK* other = track->GetTrace( m_Brd->m_Track, NULL, FLG_START ); if( other == NULL ) // Test a connection to zones { if( track->Type() != PCB_VIA_T ) { zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), track->GetLayer(), track->GetLayer(), track->GetNetCode() ); } else { ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), top_layer, bottom_layer, track->GetNetCode() ); } } if( (other == NULL) && (zone == NULL) ) { flag_erase |= 1; } else // segment, via or zone connected to this end { track->start = other; // If a via is connected to this end, // test if this via has a second item connected. // If no, remove it with the current segment if( other && other->Type() == PCB_VIA_T ) { // search for another segment following the via track->SetState( BUSY, true ); SEGVIA* via = (SEGVIA*) other; other = via->GetTrace( m_Brd->m_Track, NULL, FLG_START ); if( other == NULL ) { via->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetStart(), bottom_layer, top_layer, via->GetNetCode() ); } if( (other == NULL) && (zone == NULL) ) flag_erase |= 2; track->SetState( BUSY, false ); } } } // if track end point is not connected to a pad, // test if this track end point is connected to an other track if( (type_end & END_ON_PAD ) == 0 ) { TRACK* other = track->GetTrace( m_Brd->m_Track, NULL, FLG_END ); if( other == NULL ) // Test a connection to zones { if( track->Type() != PCB_VIA_T ) { zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), track->GetLayer(), track->GetLayer(), track->GetNetCode() ); } else { ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), top_layer, bottom_layer, track->GetNetCode() ); } } if ( (other == NULL) && (zone == NULL) ) { flag_erase |= 0x10; } else // segment, via or zone connected to this end { track->end = other; // If a via is connected to this end, test if this via has a second item connected // if no, remove it with the current segment if( other && other->Type() == PCB_VIA_T ) { // search for another segment following the via track->SetState( BUSY, true ); SEGVIA* via = (SEGVIA*) other; other = via->GetTrace( m_Brd->m_Track, NULL, FLG_END ); if( other == NULL ) { via->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetEnd(), bottom_layer, top_layer, via->GetNetCode() ); } if( (other == NULL) && (zone == NULL) ) flag_erase |= 0x20; track->SetState( BUSY, false ); } } } if( flag_erase ) { // remove segment from board track->DeleteStructure(); // iterate, because a track connected to the deleted track // is now perhaps now not connected and should be deleted item_erased = true; modified = true; } } } return modified; }
bool DIALOG_TRACK_VIA_PROPERTIES::Apply( COMMIT& aCommit ) { if( !check() ) return false; bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED; bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED; for( auto item : m_items ) { aCommit.Modify( item ); switch( item->Type() ) { case PCB_TRACE_T: { assert( m_tracks ); TRACK* t = static_cast<TRACK*>( item ); if( m_trackStartX.Valid() || m_trackStartY.Valid() ) { wxPoint start = t->GetStart(); if( m_trackStartX.Valid() ) start.x = m_trackStartX.GetValue(); if( m_trackStartY.Valid() ) start.y = m_trackStartY.GetValue(); t->SetStart( start ); } if( m_trackEndX.Valid() || m_trackEndY.Valid() ) { wxPoint end = t->GetEnd(); if( m_trackEndX.Valid() ) end.x = m_trackEndX.GetValue(); if( m_trackEndY.Valid() ) end.y = m_trackEndY.GetValue(); t->SetEnd( end ); } if( m_trackNetclass->IsChecked() ) { t->SetWidth( t->GetNetClass()->GetTrackWidth() ); } else if( m_trackWidth.Valid() ) { t->SetWidth( m_trackWidth.GetValue() ); } LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection(); if( layer != UNDEFINED_LAYER ) t->SetLayer( (LAYER_ID) layer ); if( changeLock ) t->SetLocked( setLock ); break; } case PCB_VIA_T: { assert( m_vias ); VIA* v = static_cast<VIA*>( item ); if( m_viaX.Valid() || m_viaY.Valid() ) { wxPoint pos = v->GetPosition(); if( m_viaX.Valid() ) pos.x = m_viaX.GetValue(); if( m_viaY.Valid() ) pos.y = m_viaY.GetValue(); v->SetPosition( pos ); } if( m_viaNetclass->IsChecked() ) { switch( v->GetViaType() ) { default: wxFAIL_MSG("Unhandled via type"); // fall through case VIA_THROUGH: case VIA_BLIND_BURIED: v->SetWidth( v->GetNetClass()->GetViaDiameter() ); v->SetDrill( v->GetNetClass()->GetViaDrill() ); break; case VIA_MICROVIA: v->SetWidth( v->GetNetClass()->GetuViaDiameter() ); v->SetDrill( v->GetNetClass()->GetuViaDrill() ); break; } } else { if( m_viaDiameter.Valid() ) v->SetWidth( m_viaDiameter.GetValue() ); if( m_viaDrill.Valid() ) v->SetDrill( m_viaDrill.GetValue() ); } if( changeLock ) v->SetLocked( setLock ); break; } default: assert( false ); break; } } return true; }
void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos ) { VECTOR2I origin; switch( aItem->Type() ) { case PCB_MODULE_T: { MODULE* mod = static_cast<MODULE*>( aItem ); addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() ) addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_PAD_T: { D_PAD* pad = static_cast<D_PAD*>( aItem ); addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_MODULE_EDGE_T: case PCB_LINE_T: { DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem ); VECTOR2I start = dseg->GetStart(); VECTOR2I end = dseg->GetEnd(); //LAYER_ID layer = dseg->GetLayer(); switch( dseg->GetShape() ) { case S_CIRCLE: { int r = ( start - end ).EuclideanNorm(); addAnchor( start, ORIGIN | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg ); addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg ); break; } case S_ARC: { origin = dseg->GetCenter(); addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } case S_SEGMENT: { origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor( start, CORNER | SNAPPABLE, dseg ); addAnchor( end, CORNER | SNAPPABLE, dseg ); addAnchor( origin, ORIGIN, dseg ); break; } default: { origin = dseg->GetStart(); addAnchor( origin, ORIGIN | SNAPPABLE, dseg ); break; } } break; } case PCB_TRACE_T: { TRACK* track = static_cast<TRACK*>( aItem ); VECTOR2I start = track->GetStart(); VECTOR2I end = track->GetEnd(); origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor( start, CORNER | SNAPPABLE, track ); addAnchor( end, CORNER | SNAPPABLE, track ); addAnchor( origin, ORIGIN, track); break; } case PCB_VIA_T: addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem ); break; case PCB_ZONE_AREA_T: { const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline(); int cornersCount = outline->GetCornersCount(); SHAPE_LINE_CHAIN lc; lc.SetClosed( true ); for( int i = 0; i < cornersCount; ++i ) { const VECTOR2I p ( outline->GetPos( i ) ); addAnchor( p, CORNER, aItem ); lc.Append( p ); } addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem ); break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: addAnchor( aItem->GetPosition(), ORIGIN, aItem ); default: break; } }
bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow() { auto connectivity = m_frame->GetBoard()->GetConnectivity(); int newNetCode = m_netSelector->GetSelectedNetcode(); std::vector<D_PAD*> changingPads; if ( !m_netSelector->IsIndeterminate() ) { std::set<D_PAD*> connectedPads; for( auto& item : m_items ) { const KICAD_T ourTypes[] = { PCB_TRACE_T, PCB_PAD_T, PCB_VIA_T, PCB_MODULE_T, EOT }; auto connectedItems = connectivity->GetConnectedItems( static_cast<BOARD_CONNECTED_ITEM*>( item ), ourTypes, true ); for ( auto citem : connectedItems ) { if( citem->Type() == PCB_PAD_T ) { connectedPads.insert( static_cast<D_PAD*>( citem ) ); } } } for( D_PAD* pad : connectedPads ) { if( pad->GetNetCode() != newNetCode ) changingPads.push_back( pad ); } } // Run validations: if( changingPads.size() ) { if( !confirmPadChange( changingPads ) ) return false; } if( m_vias ) { if( !m_viaDiameter.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) || !m_viaDrill.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) ) return false; if( m_ViaDiameterCtrl->IsEnabled() && !m_viaDiameter.IsIndeterminate() && m_ViaDrillCtrl->IsEnabled() && !m_viaDrill.IsIndeterminate() && m_viaDiameter.GetValue() <= m_viaDrill.GetValue() ) { DisplayError( GetParent(), _( "Via drill size must be smaller than via diameter" ) ); m_ViaDrillCtrl->SelectAll(); m_ViaDrillCtrl->SetFocus(); return false; } if( m_ViaStartLayer->GetLayerSelection() != UNDEFINED_LAYER && m_ViaStartLayer->GetLayerSelection() == m_ViaEndLayer->GetLayerSelection() ) { DisplayError( GetParent(), _( "Via start layer and end layer cannot be the same" ) ); return false; } } if( m_tracks ) { if( !m_trackWidth.Validate( GEOMETRY_MIN_SIZE, INT_MAX ) ) return false; } // If we survived that, then save the changes: bool changeLock = m_lockedCbox->Get3StateValue() != wxCHK_UNDETERMINED; bool setLock = m_lockedCbox->Get3StateValue() == wxCHK_CHECKED; for( auto item : m_items ) { m_commit.Modify( item ); switch( item->Type() ) { case PCB_TRACE_T: { wxASSERT( m_tracks ); TRACK* t = static_cast<TRACK*>( item ); if( !m_trackStartX.IsIndeterminate() ) t->SetStart( wxPoint( m_trackStartX.GetValue(), t->GetStart().y ) ); if( !m_trackStartY.IsIndeterminate() ) t->SetStart( wxPoint( t->GetStart().x, m_trackStartY.GetValue() ) ); if( !m_trackEndX.IsIndeterminate() ) t->SetEnd( wxPoint( m_trackEndX.GetValue(), t->GetEnd().y ) ); if( !m_trackEndY.IsIndeterminate() ) t->SetEnd( wxPoint( t->GetEnd().x, m_trackEndY.GetValue() ) ); if( m_trackNetclass->IsChecked() ) t->SetWidth( t->GetNetClass()->GetTrackWidth() ); else if( !m_trackWidth.IsIndeterminate() ) t->SetWidth( m_trackWidth.GetValue() ); LAYER_NUM layer = m_TrackLayerCtrl->GetLayerSelection(); if( layer != UNDEFINED_LAYER ) t->SetLayer( (PCB_LAYER_ID) layer ); if( changeLock ) t->SetLocked( setLock ); if ( !m_netSelector->IsIndeterminate() ) t->SetNetCode( m_netSelector->GetSelectedNetcode() ); break; } case PCB_VIA_T: { wxASSERT( m_vias ); VIA* v = static_cast<VIA*>( item ); if( !m_viaX.IsIndeterminate() ) v->SetPosition( wxPoint( m_viaX.GetValue(), v->GetPosition().y ) ); if( !m_viaY.IsIndeterminate() ) v->SetPosition( wxPoint( v->GetPosition().x, m_viaY.GetValue() ) ); if( m_ViaTypeChoice->GetSelection() != 3) { switch( m_ViaTypeChoice->GetSelection() ) { default: case 0: v->SetViaType( VIA_THROUGH ); v->SanitizeLayers(); break; case 1: v->SetViaType( VIA_MICROVIA ); break; case 2: v->SetViaType( VIA_BLIND_BURIED ); break; } } auto startLayer = static_cast<PCB_LAYER_ID>( m_ViaStartLayer->GetLayerSelection() ); auto endLayer = static_cast<PCB_LAYER_ID>( m_ViaEndLayer->GetLayerSelection() ); if (startLayer != UNDEFINED_LAYER ) v->SetTopLayer( startLayer ); if (endLayer != UNDEFINED_LAYER ) v->SetBottomLayer( endLayer ); v->SanitizeLayers(); if( m_viaNetclass->IsChecked() ) { switch( v->GetViaType() ) { default: wxFAIL_MSG("Unhandled via type"); // fall through case VIA_THROUGH: case VIA_BLIND_BURIED: v->SetWidth( v->GetNetClass()->GetViaDiameter() ); v->SetDrill( v->GetNetClass()->GetViaDrill() ); break; case VIA_MICROVIA: v->SetWidth( v->GetNetClass()->GetuViaDiameter() ); v->SetDrill( v->GetNetClass()->GetuViaDrill() ); break; } } else { if( !m_viaDiameter.IsIndeterminate() ) v->SetWidth( m_viaDiameter.GetValue() ); if( !m_viaDrill.IsIndeterminate() ) v->SetDrill( m_viaDrill.GetValue() ); } if ( !m_netSelector->IsIndeterminate() ) v->SetNetCode( m_netSelector->GetSelectedNetcode() ); if( changeLock ) v->SetLocked( setLock ); break; } default: wxASSERT( false ); break; } } if ( !m_netSelector->IsIndeterminate() ) { // Commit::Push() will rebuild connectivitiy propagating nets from connected pads // outwards. We therefore have to update the connected pads in order for the net // change to "stick". for( D_PAD* pad : changingPads ) { m_commit.Modify( pad ); pad->SetNetCode( m_netSelector->GetSelectedNetcode() ); } } m_commit.Push( _( "Edit track/via properties" ) ); return true; }
/* Init variables (slope, Y intersect point, flags) for * Show_Drag_Track_Segment_With_Cte_Slope() * return true if Ok, false if dragging is not possible * (2 colinear segments) */ bool InitialiseDragParameters() { double tx1, tx2, ty1, ty2; // temporary storage of points TRACK* Track; TRACK* tSegmentToStart = NULL, * tSegmentToEnd = NULL; if( g_DragSegmentList.size() == 0 ) return false; /* get the segments : * from last to first in list are: * the segment to move * the segment connected to its end point (if exists) * the segment connected to its start point (if exists) */ int ii = g_DragSegmentList.size() - 1; Track = g_DragSegmentList[ii].m_Track; if( Track == NULL ) return false; ii--; if( ii >= 0) { if( s_EndSegmentPresent ) { tSegmentToEnd = g_DragSegmentList[ii].m_Track; // Get the segment connected to // the end point ii--; } if( s_StartSegmentPresent ) { if( ii >= 0 ) tSegmentToStart = g_DragSegmentList[ii].m_Track; // Get the segment connected to // the start point } } // would be nice to eliminate collinear segments here, so we don't // have to deal with that annoying "Unable to drag this segment: two // collinear segments" s_StartPointVertical = false; s_EndPointVertical = false; s_MovingSegmentVertical = false; s_StartPointHorizontal = false; s_EndPointHorizontal = false; s_MovingSegmentHorizontal = false; // Init parameters for the starting point of the moved segment if( tSegmentToStart ) { if( tSegmentToStart->GetFlags() & ENDPOINT ) { tx1 = (double) tSegmentToStart->GetStart().x; ty1 = (double) tSegmentToStart->GetStart().y; tx2 = (double) tSegmentToStart->GetEnd().x; ty2 = (double) tSegmentToStart->GetEnd().y; } else { tx1 = (double) tSegmentToStart->GetEnd().x; ty1 = (double) tSegmentToStart->GetEnd().y; tx2 = (double) tSegmentToStart->GetStart().x; ty2 = (double) tSegmentToStart->GetStart().y; } } else // move the start point on a line starting at Track->GetStart(), and perpendicular to Track { tx1 = (double) Track->GetStart().x; ty1 = (double) Track->GetStart().y; tx2 = (double) Track->GetEnd().x; ty2 = (double) Track->GetEnd().y; RotatePoint( &tx2, &ty2, tx1, ty1, 900 ); } if( tx1 != tx2 ) { s_StartSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 ); s_StartSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 ); } else { s_StartPointVertical = true; //signal first segment vertical } if( ty1 == ty2 ) { s_StartPointHorizontal = true; } // Init parameters for the ending point of the moved segment if( tSegmentToEnd ) { //check if second line is vertical if( tSegmentToEnd->GetFlags() & STARTPOINT ) { tx1 = (double) tSegmentToEnd->GetStart().x; ty1 = (double) tSegmentToEnd->GetStart().y; tx2 = (double) tSegmentToEnd->GetEnd().x; ty2 = (double) tSegmentToEnd->GetEnd().y; } else { tx1 = (double) tSegmentToEnd->GetEnd().x; ty1 = (double) tSegmentToEnd->GetEnd().y; tx2 = (double) tSegmentToEnd->GetStart().x; ty2 = (double) tSegmentToEnd->GetStart().y; } } else // move the start point on a line starting at Track->GetEnd(), and perpendicular to Track { tx1 = (double) Track->GetEnd().x; ty1 = (double) Track->GetEnd().y; tx2 = (double) Track->GetStart().x; ty2 = (double) Track->GetStart().y; RotatePoint( &tx2, &ty2, tx1, ty1, -900 ); } if( tx2 != tx1 ) { s_EndSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 ); s_EndSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 ); } else { s_EndPointVertical = true; //signal second segment vertical } if( ty1 == ty2 ) { s_EndPointHorizontal = true; } // Init parameters for the moved segment tx1 = (double) Track->GetStart().x; ty1 = (double) Track->GetStart().y; tx2 = (double) Track->GetEnd().x; ty2 = (double) Track->GetEnd().y; if( tx2 != tx1 ) { s_MovingSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 ); } else { s_MovingSegmentVertical = true; // signal vertical line } if( ty1 == ty2 ) { s_MovingSegmentHorizontal = true; } // Test if drag is possible: if( s_MovingSegmentVertical ) { if( s_EndPointVertical || s_StartPointVertical ) return false; } else { if( !s_EndPointVertical && ( s_MovingSegmentSlope == s_EndSegmentSlope ) ) return false; if( !s_StartPointVertical && ( s_MovingSegmentSlope == s_StartSegmentSlope ) ) return false; } return true; }
void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) { if( aImage == NULL ) { return; } EDA_ITEM * pnext = Next(); EDA_ITEM * pback = Back(); switch( Type() ) { case PCB_MODULE_T: { MODULE* tmp = (MODULE*) aImage->Clone(); ( (MODULE*) aImage )->Copy( (MODULE*) this ); ( (MODULE*) this )->Copy( tmp ); delete tmp; } break; case PCB_ZONE_AREA_T: { ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone(); ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) this ); ( (ZONE_CONTAINER*) this )->Copy( tmp ); delete tmp; } break; case PCB_LINE_T: std::swap( *((DRAWSEGMENT*)this), *((DRAWSEGMENT*)aImage) ); break; case PCB_TRACE_T: case PCB_VIA_T: { TRACK* track = (TRACK*) this; TRACK* image = (TRACK*) aImage; EXCHG(track->m_Layer, image->m_Layer ); // swap start, end, width and shape for track and image. wxPoint exchp = track->GetStart(); track->SetStart( image->GetStart() ); image->SetStart( exchp ); exchp = track->GetEnd(); track->SetEnd( image->GetEnd() ); image->SetEnd( exchp ); int atmp = track->GetWidth(); track->SetWidth( image->GetWidth() ); image->SetWidth( atmp ); if( Type() == PCB_VIA_T ) { VIA *via = static_cast<VIA*>( this ); VIA *viaimage = static_cast<VIA*>( aImage ); VIATYPE_T viatmp = via->GetViaType(); via->SetViaType( viaimage->GetViaType() ); viaimage->SetViaType( viatmp ); int drilltmp = via->GetDrillValue(); if( via->IsDrillDefault() ) drilltmp = -1; int itmp = viaimage->GetDrillValue(); if( viaimage->IsDrillDefault() ) itmp = -1; EXCHG(itmp, drilltmp ); if( drilltmp > 0 ) via->SetDrill( drilltmp ); else via->SetDrillDefault(); if( itmp > 0 ) viaimage->SetDrill( itmp ); else viaimage->SetDrillDefault(); } } break; case PCB_TEXT_T: std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) ); break; case PCB_TARGET_T: std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) ); break; case PCB_DIMENSION_T: std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) ); break; case PCB_ZONE_T: default: wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() ); break; } if( pnext != Next() || pback != Back() ) { Pnext = pnext; Pback = pback; #ifdef DEBUG wxLogMessage( wxT( "SwapData Error: %s Pnext or Pback pointers modified" ), GetClass().GetData() ); #endif } }