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; }
/* test if distance between a segment is > aMinDist * segment start point is assumed in (0,0) and segment start point in m_segmEnd * and its orientation is m_segmAngle (m_segmAngle must be already initialized) * and have aSegmentWidth. */ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist ) { wxSize padHalfsize; // half dimension of the pad int r; int segmHalfWidth = aSegmentWidth / 2; int distToLine = segmHalfWidth + aMinDist; padHalfsize.x = aPad->GetSize().x >> 1; padHalfsize.y = aPad->GetSize().y >> 1; if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID ) // The size is bigger, due to GetDelta() extra size { padHalfsize.x += std::abs(aPad->GetDelta().y) / 2; // Remember: GetDelta().y is the GetSize().x change padHalfsize.y += std::abs(aPad->GetDelta().x) / 2; // Remember: GetDelta().x is the GetSize().y change } if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) { /* Easy case: just test the distance between segment and pad centre * calculate pad coordinates in the X,Y axis with X axis = segment to test */ RotatePoint( &m_padToTestPos, m_segmAngle ); return checkMarginToCircle( m_padToTestPos, distToLine + padHalfsize.x, m_segmLength ); } /* calculate the bounding box of the pad, including the clearance and the segment width * if the line from 0 to m_segmEnd does not intersect this bounding box, * the clearance is always OK * But if intersect, a better analysis of the pad shape must be done. */ m_xcliplo = m_padToTestPos.x - distToLine - padHalfsize.x; m_ycliplo = m_padToTestPos.y - distToLine - padHalfsize.y; m_xcliphi = m_padToTestPos.x + distToLine + padHalfsize.x; m_ycliphi = m_padToTestPos.y + distToLine + padHalfsize.y; wxPoint startPoint; wxPoint endPoint = m_segmEnd; double orient = aPad->GetOrientation(); RotatePoint( &startPoint, m_padToTestPos, -orient ); RotatePoint( &endPoint, m_padToTestPos, -orient ); if( checkLine( startPoint, endPoint ) ) return true; /* segment intersects the bounding box. But there is not always a DRC error. * A fine analysis of the pad shape must be done. */ switch( aPad->GetShape() ) { default: return false; case PAD_SHAPE_OVAL: { /* an oval is a complex shape, but is a rectangle and 2 circles * these 3 basic shapes are more easy to test. * * In calculations we are using a vertical oval shape * (i.e. a vertical rounded segment) * for horizontal oval shapes, swap x and y size and rotate the shape */ if( padHalfsize.x > padHalfsize.y ) { std::swap( padHalfsize.x, padHalfsize.y ); orient = AddAngles( orient, 900 ); } // here, padHalfsize.x is the radius of rounded ends. int deltay = padHalfsize.y - padHalfsize.x; // here: padHalfsize.x = radius, // deltay = dist between the centre pad and the centre of a rounded end // Test the rectangular area between the two circles (the rounded ends) m_xcliplo = m_padToTestPos.x - distToLine - padHalfsize.x; m_ycliplo = m_padToTestPos.y - deltay; m_xcliphi = m_padToTestPos.x + distToLine + padHalfsize.x; m_ycliphi = m_padToTestPos.y + deltay; if( !checkLine( startPoint, endPoint ) ) { return false; } // test the first circle startPoint.x = m_padToTestPos.x; // startPoint = centre of the upper circle of the oval shape startPoint.y = m_padToTestPos.y + deltay; // Calculate the actual position of the circle, given the pad orientation: RotatePoint( &startPoint, m_padToTestPos, orient ); // Calculate the actual position of the circle in the new X,Y axis: RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, padHalfsize.x + distToLine, m_segmLength ) ) { return false; } // test the second circle startPoint.x = m_padToTestPos.x; // startPoint = centre of the lower circle of the oval shape startPoint.y = m_padToTestPos.y - deltay; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, padHalfsize.x + distToLine, m_segmLength ) ) { return false; } } break; case PAD_SHAPE_ROUNDRECT: // a round rect is a smaller rect, with a clearance augmented by the corners radius r = aPad->GetRoundRectCornerRadius(); padHalfsize.x -= r; padHalfsize.y -= r; distToLine += r; // Fall through case PAD_SHAPE_RECT: // the area to test is a rounded rectangle. // this can be done by testing 2 rectangles and 4 circles (the corners) // Testing the first rectangle dimx + distToLine, dimy: m_xcliplo = m_padToTestPos.x - padHalfsize.x - distToLine; m_ycliplo = m_padToTestPos.y - padHalfsize.y; m_xcliphi = m_padToTestPos.x + padHalfsize.x + distToLine; m_ycliphi = m_padToTestPos.y + padHalfsize.y; if( !checkLine( startPoint, endPoint ) ) return false; // Testing the second rectangle dimx , dimy + distToLine m_xcliplo = m_padToTestPos.x - padHalfsize.x; m_ycliplo = m_padToTestPos.y - padHalfsize.y - distToLine; m_xcliphi = m_padToTestPos.x + padHalfsize.x; m_ycliphi = m_padToTestPos.y + padHalfsize.y + distToLine; if( !checkLine( startPoint, endPoint ) ) return false; // testing the 4 circles which are the clearance area of each corner: // testing the left top corner of the rectangle startPoint.x = m_padToTestPos.x - padHalfsize.x; startPoint.y = m_padToTestPos.y - padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) return false; // testing the right top corner of the rectangle startPoint.x = m_padToTestPos.x + padHalfsize.x; startPoint.y = m_padToTestPos.y - padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) return false; // testing the left bottom corner of the rectangle startPoint.x = m_padToTestPos.x - padHalfsize.x; startPoint.y = m_padToTestPos.y + padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) return false; // testing the right bottom corner of the rectangle startPoint.x = m_padToTestPos.x + padHalfsize.x; startPoint.y = m_padToTestPos.y + padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) ) return false; break; case PAD_SHAPE_TRAPEZOID: { wxPoint poly[4]; aPad->BuildPadPolygon( poly, wxSize( 0, 0 ), orient ); // Move shape to m_padToTestPos for( int ii = 0; ii < 4; ii++ ) { poly[ii] += m_padToTestPos; RotatePoint( &poly[ii], m_segmAngle ); } if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ), wxPoint(m_segmLength,0), distToLine ) ) return false; break; } } return true; }
/* test if distance between a segment is > aMinDist * segment start point is assumed in (0,0) and segment start point in m_segmEnd * and its orientation is m_segmAngle (m_segmAngle must be already initialized) * and have aSegmentWidth. */ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist ) { wxSize padHalfsize; // half the dimension of the pad wxPoint startPoint, endPoint; int seuil; int deltay; int segmHalfWidth = aSegmentWidth / 2; seuil = segmHalfWidth + aMinDist; padHalfsize.x = aPad->GetSize().x >> 1; padHalfsize.y = aPad->GetSize().y >> 1; if( aPad->GetShape() == PAD_TRAPEZOID ) // The size is bigger, due to GetDelta() extra size { padHalfsize.x += std::abs(aPad->GetDelta().y) / 2; // Remember: GetDelta().y is the GetSize().x change padHalfsize.y += std::abs(aPad->GetDelta().x) / 2; // Remember: GetDelta().x is the GetSize().y change } if( aPad->GetShape() == PAD_CIRCLE ) { /* Easy case: just test the distance between segment and pad centre * calculate pad coordinates in the X,Y axis with X axis = segment to test */ RotatePoint( &m_padToTestPos, m_segmAngle ); return checkMarginToCircle( m_padToTestPos, seuil + padHalfsize.x, m_segmLength ); } /* calculate the bounding box of the pad, including the clearance and the segment width * if the line from 0 to m_segmEnd does not intersect this bounding box, * the clearance is always OK * But if intersect, a better analysis of the pad shape must be done. */ m_xcliplo = m_padToTestPos.x - seuil - padHalfsize.x; m_ycliplo = m_padToTestPos.y - seuil - padHalfsize.y; m_xcliphi = m_padToTestPos.x + seuil + padHalfsize.x; m_ycliphi = m_padToTestPos.y + seuil + padHalfsize.y; startPoint.x = startPoint.y = 0; endPoint = m_segmEnd; double orient = aPad->GetOrientation(); RotatePoint( &startPoint, m_padToTestPos, -orient ); RotatePoint( &endPoint, m_padToTestPos, -orient ); if( checkLine( startPoint, endPoint ) ) return true; /* segment intersects the bounding box. But there is not always a DRC error. * A fine analysis of the pad shape must be done. */ switch( aPad->GetShape() ) { default: return false; case PAD_OVAL: /* an oval is a complex shape, but is a rectangle and 2 circles * these 3 basic shapes are more easy to test. */ /* We use a vertical oval shape. for horizontal ovals, swap x and y size and rotate the shape*/ if( padHalfsize.x > padHalfsize.y ) { EXCHG( padHalfsize.x, padHalfsize.y ); orient = AddAngles( orient, 900 ); } deltay = padHalfsize.y - padHalfsize.x; // here: padHalfsize.x = radius, delta = dist centre cercles a centre pad // Test the rectangle area between the two circles m_xcliplo = m_padToTestPos.x - seuil - padHalfsize.x; m_ycliplo = m_padToTestPos.y - segmHalfWidth - deltay; m_xcliphi = m_padToTestPos.x + seuil + padHalfsize.x; m_ycliphi = m_padToTestPos.y + segmHalfWidth + deltay; if( !checkLine( startPoint, endPoint ) ) { return false; } // test the first circle startPoint.x = m_padToTestPos.x; // startPoint = centre of the upper circle of the oval shape startPoint.y = m_padToTestPos.y + deltay; // Calculate the actual position of the circle, given the pad orientation: RotatePoint( &startPoint, m_padToTestPos, orient ); // Calculate the actual position of the circle in the new X,Y axis: RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, padHalfsize.x + seuil, m_segmLength ) ) { return false; } // test the second circle startPoint.x = m_padToTestPos.x; // startPoint = centre of the lower circle of the oval shape startPoint.y = m_padToTestPos.y - deltay; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, padHalfsize.x + seuil, m_segmLength ) ) { return false; } break; case PAD_RECT: /* 2 rectangle + 4 1/4 cercles a tester */ /* Test du rectangle dimx + seuil, dimy */ m_xcliplo = m_padToTestPos.x - padHalfsize.x - seuil; m_ycliplo = m_padToTestPos.y - padHalfsize.y; m_xcliphi = m_padToTestPos.x + padHalfsize.x + seuil; m_ycliphi = m_padToTestPos.y + padHalfsize.y; if( !checkLine( startPoint, endPoint ) ) return false; /* Test du rectangle dimx , dimy + seuil */ m_xcliplo = m_padToTestPos.x - padHalfsize.x; m_ycliplo = m_padToTestPos.y - padHalfsize.y - seuil; m_xcliphi = m_padToTestPos.x + padHalfsize.x; m_ycliphi = m_padToTestPos.y + padHalfsize.y + seuil; if( !checkLine( startPoint, endPoint ) ) return false; /* test des 4 cercles ( surface d'solation autour des sommets */ /* test du coin sup. gauche du pad */ startPoint.x = m_padToTestPos.x - padHalfsize.x; startPoint.y = m_padToTestPos.y - padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, seuil, m_segmLength ) ) return false; /* test du coin sup. droit du pad */ startPoint.x = m_padToTestPos.x + padHalfsize.x; startPoint.y = m_padToTestPos.y - padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, seuil, m_segmLength ) ) return false; /* test du coin inf. gauche du pad */ startPoint.x = m_padToTestPos.x - padHalfsize.x; startPoint.y = m_padToTestPos.y + padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, seuil, m_segmLength ) ) return false; /* test du coin inf. droit du pad */ startPoint.x = m_padToTestPos.x + padHalfsize.x; startPoint.y = m_padToTestPos.y + padHalfsize.y; RotatePoint( &startPoint, m_padToTestPos, orient ); RotatePoint( &startPoint, m_segmAngle ); if( !checkMarginToCircle( startPoint, seuil, m_segmLength ) ) return false; break; case PAD_TRAPEZOID: { wxPoint poly[4]; aPad->BuildPadPolygon( poly, wxSize( 0, 0 ), orient ); // Move shape to m_padToTestPos for( int ii = 0; ii < 4; ii++ ) { poly[ii] += m_padToTestPos; RotatePoint( &poly[ii], m_segmAngle ); } if( !trapezoid2segmentDRC( poly, wxPoint( 0, 0 ), wxPoint(m_segmLength,0), seuil ) ) return false; } break; } return true; }