Pcbnew: fix a very old bug in DRC, pad to pad drc tests: sometimes a test between a rectangular pad and an oval pad was skipped.
Segment Hit Test: enhanced detection near segment ends (noticeable for instance when clicking on short tracks in Pcbnew. Remove duplicate code about segment hit test. remove unused file.
This commit is contained in:
parent
5d5a50dde9
commit
78a8be0e8e
263
common/trigo.cpp
263
common/trigo.cpp
|
@ -1,176 +1,159 @@
|
||||||
/**
|
/**
|
||||||
* @file trigo.cpp
|
* @file trigo.cpp
|
||||||
* @brief Trigonometric functions.
|
* @brief Trigonometric and geometric basic functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fctsys.h>
|
#include <fctsys.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <math_for_graphics.h>
|
||||||
|
|
||||||
static bool DistanceTest( int seuil, int dx, int dy, int spot_cX, int spot_cY );
|
/* Function TestSegmentHit
|
||||||
|
* test for hit on line segment
|
||||||
|
* i.e. a reference point is within a given distance from segment
|
||||||
|
* aRefPoint = reference point to test
|
||||||
|
* aStart, aEnd are coordinates of end points segment
|
||||||
|
* aDist = maximum distance for hit
|
||||||
|
* Note: for calculation time reasons, the distance between the ref point
|
||||||
|
* and the segment is not always exactly calculated
|
||||||
|
* (we only know if the actual dist is < aDist, not exactly know this dist.
|
||||||
|
* Because many times we have horizontal or vertical segments,
|
||||||
|
* a special calcultaion is made for them
|
||||||
|
* Note: sometimes we need to calculate the distande between 2 points
|
||||||
|
* A square root should be calculated.
|
||||||
|
* However, because we just compare 2 distnaces, to avoid calculating square root,
|
||||||
|
* the square of distances are compared.
|
||||||
|
*/
|
||||||
|
static inline double square( int x ) // helper function to calculate x*x
|
||||||
|
{
|
||||||
|
return (double) x * x;
|
||||||
|
}
|
||||||
bool TestSegmentHit( wxPoint aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist )
|
bool TestSegmentHit( wxPoint aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist )
|
||||||
{
|
{
|
||||||
return DistanceTest( aDist, aEnd.x - aStart.x, aEnd.y - aStart.y,
|
// test for vertical or horizontal segment
|
||||||
aRefPoint.x - aStart.x, aRefPoint.y - aStart.y );
|
if( aEnd.x == aStart.x )
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool DistanceTest( int seuil, int dx, int dy, int spot_cX, int spot_cY )
|
|
||||||
{
|
|
||||||
/* We can have 4 cases::
|
|
||||||
* horizontal segment
|
|
||||||
* vertical segment
|
|
||||||
* 45 degrees segment
|
|
||||||
* other slopes
|
|
||||||
*/
|
|
||||||
int cXrot, cYrot, segX, segY;
|
|
||||||
int pointX, pointY;
|
|
||||||
|
|
||||||
segX = dx;
|
|
||||||
segY = dy;
|
|
||||||
pointX = spot_cX;
|
|
||||||
pointY = spot_cY;
|
|
||||||
|
|
||||||
/* Recalculating coord for the segment is in 1st quadrant (coord >= 0) */
|
|
||||||
if( segX < 0 ) /* set > 0 by symmetry about the Y axis */
|
|
||||||
{
|
{
|
||||||
segX = -segX;
|
// vertical segment
|
||||||
pointX = -pointX;
|
int ll = abs( aRefPoint.x - aStart.x );
|
||||||
}
|
|
||||||
|
|
||||||
if( segY < 0 ) /* set > 0 by symmetry about the X axis */
|
if( ll >= aDist )
|
||||||
{
|
return false;
|
||||||
segY = -segY;
|
|
||||||
pointY = -pointY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// To have only one case to examine, ensure aEnd.y > aStart.y
|
||||||
|
if( aEnd.y < aStart.y )
|
||||||
|
EXCHG( aStart.y, aEnd.y );
|
||||||
|
|
||||||
if( segY == 0 ) /* horizontal */
|
if( aRefPoint.y < aEnd.y && aRefPoint.y > aStart.y )
|
||||||
{
|
return true;
|
||||||
if( abs( pointY ) <= seuil )
|
|
||||||
|
// there is a special case: x,y near an end point (distance < dist )
|
||||||
|
// the distance should be carefully calculated
|
||||||
|
if( (aStart.y - aRefPoint.y) < aDist )
|
||||||
{
|
{
|
||||||
if( ( pointX >= 0 ) && ( pointX <= segX ) )
|
double dd = square( aRefPoint.x - aStart.x) +
|
||||||
return 1;
|
square( aRefPoint.y - aStart.y );
|
||||||
|
if( dd < square( aDist ) )
|
||||||
if( ( pointX < 0 ) && ( pointX >= -seuil ) )
|
|
||||||
{
|
|
||||||
if( ( ( pointX * pointX ) + ( pointY * pointY ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if( ( pointX > segX ) && ( pointX <= ( segX + seuil ) ) )
|
|
||||||
{
|
|
||||||
if( ( ( ( pointX - segX ) * ( pointX - segX ) )
|
|
||||||
+ ( pointY * pointY ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( segX == 0 ) /* vertical */
|
|
||||||
{
|
|
||||||
if( abs( pointX ) <= seuil )
|
|
||||||
{
|
|
||||||
if( ( pointY >= 0 ) && ( pointY <= segY ) )
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( ( pointY < 0 ) && ( pointY >= -seuil ) )
|
|
||||||
{
|
|
||||||
if( ( ( pointY * pointY ) + ( pointX * pointX ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ( pointY > segY ) && ( pointY <= ( segY + seuil ) ) )
|
|
||||||
{
|
|
||||||
if( ( ( ( pointY - segY ) * ( pointY - segY ) )
|
|
||||||
+ ( pointX * pointX ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if( segX == segY ) /* 45 degrees */
|
|
||||||
{
|
|
||||||
/* Rotate axes of 45 degrees. mouse was then
|
|
||||||
* Coord: x1 = x * y * cos45 + sin45
|
|
||||||
* y1 = y * cos45 - sin45 x *
|
|
||||||
* And the segment of track is horizontal.
|
|
||||||
* Coord recalculation of the mouse (sin45 = cos45 = .707 = 7 / 10
|
|
||||||
* Note: sin or cos45 = .707, and when recalculating coord
|
|
||||||
* dx45 and dy45, lect coeff .707 is neglected, dx and dy are
|
|
||||||
* actually 0707 times
|
|
||||||
* Too big. (security hole too small)
|
|
||||||
* Spot_cX, Y * must be by .707 * .707 = 0.5
|
|
||||||
*/
|
|
||||||
|
|
||||||
cXrot = (pointX + pointY) >> 1;
|
if( (aRefPoint.y - aEnd.y) < aDist )
|
||||||
cYrot = (pointY - pointX) >> 1;
|
|
||||||
|
|
||||||
/* Recalculating coord of segment extremity, which will be vertical
|
|
||||||
* following the orientation of axes on the screen: dx45 = pointx
|
|
||||||
* (or pointy) and 1.414 is actually greater, and dy45 = 0
|
|
||||||
*/
|
|
||||||
|
|
||||||
// * Threshold should be .707 to reflect the change in coeff dx, dy
|
|
||||||
seuil *= 7;
|
|
||||||
seuil /= 10;
|
|
||||||
|
|
||||||
if( abs( cYrot ) <= seuil ) /* ok on vertical axis */
|
|
||||||
{
|
{
|
||||||
if( ( cXrot >= 0 ) && ( cXrot <= segX ) )
|
double dd = square( aRefPoint.x - aEnd.x ) +
|
||||||
|
square( aRefPoint.y - aEnd.y );
|
||||||
|
if( dd < square( aDist ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Check extremes using the radius of a circle. */
|
|
||||||
if( ( cXrot < 0 ) && ( cXrot >= -seuil ) )
|
|
||||||
{
|
|
||||||
if( ( ( cXrot * cXrot ) + ( cYrot * cYrot ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if( ( cXrot > segX ) && ( cXrot <= ( segX + seuil ) ) )
|
|
||||||
{
|
|
||||||
if( ( ( ( cXrot - segX ) * ( cXrot - segX ) )
|
|
||||||
+ ( cYrot * cYrot ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else /* any orientation */
|
else if( aEnd.y == aStart.y )
|
||||||
{
|
{
|
||||||
/* There is a change of axis (rotation), so that the segment
|
// horizontal segment
|
||||||
* track is horizontal in the new reference
|
int ll = abs( aRefPoint.y - aStart.y );
|
||||||
*/
|
|
||||||
int angle;
|
|
||||||
|
|
||||||
angle = KiROUND( ( atan2( (double) segY, (double) segX ) * 1800.0 / M_PI ) );
|
if( ll >= aDist )
|
||||||
cXrot = pointX;
|
return false;
|
||||||
cYrot = pointY;
|
|
||||||
|
|
||||||
RotatePoint( &cXrot, &cYrot, angle ); /* Rotate the point to be tested */
|
// To have only one case to examine, ensure xf > xi
|
||||||
RotatePoint( &segX, &segY, angle ); /* Rotate the segment */
|
if( aEnd.x < aStart.x )
|
||||||
|
EXCHG( aStart.x, aEnd.x );
|
||||||
|
|
||||||
/* The track is horizontal, following the amendments to coordinate
|
if( aRefPoint.x < aEnd.x && aRefPoint.x > aStart.x )
|
||||||
* axis and, therefore segX = length of segment
|
return true;
|
||||||
*/
|
|
||||||
if( abs( cYrot ) <= seuil ) /* vertical axis */
|
// there is a special case: x,y near an end point (distance < dist )
|
||||||
|
// the distance should be carefully calculated
|
||||||
|
if( (aStart.x - aRefPoint.x) < aDist )
|
||||||
{
|
{
|
||||||
if( ( cXrot >= 0 ) && ( cXrot <= segX ) )
|
double dd = square( aRefPoint.x - aStart.x) +
|
||||||
|
square( aRefPoint.y - aStart.y );
|
||||||
|
if( dd < square( aDist ) )
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if( ( cXrot < 0 ) && ( cXrot >= -seuil ) )
|
if( (aRefPoint.x - aEnd.x) < aDist )
|
||||||
{
|
{
|
||||||
if( ( ( cXrot * cXrot ) + ( cYrot * cYrot ) ) <= ( seuil * seuil ) )
|
double dd = square(aRefPoint.x - aEnd.x) +
|
||||||
return true;
|
square( aRefPoint.y - aEnd.y);
|
||||||
}
|
if( dd < square( aDist ) )
|
||||||
|
return true;
|
||||||
if( ( cXrot > segX ) && ( cXrot <= ( segX + seuil ) ) )
|
|
||||||
{
|
|
||||||
if( ( ( ( cXrot - segX ) * ( cXrot - segX ) )
|
|
||||||
+ ( cYrot * cYrot ) ) <= ( seuil * seuil ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// oblique segment:
|
||||||
|
// First, we need to calculate the distance between the point
|
||||||
|
// and the line defined by aStart and aEnd
|
||||||
|
// this dist should be < dist
|
||||||
|
//
|
||||||
|
// find a,slope such that aStart and aEnd lie on y = a + slope*x
|
||||||
|
double slope = (double) (aEnd.y - aStart.y) / (aEnd.x - aStart.x);
|
||||||
|
double a = (double) aStart.y - slope * aStart.x;
|
||||||
|
// find c,orthoslope such that (x,y) lies on y = c + orthoslope*x,
|
||||||
|
// where orthoslope=(-1/slope)
|
||||||
|
// to calculate xp, yp = near point from aRefPoint
|
||||||
|
// which is on the line defined by aStart, aEnd
|
||||||
|
double orthoslope = -1.0 / slope;
|
||||||
|
double c = (double) aRefPoint.y - orthoslope * aRefPoint.x;
|
||||||
|
// find nearest point to (x,y) on line defined by aStart, aEnd
|
||||||
|
double xp = (a - c) / (orthoslope - slope);
|
||||||
|
double yp = a + slope * xp;
|
||||||
|
// find distance to line, in fact the square of dist,
|
||||||
|
// because we just know if it is > or < aDist
|
||||||
|
double dd = square( aRefPoint.x - xp ) + square( aRefPoint.y - yp );
|
||||||
|
double dist = square( aDist );
|
||||||
|
|
||||||
return false;
|
if( dd >= dist ) // this reference point is not a good candiadte.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// dd is < dist, therefore we should make a fine test
|
||||||
|
if( fabs( slope ) > 0.7 )
|
||||||
|
{
|
||||||
|
// line segment more vertical than horizontal
|
||||||
|
if( (aEnd.y > aStart.y && yp < aEnd.y && yp > aStart.y) ||
|
||||||
|
(aEnd.y < aStart.y && yp > aEnd.y && yp < aStart.y) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// line segment more horizontal than vertical
|
||||||
|
if( (aEnd.x > aStart.x && xp < aEnd.x && xp > aStart.x) ||
|
||||||
|
(aEnd.x < aStart.x && xp > aEnd.x && xp < aStart.x) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here, the test point is still a good candidate,
|
||||||
|
// however it is not "between" the end points of the segment.
|
||||||
|
// It is "outside" the segment, but it could be near a segment end point
|
||||||
|
// Therefore, we test the dist from the test point to each segment end point
|
||||||
|
dd = square( aRefPoint.x - aEnd.x ) + square( aRefPoint.y - aEnd.y );
|
||||||
|
if( dd < dist )
|
||||||
|
return true;
|
||||||
|
dd = square( aRefPoint.x - aStart.x ) + square( aRefPoint.y - aStart.y );
|
||||||
|
if( dd < dist )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // no hit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,30 @@
|
||||||
* @file trigo.h
|
* @file trigo.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 KiCad Developers, see change_log.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef TRIGO_H
|
#ifndef TRIGO_H
|
||||||
#define TRIGO_H
|
#define TRIGO_H
|
||||||
|
|
||||||
|
@ -72,8 +96,8 @@ double CrossProduct( wxPoint vectorA, wxPoint vectorB );
|
||||||
/**
|
/**
|
||||||
* Function TestSegmentHit
|
* Function TestSegmentHit
|
||||||
* test for hit on line segment
|
* test for hit on line segment
|
||||||
* i.e. cursor within a given distance from segment
|
* i.e. a reference point is within a given distance from segment
|
||||||
* @param aRefPoint = cursor (point to test) coords
|
* @param aRefPoint = reference point to test
|
||||||
* @param aStart is the first end-point of the line segment
|
* @param aStart is the first end-point of the line segment
|
||||||
* @param aEnd is the second end-point of the line segment
|
* @param aEnd is the second end-point of the line segment
|
||||||
* @param aDist = maximum distance for hit
|
* @param aDist = maximum distance for hit
|
||||||
|
|
|
@ -136,16 +136,10 @@ bool trapezoid2pointDRC( wxPoint aTref[4], wxPoint aPcompare, int aDist )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test distance between aPcompare and polygon edges:
|
// Test distance between aPcompare and each segment of the polygon:
|
||||||
int ii, jj;
|
for( int ii = 0, jj = 3; ii < 4; jj = ii, ii++ ) // for all edge in polygon
|
||||||
double dist = (double) aDist;
|
|
||||||
|
|
||||||
for( ii = 0, jj = 3; ii < 4; jj = ii, ii++ ) // for all edges in polygon
|
|
||||||
{
|
{
|
||||||
if( TestLineHit( aTref[ii].x, aTref[ii].y,
|
if( TestSegmentHit( aTref[ii], aTref[jj], aPcompare, aDist ) )
|
||||||
aTref[jj].x, aTref[jj].y,
|
|
||||||
aPcompare.x, aPcompare.y,
|
|
||||||
dist ) )
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,12 +596,30 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
||||||
bool swap_pads;
|
bool swap_pads;
|
||||||
swap_pads = false;
|
swap_pads = false;
|
||||||
|
|
||||||
if( aRefPad->GetShape() != PAD_CIRCLE && aPad->GetShape() == PAD_CIRCLE )
|
// swap pads to make comparisons easier
|
||||||
swap_pads = true;
|
// priority is aRefPad = ROUND then OVAL then RECT then other
|
||||||
else if( aRefPad->GetShape() != PAD_OVAL && aPad->GetShape() == PAD_OVAL )
|
if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_CIRCLE )
|
||||||
swap_pads = true;
|
{
|
||||||
else if( aRefPad->GetShape() != PAD_RECT && aPad->GetShape() == PAD_RECT )
|
// pad ref shape is here oval, rect or trapezoid
|
||||||
swap_pads = true;
|
switch( aPad->GetShape() )
|
||||||
|
{
|
||||||
|
case PAD_CIRCLE:
|
||||||
|
swap_pads = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAD_OVAL:
|
||||||
|
swap_pads = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAD_RECT:
|
||||||
|
if( aRefPad->GetShape() != PAD_OVAL )
|
||||||
|
swap_pads = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( swap_pads )
|
if( swap_pads )
|
||||||
{
|
{
|
||||||
|
@ -639,7 +651,6 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAD_RECT:
|
case PAD_RECT:
|
||||||
|
|
||||||
// pad_angle = pad orient relative to the aRefPad orient
|
// pad_angle = pad orient relative to the aRefPad orient
|
||||||
pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
|
pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
|
||||||
NORMALIZE_ANGLE_POS( pad_angle );
|
NORMALIZE_ANGLE_POS( pad_angle );
|
||||||
|
@ -707,7 +718,9 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
||||||
{
|
{
|
||||||
// Should not occur, because aPad and aRefPad are swapped
|
// Should not occur, because aPad and aRefPad are swapped
|
||||||
// to have only aPad shape RECT or TRAP and aRefPad shape TRAP or RECT.
|
// to have only aPad shape RECT or TRAP and aRefPad shape TRAP or RECT.
|
||||||
wxLogDebug( wxT( "unexpected pad shape %d") , aPad->GetShape() );
|
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad ref RECT @ %d, %d to pad shape %d @ %d, %d"),
|
||||||
|
aRefPad->GetPosition().x, aRefPad->GetPosition().y,
|
||||||
|
aPad->GetShape(), aPad->GetPosition().x, aPad->GetPosition().y );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -775,7 +788,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
wxLogDebug( wxT( "unexpected pad shape" ) );
|
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape" ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
/*************************************************************************/
|
|
||||||
/* Functions to create drill data used to create files and report files */
|
|
||||||
/*************************************************************************/
|
|
||||||
|
|
||||||
#include <algorithm> // sort
|
|
||||||
|
|
||||||
#include <fctsys.h>
|
|
||||||
#include <common.h>
|
|
||||||
#include <plot_common.h>
|
|
||||||
#include <macros.h>
|
|
||||||
|
|
||||||
#include <class_board.h>
|
|
||||||
#include <class_module.h>
|
|
||||||
#include <class_track.h>
|
|
||||||
|
|
||||||
#include <pcbnew.h>
|
|
||||||
#include <pcbplot.h>
|
|
||||||
#include <gendrill.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Local Functions
|
|
||||||
|
|
||||||
/* Compare function used for sorting holes by increasing diameter value
|
|
||||||
* and X value
|
|
||||||
*/
|
|
||||||
static bool CmpHoleDiameterValue( const HOLE_INFO& a, const HOLE_INFO& b )
|
|
||||||
{
|
|
||||||
if( a.m_Hole_Diameter != b.m_Hole_Diameter )
|
|
||||||
return a.m_Hole_Diameter < b.m_Hole_Diameter;
|
|
||||||
|
|
||||||
if( a.m_Hole_Pos.x != b.m_Hole_Pos.x )
|
|
||||||
return a.m_Hole_Pos.x < b.m_Hole_Pos.x;
|
|
||||||
|
|
||||||
return a.m_Hole_Pos.y < b.m_Hole_Pos.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function BuildHolesList
|
|
||||||
* Create the list of holes and tools for a given board
|
|
||||||
* The list is sorted by increasing drill values
|
|
||||||
* Only holes from aFirstLayer to aLastLayer copper layers are listed (for vias, because pad holes are always through holes)
|
|
||||||
* param aPcb : the given board
|
|
||||||
* param aHoleListBuffer : the std::vector<HOLE_INFO> to fill with pcb holes info
|
|
||||||
* param aToolListBuffer : the std::vector<DRILL_TOOL> to fill with tools to use
|
|
||||||
* param aFirstLayer = first layer to consider. if < 0 aFirstLayer is ignored (used to creates report file)
|
|
||||||
* param aLastLayer = last layer to consider. if < 0 aLastLayer is ignored
|
|
||||||
* param aExcludeThroughHoles : if true, exclude through holes ( pads and vias through )
|
|
||||||
* param aGenerateNPTH_list :
|
|
||||||
* true to create NPTH only list (with no plated holes)
|
|
||||||
* false to created plated holes list (with no NPTH )
|
|
||||||
*/
|
|
||||||
void Build_Holes_List( BOARD* aPcb,
|
|
||||||
std::vector<HOLE_INFO>& aHoleListBuffer,
|
|
||||||
std::vector<DRILL_TOOL>& aToolListBuffer,
|
|
||||||
int aFirstLayer, int aLastLayer, bool aExcludeThroughHoles,
|
|
||||||
bool aGenerateNPTH_list )
|
|
||||||
{
|
|
||||||
HOLE_INFO new_hole;
|
|
||||||
int hole_value;
|
|
||||||
|
|
||||||
aHoleListBuffer.clear();
|
|
||||||
aToolListBuffer.clear();
|
|
||||||
|
|
||||||
if( (aFirstLayer >= 0) && (aLastLayer >= 0) )
|
|
||||||
{
|
|
||||||
if( aFirstLayer > aLastLayer )
|
|
||||||
EXCHG( aFirstLayer, aLastLayer );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* build hole list for vias
|
|
||||||
*/
|
|
||||||
if( ! aGenerateNPTH_list ) // vias are always plated !
|
|
||||||
{
|
|
||||||
for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
|
|
||||||
{
|
|
||||||
if( track->Type() != PCB_VIA_T )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SEGVIA* via = (SEGVIA*) track;
|
|
||||||
hole_value = via->GetDrillValue();
|
|
||||||
|
|
||||||
if( hole_value == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
new_hole.m_Tool_Reference = -1; // Flag value for Not initialized
|
|
||||||
new_hole.m_Hole_Orient = 0;
|
|
||||||
new_hole.m_Hole_Diameter = hole_value;
|
|
||||||
new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;
|
|
||||||
|
|
||||||
new_hole.m_Hole_Shape = 0; // hole shape: round
|
|
||||||
new_hole.m_Hole_Pos = via->m_Start;
|
|
||||||
via->ReturnLayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer );
|
|
||||||
|
|
||||||
// ReturnLayerPair return params with m_Hole_Bottom_Layer < m_Hole_Top_Layer
|
|
||||||
if( (new_hole.m_Hole_Bottom_Layer > aFirstLayer) && (aFirstLayer >= 0) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( (new_hole.m_Hole_Top_Layer < aLastLayer) && (aLastLayer >= 0) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( aExcludeThroughHoles && (new_hole.m_Hole_Bottom_Layer == LAYER_N_BACK)
|
|
||||||
&& (new_hole.m_Hole_Top_Layer == LAYER_N_FRONT) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
aHoleListBuffer.push_back( new_hole );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build hole list for pads (assumed always through holes)
|
|
||||||
if( !aExcludeThroughHoles || aGenerateNPTH_list )
|
|
||||||
{
|
|
||||||
for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
// Read and analyse pads
|
|
||||||
for( D_PAD* pad = module->m_Pads; pad; pad = pad->Next() )
|
|
||||||
{
|
|
||||||
if( ! aGenerateNPTH_list && pad->GetAttribute() == PAD_HOLE_NOT_PLATED )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( aGenerateNPTH_list && pad->GetAttribute() != PAD_HOLE_NOT_PLATED )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( pad->GetDrillSize().x == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED);
|
|
||||||
new_hole.m_Tool_Reference = -1; // Flag is: Not initialized
|
|
||||||
new_hole.m_Hole_Orient = pad->GetOrientation();
|
|
||||||
new_hole.m_Hole_Shape = 0; // hole shape: round
|
|
||||||
new_hole.m_Hole_Diameter = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
|
|
||||||
new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;
|
|
||||||
|
|
||||||
if( pad->GetDrillShape() != PAD_CIRCLE )
|
|
||||||
new_hole.m_Hole_Shape = 1; // oval flag set
|
|
||||||
|
|
||||||
new_hole.m_Hole_Size = pad->GetDrillSize();
|
|
||||||
new_hole.m_Hole_Pos = pad->GetPosition(); // hole position
|
|
||||||
new_hole.m_Hole_Bottom_Layer = LAYER_N_BACK;
|
|
||||||
new_hole.m_Hole_Top_Layer = LAYER_N_FRONT;// pad holes are through holes
|
|
||||||
aHoleListBuffer.push_back( new_hole );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort holes per increasing diameter value
|
|
||||||
sort( aHoleListBuffer.begin(), aHoleListBuffer.end(), CmpHoleDiameterValue );
|
|
||||||
|
|
||||||
// build the tool list
|
|
||||||
int LastHole = -1; /* Set to not initialised (this is a value not used
|
|
||||||
* for aHoleListBuffer[ii].m_Hole_Diameter) */
|
|
||||||
DRILL_TOOL new_tool( 0 );
|
|
||||||
unsigned jj;
|
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < aHoleListBuffer.size(); ii++ )
|
|
||||||
{
|
|
||||||
if( aHoleListBuffer[ii].m_Hole_Diameter != LastHole )
|
|
||||||
{
|
|
||||||
new_tool.m_Diameter = ( aHoleListBuffer[ii].m_Hole_Diameter );
|
|
||||||
aToolListBuffer.push_back( new_tool );
|
|
||||||
LastHole = new_tool.m_Diameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
jj = aToolListBuffer.size();
|
|
||||||
|
|
||||||
if( jj == 0 )
|
|
||||||
continue; // Should not occurs
|
|
||||||
|
|
||||||
aHoleListBuffer[ii].m_Tool_Reference = jj; // Tool value Initialized (value >= 1)
|
|
||||||
|
|
||||||
aToolListBuffer.back().m_TotalCount++;
|
|
||||||
|
|
||||||
if( aHoleListBuffer[ii].m_Hole_Shape )
|
|
||||||
aToolListBuffer.back().m_OvalCount++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -715,7 +715,7 @@ void PCB_PARSER::parseLayers() throw( IO_ERROR, PARSE_ERROR )
|
||||||
layer.SetFixedListIndex( layerIndex );
|
layer.SetFixedListIndex( layerIndex );
|
||||||
m_board->SetLayer( layerIndex, layer );
|
m_board->SetLayer( layerIndex, layer );
|
||||||
|
|
||||||
wxLogDebug( wxT( "Mapping layer %s to index %d" ), GetChars( wname ), layerIndex );
|
// wxLogDebug( wxT( "Mapping layer %s to index %d" ), GetChars( wname ), layerIndex );
|
||||||
|
|
||||||
if( layerType != LT_UNDEFINED )
|
if( layerType != LT_UNDEFINED )
|
||||||
copperLayerCount++;
|
copperLayerCount++;
|
||||||
|
|
|
@ -18,67 +18,6 @@ double Distance( double x1, double y1, double x2, double y2 )
|
||||||
return hypot( x1 - x2, y1 - y2 );
|
return hypot( x1 - x2, y1 - y2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function TestLineHit
|
|
||||||
* test for hit on line segment i.e. a point within a given distance from segment
|
|
||||||
* @param x, y = cursor coords
|
|
||||||
* @param xi,yi,xf,yf = the end-points of the line segment
|
|
||||||
* @param dist = maximum distance for hit
|
|
||||||
* return true if dist < distance between the point and the segment
|
|
||||||
*/
|
|
||||||
bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
|
|
||||||
{
|
|
||||||
double dd;
|
|
||||||
|
|
||||||
// test for vertical or horizontal segment
|
|
||||||
if( xf==xi )
|
|
||||||
{
|
|
||||||
// vertical segment
|
|
||||||
dd = fabs( (double) (x - xi) );
|
|
||||||
|
|
||||||
if( dd<dist && ( (yf>yi && y<yf && y>yi) || (yf<yi && y>yf && y<yi) ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if( yf==yi )
|
|
||||||
{
|
|
||||||
// horizontal segment
|
|
||||||
dd = fabs( (double) (y - yi) );
|
|
||||||
|
|
||||||
if( dd<dist && ( (xf>xi && x<xf && x>xi) || (xf<xi && x>xf && x<xi) ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// oblique segment
|
|
||||||
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
|
|
||||||
double b = (double) (yf - yi) / (xf - xi);
|
|
||||||
double a = (double) yi - b * xi;
|
|
||||||
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
|
|
||||||
double d = -1.0 / b;
|
|
||||||
double c = (double) y - d * x;
|
|
||||||
// find nearest point to (x,y) on line segment (xi,yi) to (xf,yf)
|
|
||||||
double xp = (a - c) / (d - b);
|
|
||||||
double yp = a + b * xp;
|
|
||||||
// find distance
|
|
||||||
dd = sqrt( (x - xp) * (x - xp) + (y - yp) * (y - yp) );
|
|
||||||
|
|
||||||
if( fabs( b )>0.7 )
|
|
||||||
{
|
|
||||||
// line segment more vertical than horizontal
|
|
||||||
if( dd<dist && ( (yf>yi && yp<yf && yp>yi) || (yf<yi && yp>yf && yp<yi) ) )
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// line segment more horizontal than vertical
|
|
||||||
if( dd<dist && ( (xf>xi && xp<xf && xp>xi) || (xf<xi && xp>xf && xp<xi) ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // no hit
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Function FindSegmentIntersections
|
/* Function FindSegmentIntersections
|
||||||
* find intersections between line segment (xi,yi) to (xf,yf)
|
* find intersections between line segment (xi,yi) to (xf,yf)
|
||||||
|
|
|
@ -1,15 +1,5 @@
|
||||||
// math stuff for graphics, from FreePCB
|
// math stuff for graphics, from FreePCB
|
||||||
|
|
||||||
/**
|
|
||||||
* Function TestLineHit
|
|
||||||
* test for hit on line segment i.e. a point within a given distance from segment
|
|
||||||
* @param xi,yi and xf,yf = the end-points of the line segment
|
|
||||||
* @param dist = maximum distance for hit
|
|
||||||
* @param x, y = point to test coords
|
|
||||||
* @return true if hit (i.e dist < distance between the point and the segment, false if not.
|
|
||||||
*/
|
|
||||||
bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist );
|
|
||||||
|
|
||||||
/* Function FindLineSegmentIntersection
|
/* Function FindLineSegmentIntersection
|
||||||
* find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
|
* find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
|
||||||
* if b > DBL_MAX/10, assume vertical line at x = a
|
* if b > DBL_MAX/10, assume vertical line at x = a
|
||||||
|
|
Loading…
Reference in New Issue