static void calcule_connexite_1_net(TRACK* pt_start_conn,TRACK* pt_end_conn) /***************************************************************************/ /* calcule la connexite d'un net constitue de segments de piste consecutifs. Entree: pt_start_conn = adresse du 1er segment ( debut du net ) pt_end_conn = adr de fin (dernier segment) Les connexions relatives aux pads doivent etre deja calculees, car elles ne sont pas ici recalculees ( pour des raisons de temps de calcul, et du fait que lors des modif de pistes, les pads ne sont pas touches */ { TRACK * Track; /* Les pointeurs .start et .end sont mis a jour, si la connexion est du type segment a segment. la connexion sur pads est supposee etre deja calculee */ /* Raz des pointeurs sur pistes */ for( Track = pt_start_conn; Track != NULL; Track = (TRACK*) Track->Pnext) { Track->m_Sous_Netcode = 0; if( Track->GetState(BEGIN_ONPAD) == 0 ) Track->start = NULL; if( Track->GetState(END_ONPAD) == 0 ) Track->end = NULL; if (Track == pt_end_conn) break; } /* calcul des connexions */ for( Track = pt_start_conn; Track != NULL; Track = (TRACK*) Track->Pnext) { if(Track->m_StructType == TYPEVIA) { TRACK* pt_segm; int layermask = Track->ReturnMaskLayer(); for( pt_segm = pt_start_conn; pt_segm != NULL; pt_segm = (TRACK*) pt_segm->Pnext) { int curlayermask = pt_segm->ReturnMaskLayer(); if( (pt_segm->m_Start.x == Track->m_Start.x) && (pt_segm->m_Start.y == Track->m_Start.y) && ( layermask & curlayermask ) ) { pt_segm->start = Track; } if( (pt_segm->m_End.x == Track->m_Start.x) && (pt_segm->m_End.y == Track->m_Start.y) && (layermask & curlayermask) ) { pt_segm->end = Track; } if( pt_segm == pt_end_conn ) break; } } if( Track->start == NULL ) { Track->start = Locate_Piste_Connectee(Track, Track,pt_end_conn,START); } if( Track->end == NULL ) { Track->end = Locate_Piste_Connectee(Track, Track,pt_end_conn,END); } if (Track == pt_end_conn) break; } /* Generation des sous equipots du net */ propage_equipot(pt_start_conn,pt_end_conn); }
bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) { TRACK* track; wxPoint delta; // lenght on X and Y axis of segments int layerMask; int net_code_ref; wxPoint shape_pos; NETCLASS* netclass = aRefSeg->GetNetClass(); /* 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->ReturnMaskLayer(); net_code_ref = aRefSeg->GetNet(); // Phase 0 : Test vias if( aRefSeg->Type() == PCB_VIA_T ) { // test if the via size is smaller than minimum if( aRefSeg->GetShape() == VIA_MICROVIA ) { if( aRefSeg->GetWidth() < netclass->GetuViaMinDiameter() ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_TOO_SMALL_MICROVIA, m_currentMarker ); return false; } } else { if( aRefSeg->GetWidth() < netclass->GetViaMinDiameter() ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_TOO_SMALL_VIA, 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( aRefSeg->GetDrillValue() > aRefSeg->GetWidth() ) { m_currentMarker = fillMarker( aRefSeg, 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( aRefSeg->GetShape() == VIA_MICROVIA ) { int layer1, layer2; bool err = true; ( (SEGVIA*) aRefSeg )->ReturnLayerPair( &layer1, &layer2 ); if( layer1 > layer2 ) EXCHG( layer1, layer2 ); // test: if( layer1 == LAYER_N_BACK && layer2 == LAYER_N_2 ) err = false; if( layer1 == (m_pcb->GetDesignSettings().GetCopperLayerCount() - 2 ) && layer2 == LAYER_N_FRONT ) err = false; if( err ) { m_currentMarker = fillMarker( aRefSeg, NULL, DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, m_currentMarker ); return false; } } } else // This is a track segment { if( aRefSeg->GetWidth() < netclass->GetTrackMinWidth() ) { 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.SetLayerMask( ALL_CU_LAYERS ); // Ensure the hole is on all layers // Compute the min distance to pads if( testPads ) { for( unsigned ii = 0; ii<m_pcb->GetPadCount(); ++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->GetLayerMask() & layerMask ) == 0 ) { /* 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() ); 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->GetNet() // the pad must be connected && net_code_ref == pad->GetNet() ) // the pad net is the same as current net -> Ok continue; // DRC for the pad shape_pos = pad->ReturnShapePos(); 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->GetNet() ) continue; // No problem if segment are on different layers : if( ( layerMask & track->ReturnMaskLayer() ) == 0 ) 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; // If the reference segment is a via, we test it here if( aRefSeg->Type() == PCB_VIA_T ) { int angle = 0; // angle du segment a tester; 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( (int) hypot( segStartPoint.x, segStartPoint.y ) < w_dist ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_VIA_NEAR_VIA, m_currentMarker ); return false; } } else // test via to segment { // Compute l'angle 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 ) EXCHG( segStartPoint.x, segEndPoint.x ); if( segStartPoint.x > (-w_dist) && segStartPoint.x < (m_segmLength + w_dist) ) /* possible error drc */ { // 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) ) { /* 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 ) { m_currentMarker = fillMarker( aRefSeg, track, DRCE_TRACK_UNKNOWN1, 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 ) EXCHG( 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 */ int angle = ArcTangente( delta.y, delta.x ); // Compute the segment lenght: delta.x = lenght 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; }