Commit 78a8be0e authored by jean-pierre charras's avatar jean-pierre charras

Pcbnew: fix a very old bug in DRC, pad to pad drc tests: sometimes a test...

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.
parent 5d5a50dd
This diff is collapsed.
......@@ -2,6 +2,30 @@
* @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
#define TRIGO_H
......@@ -72,8 +96,8 @@ double CrossProduct( wxPoint vectorA, wxPoint vectorB );
/**
* Function TestSegmentHit
* test for hit on line segment
* i.e. cursor within a given distance from segment
* @param aRefPoint = cursor (point to test) coords
* i.e. a reference point is within a given distance from segment
* @param aRefPoint = reference point to test
* @param aStart is the first end-point of the line segment
* @param aEnd is the second end-point of the line segment
* @param aDist = maximum distance for hit
......
......@@ -136,16 +136,10 @@ bool trapezoid2pointDRC( wxPoint aTref[4], wxPoint aPcompare, int aDist )
return false;
}
// Test distance between aPcompare and polygon edges:
int ii, jj;
double dist = (double) aDist;
for( ii = 0, jj = 3; ii < 4; jj = ii, ii++ ) // for all edges in polygon
// Test distance between aPcompare and each segment of the polygon:
for( int ii = 0, jj = 3; ii < 4; jj = ii, ii++ ) // for all edge in polygon
{
if( TestLineHit( aTref[ii].x, aTref[ii].y,
aTref[jj].x, aTref[jj].y,
aPcompare.x, aPcompare.y,
dist ) )
if( TestSegmentHit( aTref[ii], aTref[jj], aPcompare, aDist ) )
return false;
}
......@@ -602,12 +596,30 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
bool swap_pads;
swap_pads = false;
if( aRefPad->GetShape() != PAD_CIRCLE && aPad->GetShape() == PAD_CIRCLE )
swap_pads = true;
else if( aRefPad->GetShape() != PAD_OVAL && aPad->GetShape() == PAD_OVAL )
swap_pads = true;
else if( aRefPad->GetShape() != PAD_RECT && aPad->GetShape() == PAD_RECT )
swap_pads = true;
// swap pads to make comparisons easier
// priority is aRefPad = ROUND then OVAL then RECT then other
if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_CIRCLE )
{
// pad ref shape is here oval, rect or trapezoid
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 )
{
......@@ -639,7 +651,6 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
break;
case PAD_RECT:
// pad_angle = pad orient relative to the aRefPad orient
pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
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
// 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;
......@@ -775,7 +788,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
break;
default:
wxLogDebug( wxT( "unexpected pad shape" ) );
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape" ) );
break;
}
......
/*************************************************************************/
/* 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 );
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 )
copperLayerCount++;
......
......@@ -18,67 +18,6 @@ double Distance( double x1, double y1, double x2, double 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
* find intersections between line segment (xi,yi) to (xf,yf)
......
// 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
* 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment