Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
kicad-source-mirror
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
kicad-source-mirror
Commits
d536f9d9
Commit
d536f9d9
authored
Sep 20, 2010
by
jean-pierre charras
Browse files
Options
Browse Files
Download
Plain Diff
DRC code cleaning, and added DRC tests for trapezoidal pads. Needs more tests.
parents
e149951b
f1df65c5
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1369 additions
and
1141 deletions
+1369
-1141
CMakeLists.txt
pcbnew/CMakeLists.txt
+1
-0
class_pad.cpp
pcbnew/class_pad.cpp
+7
-18
class_pad.h
pcbnew/class_pad.h
+15
-3
class_pad_draw_functions.cpp
pcbnew/class_pad_draw_functions.cpp
+55
-36
dialog_drc.cpp
pcbnew/dialog_drc.cpp
+1
-8
dialog_pad_properties.cpp
pcbnew/dialog_pad_properties.cpp
+3
-5
drc.cpp
pcbnew/drc.cpp
+18
-1004
drc_clearance_test_functions.cpp
pcbnew/drc_clearance_test_functions.cpp
+1112
-0
drc_stuff.h
pcbnew/drc_stuff.h
+18
-21
math_for_graphics.cpp
polygon/math_for_graphics.cpp
+19
-18
math_for_graphics.h
polygon/math_for_graphics.h
+24
-3
polygon_test_point_inside.cpp
polygon/polygon_test_point_inside.cpp
+71
-16
polygon_test_point_inside.h
polygon/polygon_test_point_inside.h
+25
-9
No files found.
pcbnew/CMakeLists.txt
View file @
d536f9d9
...
...
@@ -96,6 +96,7 @@ set(PCBNEW_SRCS
dist.cpp
dragsegm.cpp
drc.cpp
drc_clearance_test_functions.cpp
drc_marker_functions.cpp
edgemod.cpp
edit.cpp
...
...
pcbnew/class_pad.cpp
View file @
d536f9d9
...
...
@@ -764,17 +764,15 @@ bool D_PAD::IsOnLayer( int aLayer ) const
*/
bool
D_PAD
::
HitTest
(
const
wxPoint
&
ref_pos
)
{
int
deltaX
,
deltaY
;
int
dx
,
dy
;
double
dist
;
wxPoint
shape_pos
=
ReturnShapePos
();
deltaX
=
ref_pos
.
x
-
shape_pos
.
x
;
deltaY
=
ref_pos
.
y
-
shape_pos
.
y
;
wxPoint
delta
=
ref_pos
-
shape_pos
;
/* Quick test: a test point must be inside the circle. */
if
(
(
abs
(
delta
X
)
>
m_ShapeMaxRadius
)
||
(
abs
(
deltaY
)
>
m_ShapeMaxRadius
)
)
if
(
(
abs
(
delta
.
x
)
>
m_ShapeMaxRadius
)
||
(
abs
(
delta
.
y
)
>
m_ShapeMaxRadius
)
)
return
false
;
dx
=
m_Size
.
x
>>
1
;
// dx also is the radius for rounded pads
...
...
@@ -783,7 +781,7 @@ bool D_PAD::HitTest( const wxPoint& ref_pos )
switch
(
m_PadShape
&
0x7F
)
{
case
PAD_CIRCLE
:
dist
=
hypot
(
delta
X
,
deltaY
);
dist
=
hypot
(
delta
.
x
,
delta
.
y
);
if
(
wxRound
(
dist
)
<=
dx
)
return
true
;
break
;
...
...
@@ -792,22 +790,13 @@ bool D_PAD::HitTest( const wxPoint& ref_pos )
{
wxPoint
poly
[
4
];
BuildPadPolygon
(
poly
,
wxSize
(
0
,
0
),
0
);
// Build the same polygon with CPolyPt corners,
// to use TestPointInsidePolygon
static
std
::
vector
<
CPolyPt
>
polysList
;
// Is static to avoid memory reallocation
polysList
.
clear
();
for
(
int
ii
=
0
;
ii
<
4
;
ii
++
)
{
CPolyPt
corner
(
poly
[
ii
].
x
,
poly
[
ii
].
y
);
polysList
.
push_back
(
corner
);
}
RotatePoint
(
&
deltaX
,
&
deltaY
,
-
m_Orient
);
return
TestPointInsidePolygon
(
polysList
,
0
,
3
,
deltaX
,
deltaY
);
RotatePoint
(
&
delta
,
-
m_Orient
);
return
TestPointInsidePolygon
(
poly
,
4
,
delta
);
}
default
:
RotatePoint
(
&
delta
X
,
&
deltaY
,
-
m_Orient
);
if
(
(
abs
(
delta
X
)
<=
dx
)
&&
(
abs
(
deltaY
)
<=
dy
)
)
RotatePoint
(
&
delta
,
-
m_Orient
);
if
(
(
abs
(
delta
.
x
)
<=
dx
)
&&
(
abs
(
delta
.
y
)
<=
dy
)
)
return
true
;
break
;
}
...
...
pcbnew/class_pad.h
View file @
d536f9d9
...
...
@@ -148,7 +148,7 @@ public:
* Function GetShape
* @return the shape of this pad.
*/
int
GetShape
()
{
return
m_PadShape
&
0xFF
;
}
int
GetShape
()
const
{
return
m_PadShape
&
0xFF
;
}
/**
* Function GetPosition
...
...
@@ -239,14 +239,26 @@ public:
void
DrawShape
(
EDA_Rect
*
aClipBox
,
wxDC
*
aDC
,
PAD_DRAWINFO
&
aDrawInfo
);
/** function BuildPadPolygon
* Has meaning only for polygonal pads (trapez
io
d and rectangular)
* Has meaning only for polygonal pads (trapez
oi
d and rectangular)
* Build the Corner list of the polygonal shape,
* depending on shape, extra size (clearance ...) and orientation
* @param aCoord[4] = a buffer to fill.
* @param aInflateValue = wxSize: the clearance or margin value. value > 0: inflate, < 0 deflate
* @param aRotation = full rotation of the polygon
*/
void
BuildPadPolygon
(
wxPoint
aCoord
[
4
],
wxSize
aInflateValue
,
int
aRotation
);
void
BuildPadPolygon
(
wxPoint
aCoord
[
4
],
wxSize
aInflateValue
,
int
aRotation
)
const
;
/** function BuildSegmentFromOvalShape
* Has meaning only for OVAL (and ROUND) pads
* Build an equivalent segment having the same shape as the OVAL shape,
* Useful in draw function and in DRC and HitTest functions,
* because segments are already well handled by track tests
* @param aSegStart = the starting point of the equivalent segment, relative to the shape position.
* @param aSegEnd = the ending point of the equivalent segment, relative to the shape position
* @param aRotation = full rotation of the segment
* @return the width of the segment
*/
int
BuildSegmentFromOvalShape
(
wxPoint
&
aSegStart
,
wxPoint
&
aSegEnd
,
int
aRotation
)
const
;
// others
void
SetPadName
(
const
wxString
&
name
);
// Change pad name
...
...
pcbnew/class_pad_draw_functions.cpp
View file @
d536f9d9
...
...
@@ -357,9 +357,9 @@ void D_PAD::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDraw_mode,
void
D_PAD
::
DrawShape
(
EDA_Rect
*
aClipBox
,
wxDC
*
aDC
,
PAD_DRAWINFO
&
aDrawInfo
)
{
wxPoint
coord
[
4
];
int
rotdx
,
delta_cx
,
delta_cy
;
int
delta_cx
,
delta_cy
;
int
angle
=
m_Orient
;
int
seg_width
;
GRSetDrawMode
(
aDC
,
aDrawInfo
.
m_DrawMode
);
...
...
@@ -392,44 +392,30 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
break
;
case
PAD_OVAL
:
if
(
halfsize
.
x
>
halfsize
.
y
)
/* horizontal */
{
delta_cx
=
halfsize
.
x
-
halfsize
.
y
;
delta_cy
=
0
;
rotdx
=
m_Size
.
y
+
(
aDrawInfo
.
m_Mask_margin
.
y
*
2
);
}
else
/* vertical */
{
delta_cx
=
0
;
delta_cy
=
halfsize
.
y
-
halfsize
.
x
;
rotdx
=
m_Size
.
x
+
(
aDrawInfo
.
m_Mask_margin
.
x
*
2
);
}
RotatePoint
(
&
delta_cx
,
&
delta_cy
,
angle
);
{
wxPoint
segStart
,
segEnd
;
seg_width
=
BuildSegmentFromOvalShape
(
segStart
,
segEnd
,
angle
);
segStart
+=
shape_pos
;
segEnd
+=
shape_pos
;
if
(
aDrawInfo
.
m_ShowPadFilled
)
{
GRFillCSegm
(
aClipBox
,
aDC
,
shape_pos
.
x
+
delta_cx
,
shape_pos
.
y
+
delta_cy
,
shape_pos
.
x
-
delta_cx
,
shape_pos
.
y
-
delta_cy
,
rotdx
,
aDrawInfo
.
m_Color
);
GRFillCSegm
(
aClipBox
,
aDC
,
segStart
.
x
,
segStart
.
y
,
segEnd
.
x
,
segEnd
.
y
,
seg_width
,
aDrawInfo
.
m_Color
);
}
else
{
GRCSegm
(
aClipBox
,
aDC
,
shape_pos
.
x
+
delta_cx
,
shape_pos
.
y
+
delta_cy
,
shape_pos
.
x
-
delta_cx
,
shape_pos
.
y
-
delta_cy
,
rotdx
,
m_PadSketchModePenSize
,
aDrawInfo
.
m_Color
);
GRCSegm
(
aClipBox
,
aDC
,
segStart
.
x
,
segStart
.
y
,
segEnd
.
x
,
segEnd
.
y
,
seg_width
,
m_PadSketchModePenSize
,
aDrawInfo
.
m_Color
);
}
/* Draw the isolation line. */
if
(
aDrawInfo
.
m_PadClearance
)
{
rotdx
=
rotdx
+
2
*
aDrawInfo
.
m_PadClearance
;
GRCSegm
(
aClipBox
,
aDC
,
shape_pos
.
x
+
delta_cx
,
shape_pos
.
y
+
delta_cy
,
shape_pos
.
x
-
delta_cx
,
shape_pos
.
y
-
delta_cy
,
rotdx
,
aDrawInfo
.
m_Color
);
seg_width
+=
2
*
aDrawInfo
.
m_PadClearance
;
GRCSegm
(
aClipBox
,
aDC
,
segStart
.
x
,
segStart
.
y
,
segEnd
.
x
,
segEnd
.
y
,
seg_width
,
aDrawInfo
.
m_Color
);
}
}
break
;
case
PAD_RECT
:
...
...
@@ -486,9 +472,6 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
#else
if
(
aDrawInfo
.
m_Scale
*
hole
>
1
)
/* draw hole if its size is enough */
#endif
GRFilledCircle
(
aClipBox
,
aDC
,
holepos
.
x
,
holepos
.
y
,
hole
,
0
,
aDrawInfo
.
m_Color
,
aDrawInfo
.
m_HoleColor
);
break
;
...
...
@@ -501,18 +484,18 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
{
delta_cx
=
halfsize
.
x
-
halfsize
.
y
;
delta_cy
=
0
;
rotdx
=
m_Drill
.
y
;
seg_width
=
m_Drill
.
y
;
}
else
/* vertical */
{
delta_cx
=
0
;
delta_cy
=
halfsize
.
y
-
halfsize
.
x
;
rotdx
=
m_Drill
.
x
;
seg_width
=
m_Drill
.
x
;
}
RotatePoint
(
&
delta_cx
,
&
delta_cy
,
angle
);
GRFillCSegm
(
aClipBox
,
aDC
,
holepos
.
x
+
delta_cx
,
holepos
.
y
+
delta_cy
,
holepos
.
x
-
delta_cx
,
holepos
.
y
-
delta_cy
,
rotdx
,
holepos
.
x
-
delta_cx
,
holepos
.
y
-
delta_cy
,
seg_width
,
aDrawInfo
.
m_HoleColor
);
break
;
...
...
@@ -637,6 +620,42 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
}
}
/** function BuildSegmentFromOvalShape
* Has meaning only for OVAL (and ROUND) pads.
* Build an equivalent segment having the same shape as the OVAL shape,
* aSegStart and aSegEnd are the ending points of the equivalent segment of the shape
* aRotation is the asked rotation of the segment (usually m_Orient)
*/
int
D_PAD
::
BuildSegmentFromOvalShape
(
wxPoint
&
aSegStart
,
wxPoint
&
aSegEnd
,
int
aRotation
)
const
{
int
width
;
if
(
m_Size
.
y
<
m_Size
.
x
)
// Build an horizontal equiv segment
{
int
delta
=
(
m_Size
.
x
-
m_Size
.
y
)
/
2
;
aSegStart
.
x
=
-
delta
;
aSegStart
.
y
=
0
;
aSegEnd
.
x
=
delta
;
aSegEnd
.
y
=
0
;
width
=
m_Size
.
y
;
}
else
// Vertical oval: build a vertical equiv segment
{
int
delta
=
(
m_Size
.
y
-
m_Size
.
x
)
/
2
;
aSegStart
.
x
=
0
;
aSegStart
.
y
=
-
delta
;
aSegEnd
.
x
=
0
;
aSegEnd
.
y
=
delta
;
width
=
m_Size
.
x
;
}
if
(
aRotation
)
{
RotatePoint
(
&
aSegStart
,
aRotation
);
RotatePoint
(
&
aSegEnd
,
aRotation
);
}
return
width
;
}
/** function BuildPadPolygon
* Has meaning only for polygonal pads (trapeziod and rectangular)
...
...
@@ -646,7 +665,7 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
* @param aInflateValue = wxSize: the clearance or margin value. value > 0: inflate, < 0 deflate
* @param aRotation = full rotation of the polygon, usually m_Orient
*/
void
D_PAD
::
BuildPadPolygon
(
wxPoint
aCoord
[
4
],
wxSize
aInflateValue
,
int
aRotation
)
void
D_PAD
::
BuildPadPolygon
(
wxPoint
aCoord
[
4
],
wxSize
aInflateValue
,
int
aRotation
)
const
{
if
(
(
GetShape
()
!=
PAD_RECT
)
&&
(
GetShape
()
!=
PAD_TRAPEZOID
)
)
return
;
...
...
pcbnew/dialog_drc.cpp
View file @
d536f9d9
...
...
@@ -44,21 +44,17 @@ bool DIALOG_DRC_CONTROL::Show( bool show )
{
bool
ret
;
D
(
printf
(
"%s %d
\n
"
,
__func__
,
show
);)
if
(
show
)
{
ret
=
DIALOG_DRC_CONTROL_BASE
::
Show
(
show
);
if
(
s_LastPos
.
x
!=
-
1
)
{
D
(
printf
(
"setting window pos to (%d,%d)
\n
"
,
s_LastPos
.
x
,
s_LastPos
.
y
);)
//SetPosition( s_LastPos );
SetSize
(
s_LastPos
.
x
,
s_LastPos
.
y
,
s_LastSize
.
x
,
s_LastSize
.
y
,
0
);
}
else
{
D
(
printf
(
"not setting window pos (%d,%d)
\n
"
,
s_LastPos
.
x
,
s_LastPos
.
y
);)
// Do nothing: last position not yet saved.
}
}
else
...
...
@@ -66,9 +62,6 @@ bool DIALOG_DRC_CONTROL::Show( bool show )
// Save the dialog's position before hiding
s_LastPos
=
GetPosition
();
s_LastSize
=
GetSize
();
D
(
printf
(
"saving window pos as (%d,%d)
\n
"
,
s_LastPos
.
x
,
s_LastPos
.
y
);)
ret
=
DIALOG_DRC_CONTROL_BASE
::
Show
(
show
);
}
...
...
pcbnew/dialog_pad_properties.cpp
View file @
d536f9d9
...
...
@@ -195,8 +195,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
{
SetFocus
();
// Required under wxGTK if we want to demiss the dialog with the ESC key
int
tmp
;
int
internalUnits
=
m_Parent
->
m_InternalUnits
;
int
internalUnits
=
m_Parent
->
m_InternalUnits
;
wxString
msg
;
m_isFlipped
=
false
;
if
(
m_CurrentPad
)
...
...
@@ -298,7 +297,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
SetPadLayersList
(
m_dummyPad
->
m_Masque_Layer
);
msg
.
Clear
();
msg
<<
tmp
;
msg
<<
m_dummyPad
->
m_Orient
;
m_PadOrientCtrl
->
SetValue
(
msg
);
// Pad Orient
...
...
@@ -350,11 +349,10 @@ void DIALOG_PAD_PROPERTIES::initValues()
m_PadOrientCtrl
->
SetValue
(
msg
);
// Selection du type
tmp
=
m_dummyPad
->
m_Attribut
;
m_PadType
->
SetSelection
(
0
);
for
(
int
ii
=
0
;
ii
<
NBTYPES
;
ii
++
)
{
if
(
CodeType
[
ii
]
==
tmp
)
if
(
CodeType
[
ii
]
==
m_dummyPad
->
m_Attribut
)
{
m_PadType
->
SetSelection
(
ii
);
break
;
...
...
pcbnew/drc.cpp
View file @
d536f9d9
...
...
@@ -30,12 +30,9 @@
#include "fctsys.h"
#include "common.h"
#include "class_drawpanel.h"
#include "pcbnew.h"
#include "wxPcbStruct.h"
#include "autorout.h"
#include "trigo.h"
#include "gestfich.h"
#include "class_board_design_settings.h"
#include "protos.h"
...
...
@@ -55,13 +52,13 @@ void DRC::ShowDialog()
PutValueInLocalUnits
(
*
m_ui
->
m_SetTrackMinWidthCtrl
,
m_pcb
->
GetBoardDesignSettings
()
->
m_TrackMinWidth
,
m_mainWindow
->
m_InternalUnits
);
;
m_mainWindow
->
m_InternalUnits
);
PutValueInLocalUnits
(
*
m_ui
->
m_SetViaMinSizeCtrl
,
m_pcb
->
GetBoardDesignSettings
()
->
m_ViasMinSize
,
m_mainWindow
->
m_InternalUnits
);
;
m_mainWindow
->
m_InternalUnits
);
PutValueInLocalUnits
(
*
m_ui
->
m_SetMicroViakMinSizeCtrl
,
m_pcb
->
GetBoardDesignSettings
()
->
m_MicroViasMinSize
,
m_mainWindow
->
m_InternalUnits
);
;
m_mainWindow
->
m_InternalUnits
);
m_ui
->
m_CreateRptCtrl
->
SetValue
(
m_doCreateRptFile
);
m_ui
->
m_RptFilenameCtrl
->
SetValue
(
m_rptFilename
);
...
...
@@ -415,20 +412,6 @@ bool DRC::testNetClasses()
}
void
DRC
::
testTracks
()
{
for
(
TRACK
*
segm
=
m_pcb
->
m_Track
;
segm
&&
segm
->
Next
();
segm
=
segm
->
Next
()
)
{
if
(
!
doTrackDrc
(
segm
,
segm
->
Next
(),
true
)
)
{
wxASSERT
(
m_currentMarker
);
m_pcb
->
Add
(
m_currentMarker
);
m_currentMarker
=
0
;
}
}
}
/***********************/
void
DRC
::
testPad2Pad
()
/***********************/
...
...
@@ -468,6 +451,20 @@ void DRC::testPad2Pad()
}
void
DRC
::
testTracks
()
{
for
(
TRACK
*
segm
=
m_pcb
->
m_Track
;
segm
&&
segm
->
Next
();
segm
=
segm
->
Next
()
)
{
if
(
!
doTrackDrc
(
segm
,
segm
->
Next
(),
true
)
)
{
wxASSERT
(
m_currentMarker
);
m_pcb
->
Add
(
m_currentMarker
);
m_currentMarker
=
0
;
}
}
}
void
DRC
::
testUnconnected
()
{
if
(
(
m_pcb
->
m_Status_Pcb
&
LISTE_RATSNEST_ITEM_OK
)
==
0
)
...
...
@@ -552,430 +549,6 @@ void DRC::testZones( bool adoTestFillSegments )
}
/***********************************************************************/
bool
DRC
::
doTrackDrc
(
TRACK
*
aRefSeg
,
TRACK
*
aStart
,
bool
testPads
)
/***********************************************************************/
{
TRACK
*
track
;
int
dx
,
dy
;
// utilise pour calcul des dim x et dim y des 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
->
m_Start
;
// origin will be the origin of other coordinates
m_segmEnd
.
x
=
dx
=
aRefSeg
->
m_End
.
x
-
origin
.
x
;
m_segmEnd
.
y
=
dy
=
aRefSeg
->
m_End
.
y
-
origin
.
y
;
layerMask
=
aRefSeg
->
ReturnMaskLayer
();
net_code_ref
=
aRefSeg
->
GetNet
();
m_segmAngle
=
0
;
// Phase 0 : Test vias
if
(
aRefSeg
->
Type
()
==
TYPE_VIA
)
{
// test if the via size is smaller than minimum
if
(
aRefSeg
->
Shape
()
==
VIA_MICROVIA
)
{
if
(
aRefSeg
->
m_Width
<
netclass
->
GetuViaMinDiameter
()
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
NULL
,
DRCE_TOO_SMALL_MICROVIA
,
m_currentMarker
);
return
false
;
}
}
else
{
if
(
aRefSeg
->
m_Width
<
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
->
m_Width
)
{
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
->
Shape
()
==
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
->
GetBoardDesignSettings
()
->
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
->
m_Width
<
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
(
dx
||
dy
)
{
// Compute the segment angle in 0,1 degrees
m_segmAngle
=
ArcTangente
(
dy
,
dx
);
// Compute the segment length: we build an equivalent rotated segment,
// this segment is horizontal, therefore dx = length
RotatePoint
(
&
dx
,
&
dy
,
m_segmAngle
);
// dx = length, dy = 0
}
m_segmLength
=
dx
;
/******************************************/
/* 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
D_PAD
dummypad
(
(
MODULE
*
)
NULL
);
// construct this once outside following loop
dummypad
.
m_Masque_Layer
=
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
->
GetPadsCount
();
++
ii
)
{
D_PAD
*
pad
=
m_pcb
->
m_NetInfo
->
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
->
m_Masque_Layer
&
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
->
m_Drill
.
x
==
0
)
continue
;
dummypad
.
m_Size
=
pad
->
m_Drill
;
dummypad
.
SetPosition
(
pad
->
GetPosition
()
);
dummypad
.
m_PadShape
=
pad
->
m_DrillShape
;
dummypad
.
m_Orient
=
pad
->
m_Orient
;
dummypad
.
ComputeShapeMaxRadius
();
// compute the radius of the circle containing this pad
m_padToTestPos
.
x
=
dummypad
.
GetPosition
().
x
-
origin
.
x
;
m_padToTestPos
.
y
=
dummypad
.
GetPosition
().
y
-
origin
.
y
;
if
(
!
checkClearanceSegmToPad
(
&
dummypad
,
aRefSeg
->
m_Width
,
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
.
x
=
shape_pos
.
x
-
origin
.
x
;
m_padToTestPos
.
y
=
shape_pos
.
y
-
origin
.
y
;
if
(
!
checkClearanceSegmToPad
(
pad
,
aRefSeg
->
m_Width
,
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
for
(
track
=
aStart
;
track
;
track
=
track
->
Next
()
)
{
// coord des extremites du segment teste dans le repere modifie
int
x0
;
int
y0
;
int
xf
;
int
yf
;
// 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
->
m_Width
+
track
->
m_Width
)
/
2
;
// If the reference segment is a via, we test it here
if
(
aRefSeg
->
Type
()
==
TYPE_VIA
)
{
int
angle
=
0
;
// angle du segment a tester;
dx
=
track
->
m_End
.
x
-
track
->
m_Start
.
x
;
dy
=
track
->
m_End
.
y
-
track
->
m_Start
.
y
;
x0
=
aRefSeg
->
m_Start
.
x
-
track
->
m_Start
.
x
;
y0
=
aRefSeg
->
m_Start
.
y
-
track
->
m_Start
.
y
;
if
(
track
->
Type
()
==
TYPE_VIA
)
{
// Test distance between two vias, i.e. two circles, trivial case
if
(
(
int
)
hypot
(
x0
,
y0
)
<
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
(
dy
,
dx
);
// Compute new coordinates ( the segment become horizontal)
RotatePoint
(
&
dx
,
&
dy
,
angle
);
RotatePoint
(
&
x0
,
&
y0
,
angle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
w_dist
,
dx
)
)
{
m_currentMarker
=
fillMarker
(
track
,
aRefSeg
,
DRCE_VIA_NEAR_TRACK
,
m_currentMarker
);
return
false
;
}
}
continue
;
}
/* We compute x0,y0, xf,yf = 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
*/
x0
=
track
->
m_Start
.
x
-
origin
.
x
;
y0
=
track
->
m_Start
.
y
-
origin
.
y
;
xf
=
track
->
m_End
.
x
-
origin
.
x
;
yf
=
track
->
m_End
.
y
-
origin
.
y
;
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
RotatePoint
(
&
xf
,
&
yf
,
m_segmAngle
);
if
(
track
->
Type
()
==
TYPE_VIA
)
{
if
(
checkMarginToCircle
(
x0
,
y0
,
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
(
y0
==
yf
)
// parallel segments
{
if
(
abs
(
y0
)
>=
w_dist
)
continue
;
if
(
x0
>
xf
)
EXCHG
(
x0
,
xf
);
/* pour que x0 <= xf */
if
(
x0
>
(
-
w_dist
)
&&
x0
<
(
m_segmLength
+
w_dist
)
)
/* possible error drc */
{
/* Fine test : we consider the rounded shape of the ends */
if
(
x0
>=
0
&&
x0
<=
m_segmLength
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_TRACK_ENDS1
,
m_currentMarker
);
return
false
;
}
if
(
!
checkMarginToCircle
(
x0
,
y0
,
w_dist
,
m_segmLength
)
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_TRACK_ENDS2
,
m_currentMarker
);
return
false
;
}
}
if
(
xf
>
(
-
w_dist
)
&&
xf
<
(
m_segmLength
+
w_dist
)
)
{
/* Fine test : we consider the rounded shape of the ends */
if
(
xf
>=
0
&&
xf
<=
m_segmLength
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_TRACK_ENDS3
,
m_currentMarker
);
return
false
;
}
if
(
!
checkMarginToCircle
(
xf
,
yf
,
w_dist
,
m_segmLength
)
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_TRACK_ENDS4
,
m_currentMarker
);
return
false
;
}
}
if
(
x0
<=
0
&&
xf
>=
0
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_TRACK_UNKNOWN1
,
m_currentMarker
);
return
false
;
}
}
else
if
(
x0
==
xf
)
// perpendicular segments
{
if
(
(
x0
<=
(
-
w_dist
)
)
||
(
x0
>=
(
m_segmLength
+
w_dist
)
)
)
continue
;
// Test if segments are crossing
if
(
y0
>
yf
)
EXCHG
(
y0
,
yf
);
if
(
(
y0
<
0
)
&&
(
yf
>
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
(
x0
,
y0
,
w_dist
,
m_segmLength
)
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_ENDS_PROBLEM1
,
m_currentMarker
);
return
false
;
}
if
(
!
checkMarginToCircle
(
xf
,
yf
,
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
(
x0
,
y0
,
xf
,
yf
)
)
{
/* 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
(
x0
,
y0
,
xf
,
yf
)
)
{
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
int
angle
,
rx0
,
ry0
,
rxf
,
ryf
;
x0
=
track
->
m_Start
.
x
;
y0
=
track
->
m_Start
.
y
;
xf
=
track
->
m_End
.
x
;
yf
=
track
->
m_End
.
y
;
dx
=
xf
-
x0
;
dy
=
yf
-
y0
;
/* Compute the segment orientation (angle) en 0,1 degre */
angle
=
ArcTangente
(
dy
,
dx
);
/* Compute the segment lenght: dx = longueur */
RotatePoint
(
&
dx
,
&
dy
,
angle
);
/* Comute the reference segment coordinates relatives to a
* X axis = current tested segment
*/
rx0
=
aRefSeg
->
m_Start
.
x
-
x0
;
ry0
=
aRefSeg
->
m_Start
.
y
-
y0
;
rxf
=
aRefSeg
->
m_End
.
x
-
x0
;
ryf
=
aRefSeg
->
m_End
.
y
-
y0
;
RotatePoint
(
&
rx0
,
&
ry0
,
angle
);
RotatePoint
(
&
rxf
,
&
ryf
,
angle
);
if
(
!
checkMarginToCircle
(
rx0
,
ry0
,
w_dist
,
dx
)
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_ENDS_PROBLEM4
,
m_currentMarker
);
return
false
;
}
if
(
!
checkMarginToCircle
(
rxf
,
ryf
,
w_dist
,
dx
)
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
track
,
DRCE_ENDS_PROBLEM5
,
m_currentMarker
);
return
false
;
}
}
}
}
}
return
true
;
}
/*****************************************************************************/
bool
DRC
::
doPadToPadsDrc
(
D_PAD
*
aRefPad
,
LISTE_PAD
*
aStart
,
LISTE_PAD
*
aEnd
,
int
x_limit
)
...
...
@@ -987,7 +560,7 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd,
// pad to pad hole DRC, using pad to pad DRC test.
// this dummy pad is a circle or an oval.
static
D_PAD
dummypad
(
(
MODULE
*
)
NULL
);
dummypad
.
m_Masque_Layer
=
ALL_CU_LAYERS
;
// za hole is on all
layers
dummypad
.
m_Masque_Layer
|=
ALL_CU_LAYERS
;
// Ensure the hole is on all copper
layers
dummypad
.
m_LocalClearance
=
1
;
/* Use the minimal local clerance value for the dummy pad
* the clearance of the active pad will be used
* as minimum distance to a hole
...
...
@@ -1088,562 +661,3 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd,
return
true
;
}
// Rotate a vector by an angle
wxPoint
rotate
(
wxPoint
p
,
int
angle
)
{
wxPoint
n
;
double
theta
=
M_PI
*
(
double
)
angle
/
1800.0
;
n
.
x
=
wxRound
(
(
double
)
p
.
x
*
cos
(
theta
)
-
(
double
)
p
.
y
*
sin
(
theta
)
);
n
.
y
=
wxRound
(
p
.
x
*
sin
(
theta
)
+
p
.
y
*
cos
(
theta
)
);
return
n
;
}
/* test DRC between 2 pads.
* this function can be also used to test DRC between a pas and a hole,
* because a hole is like a round pad.
*/
bool
DRC
::
checkClearancePadToPad
(
D_PAD
*
aRefPad
,
D_PAD
*
aPad
)
{
int
dist
;
int
pad_angle
;
// Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
int
dist_min
=
aRefPad
->
GetClearance
(
aPad
);
// relativePadPos is the aPad shape position relative to the aRefPad shape position
wxPoint
relativePadPos
=
aPad
->
ReturnShapePos
()
-
aRefPad
->
ReturnShapePos
();
dist
=
(
int
)
hypot
(
relativePadPos
.
x
,
relativePadPos
.
y
);
// return true if clearance between aRefPad and aPad is >= dist_min, else false
bool
diag
=
true
;
// Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
if
(
(
dist
-
aRefPad
->
m_ShapeMaxRadius
-
aPad
->
m_ShapeMaxRadius
)
>=
dist_min
)
goto
exit
;
/* Here, pads are near and DRC depend on the pad shapes
* We must compare distance using a fine shape analysis
* Because a circle or oval shape is the easier shape to test, try to have
* aRefPad shape type = PAD_CIRCLE or PAD_OVAL. Swap aRefPad and aPad if needed
*/
bool
swap_pads
;
swap_pads
=
false
;
if
(
(
aRefPad
->
m_PadShape
!=
PAD_CIRCLE
)
&&
(
aPad
->
m_PadShape
==
PAD_CIRCLE
)
)
swap_pads
=
true
;
else
if
(
(
aRefPad
->
m_PadShape
!=
PAD_OVAL
)
&&
(
aPad
->
m_PadShape
==
PAD_OVAL
)
)
swap_pads
=
true
;
if
(
swap_pads
)
{
EXCHG
(
aRefPad
,
aPad
);
relativePadPos
=
-
relativePadPos
;
}
/* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL,
* if one of the 2 pads was a PAD_CIRCLE or PAD_OVAL.
* Therefore, if aRefPad is a PAD_RECT or a PAD_TRAPEZOID,
* aPad is also a PAD_RECT or a PAD_TRAPEZOID
*/
switch
(
aRefPad
->
m_PadShape
)
{
case
PAD_CIRCLE
:
/* One can use checkClearanceSegmToPad to test clearance
* aRefPad is like a track segment with a null lenght and a witdth = m_Size.x
*/
m_segmLength
=
0
;
m_segmAngle
=
0
;
m_segmEnd
.
x
=
m_segmEnd
.
y
=
0
;
m_padToTestPos
.
x
=
relativePadPos
.
x
;
m_padToTestPos
.
y
=
relativePadPos
.
y
;
diag
=
checkClearanceSegmToPad
(
aPad
,
aRefPad
->
m_Size
.
x
,
dist_min
);
break
;
case
PAD_RECT
:
RotatePoint
(
&
relativePadPos
,
aRefPad
->
m_Orient
);
// pad_angle = pad orient relative to the aRefPad orient
pad_angle
=
aRefPad
->
m_Orient
+
aPad
->
m_Orient
;
NORMALIZE_ANGLE_POS
(
pad_angle
);
if
(
aPad
->
m_PadShape
==
PAD_RECT
)
{
wxSize
size
=
aPad
->
m_Size
;
// The trivial case is if both rects are rotated by multiple of 90 deg
// Most of time this is the case, and the test is fast
if
(
(
(
aRefPad
->
m_Orient
==
0
)
||
(
aRefPad
->
m_Orient
==
900
)
||
(
aRefPad
->
m_Orient
==
1800
)
||
(
aRefPad
->
m_Orient
==
2700
)
)
&&
(
(
aPad
->
m_Orient
==
0
)
||
(
aPad
->
m_Orient
==
900
)
||
(
aPad
->
m_Orient
==
1800
)
||
(
aPad
->
m_Orient
==
2700
)
)
)
{
if
(
(
pad_angle
==
900
)
||
(
pad_angle
==
2700
)
)
{
EXCHG
(
size
.
x
,
size
.
y
);
}
// Test DRC:
diag
=
false
;
relativePadPos
.
x
=
ABS
(
relativePadPos
.
x
);
relativePadPos
.
y
=
ABS
(
relativePadPos
.
y
);
if
(
(
relativePadPos
.
x
-
(
(
size
.
x
+
aRefPad
->
m_Size
.
x
)
/
2
)
)
>=
dist_min
)
diag
=
true
;
if
(
(
relativePadPos
.
y
-
(
(
size
.
y
+
aRefPad
->
m_Size
.
y
)
/
2
)
)
>=
dist_min
)
diag
=
true
;
}
else
// al least on pad has any other orient. Test is more tricky
{
/* Use TestForIntersectionOfStraightLineSegments() for all 4 edges (segments).*/
/* Test if one center point is contained in the other and thus the pads overlap.
* This case is not covered by the following check if one pad is
* completely contained in the other (because edges don't intersect)!
*/
if
(
(
(
dist
<
aPad
->
m_Size
.
x
)
&&
(
dist
<
aPad
->
m_Size
.
y
)
)
||
(
(
dist
<
aRefPad
->
m_Size
.
x
)
&&
(
dist
<
aRefPad
->
m_Size
.
y
)
)
)
{
diag
=
false
;
}
// Vectors from center to corner
wxPoint
aPad_c2c
=
wxPoint
(
aPad
->
m_Size
.
x
/
2
,
aPad
->
m_Size
.
y
/
2
);
wxPoint
aRefPad_c2c
=
wxPoint
(
aRefPad
->
m_Size
.
x
/
2
,
aRefPad
->
m_Size
.
y
/
2
);
for
(
int
i
=
0
;
i
<
4
;
i
++
)
// for all edges in aPad
{
wxPoint
p11
=
aPad
->
ReturnShapePos
()
+
rotate
(
aPad_c2c
,
aPad
->
m_Orient
);
// flip the center-to-corner vector
if
(
i
%
2
==
0
)
{
aPad_c2c
.
x
=
-
aPad_c2c
.
x
;
}
else
{
aPad_c2c
.
y
=
-
aPad_c2c
.
y
;
}
wxPoint
p12
=
aPad
->
ReturnShapePos
()
+
rotate
(
aPad_c2c
,
aPad
->
m_Orient
);
for
(
int
j
=
0
;
j
<
4
;
j
++
)
// for all edges in aRefPad
{
wxPoint
p21
=
aRefPad
->
ReturnShapePos
()
+
rotate
(
aRefPad_c2c
,
aRefPad
->
m_Orient
);
// flip the center-to-corner vector
if
(
j
%
2
==
0
)
{
aRefPad_c2c
.
x
=
-
aRefPad_c2c
.
x
;
}
else
{
aRefPad_c2c
.
y
=
-
aRefPad_c2c
.
y
;
}
wxPoint
p22
=
aRefPad
->
ReturnShapePos
()
+
rotate
(
aRefPad_c2c
,
aRefPad
->
m_Orient
);
int
x
,
y
;
double
d
;
int
intersect
=
TestForIntersectionOfStraightLineSegments
(
p11
.
x
,
p11
.
y
,
p12
.
x
,
p12
.
y
,
p21
.
x
,
p21
.
y
,
p22
.
x
,
p22
.
y
,
&
x
,
&
y
,
&
d
);
if
(
intersect
||
(
d
<
dist_min
)
)
{
diag
=
false
;
}
}
}
}
}
else
{
// TODO: Pad -> other shape! (PAD_TRAPEZOID)
}
break
;
case
PAD_OVAL
:
/* an oval pad is like a track segment */
{
/* Create a track segment with same dimensions as the oval aRefPad
* and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
*/
int
segm_width
;
m_segmAngle
=
aRefPad
->
m_Orient
;
// Segment orient.
if
(
aRefPad
->
m_Size
.
y
<
aRefPad
->
m_Size
.
x
)
// Build an horizontal equiv segment
{
segm_width
=
aRefPad
->
m_Size
.
y
;
m_segmLength
=
aRefPad
->
m_Size
.
x
-
aRefPad
->
m_Size
.
y
;
}
else
// Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
{
segm_width
=
aRefPad
->
m_Size
.
x
;
m_segmLength
=
aRefPad
->
m_Size
.
y
-
aRefPad
->
m_Size
.
x
;
m_segmAngle
+=
900
;
}
/* the start point must be 0,0 and currently relativePadPos
* is relative the center of pad coordinate */
wxPoint
segstart
;
segstart
.
x
=
-
m_segmLength
/
2
;
// Start point coordinate of the horizontal equivalent segment
RotatePoint
(
&
segstart
,
m_segmAngle
);
// True start point coordinate of the equivalent segment
// move pad position relative to the segment origin
m_padToTestPos
=
relativePadPos
-
segstart
;
// Calculate segment end
m_segmEnd
.
x
=
-
2
*
segstart
.
x
;
m_segmEnd
.
y
=
-
2
*
segstart
.
y
;
// end of segment coordinate
diag
=
checkClearanceSegmToPad
(
aPad
,
segm_width
,
dist_min
);
break
;
}
case
PAD_TRAPEZOID
:
default
:
/* TODO...*/
break
;
}
exit
:
// the only way out (hopefully) for simpler debugging
return
diag
;
}
/* test if distance between a segment is > aMinDist
* segment start point is assumed in (0,0) and segment start point in m_segmEnd
* and have aSegmentWidth.
*/
bool
DRC
::
checkClearanceSegmToPad
(
const
D_PAD
*
aPad
,
int
aSegmentWidth
,
int
aMinDist
)
{
wxSize
padHalfsize
;
// half the dimension of the pad
int
orient
;
int
x0
,
y0
,
xf
,
yf
;
int
seuil
;
int
deltay
;
int
segmHalfWidth
=
aSegmentWidth
/
2
;
seuil
=
segmHalfWidth
+
aMinDist
;
padHalfsize
.
x
=
aPad
->
m_Size
.
x
>>
1
;
padHalfsize
.
y
=
aPad
->
m_Size
.
y
>>
1
;
if
(
aPad
->
m_PadShape
==
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
.
x
,
&
m_padToTestPos
.
y
,
m_segmAngle
);
return
checkMarginToCircle
(
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
seuil
+
padHalfsize
.
x
,
m_segmLength
);
}
else
{
/* 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
;
x0
=
y0
=
0
;
xf
=
m_segmEnd
.
x
;
yf
=
m_segmEnd
.
y
;
orient
=
aPad
->
m_Orient
;
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
-
orient
);
RotatePoint
(
&
xf
,
&
yf
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
-
orient
);
if
(
checkLine
(
x0
,
y0
,
xf
,
yf
)
)
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
->
m_PadShape
)
{
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
+=
900
;
if
(
orient
>=
3600
)
orient
-=
3600
;
}
deltay
=
padHalfsize
.
y
-
padHalfsize
.
x
;
// ici: padHalfsize.x = rayon, 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
(
x0
,
y0
,
xf
,
yf
)
)
return
false
;
// test the first circle
x0
=
m_padToTestPos
.
x
;
// x0,y0 = centre of the upper circle of the oval shape
y0
=
m_padToTestPos
.
y
+
deltay
;
// Calculate the actual position of the circle, given the pad orientation:
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
orient
);
// Calculate the actual position of the circle in the new X,Y axis:
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
padHalfsize
.
x
+
seuil
,
m_segmLength
)
)
return
false
;
// test the second circle
x0
=
m_padToTestPos
.
x
;
// x0,y0 = centre of the lower circle of the oval shape
y0
=
m_padToTestPos
.
y
-
deltay
;
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
orient
);
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
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
(
x0
,
y0
,
xf
,
yf
)
)
{
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
(
x0
,
y0
,
xf
,
yf
)
)
{
return
false
;
}
/* test des 4 cercles ( surface d'solation autour des sommets */
/* test du coin sup. gauche du pad */
x0
=
m_padToTestPos
.
x
-
padHalfsize
.
x
;
y0
=
m_padToTestPos
.
y
-
padHalfsize
.
y
;
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
orient
);
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
seuil
,
m_segmLength
)
)
{
return
false
;
}
/* test du coin sup. droit du pad */
x0
=
m_padToTestPos
.
x
+
padHalfsize
.
x
;
y0
=
m_padToTestPos
.
y
-
padHalfsize
.
y
;
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
orient
);
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
seuil
,
m_segmLength
)
)
{
return
false
;
}
/* test du coin inf. gauche du pad */
x0
=
m_padToTestPos
.
x
-
padHalfsize
.
x
;
y0
=
m_padToTestPos
.
y
+
padHalfsize
.
y
;
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
orient
);
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
seuil
,
m_segmLength
)
)
{
return
false
;
}
/* test du coin inf. droit du pad */
x0
=
m_padToTestPos
.
x
+
padHalfsize
.
x
;
y0
=
m_padToTestPos
.
y
+
padHalfsize
.
y
;
RotatePoint
(
&
x0
,
&
y0
,
m_padToTestPos
.
x
,
m_padToTestPos
.
y
,
orient
);
RotatePoint
(
&
x0
,
&
y0
,
m_segmAngle
);
if
(
!
checkMarginToCircle
(
x0
,
y0
,
seuil
,
m_segmLength
)
)
{
return
false
;
}
break
;
case
PAD_TRAPEZOID
:
//TODO
break
;
}
}
return
true
;
}
/**********************************************************************/
bool
DRC
::
checkMarginToCircle
(
int
cx
,
int
cy
,
int
radius
,
int
longueur
)
/**********************************************************************/
{
if
(
abs
(
cy
)
>
radius
)
return
true
;
if
(
(
cx
>=
-
radius
)
&&
(
cx
<=
(
longueur
+
radius
)
)
)
{
if
(
(
cx
>=
0
)
&&
(
cx
<=
longueur
)
)
return
false
;
if
(
cx
>
longueur
)
cx
-=
longueur
;
if
(
hypot
(
cx
,
cy
)
<
radius
)
return
false
;
}
return
true
;
}
/**********************************************/
/* int Tst_Ligne(int x1,int y1,int x2,int y2) */
/**********************************************/
static
inline
int
USCALE
(
unsigned
arg
,
unsigned
num
,
unsigned
den
)
{
int
ii
;
ii
=
(
int
)
(
(
(
double
)
arg
*
num
)
/
den
);
return
ii
;
}
#define WHEN_OUTSIDE return true
#define WHEN_INSIDE
bool
DRC
::
checkLine
(
int
x1
,
int
y1
,
int
x2
,
int
y2
)
{
int
temp
;
if
(
x1
>
x2
)
{
EXCHG
(
x1
,
x2
);
EXCHG
(
y1
,
y2
);
}
if
(
(
x2
<
m_xcliplo
)
||
(
x1
>
m_xcliphi
)
)
{
WHEN_OUTSIDE
;
}
if
(
y1
<
y2
)
{
if
(
(
y2
<
m_ycliplo
)
||
(
y1
>
m_ycliphi
)
)
{
WHEN_OUTSIDE
;
}
if
(
y1
<
m_ycliplo
)
{
temp
=
USCALE
(
(
x2
-
x1
),
(
m_ycliplo
-
y1
),
(
y2
-
y1
)
);
if
(
(
x1
+=
temp
)
>
m_xcliphi
)
{
WHEN_OUTSIDE
;
}
y1
=
m_ycliplo
;
WHEN_INSIDE
;
}
if
(
y2
>
m_ycliphi
)
{
temp
=
USCALE
(
(
x2
-
x1
),
(
y2
-
m_ycliphi
),
(
y2
-
y1
)
);
if
(
(
x2
-=
temp
)
<
m_xcliplo
)
{
WHEN_OUTSIDE
;
}
y2
=
m_ycliphi
;
WHEN_INSIDE
;
}
if
(
x1
<
m_xcliplo
)
{
temp
=
USCALE
(
(
y2
-
y1
),
(
m_xcliplo
-
x1
),
(
x2
-
x1
)
);
y1
+=
temp
;
x1
=
m_xcliplo
;
WHEN_INSIDE
;
}
if
(
x2
>
m_xcliphi
)
{
temp
=
USCALE
(
(
y2
-
y1
),
(
x2
-
m_xcliphi
),
(
x2
-
x1
)
);
y2
-=
temp
;
x2
=
m_xcliphi
;
WHEN_INSIDE
;
}
}
else
{
if
(
(
y1
<
m_ycliplo
)
||
(
y2
>
m_ycliphi
)
)
{
WHEN_OUTSIDE
;
}
if
(
y1
>
m_ycliphi
)
{
temp
=
USCALE
(
(
x2
-
x1
),
(
y1
-
m_ycliphi
),
(
y1
-
y2
)
);
if
(
(
x1
+=
temp
)
>
m_xcliphi
)
{
WHEN_OUTSIDE
;
}
y1
=
m_ycliphi
;
WHEN_INSIDE
;
}
if
(
y2
<
m_ycliplo
)
{
temp
=
USCALE
(
(
x2
-
x1
),
(
m_ycliplo
-
y2
),
(
y1
-
y2
)
);
if
(
(
x2
-=
temp
)
<
m_xcliplo
)
{
WHEN_OUTSIDE
;
}
y2
=
m_ycliplo
;
WHEN_INSIDE
;
}
if
(
x1
<
m_xcliplo
)
{
temp
=
USCALE
(
(
y1
-
y2
),
(
m_xcliplo
-
x1
),
(
x2
-
x1
)
);
y1
-=
temp
;
x1
=
m_xcliplo
;
WHEN_INSIDE
;
}
if
(
x2
>
m_xcliphi
)
{
temp
=
USCALE
(
(
y1
-
y2
),
(
x2
-
m_xcliphi
),
(
x2
-
x1
)
);
y2
+=
temp
;
x2
=
m_xcliphi
;
WHEN_INSIDE
;
}
}
if
(
(
(
x2
+
x1
)
/
2
<=
m_xcliphi
)
&&
(
(
x2
+
x1
)
/
2
>=
m_xcliplo
)
\
&&
(
(
y2
+
y1
)
/
2
<=
m_ycliphi
)
&&
(
(
y2
+
y1
)
/
2
>=
m_ycliplo
)
)
{
return
false
;
}
else
return
true
;
}
pcbnew/drc_clearance_test_functions.cpp
0 → 100644
View file @
d536f9d9
/**
*@file drc_clearance_test_functions.cpp
*/
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2004-2007 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2007 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
*/
/****************************/
/* DRC control */
/****************************/
#include "fctsys.h"
#include "common.h"
#include "pcbnew.h"
#include "wxPcbStruct.h"
#include "trigo.h"
#include "protos.h"
#include "drc_stuff.h"
/* compare 2 trapezoids (can be rectangle) and return true if distance > aDist
* i.e if for each edge of the first polygon distance from each edge of the other polygon
* is >= aDist
*/
bool
trapezoid2trapezoidDRC
(
wxPoint
aTref
[
4
],
wxPoint
aTcompare
[
4
],
int
aDist
)
{
/* Test if one polygon is contained in the other and thus the polygon overlap.
* This case is not covered by the following check if one polygond is
* completely contained in the other (because edges don't intersect)!
*/
if
(
TestPointInsidePolygon
(
aTref
,
4
,
aTcompare
[
0
]
)
)
return
false
;
if
(
TestPointInsidePolygon
(
aTcompare
,
4
,
aTref
[
0
]
)
)
return
false
;
int
ii
,
jj
,
kk
,
ll
;
for
(
ii
=
0
,
jj
=
3
;
ii
<
4
;
jj
=
ii
,
ii
++
)
// for all edges in aTref
{
for
(
kk
=
0
,
ll
=
3
;
kk
<
4
;
ll
=
kk
,
kk
++
)
// for all edges in aTcompare
{
double
d
;
int
intersect
=
TestForIntersectionOfStraightLineSegments
(
aTref
[
ii
].
x
,
aTref
[
ii
].
y
,
aTref
[
jj
].
x
,
aTref
[
jj
].
y
,
aTcompare
[
kk
].
x
,
aTcompare
[
kk
].
y
,
aTcompare
[
ll
].
x
,
aTcompare
[
ll
].
y
,
NULL
,
NULL
,
&
d
);
if
(
intersect
||
(
d
<
aDist
)
)
return
false
;
}
}
return
true
;
}
/* compare a trapezoids (can be rectangle) and a segment and return true if distance > aDist
*/
bool
trapezoid2segmentDRC
(
wxPoint
aTref
[
4
],
wxPoint
aSegStart
,
wxPoint
aSegEnd
,
int
aDist
)
{
/* Test if the segment is contained in the polygon.
* This case is not covered by the following check if the segment is
* completely contained in the polygon (because edges don't intersect)!
*/
if
(
TestPointInsidePolygon
(
aTref
,
4
,
aSegStart
)
)
return
false
;
int
ii
,
jj
;
for
(
ii
=
0
,
jj
=
3
;
ii
<
4
;
jj
=
ii
,
ii
++
)
// for all edges in aTref
{
double
d
;
int
intersect
=
TestForIntersectionOfStraightLineSegments
(
aTref
[
ii
].
x
,
aTref
[
ii
].
y
,
aTref
[
jj
].
x
,
aTref
[
jj
].
y
,
aSegStart
.
x
,
aSegStart
.
y
,
aSegEnd
.
x
,
aSegEnd
.
y
,
NULL
,
NULL
,
&
d
);
if
(
intersect
||
(
d
<
aDist
)
)
return
false
;
}
return
true
;
}
/* compare a trapezoid to a point and return true if distance > aDist
* do not use this function for horizontal or vertical rectangles
* because there is a faster an easier way to compare the distance
*/
bool
trapezoid2pointDRC
(
wxPoint
aTref
[
4
],
wxPoint
aPcompare
,
int
aDist
)
{
/* Test if aPcompare point is contained in the polygon.
* This case is not covered by the following check if this point is inside the polygon
*/
if
(
TestPointInsidePolygon
(
aTref
,
4
,
aPcompare
)
)
{
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
{
if
(
TestLineHit
(
aTref
[
ii
].
x
,
aTref
[
ii
].
y
,
aTref
[
jj
].
x
,
aTref
[
jj
].
y
,
aPcompare
.
x
,
aPcompare
.
y
,
dist
)
)
return
false
;
}
return
true
;
}
// Rotate a vector by an angle
wxPoint
rotate
(
wxPoint
p
,
int
angle
)
{
wxPoint
n
;
double
theta
=
M_PI
*
(
double
)
angle
/
1800.0
;
n
.
x
=
wxRound
(
(
double
)
p
.
x
*
cos
(
theta
)
-
(
double
)
p
.
y
*
sin
(
theta
)
);
n
.
y
=
wxRound
(
p
.
x
*
sin
(
theta
)
+
p
.
y
*
cos
(
theta
)
);
return
n
;
}
/***********************************************************************/
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
->
m_Start
;
// origin will be the origin of other coordinates
m_segmEnd
=
delta
=
aRefSeg
->
m_End
-
origin
;
m_segmAngle
=
0
;
layerMask
=
aRefSeg
->
ReturnMaskLayer
();
net_code_ref
=
aRefSeg
->
GetNet
();
// Phase 0 : Test vias
if
(
aRefSeg
->
Type
()
==
TYPE_VIA
)
{
// test if the via size is smaller than minimum
if
(
aRefSeg
->
Shape
()
==
VIA_MICROVIA
)
{
if
(
aRefSeg
->
m_Width
<
netclass
->
GetuViaMinDiameter
()
)
{
m_currentMarker
=
fillMarker
(
aRefSeg
,
NULL
,
DRCE_TOO_SMALL_MICROVIA
,
m_currentMarker
);
return
false
;
}
}
else
{
if
(
aRefSeg
->
m_Width
<
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
->
m_Width
)
{
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
->
Shape
()
==
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
->
GetBoardDesignSettings
()
->
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
->
m_Width
<
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
D_PAD
dummypad
(
(
MODULE
*
)
NULL
);
// construct this once outside following loop
dummypad
.
m_Masque_Layer
=
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
->
GetPadsCount
();
++
ii
)
{
D_PAD
*
pad
=
m_pcb
->
m_NetInfo
->
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
->
m_Masque_Layer
&
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
->
m_Drill
.
x
==
0
)
continue
;
dummypad
.
m_Size
=
pad
->
m_Drill
;
dummypad
.
SetPosition
(
pad
->
GetPosition
()
);
dummypad
.
m_PadShape
=
pad
->
m_DrillShape
;
dummypad
.
m_Orient
=
pad
->
m_Orient
;
dummypad
.
ComputeShapeMaxRadius
();
// compute the radius of the circle containing this pad
m_padToTestPos
=
dummypad
.
GetPosition
()
-
origin
;
if
(
!
checkClearanceSegmToPad
(
&
dummypad
,
aRefSeg
->
m_Width
,
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
->
m_Width
,
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
for
(
track
=
aStart
;
track
;
track
=
track
->
Next
()
)
{
// coord des extremites du segment teste dans le repere modifie
wxPoint
segStartPoint
;
wxPoint
segEndPoint
;
// 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
->
m_Width
+
track
->
m_Width
)
/
2
;
// If the reference segment is a via, we test it here
if
(
aRefSeg
->
Type
()
==
TYPE_VIA
)
{
int
angle
=
0
;
// angle du segment a tester;
delta
=
track
->
m_End
-
track
->
m_Start
;
segStartPoint
=
aRefSeg
->
m_Start
-
track
->
m_Start
;
if
(
track
->
Type
()
==
TYPE_VIA
)
{
// 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
->
m_Start
-
origin
;
segEndPoint
=
track
->
m_End
-
origin
;
RotatePoint
(
&
segStartPoint
,
m_segmAngle
);
RotatePoint
(
&
segEndPoint
,
m_segmAngle
);
if
(
track
->
Type
()
==
TYPE_VIA
)
{
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
->
m_Start
;
segEndPoint
=
track
->
m_End
;
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
->
m_Start
-
segStartPoint
;
wxPoint
relEndPos
=
aRefSeg
->
m_End
-
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 DRC between 2 pads.
* this function can be also used to test DRC between a pas and a hole,
* because a hole is like a round pad.
*/
bool
DRC
::
checkClearancePadToPad
(
D_PAD
*
aRefPad
,
D_PAD
*
aPad
)
{
int
dist
;
int
pad_angle
;
// Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
int
dist_min
=
aRefPad
->
GetClearance
(
aPad
);
// relativePadPos is the aPad shape position relative to the aRefPad shape position
wxPoint
relativePadPos
=
aPad
->
ReturnShapePos
()
-
aRefPad
->
ReturnShapePos
();
dist
=
(
int
)
hypot
(
relativePadPos
.
x
,
relativePadPos
.
y
);
// Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
if
(
(
dist
-
aRefPad
->
m_ShapeMaxRadius
-
aPad
->
m_ShapeMaxRadius
)
>=
dist_min
)
return
true
;
/* Here, pads are near and DRC depend on the pad shapes
* We must compare distance using a fine shape analysis
* Because a circle or oval shape is the easier shape to test, try to have
* aRefPad shape type = PAD_CIRCLE or PAD_OVAL.
* if aRefPad = TRAP. and aPad = RECT, also swap pads
* Swap aRefPad and aPad if needed
*/
bool
swap_pads
;
swap_pads
=
false
;
if
(
(
aRefPad
->
m_PadShape
!=
PAD_CIRCLE
)
&&
(
aPad
->
m_PadShape
==
PAD_CIRCLE
)
)
swap_pads
=
true
;
else
if
(
(
aRefPad
->
m_PadShape
!=
PAD_OVAL
)
&&
(
aPad
->
m_PadShape
==
PAD_OVAL
)
)
swap_pads
=
true
;
else
if
(
(
aRefPad
->
m_PadShape
!=
PAD_RECT
)
&&
(
aPad
->
m_PadShape
==
PAD_RECT
)
)
swap_pads
=
true
;
if
(
swap_pads
)
{
EXCHG
(
aRefPad
,
aPad
);
relativePadPos
=
-
relativePadPos
;
}
/* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL,
* if one of the 2 pads was a PAD_CIRCLE or PAD_OVAL.
* Therefore, if aRefPad is a PAD_RECT or a PAD_TRAPEZOID,
* aPad is also a PAD_RECT or a PAD_TRAPEZOID
*/
bool
diag
=
true
;
switch
(
aRefPad
->
m_PadShape
)
{
case
PAD_CIRCLE
:
/* One can use checkClearanceSegmToPad to test clearance
* aRefPad is like a track segment with a null lenght and a witdth = m_Size.x
*/
m_segmLength
=
0
;
m_segmAngle
=
0
;
m_segmEnd
.
x
=
m_segmEnd
.
y
=
0
;
m_padToTestPos
=
relativePadPos
;
diag
=
checkClearanceSegmToPad
(
aPad
,
aRefPad
->
m_Size
.
x
,
dist_min
);
break
;
case
PAD_RECT
:
// pad_angle = pad orient relative to the aRefPad orient
pad_angle
=
aRefPad
->
m_Orient
+
aPad
->
m_Orient
;
NORMALIZE_ANGLE_POS
(
pad_angle
);
if
(
aPad
->
m_PadShape
==
PAD_RECT
)
{
wxSize
size
=
aPad
->
m_Size
;
// The trivial case is if both rects are rotated by multiple of 90 deg
// Most of time this is the case, and the test is fast
if
(
(
(
aRefPad
->
m_Orient
==
0
)
||
(
aRefPad
->
m_Orient
==
900
)
||
(
aRefPad
->
m_Orient
==
1800
)
||
(
aRefPad
->
m_Orient
==
2700
)
)
&&
(
(
aPad
->
m_Orient
==
0
)
||
(
aPad
->
m_Orient
==
900
)
||
(
aPad
->
m_Orient
==
1800
)
||
(
aPad
->
m_Orient
==
2700
)
)
)
{
if
(
(
pad_angle
==
900
)
||
(
pad_angle
==
2700
)
)
{
EXCHG
(
size
.
x
,
size
.
y
);
}
// Test DRC:
diag
=
false
;
RotatePoint
(
&
relativePadPos
,
aRefPad
->
m_Orient
);
relativePadPos
.
x
=
ABS
(
relativePadPos
.
x
);
relativePadPos
.
y
=
ABS
(
relativePadPos
.
y
);
if
(
(
relativePadPos
.
x
-
(
(
size
.
x
+
aRefPad
->
m_Size
.
x
)
/
2
)
)
>=
dist_min
)
diag
=
true
;
if
(
(
relativePadPos
.
y
-
(
(
size
.
y
+
aRefPad
->
m_Size
.
y
)
/
2
)
)
>=
dist_min
)
diag
=
true
;
}
else
// at least one pad has any other orient. Test is more tricky
{
// Use the trapezoid2trapezoidDRC which also compare 2 rectangles with any orientation
wxPoint
polyref
[
4
];
// Shape of aRefPad
wxPoint
polycompare
[
4
];
// Shape of aPad
aRefPad
->
BuildPadPolygon
(
polyref
,
wxSize
(
0
,
0
),
aRefPad
->
m_Orient
);
aPad
->
BuildPadPolygon
(
polycompare
,
wxSize
(
0
,
0
),
aPad
->
m_Orient
);
// Move aPad shape to relativePadPos
for
(
int
ii
=
0
;
ii
<
4
;
ii
++
)
polycompare
[
ii
]
+=
relativePadPos
;
// And now test polygons:
if
(
!
trapezoid2trapezoidDRC
(
polyref
,
polycompare
,
dist_min
)
)
diag
=
false
;
}
}
else
if
(
aPad
->
m_PadShape
==
PAD_TRAPEZOID
)
{
wxPoint
polyref
[
4
];
// Shape of aRefPad
wxPoint
polycompare
[
4
];
// Shape of aPad
aRefPad
->
BuildPadPolygon
(
polyref
,
wxSize
(
0
,
0
),
aRefPad
->
m_Orient
);
aPad
->
BuildPadPolygon
(
polycompare
,
wxSize
(
0
,
0
),
aPad
->
m_Orient
);
// Move aPad shape to relativePadPos
for
(
int
ii
=
0
;
ii
<
4
;
ii
++
)
polycompare
[
ii
]
+=
relativePadPos
;
// And now test polygons:
if
(
!
trapezoid2trapezoidDRC
(
polyref
,
polycompare
,
dist_min
)
)
diag
=
false
;
}
else
// Should not occurs, 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"
)
);
}
break
;
case
PAD_OVAL
:
/* an oval pad is like a track segment */
{
/* Create a track segment with same dimensions as the oval aRefPad
* and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
*/
int
segm_width
;
m_segmAngle
=
aRefPad
->
m_Orient
;
// Segment orient.
if
(
aRefPad
->
m_Size
.
y
<
aRefPad
->
m_Size
.
x
)
// Build an horizontal equiv segment
{
segm_width
=
aRefPad
->
m_Size
.
y
;
m_segmLength
=
aRefPad
->
m_Size
.
x
-
aRefPad
->
m_Size
.
y
;
}
else
// Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
{
segm_width
=
aRefPad
->
m_Size
.
x
;
m_segmLength
=
aRefPad
->
m_Size
.
y
-
aRefPad
->
m_Size
.
x
;
m_segmAngle
+=
900
;
}
/* the start point must be 0,0 and currently relativePadPos
* is relative the center of pad coordinate */
wxPoint
segstart
;
segstart
.
x
=
-
m_segmLength
/
2
;
// Start point coordinate of the horizontal equivalent segment
RotatePoint
(
&
segstart
,
m_segmAngle
);
// True start point coordinate of the equivalent segment
// move pad position relative to the segment origin
m_padToTestPos
=
relativePadPos
-
segstart
;
// Calculate segment end
m_segmEnd
.
x
=
-
2
*
segstart
.
x
;
m_segmEnd
.
y
=
-
2
*
segstart
.
y
;
// end of segment coordinate
diag
=
checkClearanceSegmToPad
(
aPad
,
segm_width
,
dist_min
);
break
;
}
case
PAD_TRAPEZOID
:
// at this point, aPad is also a trapezoid, because all other shapes
// have priority, and are already tested
wxASSERT
(
aPad
->
m_PadShape
==
PAD_TRAPEZOID
);
{
wxPoint
polyref
[
4
];
// Shape of aRefPad
wxPoint
polycompare
[
4
];
// Shape of aPad
aRefPad
->
BuildPadPolygon
(
polyref
,
wxSize
(
0
,
0
),
aRefPad
->
m_Orient
);
aPad
->
BuildPadPolygon
(
polycompare
,
wxSize
(
0
,
0
),
aPad
->
m_Orient
);
// Move aPad shape to relativePadPos
for
(
int
ii
=
0
;
ii
<
4
;
ii
++
)
polycompare
[
ii
]
+=
relativePadPos
;
// And now test polygons:
if
(
!
trapezoid2trapezoidDRC
(
polyref
,
polycompare
,
dist_min
)
)
diag
=
false
;
}
break
;
default
:
wxLogDebug
(
wxT
(
"unexpected pad shape"
)
);
break
;
}
return
diag
;
}
/* test if distance between a segment is > aMinDist
* segment start point is assumed in (0,0) and segment start point in m_segmEnd
* and have aSegmentWidth.
*/
bool
DRC
::
checkClearanceSegmToPad
(
const
D_PAD
*
aPad
,
int
aSegmentWidth
,
int
aMinDist
)
{
wxSize
padHalfsize
;
// half the dimension of the pad
int
orient
;
wxPoint
startPoint
,
endPoint
;
int
seuil
;
int
deltay
;
int
segmHalfWidth
=
aSegmentWidth
/
2
;
seuil
=
segmHalfWidth
+
aMinDist
;
padHalfsize
.
x
=
aPad
->
m_Size
.
x
>>
1
;
padHalfsize
.
y
=
aPad
->
m_Size
.
y
>>
1
;
if
(
aPad
->
m_PadShape
==
PAD_TRAPEZOID
)
// The size is bigger, due to m_DeltaSize extra size
{
padHalfsize
.
x
+=
ABS
(
aPad
->
m_DeltaSize
.
y
)
/
2
;
// Remember: m_DeltaSize.y is the m_Size.x change
padHalfsize
.
y
+=
ABS
(
aPad
->
m_DeltaSize
.
x
)
/
2
;
// Remember: m_DeltaSize.x is the m_Size.x change
}
if
(
aPad
->
m_PadShape
==
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
;
orient
=
aPad
->
m_Orient
;
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
->
m_PadShape
)
{
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
+=
900
;
if
(
orient
>=
3600
)
orient
-=
3600
;
}
deltay
=
padHalfsize
.
y
-
padHalfsize
.
x
;
// ici: padHalfsize.x = rayon, 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
;
// segStartPoint.x,segStartPoint.y = 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
;
// segStartPoint.x,segStartPoint.y = 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
;
}
/**
* Helper function checkMarginToCircle
* Check the distance between a circle (round pad, via or round end of track)
* and a segment. the segment is expected starting at 0,0, and on the X axis
* return true if distance >= aRadius
*/
bool
DRC
::
checkMarginToCircle
(
wxPoint
aCentre
,
int
aRadius
,
int
aLength
)
{
if
(
abs
(
aCentre
.
y
)
>
aRadius
)
// trivial case
return
true
;
// Here, didstance between aCentre and X axis is < aRadius
if
(
(
aCentre
.
x
>=
-
aRadius
)
&&
(
aCentre
.
x
<=
(
aLength
+
aRadius
)
)
)
{
if
(
(
aCentre
.
x
>=
0
)
&&
(
aCentre
.
x
<=
aLength
)
)
return
false
;
// aCentre is between the starting point and the ending point of the segm
if
(
aCentre
.
x
>
aLength
)
// aCentre is after the ending point
aCentre
.
x
-=
aLength
;
// move aCentre to the starting point of the segment
if
(
hypot
(
aCentre
.
x
,
aCentre
.
y
)
<
aRadius
)
// distance between aCentre and the starting point or the ending point is < aRadius
return
false
;
}
return
true
;
}
// Helper function used in checkLine::
static
inline
int
USCALE
(
unsigned
arg
,
unsigned
num
,
unsigned
den
)
{
int
ii
;
ii
=
(
int
)
(
(
(
double
)
arg
*
num
)
/
den
);
return
ii
;
}
/** Helper function checkLine
* Test if a line intersects a bounding box (a rectangle)
* The rectangle is defined by m_xcliplo, m_ycliplo and m_xcliphi, m_ycliphi
* return true if the line from aSegStart to aSegEnd is outside the bounding box
*/
bool
DRC
::
checkLine
(
wxPoint
aSegStart
,
wxPoint
aSegEnd
)
{
#define WHEN_OUTSIDE return true
#define WHEN_INSIDE
int
temp
;
if
(
aSegStart
.
x
>
aSegEnd
.
x
)
EXCHG
(
aSegStart
,
aSegEnd
);
if
(
(
aSegEnd
.
x
<
m_xcliplo
)
||
(
aSegStart
.
x
>
m_xcliphi
)
)
{
WHEN_OUTSIDE
;
}
if
(
aSegStart
.
y
<
aSegEnd
.
y
)
{
if
(
(
aSegEnd
.
y
<
m_ycliplo
)
||
(
aSegStart
.
y
>
m_ycliphi
)
)
{
WHEN_OUTSIDE
;
}
if
(
aSegStart
.
y
<
m_ycliplo
)
{
temp
=
USCALE
(
(
aSegEnd
.
x
-
aSegStart
.
x
),
(
m_ycliplo
-
aSegStart
.
y
),
(
aSegEnd
.
y
-
aSegStart
.
y
)
);
if
(
(
aSegStart
.
x
+=
temp
)
>
m_xcliphi
)
{
WHEN_OUTSIDE
;
}
aSegStart
.
y
=
m_ycliplo
;
WHEN_INSIDE
;
}
if
(
aSegEnd
.
y
>
m_ycliphi
)
{
temp
=
USCALE
(
(
aSegEnd
.
x
-
aSegStart
.
x
),
(
aSegEnd
.
y
-
m_ycliphi
),
(
aSegEnd
.
y
-
aSegStart
.
y
)
);
if
(
(
aSegEnd
.
x
-=
temp
)
<
m_xcliplo
)
{
WHEN_OUTSIDE
;
}
aSegEnd
.
y
=
m_ycliphi
;
WHEN_INSIDE
;
}
if
(
aSegStart
.
x
<
m_xcliplo
)
{
temp
=
USCALE
(
(
aSegEnd
.
y
-
aSegStart
.
y
),
(
m_xcliplo
-
aSegStart
.
x
),
(
aSegEnd
.
x
-
aSegStart
.
x
)
);
aSegStart
.
y
+=
temp
;
aSegStart
.
x
=
m_xcliplo
;
WHEN_INSIDE
;
}
if
(
aSegEnd
.
x
>
m_xcliphi
)
{
temp
=
USCALE
(
(
aSegEnd
.
y
-
aSegStart
.
y
),
(
aSegEnd
.
x
-
m_xcliphi
),
(
aSegEnd
.
x
-
aSegStart
.
x
)
);
aSegEnd
.
y
-=
temp
;
aSegEnd
.
x
=
m_xcliphi
;
WHEN_INSIDE
;
}
}
else
{
if
(
(
aSegStart
.
y
<
m_ycliplo
)
||
(
aSegEnd
.
y
>
m_ycliphi
)
)
{
WHEN_OUTSIDE
;
}
if
(
aSegStart
.
y
>
m_ycliphi
)
{
temp
=
USCALE
(
(
aSegEnd
.
x
-
aSegStart
.
x
),
(
aSegStart
.
y
-
m_ycliphi
),
(
aSegStart
.
y
-
aSegEnd
.
y
)
);
if
(
(
aSegStart
.
x
+=
temp
)
>
m_xcliphi
)
{
WHEN_OUTSIDE
;
}
aSegStart
.
y
=
m_ycliphi
;
WHEN_INSIDE
;
}
if
(
aSegEnd
.
y
<
m_ycliplo
)
{
temp
=
USCALE
(
(
aSegEnd
.
x
-
aSegStart
.
x
),
(
m_ycliplo
-
aSegEnd
.
y
),
(
aSegStart
.
y
-
aSegEnd
.
y
)
);
if
(
(
aSegEnd
.
x
-=
temp
)
<
m_xcliplo
)
{
WHEN_OUTSIDE
;
}
aSegEnd
.
y
=
m_ycliplo
;
WHEN_INSIDE
;
}
if
(
aSegStart
.
x
<
m_xcliplo
)
{
temp
=
USCALE
(
(
aSegStart
.
y
-
aSegEnd
.
y
),
(
m_xcliplo
-
aSegStart
.
x
),
(
aSegEnd
.
x
-
aSegStart
.
x
)
);
aSegStart
.
y
-=
temp
;
aSegStart
.
x
=
m_xcliplo
;
WHEN_INSIDE
;
}
if
(
aSegEnd
.
x
>
m_xcliphi
)
{
temp
=
USCALE
(
(
aSegStart
.
y
-
aSegEnd
.
y
),
(
aSegEnd
.
x
-
m_xcliphi
),
(
aSegEnd
.
x
-
aSegStart
.
x
)
);
aSegEnd
.
y
+=
temp
;
aSegEnd
.
x
=
m_xcliphi
;
WHEN_INSIDE
;
}
}
if
(
(
(
aSegEnd
.
x
+
aSegStart
.
x
)
/
2
<=
m_xcliphi
)
&&
(
(
aSegEnd
.
x
+
aSegStart
.
x
)
/
2
>=
m_xcliplo
)
\
&&
(
(
aSegEnd
.
y
+
aSegStart
.
y
)
/
2
<=
m_ycliphi
)
&&
(
(
aSegEnd
.
y
+
aSegStart
.
y
)
/
2
>=
m_ycliplo
)
)
{
return
false
;
}
else
return
true
;
}
pcbnew/drc_stuff.h
View file @
d536f9d9
...
...
@@ -173,10 +173,10 @@ private:
/* variables used in checkLine to test DRC segm to segm:
* define the area relative to the ref segment that does not contains anu other segment
*/
int
m_xcliplo
;
int
m_ycliplo
;
int
m_xcliphi
;
int
m_ycliphi
;
int
m_xcliplo
;
int
m_ycliplo
;
int
m_xcliphi
;
int
m_ycliphi
;
WinEDA_PcbFrame
*
m_mainWindow
;
BOARD
*
m_pcb
;
...
...
@@ -329,30 +329,27 @@ private:
/**
* Function checkMarginToCircle
* @todo this translation is no good, fix this:
* calculates the distance from a circle (via or round end of track) to the
* segment of reference on the right hand side.
*
* @param cx The x coordinate of the circle's center
* @param cy The y coordinate of the circle's center
* @param radius A "keep out" radius centered over the circle
* @param length The length of the segment (i.e. coordinate of end)
* Helper function checkMarginToCircle
* Check the distance from a point to
* a segment. the segment is expected starting at 0,0, and on the X axis
* (used to test DRC between a segment and a round pad, via or round end of a track
* @param aCentre The coordinate of the circle's center
* @param aRadius A "keep out" radius centered over the circle
* @param aLength The length of the segment (i.e. coordinate of end, becuase it is on the X axis)
* @return bool - true if distance >= radius, else
* false when distance <
r
adius
* false when distance <
aR
adius
*/
static
bool
checkMarginToCircle
(
int
cx
,
int
cy
,
int
radius
,
int
l
ength
);
static
bool
checkMarginToCircle
(
wxPoint
aCentre
,
int
aRadius
,
int
aL
ength
);
/**
* Function checkLine
* tests to see if one track is in contact with another track.
*
* Cette routine controle si la ligne (x1,y1 x2,y2) a une partie s'inscrivant
* dans le cadre (xcliplo,ycliplo xcliphi,ycliphi) (variables globales,
* locales a ce fichier)
* (helper function used in drc calculations to see if one track is in contact with another track).
* Test if a line intersects a bounding box (a rectangle)
* The rectangle is defined by m_xcliplo, m_ycliplo and m_xcliphi, m_ycliphi
* return true if the line from aSegStart to aSegEnd is outside the bounding box
*/
bool
checkLine
(
int
x1
,
int
y1
,
int
x2
,
int
y2
);
bool
checkLine
(
wxPoint
aSegStart
,
wxPoint
aSegEnd
);
//-----</single tests>---------------------------------------------
...
...
polygon/math_for_graphics.cpp
View file @
d536f9d9
// math for graphics utility routines, from FreePCB
// math for graphics utility routines
and RC
, from FreePCB
#include <vector>
...
...
@@ -13,13 +13,14 @@
using
namespace
std
;
// test for hit on line segment
// i.e. cursor within a given distance from segment
// enter with: x,y = cursor coords
// (xi,yi) and (xf,yf) are the end-points of the line segment
// dist = maximum distance for hit
//
int
TestLineHit
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
x
,
int
y
,
double
dist
)
/** 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 and 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
;
...
...
@@ -29,14 +30,14 @@ int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
// vertical segment
dd
=
fabs
(
(
double
)(
x
-
xi
)
);
if
(
dd
<
dist
&&
(
(
yf
>
yi
&&
y
<
yf
&&
y
>
yi
)
||
(
yf
<
yi
&&
y
>
yf
&&
y
<
yi
)
)
)
return
1
;
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
1
;
return
true
;
}
else
{
...
...
@@ -62,10 +63,10 @@ int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
{
// line segment more horizontal than vertical
if
(
dd
<
dist
&&
(
(
xf
>
xi
&&
xp
<
xf
&&
xp
>
xi
)
||
(
xf
<
xi
&&
xp
>
xf
&&
xp
<
xi
)
)
)
return
1
;
return
true
;
}
}
return
0
;
// no hit
return
false
;
// no hit
}
...
...
@@ -482,12 +483,12 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
return
1
;
}
/
/ Test for intersection of line s
egments
// If lines are parallel, returns false
// If true, returns intersection coords in x, y
// if false, returns min. distance in dist (may be 0.0 if parallel)
// and coords on nearest point in one of the segments in (x,y
)
/
/
/
** function TestForIntersectionOfStraightLineS
egments
* Test for intersection of line segments
* If lines are parallel, returns false
* If true, returns also intersection coords in x, y
* if false, returns min. distance in dist (may be 0.0 if parallel
)
*
/
bool
TestForIntersectionOfStraightLineSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
*
x
,
int
*
y
,
double
*
d
)
...
...
polygon/math_for_graphics.h
View file @
d536f9d9
...
...
@@ -13,8 +13,6 @@ typedef struct PointTag
typedef
struct
EllipseTag
{
PointT
Center
;
/* ellipse center */
// double MaxRad,MinRad; /* major and minor axis */
// double Phi; /* major axis rotation */
double
xrad
,
yrad
;
// radii on x and y
double
theta1
,
theta2
;
// start and end angle for arc
}
EllipseKH
;
...
...
@@ -22,7 +20,16 @@ typedef struct EllipseTag
// math stuff for graphics
bool
Quadratic
(
double
a
,
double
b
,
double
c
,
double
*
x1
,
double
*
x2
);
int
TestLineHit
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
x
,
int
y
,
double
dist
);
/** 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
);
int
FindLineSegmentIntersection
(
double
a
,
double
b
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
,
double
*
dist
=
NULL
);
int
FindSegmentIntersections
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
...
...
@@ -30,9 +37,23 @@ int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
double
x
[]
=
NULL
,
double
y
[]
=
NULL
);
bool
FindLineEllipseIntersections
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x1
,
double
*
x2
);
bool
FindVerticalLineEllipseIntersections
(
double
a
,
double
b
,
double
x
,
double
*
y1
,
double
*
y2
);
/** function TestForIntersectionOfStraightLineSegments
* Test for intersection of line segments
* If lines are parallel, returns false
* If true, returns also intersection coords in x, y
* if false, returns min. distance in dist (may be 0.0 if parallel)
* and coords on nearest point in one of the segments in (x,y)
* @param x1i, y1i, x1f, y1f = integer coordinates of the first segment
* @param x2i, y2i, x2f, y2f = integer coordinates of the other segment
* @param x, y = pointers on 2 integer to store the intersection coordinates (can be NULL)
* @param dist = pointeur on a double to store the dist.
* @return true if intersect.
*/
bool
TestForIntersectionOfStraightLineSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
*
x
=
NULL
,
int
*
y
=
NULL
,
double
*
dist
=
NULL
);
int
GetClearanceBetweenSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
style1
,
int
w1
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
style2
,
int
w2
,
int
max_cl
,
int
*
x
,
int
*
y
);
...
...
polygon/polygon_test_point_inside.cpp
View file @
d536f9d9
/////////////////////////////////////////////////////////////////////////////
// Name: polygon_test_point_inside.cpp
/////////////////////////////////////////////////////////////////////////////
/**
* @file polygon_test_point_inside.cpp
*/
#include <math.h>
#include <vector>
#include "PolyLine.h"
using
namespace
std
;
/* this algo uses the the Jordan curve theorem to find if a point is inside or outside a polygon:
* It run a semi-infinite line horizontally (increasing x, fixed y)
* out from the test point, and count how many edges it crosses.
* At each crossing, the ray switches between inside and outside.
* If odd count, the test point is inside the polygon
* This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test.
* Take care to starting and ending points of segments outlines, when the horizontal line crosses a segment outline
* Take care to starting and ending points of segments outlines, when the horizontal line crosses a segment outline
* exactly on an ending point:
* Because the starting point of a segment is also the ending point of the previous, only one must be used.
* And we do no use twice the same segment, so we do NOT use both starting and ending points of these 2 segments.
...
...
@@ -30,16 +27,19 @@ using namespace std;
#define INSIDE true
bool
TestPointInsidePolygon
(
std
::
vector
<
CPolyPt
>
aPolysList
,
int
istart
,
int
iend
,
int
refx
,
int
refy
)
int
aIdxstart
,
int
aIdxend
,
int
aRefx
,
int
aRefy
)
/** Function TestPointInsidePolygon
* test if a point is inside or outside a polygon.
* the polygon must have only lines (not arcs) for outlines.
* Use TestPointInside or TestPointInsideContour for more complex polygons
* @param aPolysList: the list of polygons
* @param
i
start: the starting point of a given polygon in m_FilledPolysList.
* @param
i
end: the ending point of the polygon in m_FilledPolysList.
* @param
refx,r
efy: the point coordinate to test
* @param
aIdx
start: the starting point of a given polygon in m_FilledPolysList.
* @param
aIdx
end: the ending point of the polygon in m_FilledPolysList.
* @param
aRefx, aR
efy: the point coordinate to test
* @return true if the point is inside, false for outside
*/
{
...
...
@@ -48,7 +48,62 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int
count
=
0
;
// find all intersection points of line with polyline sides
for
(
ics
=
istart
,
ice
=
iend
;
ics
<=
iend
;
ice
=
ics
++
)
for
(
ics
=
aIdxstart
,
ice
=
aIdxend
;
ics
<=
aIdxend
;
ice
=
ics
++
)
{
int
seg_startX
=
aPolysList
[
ics
].
x
;
int
seg_startY
=
aPolysList
[
ics
].
y
;
int
seg_endX
=
aPolysList
[
ice
].
x
;
int
seg_endY
=
aPolysList
[
ice
].
y
;
/* Trivial cases: skip if ref above or below the segment to test */
if
(
(
seg_startY
>
aRefy
)
&&
(
seg_endY
>
aRefy
)
)
continue
;
// segment below ref point, or one of its ends has the same Y pos as the ref point: skip
// So we eliminate one end point of 2 consecutive segments.
// Note: also we skip horizontal segments if ref point is on this horizontal line
// So reference points on horizontal segments outlines always are seen as outside the polygon
if
(
(
seg_startY
<=
aRefy
)
&&
(
seg_endY
<=
aRefy
)
)
continue
;
/* refy is between seg_startY and seg_endY.
* note: here: horizontal segments (seg_startY == seg_endY) are skipped,
* either by the first test or by the second test
* see if an horizontal semi infinite line from refx is intersecting the segment
*/
// calculate the x position of the intersection of this segment and the semi infinite line
// this is more easier if we move the X,Y axis origin to the segment start point:
seg_endX
-=
seg_startX
;
seg_endY
-=
seg_startY
;
double
newrefx
=
(
double
)
(
aRefx
-
seg_startX
);
double
newrefy
=
(
double
)
(
aRefy
-
seg_startY
);
// Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY)
// with the horizontal line at the new refy position
// the line slope = seg_endY/seg_endX;
// and the x pos relative to the new origin is intersec_x = refy/slope
// Note: because horizontal segments are skipped, 1/slope exists (seg_end_y never == O)
double
intersec_x
=
newrefy
*
seg_endX
/
seg_endY
;
if
(
newrefx
<
intersec_x
)
// Intersection found with the semi-infinite line from refx to infinite
count
++
;
}
return
count
&
1
?
INSIDE
:
OUTSIDE
;
}
/* Function TestPointInsidePolygon (overlaid)
* same as previous, but use wxPoint and aCount corners
*/
bool
TestPointInsidePolygon
(
wxPoint
*
aPolysList
,
int
aCount
,
wxPoint
aRefPoint
)
{
// count intersection points to right of (refx,refy). If odd number, point (refx,refy) is inside polyline
int
ics
,
ice
;
int
count
=
0
;
// find all intersection points of line with polyline sides
for
(
ics
=
0
,
ice
=
aCount
-
1
;
ics
<
aCount
;
ice
=
ics
++
)
{
int
seg_startX
=
aPolysList
[
ics
].
x
;
int
seg_startY
=
aPolysList
[
ics
].
y
;
...
...
@@ -56,14 +111,14 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int
seg_endY
=
aPolysList
[
ice
].
y
;
/* Trivial cases: skip if ref above or below the segment to test */
if
(
(
seg_startY
>
refy
)
&&
(
seg_endY
>
ref
y
)
)
if
(
(
seg_startY
>
aRefPoint
.
y
)
&&
(
seg_endY
>
aRefPoint
.
y
)
)
continue
;
// segment below ref point, or one of its ends has the same Y pos as the ref point: skip
// So we eliminate one end point of 2 consecutive segments.
// Note: also we skip horizontal segments if ref point is on this horizontal line
// So reference points on horizontal segments outlines always are seen as outside the polygon
if
(
(
seg_startY
<=
refy
)
&&
(
seg_endY
<=
ref
y
)
)
if
(
(
seg_startY
<=
aRefPoint
.
y
)
&&
(
seg_endY
<=
aRefPoint
.
y
)
)
continue
;
/* refy is between seg_startY and seg_endY.
...
...
@@ -76,8 +131,8 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
// this is more easier if we move the X,Y axis origin to the segment start point:
seg_endX
-=
seg_startX
;
seg_endY
-=
seg_startY
;
double
newrefx
=
(
double
)
(
ref
x
-
seg_startX
);
double
newrefy
=
(
double
)
(
ref
y
-
seg_startY
);
double
newrefx
=
(
double
)
(
aRefPoint
.
x
-
seg_startX
);
double
newrefy
=
(
double
)
(
aRefPoint
.
y
-
seg_startY
);
// Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY)
// with the horizontal line at the new refy position
...
...
polygon/polygon_test_point_inside.h
View file @
d536f9d9
...
...
@@ -2,18 +2,34 @@
// Name: polygon_test_point_inside.h
/////////////////////////////////////////////////////////////////////////////
using
namespace
std
;
#ifndef __WXWINDOWS__
// define here wxPoint if we want to compile outside wxWidgets
class
wxPoint
{
public
:
int
x
,
y
;
};
#endif
/** Function TestPointInsidePolygon
* test if a point is inside or outside a polygon.
* @param aPolysList: the list of polygons
* @param
i
start: the starting point of a given polygon in m_FilledPolysList.
* @param
i
end: the ending point of the polygon in m_FilledPolysList.
* @param
refx, r
efy: the point coordinate to test
* @param
aIdx
start: the starting point of a given polygon in m_FilledPolysList.
* @param
aIdx
end: the ending point of the polygon in m_FilledPolysList.
* @param
aRefx, aR
efy: the point coordinate to test
* @return true if the point is inside, false for outside
*/
bool
TestPointInsidePolygon
(
std
::
vector
<
CPolyPt
>
aPolysList
,
int
istart
,
int
iend
,
int
refx
,
int
refy
);
int
aIdxstart
,
int
aIdxend
,
int
aRefx
,
int
aRefy
);
/** Function TestPointInsidePolygon (overlaid)
* same as previous, but mainly use wxPoint
* @param aPolysList: the list of polygons
* @param aCount: corners count in aPolysList.
* @param aRefPoint: the point coordinate to test
* @return true if the point is inside, false for outside
*/
bool
TestPointInsidePolygon
(
wxPoint
*
aPolysList
,
int
aCount
,
wxPoint
aRefPoint
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment