/* 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; }
/* 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 wxPoint startPoint, endPoint; 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; 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_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_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( !trapezoid2segmentDRC( poly, wxPoint( 0, 0 ), wxPoint(m_segmLength,0), distToLine ) ) return false; } break; } return true; }