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
5598acb6
Commit
5598acb6
authored
Sep 26, 2013
by
Maciej Sumiński
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Uncrustifying push&shove router
parent
87b3f2e4
Changes
37
Hide whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
6611 additions
and
6048 deletions
+6611
-6048
CMakeLists.txt
pcbnew/router/CMakeLists.txt
+47
-46
direction.h
pcbnew/router/direction.h
+298
-261
pns_index.h
pcbnew/router/pns_index.h
+181
-159
pns_item.cpp
pcbnew/router/pns_item.cpp
+53
-36
pns_item.h
pcbnew/router/pns_item.h
+111
-108
pns_itemset.cpp
pcbnew/router/pns_itemset.cpp
+43
-34
pns_itemset.h
pcbnew/router/pns_itemset.h
+20
-19
pns_joint.h
pcbnew/router/pns_joint.h
+157
-138
pns_layerset.h
pcbnew/router/pns_layerset.h
+90
-88
pns_line.cpp
pcbnew/router/pns_line.cpp
+657
-598
pns_line.h
pcbnew/router/pns_line.h
+217
-204
pns_line_placer.cpp
pcbnew/router/pns_line_placer.cpp
+543
-578
pns_line_placer.h
pcbnew/router/pns_line_placer.h
+213
-114
pns_node.cpp
pcbnew/router/pns_node.cpp
+781
-695
pns_node.h
pcbnew/router/pns_node.h
+190
-169
pns_optimizer.cpp
pcbnew/router/pns_optimizer.cpp
+621
-561
pns_optimizer.h
pcbnew/router/pns_optimizer.h
+98
-95
pns_router.cpp
pcbnew/router/pns_router.cpp
+624
-585
pns_router.h
pcbnew/router/pns_router.h
+103
-106
pns_routing_settings.h
pcbnew/router/pns_routing_settings.h
+25
-24
pns_segment.h
pcbnew/router/pns_segment.h
+89
-83
pns_shove.cpp
pcbnew/router/pns_shove.cpp
+412
-387
pns_shove.h
pcbnew/router/pns_shove.h
+43
-39
pns_solid.cpp
pcbnew/router/pns_solid.cpp
+30
-31
pns_solid.h
pcbnew/router/pns_solid.h
+32
-31
pns_utils.cpp
pcbnew/router/pns_utils.cpp
+20
-17
pns_utils.h
pcbnew/router/pns_utils.h
+6
-6
pns_via.cpp
pcbnew/router/pns_via.cpp
+111
-98
pns_via.h
pcbnew/router/pns_via.h
+92
-87
pns_walkaround.cpp
pcbnew/router/pns_walkaround.cpp
+185
-175
pns_walkaround.h
pcbnew/router/pns_walkaround.h
+72
-73
readme.txt
pcbnew/router/readme.txt
+0
-4
router_preview_item.cpp
pcbnew/router/router_preview_item.cpp
+167
-134
router_preview_item.h
pcbnew/router/router_preview_item.h
+58
-58
router_tool.cpp
pcbnew/router/router_tool.cpp
+187
-170
router_tool.h
pcbnew/router/router_tool.h
+23
-22
trace.h
pcbnew/router/trace.h
+12
-15
No files found.
pcbnew/router/CMakeLists.txt
View file @
5598acb6
include_directories
(
BEFORE
${
INC_BEFORE
}
)
include_directories
(
BEFORE
${
INC_BEFORE
}
)
include_directories
(
include_directories
(
./
./
../
../
../../include
../../
include
../../pcbnew
../../
pcbnew
../../polygon
../../
polygon
$
{
INC_AFTER
}
$
{ INC_AFTER
}
)
)
set
(
PCBNEW_PNS_SRCS
set
(
PCBNEW_PNS_SRCS
direction.h
direction.h
pns_via.h
pns_via.h
pns_routing_settings.h
pns_routing_settings.h
pns_shove.cpp
pns_shove.cpp
pns_line.cpp
pns_line.cpp
pns_utils.h
pns_utils.h
pns_layerset.h
pns_layerset.h
trace.h
trace.h
pns_line.h
pns_line.h
pns_walkaround.cpp
pns_walkaround.cpp
pns_node.h
pns_node.h
pns_line_placer.cpp
pns_line_placer.cpp
pns_utils.cpp
pns_utils.cpp
pns_solid.h
pns_solid.h
pns_item.cpp
pns_item.cpp
pns_via.cpp
pns_via.cpp
pns_node.cpp
pns_node.cpp
pns_solid.cpp
pns_solid.cpp
pns_line_placer.h
pns_line_placer.h
pns_optimizer.h
pns_optimizer.h
pns_walkaround.h
pns_walkaround.h
pns_shove.h
pns_shove.h
pns_router.h
pns_router.h
pns_router.cpp
pns_router.cpp
pns_index.h
pns_index.h
pns_item.h
pns_item.h
pns_optimizer.cpp
pns_optimizer.cpp
pns_joint.h
pns_joint.h
pns_segment.h
pns_segment.h
pns_itemset.h
pns_itemset.h
pns_itemset.cpp
pns_itemset.cpp
router_tool.cpp
router_tool.cpp
router_tool.h
router_tool.h
router_preview_item.cpp
router_preview_item.cpp
router_preview_item.h
router_preview_item.h
)
)
add_library
(
pnsrouter STATIC
${
PCBNEW_PNS_SRCS
}
)
add_library
(
pnsrouter STATIC
${
PCBNEW_PNS_SRCS
}
)
pcbnew/router/direction.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -31,265 +31,302 @@
...
@@ -31,265 +31,302 @@
class
DIRECTION_45
class
DIRECTION_45
{
{
public
:
public
:
/**
/**
* Enum Directions
* Enum Directions
* Represents available directions - there are 8 of them, as on a rectilinear map (north = up) +
* Represents available directions - there are 8 of them, as on a rectilinear map (north = up) +
* an extra undefined direction, reserved for traces that don't respect 45-degree routing regime.
* an extra undefined direction, reserved for traces that don't respect 45-degree routing regime.
*/
*/
enum
Directions
{
enum
Directions
N
=
0
,
{
NE
=
1
,
N
=
0
,
E
=
2
,
NE
=
1
,
SE
=
3
,
E
=
2
,
S
=
4
,
SE
=
3
,
SW
=
5
,
S
=
4
,
W
=
6
,
SW
=
5
,
NW
=
7
,
W
=
6
,
UNDEFINED
=
-
1
NW
=
7
,
};
UNDEFINED
=
-
1
};
/**
* Enum AngleType
/**
* Represents kind of angle formed by vectors heading in two DIRECTION_45s.
* Enum AngleType
*/
* Represents kind of angle formed by vectors heading in two DIRECTION_45s.
enum
AngleType
{
*/
ANG_OBTUSE
=
0x1
,
enum
AngleType
ANG_RIGHT
=
0x2
,
{
ANG_ACUTE
=
0x4
,
ANG_OBTUSE
=
0x01
,
ANG_STRAIGHT
=
0x8
,
ANG_RIGHT
=
0x02
,
ANG_HALF_FULL
=
0x10
,
ANG_ACUTE
=
0x04
,
ANG_UNDEFINED
=
0x20
ANG_STRAIGHT
=
0x08
,
};
ANG_HALF_FULL
=
0x10
,
ANG_UNDEFINED
=
0x20
DIRECTION_45
(
Directions
aDir
=
UNDEFINED
)
:
m_dir
(
aDir
)
{};
};
/**
DIRECTION_45
(
Directions
aDir
=
UNDEFINED
)
:
m_dir
(
aDir
)
{};
* Constructor
* @param aVec vector, whose direction will be translated into a DIRECTION_45.
/**
*/
* Constructor
DIRECTION_45
(
const
VECTOR2I
&
aVec
)
* @param aVec vector, whose direction will be translated into a DIRECTION_45.
{
*/
construct
(
aVec
);
DIRECTION_45
(
const
VECTOR2I
&
aVec
)
}
{
construct
(
aVec
);
/**
}
* Constructor
* @param aSeg segment, whose direction will be translated into a DIRECTION_45.
/**
*/
* Constructor
DIRECTION_45
(
const
SEG
&
aSeg
)
* @param aSeg segment, whose direction will be translated into a DIRECTION_45.
{
*/
construct
(
aSeg
.
b
-
aSeg
.
a
);
DIRECTION_45
(
const
SEG
&
aSeg
)
}
{
construct
(
aSeg
.
b
-
aSeg
.
a
);
/**
}
* Function Format()
* Formats the direction in a human readable word.
/**
* @return name of the direction
* Function Format()
*/
* Formats the direction in a human readable word.
const
std
::
string
Format
()
const
* @return name of the direction
{
*/
switch
(
m_dir
)
const
std
::
string
Format
()
const
{
{
case
N
:
return
"north"
;
switch
(
m_dir
)
case
NE
:
return
"north-east"
;
{
case
E
:
return
"east"
;
case
N
:
case
SE
:
return
"south-east"
;
return
"north"
;
case
S
:
return
"south"
;
case
SW
:
return
"south-west"
;
case
NE
:
case
W
:
return
"west"
;
return
"north-east"
;
case
NW
:
return
"north-west"
;
case
UNDEFINED
:
return
"undefined"
;
case
E
:
default
:
return
"<Error>"
;
return
"east"
;
}
}
case
SE
:
return
"south-east"
;
/**
* Function Opposite()
case
S
:
* Returns a direction opposite (180 degree) to (this)
return
"south"
;
* @return opposite direction
*/
case
SW
:
DIRECTION_45
Opposite
()
const
return
"south-west"
;
{
if
(
m_dir
==
UNDEFINED
)
case
W
:
return
UNDEFINED
;
return
"west"
;
const
Directions
OppositeMap
[]
=
{
S
,
SW
,
W
,
NW
,
N
,
NE
,
E
,
SE
}
;
return
OppositeMap
[
m_dir
];
case
NW
:
}
return
"north-west"
;
/**
case
UNDEFINED
:
* Function Angle()
return
"undefined"
;
* Returns the type of angle between directions (this) and aOther.
* @param aOther direction to compare angle with
default
:
*/
return
"<Error>"
;
AngleType
Angle
(
const
DIRECTION_45
&
aOther
)
const
}
{
}
if
(
m_dir
==
UNDEFINED
||
aOther
.
m_dir
==
UNDEFINED
)
return
ANG_UNDEFINED
;
/**
* Function Opposite()
int
d
=
std
::
abs
(
m_dir
-
aOther
.
m_dir
);
* Returns a direction opposite (180 degree) to (this)
* @return opposite direction
if
(
d
==
1
||
d
==
7
)
*/
return
ANG_OBTUSE
;
DIRECTION_45
Opposite
()
const
else
if
(
d
==
2
||
d
==
6
)
{
return
ANG_RIGHT
;
if
(
m_dir
==
UNDEFINED
)
else
if
(
d
==
3
||
d
==
5
)
return
UNDEFINED
;
return
ANG_ACUTE
;
else
if
(
d
==
4
)
const
Directions
OppositeMap
[]
=
{
S
,
SW
,
W
,
NW
,
N
,
NE
,
E
,
SE
};
return
ANG_HALF_FULL
;
return
OppositeMap
[
m_dir
];
else
}
return
ANG_STRAIGHT
;
}
/**
* Function Angle()
/**
* Returns the type of angle between directions (this) and aOther.
* Function IsObtuse()
* @param aOther direction to compare angle with
* @return true, when (this) forms an obtuse angle with aOther
*/
*/
AngleType
Angle
(
const
DIRECTION_45
&
aOther
)
const
bool
IsObtuse
(
const
DIRECTION_45
&
aOther
)
const
{
{
if
(
m_dir
==
UNDEFINED
||
aOther
.
m_dir
==
UNDEFINED
)
return
Angle
(
aOther
)
==
ANG_OBTUSE
;
return
ANG_UNDEFINED
;
}
int
d
=
std
::
abs
(
m_dir
-
aOther
.
m_dir
);
/**
* Function IsDiagonal()
if
(
d
==
1
||
d
==
7
)
* Returns true if the direction is diagonal (e.g. North-West, South-East, etc)
return
ANG_OBTUSE
;
* @return true, when diagonal.
else
if
(
d
==
2
||
d
==
6
)
*/
return
ANG_RIGHT
;
bool
IsDiagonal
()
const
else
if
(
d
==
3
||
d
==
5
)
{
return
ANG_ACUTE
;
return
(
m_dir
%
2
)
==
1
;
else
if
(
d
==
4
)
}
return
ANG_HALF_FULL
;
else
/**
return
ANG_STRAIGHT
;
* Function BuildInitialTrace()
}
*
* Builds a 2-segment line chain between points aP0 and aP1 and following 45-degree routing
/**
* regime. If aStartDiagonal is true, the trace starts with a diagonal segment.
* Function IsObtuse()
* @param aP0 starting point
* @return true, when (this) forms an obtuse angle with aOther
* @param aP1 ending point
*/
* @param aStartDiagonal whether the first segment has to be diagonal
bool
IsObtuse
(
const
DIRECTION_45
&
aOther
)
const
* @return the trace
{
*/
return
Angle
(
aOther
)
==
ANG_OBTUSE
;
const
SHAPE_LINE_CHAIN
BuildInitialTrace
(
const
VECTOR2I
&
aP0
,
const
VECTOR2I
&
aP1
,
bool
aStartDiagonal
=
false
)
const
}
{
int
w
=
abs
(
aP1
.
x
-
aP0
.
x
);
/**
int
h
=
abs
(
aP1
.
y
-
aP0
.
y
);
* Function IsDiagonal()
int
sw
=
sign
(
aP1
.
x
-
aP0
.
x
);
* Returns true if the direction is diagonal (e.g. North-West, South-East, etc)
int
sh
=
sign
(
aP1
.
y
-
aP0
.
y
);
* @return true, when diagonal.
*/
VECTOR2I
mp0
,
mp1
;
bool
IsDiagonal
()
const
{
// we are more horizontal than vertical?
return
(
m_dir
%
2
)
==
1
;
if
(
w
>
h
)
}
{
mp0
=
VECTOR2I
((
w
-
h
)
*
sw
,
0
);
// direction: E
/**
mp1
=
VECTOR2I
(
h
*
sw
,
h
*
sh
);
// direction: NE
* Function BuildInitialTrace()
}
else
{
*
mp0
=
VECTOR2I
(
0
,
sh
*
(
h
-
w
));
// direction: N
* Builds a 2-segment line chain between points aP0 and aP1 and following 45-degree routing
mp1
=
VECTOR2I
(
sw
*
w
,
sh
*
w
);
// direction: NE
* regime. If aStartDiagonal is true, the trace starts with a diagonal segment.
}
* @param aP0 starting point
* @param aP1 ending point
bool
start_diagonal
;
* @param aStartDiagonal whether the first segment has to be diagonal
* @return the trace
if
(
m_dir
==
UNDEFINED
)
*/
start_diagonal
=
aStartDiagonal
;
const
SHAPE_LINE_CHAIN
BuildInitialTrace
(
const
VECTOR2I
&
aP0
,
else
const
VECTOR2I
&
aP1
,
start_diagonal
=
IsDiagonal
();
bool
aStartDiagonal
=
false
)
const
{
SHAPE_LINE_CHAIN
pl
;
int
w
=
abs
(
aP1
.
x
-
aP0
.
x
);
int
h
=
abs
(
aP1
.
y
-
aP0
.
y
);
pl
.
Append
(
aP0
);
int
sw
=
sign
(
aP1
.
x
-
aP0
.
x
);
if
(
start_diagonal
)
int
sh
=
sign
(
aP1
.
y
-
aP0
.
y
);
pl
.
Append
(
aP0
+
mp1
);
else
VECTOR2I
mp0
,
mp1
;
pl
.
Append
(
aP0
+
mp0
);
// we are more horizontal than vertical?
pl
.
Append
(
aP1
);
if
(
w
>
h
)
pl
.
Simplify
();
{
return
pl
;
mp0
=
VECTOR2I
(
(
w
-
h
)
*
sw
,
0
);
// direction: E
};
mp1
=
VECTOR2I
(
h
*
sw
,
h
*
sh
);
// direction: NE
}
bool
operator
==
(
const
DIRECTION_45
&
aOther
)
const
else
{
{
return
aOther
.
m_dir
==
m_dir
;
mp0
=
VECTOR2I
(
0
,
sh
*
(
h
-
w
)
);
// direction: N
}
mp1
=
VECTOR2I
(
sw
*
w
,
sh
*
w
);
// direction: NE
}
bool
operator
!=
(
const
DIRECTION_45
&
aOther
)
const
{
bool
start_diagonal
;
return
aOther
.
m_dir
!=
m_dir
;
}
if
(
m_dir
==
UNDEFINED
)
start_diagonal
=
aStartDiagonal
;
const
DIRECTION_45
Right
()
const
else
{
start_diagonal
=
IsDiagonal
();
DIRECTION_45
r
;
r
.
m_dir
=
(
Directions
)
(
m_dir
+
1
);
SHAPE_LINE_CHAIN
pl
;
if
(
r
.
m_dir
==
NW
)
r
.
m_dir
=
N
;
pl
.
Append
(
aP0
);
return
r
;
}
if
(
start_diagonal
)
pl
.
Append
(
aP0
+
mp1
);
else
pl
.
Append
(
aP0
+
mp0
);
pl
.
Append
(
aP1
);
pl
.
Simplify
();
return
pl
;
};
bool
operator
==
(
const
DIRECTION_45
&
aOther
)
const
{
return
aOther
.
m_dir
==
m_dir
;
}
bool
operator
!=
(
const
DIRECTION_45
&
aOther
)
const
{
return
aOther
.
m_dir
!=
m_dir
;
}
const
DIRECTION_45
Right
()
const
{
DIRECTION_45
r
;
r
.
m_dir
=
(
Directions
)
(
m_dir
+
1
);
if
(
r
.
m_dir
==
NW
)
r
.
m_dir
=
N
;
return
r
;
}
private
:
private
:
template
<
typename
T
>
int
sign
(
T
val
)
const
{
template
<
typename
T
>
return
(
T
(
0
)
<
val
)
-
(
val
<
T
(
0
));
int
sign
(
T
val
)
const
}
{
return
(
T
(
0
)
<
val
)
-
(
val
<
T
(
0
)
);
/**
}
* Function construct()
* Calculates the direction from a vector. If the vector's angle is not a multiple of 45
/**
* degrees, the direction is rounded to the nearest octant.
* Function construct()
* @param aVec our vector
* Calculates the direction from a vector. If the vector's angle is not a multiple of 45
*/
* degrees, the direction is rounded to the nearest octant.
void
construct
(
const
VECTOR2I
&
aVec
)
* @param aVec our vector
{
*/
m_dir
=
UNDEFINED
;
void
construct
(
const
VECTOR2I
&
aVec
)
if
(
aVec
.
x
==
0
&&
aVec
.
y
==
0
)
{
return
;
m_dir
=
UNDEFINED
;
double
mag
=
360
.
0
-
(
180
.
0
/
M_PI
*
atan2
((
double
)
aVec
.
y
,
(
double
)
aVec
.
x
))
+
90
.
0
;
if
(
aVec
.
x
==
0
&&
aVec
.
y
==
0
)
if
(
mag
>=
360
.
0
)
return
;
mag
-=
360
.
0
;
if
(
mag
<
0
.
0
)
double
mag
=
360
.
0
-
(
180
.
0
/
M_PI
*
atan2
(
(
double
)
aVec
.
y
,
(
double
)
aVec
.
x
)
)
+
90
.
0
;
mag
+=
360
.
0
;
if
(
mag
>=
360
.
0
)
m_dir
=
(
Directions
)
((
mag
+
22
.
5
)
/
45
.
0
);
mag
-=
360
.
0
;
if
(
m_dir
>=
8
)
if
(
mag
<
0
.
0
)
m_dir
=
(
Directions
)
(
m_dir
-
8
);
mag
+=
360
.
0
;
if
(
m_dir
<
0
)
m_dir
=
(
Directions
)
(
m_dir
+
8
);
m_dir
=
(
Directions
)(
(
mag
+
22
.
5
)
/
45
.
0
);
return
;
if
(
m_dir
>=
8
)
if
(
aVec
.
y
<
0
)
m_dir
=
(
Directions
)(
m_dir
-
8
);
{
if
(
aVec
.
x
>
0
)
if
(
m_dir
<
0
)
m_dir
=
NE
;
m_dir
=
(
Directions
)(
m_dir
+
8
);
else
if
(
aVec
.
x
<
0
)
m_dir
=
NW
;
return
;
else
m_dir
=
N
;
if
(
aVec
.
y
<
0
)
}
{
else
if
(
aVec
.
y
==
0
)
if
(
aVec
.
x
>
0
)
{
m_dir
=
NE
;
if
(
aVec
.
x
>
0
)
else
if
(
aVec
.
x
<
0
)
m_dir
=
E
;
m_dir
=
NW
;
else
else
m_dir
=
W
;
m_dir
=
N
;
}
}
else
// aVec.y>0
else
if
(
aVec
.
y
==
0
)
{
{
if
(
aVec
.
x
>
0
)
if
(
aVec
.
x
>
0
)
m_dir
=
SE
;
m_dir
=
E
;
else
if
(
aVec
.
x
<
0
)
else
m_dir
=
SW
;
m_dir
=
W
;
else
}
m_dir
=
S
;
else
// aVec.y>0
}
{
}
if
(
aVec
.
x
>
0
)
m_dir
=
SE
;
Directions
m_dir
;
///> our actual direction
else
if
(
aVec
.
x
<
0
)
};
m_dir
=
SW
;
else
#endif // __DIRECTION_H
m_dir
=
S
;
}
}
Directions
m_dir
;
///> our actual direction
};
#endif // __DIRECTION_H
pcbnew/router/pns_index.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -37,205 +37,227 @@
...
@@ -37,205 +37,227 @@
* overlap and improving search time.
* overlap and improving search time.
**/
**/
class
PNS_INDEX
{
class
PNS_INDEX
{
public
:
public
:
typedef
std
::
list
<
PNS_ITEM
*>
NetItemsList
;
typedef
std
::
list
<
PNS_ITEM
*>
NetItemsList
;
typedef
SHAPE_INDEX
<
PNS_ITEM
*>
ItemShapeIndex
;
typedef
SHAPE_INDEX
<
PNS_ITEM
*>
ItemShapeIndex
;
typedef
boost
::
unordered_set
<
PNS_ITEM
*>
ItemSet
;
typedef
boost
::
unordered_set
<
PNS_ITEM
*>
ItemSet
;
PNS_INDEX
();
~
PNS_INDEX
();
void
Add
(
PNS_ITEM
*
aItem
);
void
Remove
(
PNS_ITEM
*
aItem
);
void
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
);
template
<
class
Visitor
>
PNS_INDEX
();
int
Query
(
const
PNS_ITEM
*
aItem
,
int
aMinDistance
,
Visitor
&
v
);
~
PNS_INDEX
();
template
<
class
Visitor
>
int
Query
(
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
);
void
Clear
();
void
Add
(
PNS_ITEM
*
aItem
);
void
Remove
(
PNS_ITEM
*
aItem
);
void
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
);
NetItemsList
*
GetItemsForNet
(
int
aNet
)
;
template
<
class
Visitor
>
int
Query
(
const
PNS_ITEM
*
aItem
,
int
aMinDistance
,
Visitor
&
v
);
ItemSet
::
iterator
begin
()
{
return
m_allItems
.
begin
();
}
template
<
class
Visitor
>
ItemSet
::
iterator
end
()
{
return
m_allItems
.
end
();
}
int
Query
(
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
);
bool
Contains
(
PNS_ITEM
*
aItem
)
const
{
void
Clear
();
return
m_allItems
.
find
(
aItem
)
!=
m_allItems
.
end
();
}
int
Size
()
const
{
return
m_allItems
.
size
();
}
NetItemsList
*
GetItemsForNet
(
int
aNet
);
private
:
ItemSet
::
iterator
begin
()
{
return
m_allItems
.
begin
();
}
ItemSet
::
iterator
end
()
{
return
m_allItems
.
end
();
}
static
const
int
MaxSubIndices
=
64
;
static
const
int
SI_Multilayer
=
2
;
static
const
int
SI_SegDiagonal
=
0
;
static
const
int
SI_SegStraight
=
1
;
static
const
int
SI_Traces
=
3
;
static
const
int
SI_PadsTop
=
0
;
static
const
int
SI_PadsBottom
=
1
;
template
<
class
Visitor
>
bool
Contains
(
PNS_ITEM
*
aItem
)
const
int
querySingle
(
int
index
,
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
);
{
return
m_allItems
.
find
(
aItem
)
!=
m_allItems
.
end
();
}
ItemShapeIndex
*
getSubindex
(
const
PNS_ITEM
*
aItem
);
int
Size
()
const
{
return
m_allItems
.
size
();
}
ItemShapeIndex
*
m_subIndices
[
MaxSubIndices
];
private
:
std
::
map
<
int
,
NetItemsList
>
m_netMap
;
static
const
int
MaxSubIndices
=
64
;
ItemSet
m_allItems
;
static
const
int
SI_Multilayer
=
2
;
static
const
int
SI_SegDiagonal
=
0
;
static
const
int
SI_SegStraight
=
1
;
static
const
int
SI_Traces
=
3
;
static
const
int
SI_PadsTop
=
0
;
static
const
int
SI_PadsBottom
=
1
;
template
<
class
Visitor
>
int
querySingle
(
int
index
,
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
);
ItemShapeIndex
*
getSubindex
(
const
PNS_ITEM
*
aItem
);
ItemShapeIndex
*
m_subIndices
[
MaxSubIndices
];
std
::
map
<
int
,
NetItemsList
>
m_netMap
;
ItemSet
m_allItems
;
};
};
PNS_INDEX
::
PNS_INDEX
()
PNS_INDEX
::
PNS_INDEX
()
{
{
memset
(
m_subIndices
,
0
,
sizeof
(
m_subIndices
)
);
memset
(
m_subIndices
,
0
,
sizeof
(
m_subIndices
)
);
}
}
PNS_INDEX
::
ItemShapeIndex
*
PNS_INDEX
::
getSubindex
(
const
PNS_ITEM
*
aItem
)
PNS_INDEX
::
ItemShapeIndex
*
PNS_INDEX
::
getSubindex
(
const
PNS_ITEM
*
aItem
)
{
{
int
idx_n
=
-
1
;
int
idx_n
=
-
1
;
const
PNS_LAYERSET
l
=
aItem
->
GetLayers
();
const
PNS_LAYERSET
l
=
aItem
->
GetLayers
();
switch
(
aItem
->
GetKind
())
switch
(
aItem
->
GetKind
()
)
{
{
case
PNS_ITEM
:
:
VIA
:
case
PNS_ITEM
:
:
VIA
:
idx_n
=
SI_Multilayer
;
idx_n
=
SI_Multilayer
;
break
;
break
;
case
PNS_ITEM
:
:
SOLID
:
{
case
PNS_ITEM
:
:
SOLID
:
if
(
l
.
IsMultilayer
()
)
{
idx_n
=
SI_Multilayer
;
if
(
l
.
IsMultilayer
()
)
else
if
(
l
.
Start
()
==
0
)
// fixme: use kicad layer codes
idx_n
=
SI_Multilayer
;
idx_n
=
SI_PadsTop
;
else
if
(
l
.
Start
()
==
0
)
// fixme: use kicad layer codes
else
if
(
l
.
Start
()
==
15
)
idx_n
=
SI_PadsTop
;
idx_n
=
SI_PadsBottom
;
else
if
(
l
.
Start
()
==
15
)
break
;
idx_n
=
SI_PadsBottom
;
}
case
PNS_ITEM
:
:
SEGMENT
:
break
;
case
PNS_ITEM
:
:
LINE
:
}
idx_n
=
SI_Traces
+
2
*
l
.
Start
()
+
SI_SegStraight
;
break
;
case
PNS_ITEM
:
:
SEGMENT
:
default
:
case
PNS_ITEM
:
:
LINE
:
break
;
idx_n
=
SI_Traces
+
2
*
l
.
Start
()
+
SI_SegStraight
;
}
break
;
assert
(
idx_n
>=
0
&&
idx_n
<
MaxSubIndices
);
default
:
if
(
!
m_subIndices
[
idx_n
])
break
;
m_subIndices
[
idx_n
]
=
new
ItemShapeIndex
;
}
return
m_subIndices
[
idx_n
];
assert
(
idx_n
>=
0
&&
idx_n
<
MaxSubIndices
);
if
(
!
m_subIndices
[
idx_n
]
)
m_subIndices
[
idx_n
]
=
new
ItemShapeIndex
;
return
m_subIndices
[
idx_n
];
}
}
void
PNS_INDEX
::
Add
(
PNS_ITEM
*
aItem
)
void
PNS_INDEX
::
Add
(
PNS_ITEM
*
aItem
)
{
{
ItemShapeIndex
*
idx
=
getSubindex
(
aItem
);
ItemShapeIndex
*
idx
=
getSubindex
(
aItem
);
idx
->
Add
(
aItem
);
idx
->
Add
(
aItem
);
m_allItems
.
insert
(
aItem
);
m_allItems
.
insert
(
aItem
);
int
net
=
aItem
->
GetNet
(
);
int
net
=
aItem
->
GetNet
();
if
(
net
>=
0
)
if
(
net
>=
0
)
{
{
m_netMap
[
net
].
push_back
(
aItem
);
m_netMap
[
net
].
push_back
(
aItem
);
}
}
}
}
void
PNS_INDEX
::
Remove
(
PNS_ITEM
*
aItem
)
void
PNS_INDEX
::
Remove
(
PNS_ITEM
*
aItem
)
{
{
ItemShapeIndex
*
idx
=
getSubindex
(
aItem
);
ItemShapeIndex
*
idx
=
getSubindex
(
aItem
);
idx
->
Remove
(
aItem
);
m_allItems
.
erase
(
aItem
);
idx
->
Remove
(
aItem
);
m_allItems
.
erase
(
aItem
);
int
net
=
aItem
->
GetNet
();
int
net
=
aItem
->
GetNet
();
if
(
net
>=
0
&&
m_netMap
.
find
(
net
)
!=
m_netMap
.
end
())
m_netMap
[
net
].
remove
(
aItem
);
if
(
net
>=
0
&&
m_netMap
.
find
(
net
)
!=
m_netMap
.
end
()
)
m_netMap
[
net
].
remove
(
aItem
);
}
}
void
PNS_INDEX
::
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
)
void
PNS_INDEX
::
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
)
{
{
Remove
(
aOldItem
);
Remove
(
aOldItem
);
Add
(
aNewItem
);
Add
(
aNewItem
);
}
}
template
<
class
Visitor
>
template
<
class
Visitor
>
int
PNS_INDEX
::
querySingle
(
int
index
,
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
)
int
PNS_INDEX
::
querySingle
(
int
index
,
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
)
{
{
if
(
!
m_subIndices
[
index
])
if
(
!
m_subIndices
[
index
]
)
return
0
;
return
0
;
return
m_subIndices
[
index
]
->
Query
(
aShape
,
aMinDistance
,
v
,
false
);
}
return
m_subIndices
[
index
]
->
Query
(
aShape
,
aMinDistance
,
v
,
false
);
}
template
<
class
Visitor
>
template
<
class
Visitor
>
int
PNS_INDEX
::
Query
(
const
PNS_ITEM
*
aItem
,
int
aMinDistance
,
Visitor
&
v
)
int
PNS_INDEX
::
Query
(
const
PNS_ITEM
*
aItem
,
int
aMinDistance
,
Visitor
&
v
)
{
{
const
SHAPE
*
shape
=
aItem
->
GetShape
();
const
SHAPE
*
shape
=
aItem
->
GetShape
();
int
total
=
0
;
int
total
=
0
;
total
+=
querySingle
(
SI_Multilayer
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_Multilayer
,
shape
,
aMinDistance
,
v
);
const
PNS_LAYERSET
layers
=
aItem
->
GetLayers
();
const
PNS_LAYERSET
layers
=
aItem
->
GetLayers
();
if
(
layers
.
IsMultilayer
()
)
if
(
layers
.
IsMultilayer
())
{
{
total
+=
querySingle
(
SI_PadsTop
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_PadsTop
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_PadsBottom
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_PadsBottom
,
shape
,
aMinDistance
,
v
);
for
(
int
i
=
layers
.
Start
();
i
<=
layers
.
End
();
++
i
)
total
+=
querySingle
(
SI_Traces
+
2
*
i
+
SI_SegStraight
,
shape
,
aMinDistance
,
v
);
for
(
int
i
=
layers
.
Start
();
i
<=
layers
.
End
();
++
i
)
}
total
+=
querySingle
(
SI_Traces
+
2
*
i
+
SI_SegStraight
,
shape
,
aMinDistance
,
v
);
else
{
}
else
{
int
l
=
layers
.
Start
();
int
l
=
layers
.
Start
();
if
(
l
==
0
)
if
(
l
==
0
)
total
+=
querySingle
(
SI_PadsTop
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_PadsTop
,
shape
,
aMinDistance
,
v
);
else
if
(
l
==
15
)
else
if
(
l
==
15
)
total
+=
querySingle
(
SI_PadsBottom
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_PadsBottom
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_Traces
+
2
*
l
+
SI_SegStraight
,
shape
,
aMinDistance
,
v
);
total
+=
querySingle
(
SI_Traces
+
2
*
l
+
SI_SegStraight
,
shape
,
aMinDistance
,
v
);
}
}
return
total
;
return
total
;
}
}
template
<
class
Visitor
>
template
<
class
Visitor
>
int
PNS_INDEX
::
Query
(
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
)
int
PNS_INDEX
::
Query
(
const
SHAPE
*
aShape
,
int
aMinDistance
,
Visitor
&
v
)
{
{
int
total
=
0
;
int
total
=
0
;
for
(
int
i
=
0
;
i
<
MaxSubIndices
;
i
++
)
total
+=
querySingle
(
i
,
aShape
,
aMinDistance
,
v
);
for
(
int
i
=
0
;
i
<
MaxSubIndices
;
i
++
)
return
total
;
total
+=
querySingle
(
i
,
aShape
,
aMinDistance
,
v
);
}
return
total
;
}
void
PNS_INDEX
::
Clear
()
void
PNS_INDEX
::
Clear
()
{
{
for
(
int
i
=
0
;
i
<
MaxSubIndices
;
++
i
)
for
(
int
i
=
0
;
i
<
MaxSubIndices
;
++
i
)
{
{
ItemShapeIndex
*
idx
=
m_subIndices
[
i
];
ItemShapeIndex
*
idx
=
m_subIndices
[
i
];
if
(
idx
)
delete
idx
;
if
(
idx
)
m_subIndices
[
i
]
=
NULL
;
delete
idx
;
}
m_subIndices
[
i
]
=
NULL
;
}
}
}
PNS_INDEX
::~
PNS_INDEX
()
PNS_INDEX
::~
PNS_INDEX
()
{
{
Clear
();
Clear
();
}
}
PNS_INDEX
::
NetItemsList
*
PNS_INDEX
::
GetItemsForNet
(
int
aNet
)
PNS_INDEX
::
NetItemsList
*
PNS_INDEX
::
GetItemsForNet
(
int
aNet
)
{
{
if
(
m_netMap
.
find
(
aNet
)
==
m_netMap
.
end
())
if
(
m_netMap
.
find
(
aNet
)
==
m_netMap
.
end
()
)
return
NULL
;
return
NULL
;
return
&
m_netMap
[
aNet
];
return
&
m_netMap
[
aNet
];
}
}
#endif
#endif
pcbnew/router/pns_item.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -21,52 +21,69 @@
...
@@ -21,52 +21,69 @@
#include "pns_item.h"
#include "pns_item.h"
#include "pns_line.h"
#include "pns_line.h"
bool
PNS_ITEM
::
collideSimple
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
bool
PNS_ITEM
::
collideSimple
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
{
{
// same nets? no collision!
// same nets? no collision!
if
(
m_net
==
aOther
->
m_net
)
if
(
m_net
==
aOther
->
m_net
)
return
false
;
return
false
;
// check if we are not on completely different layers first
// check if we are not on completely different layers first
if
(
!
m_layers
.
Overlaps
(
aOther
->
m_layers
)
)
if
(
!
m_layers
.
Overlaps
(
aOther
->
m_layers
)
)
return
false
;
return
false
;
return
GetShape
()
->
Collide
(
aOther
->
GetShape
(),
aClearance
);
return
GetShape
()
->
Collide
(
aOther
->
GetShape
(),
aClearance
);
// fixme: MTV
// fixme: MTV
}
}
bool
PNS_ITEM
::
Collide
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
bool
PNS_ITEM
::
Collide
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
{
{
if
(
collideSimple
(
aOther
,
aClearance
,
aNeedMTV
,
aMTV
)
)
if
(
collideSimple
(
aOther
,
aClearance
,
aNeedMTV
,
aMTV
)
)
return
true
;
return
true
;
// special case for "head" line with a via attached at the end.
// special case for "head" line with a via attached at the end.
if
(
aOther
->
m_kind
==
LINE
)
if
(
aOther
->
m_kind
==
LINE
)
{
{
const
PNS_LINE
*
line
=
static_cast
<
const
PNS_LINE
*>
(
aOther
);
const
PNS_LINE
*
line
=
static_cast
<
const
PNS_LINE
*>
(
aOther
);
if
(
line
->
EndsWithVia
())
return
collideSimple
(
&
line
->
GetVia
(),
aClearance
-
line
->
GetWidth
()
/
2
,
aNeedMTV
,
aMTV
);
if
(
line
->
EndsWithVia
()
)
}
return
collideSimple
(
&
line
->
GetVia
(),
aClearance
-
line
->
GetWidth
()
/
2
,
aNeedMTV
,
aMTV
);
return
false
;
}
return
false
;
}
}
const
std
::
string
PNS_ITEM
::
GetKindStr
()
const
const
std
::
string
PNS_ITEM
::
GetKindStr
()
const
{
{
switch
(
m_kind
)
switch
(
m_kind
)
{
{
case
LINE
:
return
"line"
;
case
LINE
:
case
SEGMENT
:
return
"segment"
;
return
"line"
;
case
VIA
:
return
"via"
;
case
JOINT
:
return
"joint"
;
case
SEGMENT
:
case
SOLID
:
return
"solid"
;
return
"segment"
;
default
:
return
"unknown"
;
}
case
VIA
:
return
"via"
;
case
JOINT
:
return
"joint"
;
case
SOLID
:
return
"solid"
;
default
:
return
"unknown"
;
}
}
}
PNS_ITEM
::~
PNS_ITEM
()
PNS_ITEM
::~
PNS_ITEM
()
{
{
}
}
\ No newline at end of file
pcbnew/router/pns_item.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -37,119 +37,122 @@ class PNS_NODE;
...
@@ -37,119 +37,122 @@ class PNS_NODE;
* Base class for PNS router board items. Implements the shared properties of all PCB items -
* Base class for PNS router board items. Implements the shared properties of all PCB items -
* net, spanned layers, geometric shape & refererence to owning model.
* net, spanned layers, geometric shape & refererence to owning model.
*/
*/
class
PNS_ITEM
class
PNS_ITEM
{
{
public
:
public
:
static
const
int
UnusedNet
=
INT_MAX
;
static
const
int
UnusedNet
=
INT_MAX
;
///> Supported item types
///> Supported item types
enum
PnsKind
enum
PnsKind
{
{
SOLID
=
1
,
SOLID
=
1
,
LINE
=
2
,
LINE
=
2
,
JOINT
=
4
,
JOINT
=
4
,
SEGMENT
=
8
,
SEGMENT
=
8
,
VIA
=
16
,
VIA
=
16
,
ANY
=
0xff
ANY
=
0xff
};
};
PNS_ITEM
(
PnsKind
aKind
)
PNS_ITEM
(
PnsKind
aKind
)
{
{
m_net
=
UnusedNet
;
m_net
=
UnusedNet
;
m_movable
=
true
;
m_movable
=
true
;
m_kind
=
aKind
;
m_kind
=
aKind
;
m_parent
=
NULL
;
m_parent
=
NULL
;
m_world
=
NULL
;
m_world
=
NULL
;
m_owner
=
NULL
;
m_owner
=
NULL
;
}
}
PNS_ITEM
(
const
PNS_ITEM
&
aOther
)
PNS_ITEM
(
const
PNS_ITEM
&
aOther
)
{
{
m_layers
=
aOther
.
m_layers
;
m_layers
=
aOther
.
m_layers
;
m_net
=
aOther
.
m_net
;
m_net
=
aOther
.
m_net
;
m_movable
=
aOther
.
m_movable
;
m_movable
=
aOther
.
m_movable
;
m_kind
=
aOther
.
m_kind
;
m_kind
=
aOther
.
m_kind
;
m_world
=
aOther
.
m_world
;
m_world
=
aOther
.
m_world
;
m_parent
=
aOther
.
m_parent
;
m_parent
=
aOther
.
m_parent
;
m_owner
=
NULL
;
m_owner
=
NULL
;
}
}
virtual
~
PNS_ITEM
();
virtual
~
PNS_ITEM
();
virtual
PNS_ITEM
*
Clone
()
const
=
0
;
virtual
PNS_ITEM
*
Clone
()
const
=
0
;
///> Returns a convex polygon "hull" of a the item, that is used as the walkaround
///> Returns a convex polygon "hull" of a the item, that is used as the walkaround
/// path.
/// path.
/// aClearance defines how far from the body of the item the hull should be,
/// aClearance defines how far from the body of the item the hull should be,
/// aWalkaroundThickness is the width of the line that walks around this hull.
/// aWalkaroundThickness is the width of the line that walks around this hull.
virtual
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
=
0
,
int
aWalkaroundThickness
=
0
)
const
virtual
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
=
0
,
int
aWalkaroundThickness
=
0
)
const
{
{
return
SHAPE_LINE_CHAIN
();
return
SHAPE_LINE_CHAIN
();
};
};
PnsKind
GetKind
()
const
{
return
m_kind
;
}
bool
OfKind
(
int
aKind
)
const
{
return
(
aKind
&
m_kind
)
!=
0
;
}
PnsKind
GetKind
()
const
{
return
m_kind
;
}
bool
OfKind
(
int
aKind
)
const
{
return
(
aKind
&
m_kind
)
!=
0
;
}
const
std
::
string
GetKindStr
()
const
;
const
std
::
string
GetKindStr
()
const
;
///> Gets/Sets the corresponding parent object in the host application's model (pcbnew)
void
SetParent
(
BOARD_ITEM
*
aParent
)
{
m_parent
=
aParent
;
}
///> Gets/Sets the corresponding parent object in the host application's model (pcbnew)
BOARD_ITEM
*
GetParent
()
const
{
return
m_parent
;
}
void
SetParent
(
BOARD_ITEM
*
aParent
)
{
m_parent
=
aParent
;
}
BOARD_ITEM
*
GetParent
()
const
{
return
m_parent
;
}
///> Net accessors
int
GetNet
()
const
{
return
m_net
;
}
///> Net accessors
void
SetNet
(
int
aNet
)
{
m_net
=
aNet
;
}
int
GetNet
()
const
{
return
m_net
;
}
void
SetNet
(
int
aNet
)
{
m_net
=
aNet
;
}
///> Layers accessors
const
PNS_LAYERSET
&
GetLayers
()
const
{
return
m_layers
;
}
///> Layers accessors
void
SetLayers
(
const
PNS_LAYERSET
&
aLayers
)
{
m_layers
=
aLayers
;
}
const
PNS_LAYERSET
&
GetLayers
()
const
{
return
m_layers
;
}
void
SetLayer
(
int
aLayer
)
void
SetLayers
(
const
PNS_LAYERSET
&
aLayers
)
{
m_layers
=
aLayers
;
}
{
void
SetLayer
(
int
aLayer
)
{
m_layers
=
PNS_LAYERSET
(
aLayer
,
aLayer
);
}
m_layers
=
PNS_LAYERSET
(
aLayer
,
aLayer
);
}
///> Ownership management. An item can belong to a single PNS_NODE or stay unowned.
void
SetOwner
(
PNS_NODE
*
aOwner
)
{
m_owner
=
aOwner
;
}
///> Ownership management. An item can belong to a single PNS_NODE or stay unowned.
bool
BelongsTo
(
PNS_NODE
*
aNode
)
const
{
return
m_owner
==
aNode
;
}
void
SetOwner
(
PNS_NODE
*
aOwner
)
{
m_owner
=
aOwner
;
}
PNS_NODE
*
GetOwner
()
const
{
return
m_owner
;
}
bool
BelongsTo
(
PNS_NODE
*
aNode
)
const
{
return
m_owner
==
aNode
;
}
PNS_NODE
*
GetOwner
()
const
{
return
m_owner
;
}
///> Sets the world that is used for collision resolution.
void
SetWorld
(
PNS_NODE
*
aWorld
)
{
m_world
=
aWorld
;
}
///> Sets the world that is used for collision resolution.
PNS_NODE
*
GetWorld
()
const
{
return
m_world
;
}
void
SetWorld
(
PNS_NODE
*
aWorld
)
{
m_world
=
aWorld
;
}
PNS_NODE
*
GetWorld
()
const
{
return
m_world
;
}
///> Collision function. Checks if the item aOther is closer to us than
///> Collision function. Checks if the item aOther is closer to us than
/// aClearance and returns true if so. It can also calculate a minimum translation vector that resolves the
/// aClearance and returns true if so. It can also calculate a minimum translation vector that
/// collision if needed.
/// resolves the collision if needed.
virtual
bool
Collide
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
;
virtual
bool
Collide
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
;
///> A shortcut without MTV calculation
bool
Collide
(
const
PNS_ITEM
*
aOther
,
int
aClearance
)
const
///> A shortcut without MTV calculation
{
bool
Collide
(
const
PNS_ITEM
*
aOther
,
int
aClearance
)
const
VECTOR2I
dummy
;
{
return
Collide
(
aOther
,
aClearance
,
false
,
dummy
);
VECTOR2I
dummy
;
}
return
Collide
(
aOther
,
aClearance
,
false
,
dummy
);
///> Returns the geometric shape of the item
}
virtual
const
SHAPE
*
GetShape
()
const
{
return
NULL
;
///> Returns the geometric shape of the item
}
virtual
const
SHAPE
*
GetShape
()
const
{
return
NULL
;
}
private
:
private
:
bool
collideSimple
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
;
bool
collideSimple
(
const
PNS_ITEM
*
aOther
,
int
aClearance
,
bool
aNeedMTV
,
VECTOR2I
&
aMTV
)
const
;
protected
:
protected
:
PnsKind
m_kind
;
PnsKind
m_kind
;
BOARD_ITEM
*
m_parent
;
PNS_NODE
*
m_world
;
BOARD_ITEM
*
m_parent
;
PNS_NODE
*
m_owner
;
PNS_NODE
*
m_world
;
PNS_LAYERSET
m_layers
;
PNS_NODE
*
m_owner
;
PNS_LAYERSET
m_layers
;
bool
m_movable
;
bool
m_movable
;
int
m_net
;
int
m_net
;
};
};
#endif
// __PNS_ITEM_H
#endif
// __PNS_ITEM_Ha
pcbnew/router/pns_itemset.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -25,49 +25,58 @@
...
@@ -25,49 +25,58 @@
PNS_ITEMSET
::
PNS_ITEMSET
()
PNS_ITEMSET
::
PNS_ITEMSET
()
{
{
}
}
PNS_ITEMSET
::~
PNS_ITEMSET
()
PNS_ITEMSET
::~
PNS_ITEMSET
()
{
{
}
}
PNS_ITEMSET
&
PNS_ITEMSET
::
FilterLayers
(
int
aStart
,
int
aEnd
)
PNS_ITEMSET
&
PNS_ITEMSET
::
FilterLayers
(
int
aStart
,
int
aEnd
)
{
{
ItemVector
newItems
;
ItemVector
newItems
;
PNS_LAYERSET
l
;
PNS_LAYERSET
l
;
if
(
aEnd
<
0
)
l
=
PNS_LAYERSET
(
aStart
);
if
(
aEnd
<
0
)
else
l
=
PNS_LAYERSET
(
aStart
);
l
=
PNS_LAYERSET
(
aStart
,
aEnd
);
else
l
=
PNS_LAYERSET
(
aStart
,
aEnd
);
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_items
)
if
(
item
->
GetLayers
().
Overlaps
(
l
))
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_items
)
newItems
.
push_back
(
item
);
m_items
=
newItems
;
if
(
item
->
GetLayers
().
Overlaps
(
l
)
)
return
*
this
;
newItems
.
push_back
(
item
);
m_items
=
newItems
;
return
*
this
;
}
}
PNS_ITEMSET
&
PNS_ITEMSET
::
FilterKinds
(
int
aKindMask
)
PNS_ITEMSET
&
PNS_ITEMSET
::
FilterKinds
(
int
aKindMask
)
{
{
ItemVector
newItems
;
ItemVector
newItems
;
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_items
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_items
)
if
(
item
->
GetKind
()
&
aKindMask
)
newItems
.
push_back
(
item
);
if
(
item
->
GetKind
()
&
aKindMask
)
m_items
=
newItems
;
newItems
.
push_back
(
item
);
return
*
this
;
m_items
=
newItems
;
return
*
this
;
}
}
PNS_ITEMSET
&
PNS_ITEMSET
::
FilterNet
(
int
aNet
)
PNS_ITEMSET
&
PNS_ITEMSET
::
FilterNet
(
int
aNet
)
{
{
ItemVector
newItems
;
ItemVector
newItems
;
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_items
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_items
)
if
(
item
->
GetNet
()
==
aNet
)
newItems
.
push_back
(
item
);
if
(
item
->
GetNet
()
==
aNet
)
m_items
=
newItems
;
newItems
.
push_back
(
item
);
return
*
this
;
m_items
=
newItems
;
return
*
this
;
}
}
pcbnew/router/pns_itemset.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -28,35 +28,36 @@
...
@@ -28,35 +28,36 @@
/**
/**
* Class PNS_ITEMSET
* Class PNS_ITEMSET
*
*
* Holds a list of board items, that can be filtered against net, kinds, layers, etc.
* Holds a list of board items, that can be filtered against net, kinds,
* layers, etc.
**/
**/
class
PNS_ITEMSET
class
PNS_ITEMSET
{
{
public
:
public
:
typedef
std
::
vector
<
PNS_ITEM
*>
ItemVector
;
typedef
std
::
vector
<
PNS_ITEM
*>
ItemVector
;
PNS_ITEMSET
();
~
PNS_ITEMSET
();
PNS_ITEMSET
();
ItemVector
&
Items
()
{
return
m_items
;
}
~
PNS_ITEMSET
();
ItemVector
&
Items
()
{
return
m_items
;
}
PNS_ITEMSET
&
FilterLayers
(
int
aStart
,
int
aEnd
=
-
1
);
PNS_ITEMSET
&
FilterKinds
(
int
aKindMask
);
PNS_ITEMSET
&
FilterNet
(
int
aNet
);
PNS_ITEMSET
&
FilterLayers
(
int
aStart
,
int
aEnd
=
-
1
);
int
Size
()
{
return
m_items
.
size
();
}
PNS_ITEMSET
&
FilterKinds
(
int
aKindMask
);
PNS_ITEMSET
&
FilterNet
(
int
aNet
);
int
Size
()
{
return
m_items
.
size
();
}
void
Add
(
PNS_ITEM
*
item
)
void
Add
(
PNS_ITEM
*
item
)
{
{
m_items
.
push_back
(
item
);
m_items
.
push_back
(
item
);
}
}
PNS_ITEM
*
Get
(
int
index
)
const
{
return
m_items
[
index
];
}
PNS_ITEM
*
Get
(
int
index
)
const
{
return
m_items
[
index
];
}
private
:
private
:
ItemVector
m_items
;
ItemVector
m_items
;
};
};
#endif
#endif
pcbnew/router/pns_joint.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -31,158 +31,177 @@
...
@@ -31,158 +31,177 @@
/**
/**
* Class PNS_JOINT
* Class PNS_JOINT
*
*
* Represents a 2D point on a given set of layers and belonging to a certain net,
* Represents a 2D point on a given set of layers and belonging to a certain
* that links together a number of board items.
* net, that links together a number of board items.
* A hash table of joints is used by the router to follow connectivity between the items.
* A hash table of joints is used by the router to follow connectivity between
* the items.
**/
**/
class
PNS_JOINT
:
public
PNS_ITEM
class
PNS_JOINT
:
public
PNS_ITEM
{
{
public
:
public
:
typedef
std
::
vector
<
PNS_ITEM
*>
LinkedItems
;
typedef
std
::
vector
<
PNS_ITEM
*>
LinkedItems
;
///> joints are hashed by their position, layers and net. Linked items are, obviously, not hashed
///> Joints are hashed by their position, layers and net.
struct
HashTag
{
/// Linked items are, obviously, not hashed
VECTOR2I
pos
;
struct
HashTag
int
net
;
{
};
VECTOR2I
pos
;
int
net
;
PNS_JOINT
()
:
};
PNS_ITEM
(
JOINT
)
{}
PNS_JOINT
()
:
PNS_JOINT
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
=
-
1
)
:
PNS_ITEM
(
JOINT
)
{}
PNS_ITEM
(
JOINT
)
{
PNS_JOINT
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
m_tag
.
pos
=
aPos
;
int
aNet
=
-
1
)
:
m_tag
.
net
=
aNet
;
PNS_ITEM
(
JOINT
)
m_layers
=
aLayers
;
{
}
m_tag
.
pos
=
aPos
;
m_tag
.
net
=
aNet
;
PNS_JOINT
(
const
PNS_JOINT
&
b
)
:
m_layers
=
aLayers
;
PNS_ITEM
(
JOINT
)
}
{
m_layers
=
b
.
m_layers
;
PNS_JOINT
(
const
PNS_JOINT
&
b
)
:
m_tag
.
pos
=
b
.
m_tag
.
pos
;
PNS_ITEM
(
JOINT
)
m_tag
.
net
=
b
.
m_tag
.
net
;
{
m_linkedItems
=
b
.
m_linkedItems
;
m_layers
=
b
.
m_layers
;
m_layers
=
b
.
m_layers
;
m_tag
.
pos
=
b
.
m_tag
.
pos
;
}
m_tag
.
net
=
b
.
m_tag
.
net
;
m_linkedItems
=
b
.
m_linkedItems
;
PNS_ITEM
*
Clone
()
const
m_layers
=
b
.
m_layers
;
{
}
assert
(
false
);
return
NULL
;
PNS_ITEM
*
Clone
()
const
}
{
assert
(
false
);
///> returns true if the joint is a trivial line corner, connecting two segments of the same net, on the same layer.
return
NULL
;
bool
IsLineCorner
()
const
}
{
if
(
m_linkedItems
.
size
()
!=
2
)
///> Returns true if the joint is a trivial line corner, connecting two
return
false
;
/// segments of the same net, on the same layer.
bool
IsLineCorner
()
const
if
(
m_linkedItems
[
0
]
->
GetKind
()
!=
SEGMENT
||
m_linkedItems
[
1
]
->
GetKind
()
!=
SEGMENT
)
{
return
false
;
if
(
m_linkedItems
.
size
()
!=
2
)
return
false
;
PNS_SEGMENT
*
seg1
=
static_cast
<
PNS_SEGMENT
*>
(
m_linkedItems
[
0
]);
PNS_SEGMENT
*
seg2
=
static_cast
<
PNS_SEGMENT
*>
(
m_linkedItems
[
1
]);
if
(
m_linkedItems
[
0
]
->
GetKind
()
!=
SEGMENT
||
m_linkedItems
[
1
]
->
GetKind
()
!=
SEGMENT
)
// joints between segments of different widths are not trivial.
return
false
;
return
(
seg1
->
GetWidth
()
==
seg2
->
GetWidth
());
}
PNS_SEGMENT
*
seg1
=
static_cast
<
PNS_SEGMENT
*>
(
m_linkedItems
[
0
]);
PNS_SEGMENT
*
seg2
=
static_cast
<
PNS_SEGMENT
*>
(
m_linkedItems
[
1
]);
///> Links the joint to a given board item (when it's added to the PNS_NODE)
void
Link
(
PNS_ITEM
*
aItem
)
// joints between segments of different widths are not trivial.
{
return
seg1
->
GetWidth
()
==
seg2
->
GetWidth
();
LinkedItems
::
iterator
f
=
std
::
find
(
m_linkedItems
.
begin
(),
m_linkedItems
.
end
(),
aItem
);
}
if
(
f
!=
m_linkedItems
.
end
())
return
;
///> Links the joint to a given board item (when it's added to the PNS_NODE)
m_linkedItems
.
push_back
(
aItem
);
void
Link
(
PNS_ITEM
*
aItem
)
}
{
LinkedItems
::
iterator
f
=
std
::
find
(
m_linkedItems
.
begin
(),
///> Unlinks a given board item from the joint (upon its removal from a PNS_NODE)
m_linkedItems
.
end
(),
aItem
);
///> Returns true if the joint became dangling after unlinking.
bool
Unlink
(
PNS_ITEM
*
aItem
)
if
(
f
!=
m_linkedItems
.
end
()
)
{
return
;
LinkedItems
::
iterator
f
=
std
::
find
(
m_linkedItems
.
begin
(),
m_linkedItems
.
end
(),
aItem
);
if
(
f
!=
m_linkedItems
.
end
())
m_linkedItems
.
push_back
(
aItem
);
m_linkedItems
.
erase
(
f
);
}
return
(
m_linkedItems
.
size
()
==
0
);
}
///> Unlinks a given board item from the joint (upon its removal from a PNS_NODE)
///> Returns true if the joint became dangling after unlinking.
///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns
bool
Unlink
(
PNS_ITEM
*
aItem
)
///> NULL, indicating the end of line.
{
PNS_SEGMENT
*
NextSegment
(
PNS_SEGMENT
*
aCurrent
)
const
LinkedItems
::
iterator
f
=
std
::
find
(
m_linkedItems
.
begin
(),
{
m_linkedItems
.
end
(),
aItem
);
if
(
!
IsLineCorner
())
return
NULL
;
if
(
f
!=
m_linkedItems
.
end
()
)
m_linkedItems
.
erase
(
f
);
return
static_cast
<
PNS_SEGMENT
*>
(
m_linkedItems
[
m_linkedItems
[
0
]
==
aCurrent
?
1
:
0
]
);
}
return
m_linkedItems
.
size
()
==
0
;
}
/// trivial accessors
const
HashTag
&
GetTag
()
const
{
return
m_tag
;
}
///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns
const
VECTOR2I
&
GetPos
()
const
{
return
m_tag
.
pos
;
}
///> NULL, indicating the end of line.
int
GetNet
()
const
{
return
m_tag
.
net
;
}
PNS_SEGMENT
*
NextSegment
(
PNS_SEGMENT
*
aCurrent
)
const
LinkedItems
&
GetLinkList
()
{
return
m_linkedItems
;
};
{
if
(
!
IsLineCorner
()
)
///> Returns the number of linked items of types listed in aMask.
return
NULL
;
int
LinkCount
(
int
aMask
=
-
1
)
const
{
return
static_cast
<
PNS_SEGMENT
*>
(
m_linkedItems
[
m_linkedItems
[
0
]
==
aCurrent
?
1
:
0
]
);
int
n
=
0
;
}
for
(
LinkedItems
::
const_iterator
i
=
m_linkedItems
.
begin
();
i
!=
m_linkedItems
.
end
();
++
i
)
if
(
(
*
i
)
->
GetKind
()
&
aMask
)
/// trivial accessors
n
++
;
const
HashTag
&
GetTag
()
const
{
return
m_tag
;
}
return
n
;
const
VECTOR2I
&
GetPos
()
const
{
return
m_tag
.
pos
;
}
}
int
GetNet
()
const
{
return
m_tag
.
net
;
}
LinkedItems
&
GetLinkList
()
{
return
m_linkedItems
;
};
void
Dump
()
const
;
///> Returns the number of linked items of types listed in aMask.
bool
operator
==
(
const
PNS_JOINT
&
rhs
)
const
int
LinkCount
(
int
aMask
=
-
1
)
const
{
{
return
m_tag
.
pos
==
rhs
.
m_tag
.
pos
&&
m_tag
.
net
==
rhs
.
m_tag
.
net
;
int
n
=
0
;
}
for
(
LinkedItems
::
const_iterator
i
=
m_linkedItems
.
begin
();
void
Merge
(
const
PNS_JOINT
&
aJoint
)
i
!=
m_linkedItems
.
end
();
++
i
)
{
if
(
(
*
i
)
->
GetKind
()
&
aMask
)
if
(
!
Overlaps
(
aJoint
))
n
++
;
return
;
return
n
;
m_layers
.
Merge
(
aJoint
.
m_layers
);
}
// fixme: duplicate links (?)
void
Dump
()
const
;
for
(
LinkedItems
::
const_iterator
i
=
aJoint
.
m_linkedItems
.
begin
();
i
!=
aJoint
.
m_linkedItems
.
end
();
++
i
)
m_linkedItems
.
push_back
(
*
i
);
bool
operator
==
(
const
PNS_JOINT
&
rhs
)
const
}
{
return
m_tag
.
pos
==
rhs
.
m_tag
.
pos
&&
m_tag
.
net
==
rhs
.
m_tag
.
net
;
bool
Overlaps
(
const
PNS_JOINT
&
rhs
)
const
}
{
return
m_tag
.
pos
==
rhs
.
m_tag
.
pos
&&
m_tag
.
net
==
rhs
.
m_tag
.
net
&&
m_layers
.
Overlaps
(
rhs
.
m_layers
);
void
Merge
(
const
PNS_JOINT
&
aJoint
)
}
{
if
(
!
Overlaps
(
aJoint
)
)
return
;
m_layers
.
Merge
(
aJoint
.
m_layers
);
// fixme: duplicate links (?)
for
(
LinkedItems
::
const_iterator
i
=
aJoint
.
m_linkedItems
.
begin
();
i
!=
aJoint
.
m_linkedItems
.
end
();
++
i
)
m_linkedItems
.
push_back
(
*
i
);
}
bool
Overlaps
(
const
PNS_JOINT
&
rhs
)
const
{
return
m_tag
.
pos
==
rhs
.
m_tag
.
pos
&&
m_tag
.
net
==
rhs
.
m_tag
.
net
&&
m_layers
.
Overlaps
(
rhs
.
m_layers
);
}
private
:
private
:
///> hash tag for unordered_multimap
HashTag
m_tag
;
///> hash tag for unordered_multimap
///> list of items linked to this joint
HashTag
m_tag
;
LinkedItems
m_linkedItems
;
///> list of items linked to this joint
LinkedItems
m_linkedItems
;
};
};
// hash function & comparison operator for boost::unordered_map<>
// hash function & comparison operator for boost::unordered_map<>
inline
bool
operator
==
(
PNS_JOINT
::
HashTag
const
&
p1
,
PNS_JOINT
::
HashTag
const
&
p2
)
inline
bool
operator
==
(
PNS_JOINT
::
HashTag
const
&
p1
,
PNS_JOINT
::
HashTag
const
&
p2
)
{
{
return
p1
.
pos
==
p2
.
pos
&&
p1
.
net
==
p2
.
net
;
return
p1
.
pos
==
p2
.
pos
&&
p1
.
net
==
p2
.
net
;
}
}
inline
std
::
size_t
hash_value
(
PNS_JOINT
::
HashTag
const
&
p
)
inline
std
::
size_t
hash_value
(
PNS_JOINT
::
HashTag
const
&
p
)
{
{
std
::
size_t
seed
=
0
;
std
::
size_t
seed
=
0
;
boost
::
hash_combine
(
seed
,
p
.
pos
.
x
);
boost
::
hash_combine
(
seed
,
p
.
pos
.
x
);
boost
::
hash_combine
(
seed
,
p
.
pos
.
y
);
boost
::
hash_combine
(
seed
,
p
.
pos
.
y
);
boost
::
hash_combine
(
seed
,
p
.
net
);
boost
::
hash_combine
(
seed
,
p
.
net
);
return
seed
;
return
seed
;
}
}
#endif // __PNS_JOINT_H
#endif // __PNS_JOINT_H
pcbnew/router/pns_layerset.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -26,93 +26,95 @@
...
@@ -26,93 +26,95 @@
/**
/**
* Class PNS_LAYERSET
* Class PNS_LAYERSET
*
*
* Represents a contiguous set of PCB layers.
* Represents a contiguous set of PCB layers.
*/
*/
class
PNS_LAYERSET
class
PNS_LAYERSET
{
{
public
:
public
:
PNS_LAYERSET
()
:
PNS_LAYERSET
()
:
m_start
(
-
1
),
m_start
(
-
1
),
m_end
(
-
1
)
m_end
(
-
1
)
{};
{};
PNS_LAYERSET
(
int
aStart
,
int
aEnd
)
PNS_LAYERSET
(
int
aStart
,
int
aEnd
)
{
{
if
(
aStart
>
aEnd
)
if
(
aStart
>
aEnd
)
std
::
swap
(
aStart
,
aEnd
);
std
::
swap
(
aStart
,
aEnd
);
m_start
=
aStart
;
m_start
=
aStart
;
m_end
=
aEnd
;
m_end
=
aEnd
;
}
}
PNS_LAYERSET
(
int
aLayer
)
PNS_LAYERSET
(
int
aLayer
)
{
{
m_start
=
m_end
=
aLayer
;
m_start
=
m_end
=
aLayer
;
}
}
PNS_LAYERSET
(
const
PNS_LAYERSET
&
b
)
:
PNS_LAYERSET
(
const
PNS_LAYERSET
&
b
)
:
m_start
(
b
.
m_start
),
m_start
(
b
.
m_start
),
m_end
(
b
.
m_end
)
m_end
(
b
.
m_end
)
{}
{}
~
PNS_LAYERSET
()
{};
~
PNS_LAYERSET
()
{};
const
PNS_LAYERSET
&
operator
=
(
const
PNS_LAYERSET
&
b
)
const
PNS_LAYERSET
&
operator
=
(
const
PNS_LAYERSET
&
b
)
{
{
m_start
=
b
.
m_start
;
m_start
=
b
.
m_start
;
m_end
=
b
.
m_end
;
m_end
=
b
.
m_end
;
return
*
this
;
return
*
this
;
}
}
bool
Overlaps
(
const
PNS_LAYERSET
&
aOther
)
const
bool
Overlaps
(
const
PNS_LAYERSET
&
aOther
)
const
{
{
return
m_end
>=
aOther
.
m_start
&&
m_start
<=
aOther
.
m_end
;
return
m_end
>=
aOther
.
m_start
&&
m_start
<=
aOther
.
m_end
;
}
}
bool
Overlaps
(
const
int
aLayer
)
const
bool
Overlaps
(
const
int
aLayer
)
const
{
{
return
aLayer
>=
m_start
&&
aLayer
<=
m_end
;
return
aLayer
>=
m_start
&&
aLayer
<=
m_end
;
}
}
bool
IsMultilayer
(
)
const
bool
IsMultilayer
()
const
{
{
return
m_start
!=
m_end
;
return
m_start
!=
m_end
;
}
}
int
Start
()
const
{
int
Start
()
const
return
m_start
;
{
}
return
m_start
;
}
int
End
()
const
{
return
m_end
;
int
End
()
const
}
{
return
m_end
;
void
Merge
(
const
PNS_LAYERSET
&
aOther
)
}
{
if
(
m_start
<
0
||
m_end
<
0
)
void
Merge
(
const
PNS_LAYERSET
&
aOther
)
{
{
m_start
=
aOther
.
m_start
;
if
(
m_start
<
0
||
m_end
<
0
)
m_end
=
aOther
.
m_end
;
{
return
;
m_start
=
aOther
.
m_start
;
}
m_end
=
aOther
.
m_end
;
return
;
if
(
aOther
.
m_start
<
m_start
)
}
m_start
=
aOther
.
m_start
;
if
(
aOther
.
m_end
>
m_end
)
if
(
aOther
.
m_start
<
m_start
)
m_end
=
aOther
.
m_end
;
m_start
=
aOther
.
m_start
;
}
if
(
aOther
.
m_end
>
m_end
)
///> Shortcut for comparisons/overlap tests
m_end
=
aOther
.
m_end
;
static
PNS_LAYERSET
All
()
}
{
return
PNS_LAYERSET
(
0
,
256
);
///> Shortcut for comparisons/overlap tests
}
static
PNS_LAYERSET
All
()
{
private
:
return
PNS_LAYERSET
(
0
,
256
);
}
int
m_start
;
int
m_end
;
private
:
int
m_start
;
int
m_end
;
};
};
#endif // __PNS_LAYERSET_H
#endif // __PNS_LAYERSET_H
pcbnew/router/pns_line.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -23,7 +23,6 @@
...
@@ -23,7 +23,6 @@
#include <math/vector2d.h>
#include <math/vector2d.h>
#include "pns_line.h"
#include "pns_line.h"
#include "pns_node.h"
#include "pns_node.h"
#include "pns_via.h"
#include "pns_via.h"
...
@@ -33,672 +32,732 @@
...
@@ -33,672 +32,732 @@
using
namespace
std
;
using
namespace
std
;
using
boost
::
optional
;
using
boost
::
optional
;
PNS_LINE
*
PNS_LINE
::
Clone
()
const
PNS_LINE
*
PNS_LINE
::
Clone
()
const
{
{
PNS_LINE
*
l
=
new
PNS_LINE
();
PNS_LINE
*
l
=
new
PNS_LINE
();
l
->
m_line
=
m_line
;
l
->
m_line
=
m_line
;
l
->
m_width
=
m_width
;
l
->
m_width
=
m_width
;
l
->
m_layers
=
m_layers
;
l
->
m_layers
=
m_layers
;
l
->
m_net
=
m_net
;
l
->
m_net
=
m_net
;
l
->
m_movable
=
m_movable
;
l
->
m_movable
=
m_movable
;
l
->
m_segmentRefs
=
NULL
;
l
->
m_segmentRefs
=
NULL
;
l
->
m_hasVia
=
m_hasVia
;
l
->
m_hasVia
=
m_hasVia
;
l
->
m_via
=
m_via
;
l
->
m_via
=
m_via
;
return
l
;
return
l
;
}
}
PNS_LINE
*
PNS_LINE
::
CloneProperties
()
const
PNS_LINE
*
PNS_LINE
::
CloneProperties
()
const
{
{
PNS_LINE
*
l
=
new
PNS_LINE
();
PNS_LINE
*
l
=
new
PNS_LINE
();
l
->
m_width
=
m_width
;
l
->
m_layers
=
m_layers
;
l
->
m_net
=
m_net
;
l
->
m_movable
=
m_movable
;
return
l
;
}
l
->
m_width
=
m_width
;
l
->
m_layers
=
m_layers
;
l
->
m_net
=
m_net
;
l
->
m_movable
=
m_movable
;
return
l
;
PNS_SEGMENT
*
PNS_SEGMENT
::
Clone
()
const
}
PNS_SEGMENT
*
PNS_SEGMENT
::
Clone
()
const
{
{
PNS_SEGMENT
*
s
=
new
PNS_SEGMENT
;
PNS_SEGMENT
*
s
=
new
PNS_SEGMENT
;
s
->
m_width
=
m_width
;
s
->
m_net
=
m_net
;
s
->
m_width
=
m_width
;
s
->
m_shape
=
m_shape
;
s
->
m_net
=
m_net
;
s
->
m_layers
=
m_layers
;
s
->
m_shape
=
m_shape
;
s
->
m_layers
=
m_layers
;
return
s
;
//
assert(false);
return
s
;
//
assert(false);
}
}
#if 1
#if 1
bool
PNS_LINE
::
MergeObtuseSegments
(
)
bool
PNS_LINE
::
MergeObtuseSegments
(
)
{
{
int
step
=
m_line
.
PointCount
()
-
3
;
int
step
=
m_line
.
PointCount
()
-
3
;
int
iter
=
0
;
int
iter
=
0
;
int
segs_pre
=
m_line
.
SegmentCount
();
int
segs_pre
=
m_line
.
SegmentCount
();
if
(
step
<
0
)
if
(
step
<
0
)
return
false
;
return
false
;
SHAPE_LINE_CHAIN
current_path
(
m_line
);
SHAPE_LINE_CHAIN
current_path
(
m_line
);
while
(
1
)
while
(
1
)
{
{
iter
++
;
iter
++
;
int
n_segs
=
current_path
.
SegmentCount
();
int
n_segs
=
current_path
.
SegmentCount
();
int
max_step
=
n_segs
-
2
;
int
max_step
=
n_segs
-
2
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
<
2
)
{
if
(
step
<
2
)
m_line
=
current_path
;
{
return
current_path
.
SegmentCount
()
<
segs_pre
;
m_line
=
current_path
;
}
return
current_path
.
SegmentCount
()
<
segs_pre
;
}
bool
found_anything
=
false
;
int
n
=
0
;
bool
found_anything
=
false
;
int
n
=
0
;
while
(
n
<
n_segs
-
step
)
{
while
(
n
<
n_segs
-
step
)
const
SEG
s1
=
current_path
.
CSegment
(
n
);
{
const
SEG
s2
=
current_path
.
CSegment
(
n
+
step
);
const
SEG
s1
=
current_path
.
CSegment
(
n
);
SEG
s1opt
,
s2opt
;
const
SEG
s2
=
current_path
.
CSegment
(
n
+
step
);
SEG
s1opt
,
s2opt
;
if
(
DIRECTION_45
(
s1
).
IsObtuse
(
DIRECTION_45
(
s2
)))
{
if
(
DIRECTION_45
(
s1
).
IsObtuse
(
DIRECTION_45
(
s2
)
)
)
VECTOR2I
ip
=
*
s1
.
IntersectLines
(
s2
);
{
VECTOR2I
ip
=
*
s1
.
IntersectLines
(
s2
);
if
(
s1
.
Distance
(
ip
)
<=
1
||
s2
.
Distance
(
ip
)
<=
1
)
{
if
(
s1
.
Distance
(
ip
)
<=
1
||
s2
.
Distance
(
ip
)
<=
1
)
s1opt
=
SEG
(
s1
.
a
,
ip
);
{
s2opt
=
SEG
(
ip
,
s2
.
b
);
s1opt
=
SEG
(
s1
.
a
,
ip
);
}
else
{
s2opt
=
SEG
(
ip
,
s2
.
b
);
s1opt
=
SEG
(
s1
.
a
,
ip
);
}
s2opt
=
SEG
(
ip
,
s2
.
b
);
else
}
{
s1opt
=
SEG
(
s1
.
a
,
ip
);
s2opt
=
SEG
(
ip
,
s2
.
b
);
if
(
DIRECTION_45
(
s1opt
).
IsObtuse
(
DIRECTION_45
(
s2opt
)))
}
{
SHAPE_LINE_CHAIN
opt_path
;
opt_path
.
Append
(
s1opt
.
a
);
if
(
DIRECTION_45
(
s1opt
).
IsObtuse
(
DIRECTION_45
(
s2opt
)
)
)
opt_path
.
Append
(
s1opt
.
b
);
{
opt_path
.
Append
(
s2opt
.
b
);
SHAPE_LINE_CHAIN
opt_path
;
opt_path
.
Append
(
s1opt
.
a
);
PNS_LINE
opt_track
(
*
this
,
opt_path
);
opt_path
.
Append
(
s1opt
.
b
);
opt_path
.
Append
(
s2opt
.
b
);
if
(
!
m_world
->
CheckColliding
(
&
opt_track
,
PNS_ITEM
::
ANY
))
{
PNS_LINE
opt_track
(
*
this
,
opt_path
);
current_path
.
Replace
(
s1
.
Index
()
+
1
,
s2
.
Index
(),
ip
);
n_segs
=
current_path
.
SegmentCount
();
if
(
!
m_world
->
CheckColliding
(
&
opt_track
,
PNS_ITEM
::
ANY
)
)
found_anything
=
true
;
{
break
;
current_path
.
Replace
(
s1
.
Index
()
+
1
,
s2
.
Index
(),
ip
);
}
n_segs
=
current_path
.
SegmentCount
();
}
found_anything
=
true
;
}
break
;
n
++
;
}
}
}
}
if
(
!
found_anything
)
{
n
++
;
if
(
step
<=
2
)
}
{
m_line
=
current_path
;
if
(
!
found_anything
)
return
m_line
.
SegmentCount
()
<
segs_pre
;
{
}
if
(
step
<=
2
)
step
--
;
{
}
m_line
=
current_path
;
}
return
m_line
.
SegmentCount
()
<
segs_pre
;
return
m_line
.
SegmentCount
()
<
segs_pre
;
}
step
--
;
}
}
return
m_line
.
SegmentCount
()
<
segs_pre
;
}
}
bool
PNS_LINE
::
MergeSegments
(
)
bool
PNS_LINE
::
MergeSegments
()
{
{
int
step
=
m_line
.
PointCount
()
-
3
;
int
step
=
m_line
.
PointCount
()
-
3
;
int
iter
=
0
;
int
iter
=
0
;
int
segs_pre
=
m_line
.
SegmentCount
();
int
segs_pre
=
m_line
.
SegmentCount
();
if
(
step
<
0
)
if
(
step
<
0
)
return
false
;
return
false
;
SHAPE_LINE_CHAIN
current_path
(
m_line
);
SHAPE_LINE_CHAIN
current_path
(
m_line
);
while
(
1
)
while
(
1
)
{
{
iter
++
;
iter
++
;
int
n_segs
=
current_path
.
SegmentCount
();
int
n_segs
=
current_path
.
SegmentCount
();
int
max_step
=
n_segs
-
2
;
int
max_step
=
n_segs
-
2
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
<
2
)
{
if
(
step
<
2
)
m_line
=
current_path
;
{
return
current_path
.
SegmentCount
()
<
segs_pre
;
m_line
=
current_path
;
}
return
current_path
.
SegmentCount
()
<
segs_pre
;
}
bool
found_anything
=
false
;
int
n
=
0
;
bool
found_anything
=
false
;
int
n
=
0
;
while
(
n
<
n_segs
-
step
)
{
while
(
n
<
n_segs
-
step
)
const
SEG
s1
=
current_path
.
CSegment
(
n
);
{
const
SEG
s2
=
current_path
.
CSegment
(
n
+
step
);
const
SEG
s1
=
current_path
.
CSegment
(
n
);
SEG
s1opt
,
s2opt
;
const
SEG
s2
=
current_path
.
CSegment
(
n
+
step
);
SEG
s1opt
,
s2opt
;
if
(
n
>
0
)
{
if
(
n
>
0
)
SHAPE_LINE_CHAIN
path_straight
=
DIRECTION_45
().
BuildInitialTrace
(
s1
.
a
,
s2
.
a
,
false
);
{
SHAPE_LINE_CHAIN
path_diagonal
=
DIRECTION_45
().
BuildInitialTrace
(
s1
.
a
,
s2
.
a
,
true
);
SHAPE_LINE_CHAIN
path_straight
=
DIRECTION_45
().
BuildInitialTrace
(
s1
.
a
,
s2
.
a
,
false
);
SHAPE_LINE_CHAIN
path_diagonal
=
DIRECTION_45
().
BuildInitialTrace
(
s1
.
a
,
}
s2
.
a
,
true
);
if
(
DIRECTION_45
(
s1
)
==
DIRECTION_45
(
s2
))
}
{
if
(
s1
.
Collinear
(
s2
))
if
(
DIRECTION_45
(
s1
)
==
DIRECTION_45
(
s2
)
)
{
{
//printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step);
if
(
s1
.
Collinear
(
s2
)
)
{
SHAPE_LINE_CHAIN
opt_path
;
// printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step);
opt_path
.
Append
(
s1
.
a
);
opt_path
.
Append
(
s2
.
b
);
SHAPE_LINE_CHAIN
opt_path
;
opt_path
.
Append
(
s1
.
a
);
PNS_LINE
tmp
(
*
this
,
opt_path
);
opt_path
.
Append
(
s2
.
b
);
if
(
!
m_world
->
CheckColliding
(
&
tmp
,
PNS_ITEM
::
ANY
))
PNS_LINE
tmp
(
*
this
,
opt_path
);
{
current_path
.
Remove
(
s1
.
Index
()
+
1
,
s2
.
Index
());
if
(
!
m_world
->
CheckColliding
(
&
tmp
,
PNS_ITEM
::
ANY
)
)
n_segs
=
current_path
.
SegmentCount
();
{
found_anything
=
true
;
current_path
.
Remove
(
s1
.
Index
()
+
1
,
s2
.
Index
()
);
break
;
n_segs
=
current_path
.
SegmentCount
();
}
found_anything
=
true
;
break
;
}
}
}
}
}
else
if
(
DIRECTION_45
(
s1
).
IsObtuse
(
DIRECTION_45
(
s2
)
)
)
else
if
(
DIRECTION_45
(
s1
).
IsObtuse
(
DIRECTION_45
(
s2
)))
{
{
VECTOR2I
ip
=
*
s1
.
IntersectLines
(
s2
);
VECTOR2I
ip
=
*
s1
.
IntersectLines
(
s2
);
if
(
s1
.
Distance
(
ip
)
<=
1
||
s2
.
Distance
(
ip
)
<=
1
)
if
(
s1
.
Distance
(
ip
)
<=
1
||
s2
.
Distance
(
ip
)
<=
1
)
{
{
s1opt
=
SEG
(
s1
.
a
,
ip
);
s1opt
=
SEG
(
s1
.
a
,
ip
);
s2opt
=
SEG
(
ip
,
s2
.
b
);
s2opt
=
SEG
(
ip
,
s2
.
b
);
}
}
else
{
else
s1opt
=
SEG
(
s1
.
a
,
ip
);
{
s2opt
=
SEG
(
ip
,
s2
.
b
);
s1opt
=
SEG
(
s1
.
a
,
ip
);
}
s2opt
=
SEG
(
ip
,
s2
.
b
);
}
if
(
DIRECTION_45
(
s1opt
).
IsObtuse
(
DIRECTION_45
(
s2opt
)))
{
if
(
DIRECTION_45
(
s1opt
).
IsObtuse
(
DIRECTION_45
(
s2opt
)
)
)
SHAPE_LINE_CHAIN
opt_path
;
{
opt_path
.
Append
(
s1opt
.
a
);
SHAPE_LINE_CHAIN
opt_path
;
opt_path
.
Append
(
s1opt
.
b
);
opt_path
.
Append
(
s1opt
.
a
);
opt_path
.
Append
(
s2opt
.
b
);
opt_path
.
Append
(
s1opt
.
b
);
opt_path
.
Append
(
s2opt
.
b
);
PNS_LINE
opt_track
(
*
this
,
opt_path
);
PNS_LINE
opt_track
(
*
this
,
opt_path
);
if
(
!
m_world
->
CheckColliding
(
&
opt_track
,
PNS_ITEM
::
ANY
))
{
if
(
!
m_world
->
CheckColliding
(
&
opt_track
,
PNS_ITEM
::
ANY
)
)
current_path
.
Replace
(
s1
.
Index
()
+
1
,
s2
.
Index
(),
ip
);
{
n_segs
=
current_path
.
SegmentCount
();
current_path
.
Replace
(
s1
.
Index
()
+
1
,
s2
.
Index
(),
ip
);
found_anything
=
true
;
n_segs
=
current_path
.
SegmentCount
();
break
;
found_anything
=
true
;
}
break
;
}
}
}
}
}
n
++
;
}
n
++
;
}
if
(
!
found_anything
)
{
if
(
!
found_anything
)
if
(
step
<=
2
)
{
{
if
(
step
<=
2
)
m_line
=
current_path
;
{
return
m_line
.
SegmentCount
()
<
segs_pre
;
m_line
=
current_path
;
}
return
m_line
.
SegmentCount
()
<
segs_pre
;
step
--
;
}
}
}
step
--
;
return
m_line
.
SegmentCount
()
<
segs_pre
;
}
}
return
m_line
.
SegmentCount
()
<
segs_pre
;
}
}
#endif
#endif
int
PNS_LINE
::
CountCorners
(
int
aAngles
)
int
PNS_LINE
::
CountCorners
(
int
aAngles
)
{
{
int
count
=
0
;
int
count
=
0
;
for
(
int
i
=
0
;
i
<
m_line
.
SegmentCount
()
-
1
;
i
++
)
{
for
(
int
i
=
0
;
i
<
m_line
.
SegmentCount
()
-
1
;
i
++
)
const
SEG
seg1
=
m_line
.
CSegment
(
i
);
{
const
SEG
seg2
=
m_line
.
CSegment
(
i
+
1
);
const
SEG
seg1
=
m_line
.
CSegment
(
i
);
const
SEG
seg2
=
m_line
.
CSegment
(
i
+
1
);
const
DIRECTION_45
dir1
(
seg1
);
const
DIRECTION_45
dir2
(
seg2
);
const
DIRECTION_45
dir1
(
seg1
);
const
DIRECTION_45
dir2
(
seg2
);
DIRECTION_45
::
AngleType
a
=
dir1
.
Angle
(
dir2
);
if
(
a
&
aAngles
)
DIRECTION_45
::
AngleType
a
=
dir1
.
Angle
(
dir2
);
count
++
;
}
if
(
a
&
aAngles
)
return
count
;
count
++
;
}
return
count
;
}
}
//#define DUMP_TEST_CASES
// #define DUMP_TEST_CASES
// fixme: damn f*****g inefficient and incredibly crappily written
// fixme: damn f*****g inefficient and incredibly crappily written
void
PNS_LINE
::
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
void
PNS_LINE
::
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
SHAPE_LINE_CHAIN
&
aPrePath
,
SHAPE_LINE_CHAIN
&
aPrePath
,
SHAPE_LINE_CHAIN
&
aWalkaroundPath
,
SHAPE_LINE_CHAIN
&
aWalkaroundPath
,
SHAPE_LINE_CHAIN
&
aPostPath
,
SHAPE_LINE_CHAIN
&
aPostPath
,
bool
aCw
)
const
bool
aCw
)
const
{
{
typedef
SHAPE_LINE_CHAIN
::
Intersection
Intersection
;
typedef
SHAPE_LINE_CHAIN
::
Intersection
Intersection
;
SHAPE_LINE_CHAIN
l_orig
(
m_line
);
SHAPE_LINE_CHAIN
l_hull
;
vector
<
bool
>
outside
,
on_edge
,
inside
;
SHAPE_LINE_CHAIN
path
;
SHAPE_LINE_CHAIN
l_orig
(
m_line
);
vector
<
Intersection
>
isects
;
SHAPE_LINE_CHAIN
l_hull
;
vector
<
bool
>
outside
,
on_edge
,
inside
;
SHAPE_LINE_CHAIN
path
;
vector
<
Intersection
>
isects
;
// don't calculate walkaround for empty lines
// don't calculate walkaround for empty lines
if
(
m_line
.
PointCount
()
<
2
)
if
(
m_line
.
PointCount
()
<
2
)
return
;
return
;
#ifdef DUMP_TEST_CASES
#ifdef DUMP_TEST_CASES
printf
(
"%s
\n
"
,
m_line
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
m_line
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
aObstacle
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
aObstacle
.
Format
().
c_str
()
);
#endif
#endif
aObstacle
.
Intersect
(
m_line
,
isects
);
aObstacle
.
Intersect
(
m_line
,
isects
);
//printf("NewWalk intersectiosn :%d\n" ,isects.size());
if
(
!
aCw
)
// printf("NewWalk intersectiosn :%d\n" ,isects.size());
l_hull
=
aObstacle
.
Reverse
();
if
(
!
aCw
)
else
l_hull
=
aObstacle
.
Reverse
();
l_hull
=
aObstacle
;
else
l_hull
=
aObstacle
;
BOOST_FOREACH
(
Intersection
isect
,
isects
)
BOOST_FOREACH
(
Intersection
isect
,
isects
)
{
{
l_orig
.
Split
(
isect
.
p
);
l_orig
.
Split
(
isect
.
p
);
l_hull
.
Split
(
isect
.
p
);
l_hull
.
Split
(
isect
.
p
);
}
}
#ifdef DUMP_TEST_CASES
#ifdef DUMP_TEST_CASES
printf
(
"%s
\n
"
,
m_line
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
m_line
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
aObstacle
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
aObstacle
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
l_orig
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
l_orig
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
l_hull
.
Format
().
c_str
()
);
printf
(
"%s
\n
"
,
l_hull
.
Format
().
c_str
()
);
#endif
#endif
//printf("Pts: line %d hull %d\n", l_orig.PointCount(), l_hull.PointCount());
// printf("Pts: line %d hull %d\n", l_orig.PointCount(), l_hull.PointCount());
int
first_post
=
-
1
;
int
first_post
=
-
1
;
int
last_pre
=
-
1
;
int
last_pre
=
-
1
;
for
(
int
i
=
0
;
i
<
l_orig
.
PointCount
();
i
++
)
for
(
int
i
=
0
;
i
<
l_orig
.
PointCount
();
i
++
)
{
{
int
ei
=
l_hull
.
Find
(
l_orig
.
CPoint
(
i
))
;
int
ei
=
l_hull
.
Find
(
l_orig
.
CPoint
(
i
)
);
bool
edge
=
ei
>=
0
;
bool
edge
=
ei
>=
0
;
bool
in
=
l_hull
.
PointInside
(
l_orig
.
CPoint
(
i
))
&&
!
edge
;
bool
in
=
l_hull
.
PointInside
(
l_orig
.
CPoint
(
i
)
)
&&
!
edge
;
bool
out
=
!
(
in
||
edge
);
bool
out
=
!
(
in
||
edge
);
outside
.
push_back
(
out
);
outside
.
push_back
(
out
);
on_edge
.
push_back
(
edge
);
on_edge
.
push_back
(
edge
);
inside
.
push_back
(
in
);
inside
.
push_back
(
in
);
}
}
for
(
int
i
=
l_orig
.
PointCount
()
-
1
;
i
>=
1
;
i
--
)
for
(
int
i
=
l_orig
.
PointCount
()
-
1
;
i
>=
1
;
i
--
)
if
(
inside
[
i
]
&&
outside
[
i
-
1
]
)
if
(
inside
[
i
]
&&
outside
[
i
-
1
])
{
{
SHAPE_LINE_CHAIN
::
Intersections
ips
;
SHAPE_LINE_CHAIN
::
Intersections
ips
;
l_hull
.
Intersect
(
SEG
(
l_orig
.
CPoint
(
i
),
l_orig
.
CPoint
(
i
-
1
)
),
ips
);
l_hull
.
Intersect
(
SEG
(
l_orig
.
CPoint
(
i
),
l_orig
.
CPoint
(
i
-
1
)
),
ips
);
l_orig
.
Remove
(
i
,
-
1
);
l_orig
.
Remove
(
i
,
-
1
);
l_orig
.
Append
(
ips
[
0
].
p
);
l_orig
.
Append
(
ips
[
0
].
p
);
break
;
break
;
}
}
else
if
(
inside
[
i
]
&&
on_edge
[
i
-
1
]
)
else
if
(
inside
[
i
]
&&
on_edge
[
i
-
1
])
{
{
l_orig
.
Remove
(
i
,
-
1
);
l_orig
.
Remove
(
i
,
-
1
);
// n = i;
//n = i;
}
}
else
if
(
!
inside
[
i
])
else
if
(
!
inside
[
i
]
)
break
;
break
;
if
(
!
outside
.
size
()
&&
on_edge
.
size
()
<
2
)
if
(
!
outside
.
size
()
&&
on_edge
.
size
()
<
2
)
return
;
return
;
for
(
int
i
=
0
;
i
<
l_orig
.
PointCount
();
i
++
)
for
(
int
i
=
0
;
i
<
l_orig
.
PointCount
();
i
++
)
{
{
const
VECTOR2I
p
=
l_orig
.
Point
(
i
);
const
VECTOR2I
p
=
l_orig
.
Point
(
i
);
if
(
outside
[
i
]
||
(
on_edge
[
i
]
&&
i
==
(
l_orig
.
PointCount
()
-
1
)))
if
(
outside
[
i
]
||
(
on_edge
[
i
]
&&
i
==
(
l_orig
.
PointCount
()
-
1
)
)
)
{
{
if
(
last_pre
<
0
)
if
(
last_pre
<
0
)
aPrePath
.
Append
(
p
);
aPrePath
.
Append
(
p
);
path
.
Append
(
p
);
}
path
.
Append
(
p
);
else
if
(
on_edge
[
i
]
)
}
{
else
if
(
on_edge
[
i
]
)
int
li
=
-
1
;
{
if
(
last_pre
<
0
)
int
li
=
-
1
;
{
aPrePath
.
Append
(
p
);
if
(
last_pre
<
0
)
last_pre
=
path
.
PointCount
();
{
}
aPrePath
.
Append
(
p
);
if
(
i
==
l_orig
.
PointCount
()
-
1
||
outside
[
i
+
1
])
last_pre
=
path
.
PointCount
();
{
}
path
.
Append
(
p
);
}
if
(
i
==
l_orig
.
PointCount
()
-
1
||
outside
[
i
+
1
]
)
else
{
{
path
.
Append
(
p
);
int
vi2
=
l_hull
.
Find
(
l_orig
.
CPoint
(
i
)
);
}
else
path
.
Append
(
l_hull
.
CPoint
(
vi2
));
{
for
(
int
j
=
(
vi2
+
1
)
%
l_hull
.
PointCount
();
j
!=
vi2
;
j
=
(
j
+
1
)
%
l_hull
.
PointCount
())
int
vi2
=
l_hull
.
Find
(
l_orig
.
CPoint
(
i
)
);
{
path
.
Append
(
l_hull
.
CPoint
(
j
));
path
.
Append
(
l_hull
.
CPoint
(
vi2
)
);
li
=
l_orig
.
Find
(
l_hull
.
CPoint
(
j
));
if
(
li
>=
0
&&
(
li
==
(
l_orig
.
PointCount
()
-
1
)
||
outside
[
li
+
1
]))
for
(
int
j
=
(
vi2
+
1
)
%
l_hull
.
PointCount
();
break
;
j
!=
vi2
;
}
j
=
(
j
+
1
)
%
l_hull
.
PointCount
()
)
{
if
(
li
>=
0
)
{
path
.
Append
(
l_hull
.
CPoint
(
j
)
);
if
(
i
>=
li
)
li
=
l_orig
.
Find
(
l_hull
.
CPoint
(
j
)
);
break
;
else
{
if
(
li
>=
0
&&
(
li
==
(
l_orig
.
PointCount
()
-
1
)
||
i
=
li
;
outside
[
li
+
1
])
)
}
break
;
}
}
}
if
(
li
>=
0
)
first_post
=
path
.
PointCount
()
-
1
;
{
}
if
(
i
>=
li
)
}
break
;
else
if
(
last_pre
<
0
&&
first_post
<
0
)
i
=
li
;
return
;
}
}
aWalkaroundPath
=
path
.
Slice
(
last_pre
,
first_post
);
if
(
first_post
>=
0
)
first_post
=
path
.
PointCount
()
-
1
;
aPostPath
=
path
.
Slice
(
first_post
,
-
1
);
}
}
if
(
last_pre
<
0
&&
first_post
<
0
)
return
;
aWalkaroundPath
=
path
.
Slice
(
last_pre
,
first_post
);
if
(
first_post
>=
0
)
aPostPath
=
path
.
Slice
(
first_post
,
-
1
);
}
}
bool
PNS_LINE
::
onEdge
(
const
SHAPE_LINE_CHAIN
&
obstacle
,
VECTOR2I
p
,
int
&
ei
,
bool
&
is_vertex
)
const
bool
PNS_LINE
::
onEdge
(
const
SHAPE_LINE_CHAIN
&
obstacle
,
VECTOR2I
p
,
int
&
ei
,
bool
&
is_vertex
)
const
{
{
int
vtx
=
obstacle
.
Find
(
p
);
int
vtx
=
obstacle
.
Find
(
p
);
if
(
vtx
>=
0
)
if
(
vtx
>=
0
)
{
{
ei
=
vtx
;
ei
=
vtx
;
is_vertex
=
true
;
is_vertex
=
true
;
return
true
;
return
true
;
}
}
for
(
int
s
=
0
;
s
<
obstacle
.
SegmentCount
();
s
++
)
for
(
int
s
=
0
;
s
<
obstacle
.
SegmentCount
();
s
++
)
{
{
if
(
obstacle
.
CSegment
(
s
).
Contains
(
p
)
)
if
(
obstacle
.
CSegment
(
s
).
Contains
(
p
)
)
{
{
ei
=
s
;
ei
=
s
;
is_vertex
=
false
;
is_vertex
=
false
;
return
true
;
return
true
;
}
}
}
}
return
false
;
return
false
;
}
}
bool
PNS_LINE
::
walkScan
(
const
SHAPE_LINE_CHAIN
&
line
,
const
SHAPE_LINE_CHAIN
&
obstacle
,
bool
reverse
,
VECTOR2I
&
ip
,
int
&
index_o
,
int
&
index_l
,
bool
&
is_vertex
)
const
bool
PNS_LINE
::
walkScan
(
const
SHAPE_LINE_CHAIN
&
line
,
const
SHAPE_LINE_CHAIN
&
obstacle
,
bool
reverse
,
VECTOR2I
&
ip
,
int
&
index_o
,
int
&
index_l
,
bool
&
is_vertex
)
const
{
{
int
sc
=
line
.
SegmentCount
();
int
sc
=
line
.
SegmentCount
();
for
(
int
i
=
0
;
i
<
line
.
SegmentCount
();
i
++
)
{
for
(
int
i
=
0
;
i
<
line
.
SegmentCount
();
i
++
)
{
printf
(
"check-seg rev %d %d/%d %d
\n
"
,
reverse
,
i
,
sc
,
sc
-
1
-
i
);
printf
(
"check-seg rev %d %d/%d %d
\n
"
,
reverse
,
i
,
sc
,
sc
-
1
-
i
);
SEG
tmp
=
line
.
CSegment
(
reverse
?
sc
-
1
-
i
:
i
);
SEG
tmp
=
line
.
CSegment
(
reverse
?
sc
-
1
-
i
:
i
);
SEG
s
(
tmp
.
a
,
tmp
.
b
);
SEG
s
(
tmp
.
a
,
tmp
.
b
);
if
(
reverse
)
{
if
(
reverse
)
s
.
a
=
tmp
.
b
;
{
s
.
b
=
tmp
.
a
;
s
.
a
=
tmp
.
b
;
}
s
.
b
=
tmp
.
a
;
}
if
(
onEdge
(
obstacle
,
s
.
a
,
index_o
,
is_vertex
))
{
if
(
onEdge
(
obstacle
,
s
.
a
,
index_o
,
is_vertex
)
)
index_l
=
(
reverse
?
sc
-
1
-
i
:
i
);
{
ip
=
s
.
a
;
index_l
=
(
reverse
?
sc
-
1
-
i
:
i
);
printf
(
"vertex %d on-%s %d
\n
"
,
index_l
,
is_vertex
?
"vertex"
:
"edge"
,
index_o
);
ip
=
s
.
a
;
return
true
;
printf
(
"vertex %d on-%s %d
\n
"
,
index_l
,
}
is_vertex
?
"vertex"
:
"edge"
,
index_o
);
return
true
;
if
(
onEdge
(
obstacle
,
s
.
b
,
index_o
,
is_vertex
))
}
{
index_l
=
(
reverse
?
sc
-
1
-
i
-
1
:
i
+
1
);
if
(
onEdge
(
obstacle
,
s
.
b
,
index_o
,
is_vertex
)
)
ip
=
s
.
b
;
{
printf
(
"vertex %d on-%s %d
\n
"
,
index_l
,
is_vertex
?
"vertex"
:
"edge"
,
index_o
);
index_l
=
(
reverse
?
sc
-
1
-
i
-
1
:
i
+
1
);
return
true
;
ip
=
s
.
b
;
}
printf
(
"vertex %d on-%s %d
\n
"
,
index_l
,
is_vertex
?
"vertex"
:
"edge"
,
index_o
);
SHAPE_LINE_CHAIN
::
Intersections
ips
;
return
true
;
int
n_is
=
obstacle
.
Intersect
(
s
,
ips
);
}
if
(
n_is
>
0
)
SHAPE_LINE_CHAIN
::
Intersections
ips
;
{
int
n_is
=
obstacle
.
Intersect
(
s
,
ips
);
index_o
=
ips
[
0
].
our
.
Index
();
index_l
=
reverse
?
sc
-
1
-
i
:
i
;
if
(
n_is
>
0
)
printf
(
"segment-%d intersects edge-%d
\n
"
,
index_l
,
index_o
);
{
ip
=
ips
[
0
].
p
;
index_o
=
ips
[
0
].
our
.
Index
();
return
true
;
index_l
=
reverse
?
sc
-
1
-
i
:
i
;
}
printf
(
"segment-%d intersects edge-%d
\n
"
,
index_l
,
index_o
);
}
ip
=
ips
[
0
].
p
;
return
false
;
return
true
;
}
}
return
false
;
}
}
bool
PNS_LINE
::
Walkaround
(
SHAPE_LINE_CHAIN
obstacle
,
SHAPE_LINE_CHAIN
&
pre
,
SHAPE_LINE_CHAIN
&
walk
,
SHAPE_LINE_CHAIN
&
post
,
bool
cw
)
const
{
const
SHAPE_LINE_CHAIN
&
line
=
GetCLine
();
VECTOR2I
ip_start
;
int
index_o_start
,
index_l_start
;
VECTOR2I
ip_end
;
int
index_o_end
,
index_l_end
;
bool
is_vertex_start
,
is_vertex_end
;
if
(
line
.
SegmentCount
()
<
1
)
return
false
;
if
(
obstacle
.
PointInside
(
line
.
CPoint
(
0
))
||
obstacle
.
PointInside
(
line
.
CPoint
(
-
1
)))
return
false
;
// printf("forward:\n");
bool
found
=
walkScan
(
line
,
obstacle
,
false
,
ip_start
,
index_o_start
,
index_l_start
,
is_vertex_start
);
//printf("reverse:\n");
found
|=
walkScan
(
line
,
obstacle
,
true
,
ip_end
,
index_o_end
,
index_l_end
,
is_vertex_end
);
if
(
!
found
||
ip_start
==
ip_end
)
{
pre
=
line
;
return
true
;
}
pre
=
line
.
Slice
(
0
,
index_l_start
);
pre
.
Append
(
ip_start
);
walk
.
Clear
();
walk
.
Append
(
ip_start
);
if
(
cw
)
{
int
is
=
(
index_o_start
+
1
)
%
obstacle
.
PointCount
();
int
ie
=
(
is_vertex_end
?
index_o_end
:
index_o_end
+
1
)
%
obstacle
.
PointCount
();
while
(
1
)
{
printf
(
"is %d
\n
"
,
is
);
walk
.
Append
(
obstacle
.
CPoint
(
is
));
if
(
is
==
ie
)
break
;
is
++
;
if
(
is
==
obstacle
.
PointCount
()
)
is
=
0
;
}
}
else
{
int
is
=
index_o_start
;
int
ie
=
(
is_vertex_end
?
index_o_end
:
index_o_end
)
%
obstacle
.
PointCount
();
while
(
1
)
{
printf
(
"is %d
\n
"
,
is
);
walk
.
Append
(
obstacle
.
CPoint
(
is
));
if
(
is
==
ie
)
break
;
is
--
;
if
(
is
<
0
)
is
=
obstacle
.
PointCount
()
-
1
;
}
}
walk
.
Append
(
ip_end
);
post
.
Clear
();
post
.
Append
(
ip_end
);
post
.
Append
(
line
.
Slice
(
is_vertex_end
?
index_l_end
:
index_l_end
+
1
,
-
1
));
//for(int i = (index_o_start + 1) % obstacle.PointCount();
// i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount())
//{
//printf("append %d\n", i);
//walk.Append(obstacle.CPoint(i));
//}
return
true
;
bool
PNS_LINE
::
Walkaround
(
SHAPE_LINE_CHAIN
obstacle
,
SHAPE_LINE_CHAIN
&
pre
,
SHAPE_LINE_CHAIN
&
walk
,
SHAPE_LINE_CHAIN
&
post
,
bool
cw
)
const
{
const
SHAPE_LINE_CHAIN
&
line
=
GetCLine
();
VECTOR2I
ip_start
;
int
index_o_start
,
index_l_start
;
VECTOR2I
ip_end
;
int
index_o_end
,
index_l_end
;
bool
is_vertex_start
,
is_vertex_end
;
if
(
line
.
SegmentCount
()
<
1
)
return
false
;
if
(
obstacle
.
PointInside
(
line
.
CPoint
(
0
)
)
||
obstacle
.
PointInside
(
line
.
CPoint
(
-
1
)
)
)
return
false
;
// printf("forward:\n");
bool
found
=
walkScan
(
line
,
obstacle
,
false
,
ip_start
,
index_o_start
,
index_l_start
,
is_vertex_start
);
// printf("reverse:\n");
found
|=
walkScan
(
line
,
obstacle
,
true
,
ip_end
,
index_o_end
,
index_l_end
,
is_vertex_end
);
if
(
!
found
||
ip_start
==
ip_end
)
{
pre
=
line
;
return
true
;
}
pre
=
line
.
Slice
(
0
,
index_l_start
);
pre
.
Append
(
ip_start
);
walk
.
Clear
();
walk
.
Append
(
ip_start
);
if
(
cw
)
{
int
is
=
(
index_o_start
+
1
)
%
obstacle
.
PointCount
();
int
ie
=
(
is_vertex_end
?
index_o_end
:
index_o_end
+
1
)
%
obstacle
.
PointCount
();
while
(
1
)
{
printf
(
"is %d
\n
"
,
is
);
walk
.
Append
(
obstacle
.
CPoint
(
is
)
);
if
(
is
==
ie
)
break
;
is
++
;
if
(
is
==
obstacle
.
PointCount
()
)
is
=
0
;
}
}
else
{
int
is
=
index_o_start
;
int
ie
=
(
is_vertex_end
?
index_o_end
:
index_o_end
)
%
obstacle
.
PointCount
();
while
(
1
)
{
printf
(
"is %d
\n
"
,
is
);
walk
.
Append
(
obstacle
.
CPoint
(
is
)
);
if
(
is
==
ie
)
break
;
is
--
;
if
(
is
<
0
)
is
=
obstacle
.
PointCount
()
-
1
;
}
}
walk
.
Append
(
ip_end
);
post
.
Clear
();
post
.
Append
(
ip_end
);
post
.
Append
(
line
.
Slice
(
is_vertex_end
?
index_l_end
:
index_l_end
+
1
,
-
1
)
);
// for(int i = (index_o_start + 1) % obstacle.PointCount();
// i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount())
// {
// printf("append %d\n", i);
// walk.Append(obstacle.CPoint(i));
// }
return
true
;
}
}
void
PNS_LINE
::
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
void
PNS_LINE
::
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
SHAPE_LINE_CHAIN
&
aPath
,
SHAPE_LINE_CHAIN
&
aPath
,
bool
aCw
)
const
bool
aCw
)
const
{
{
SHAPE_LINE_CHAIN
walk
,
post
;
SHAPE_LINE_CHAIN
walk
,
post
;
NewWalkaround
(
aObstacle
,
aPath
,
walk
,
post
,
aCw
);
aPath
.
Append
(
walk
);
NewWalkaround
(
aObstacle
,
aPath
,
walk
,
post
,
aCw
);
aPath
.
Append
(
post
);
aPath
.
Append
(
walk
);
aPath
.
Simplify
();
aPath
.
Append
(
post
);
aPath
.
Simplify
();
}
}
void
PNS_LINE
::
Walkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
SHAPE_LINE_CHAIN
&
aPath
,
void
PNS_LINE
::
Walkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
bool
aCw
)
const
SHAPE_LINE_CHAIN
&
aPath
,
bool
aCw
)
const
{
{
SHAPE_LINE_CHAIN
walk
,
post
;
SHAPE_LINE_CHAIN
walk
,
post
;
Walkaround
(
aObstacle
,
aPath
,
walk
,
post
,
aCw
);
aPath
.
Append
(
walk
);
Walkaround
(
aObstacle
,
aPath
,
walk
,
post
,
aCw
);
aPath
.
Append
(
post
);
aPath
.
Append
(
walk
);
aPath
.
Simplify
();
aPath
.
Append
(
post
);
aPath
.
Simplify
();
}
}
const
SHAPE_LINE_CHAIN
PNS_SEGMENT
::
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
const
SHAPE_LINE_CHAIN
PNS_SEGMENT
::
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
{
{
int
d
=
aClearance
+
10
;
int
d
=
aClearance
+
10
;
int
x
=
(
int
)
(
2.0
/
(
1.0
+
M_SQRT2
)
*
d
)
+
2
;
int
x
=
(
int
)(
2.0
/
(
1.0
+
M_SQRT2
)
*
d
)
+
2
;
const
VECTOR2I
a
=
m_shape
.
CPoint
(
0
);
const
VECTOR2I
a
=
m_shape
.
CPoint
(
0
);
const
VECTOR2I
b
=
m_shape
.
CPoint
(
1
);
const
VECTOR2I
b
=
m_shape
.
CPoint
(
1
);
VECTOR2I
dir
=
b
-
a
;
VECTOR2I
dir
=
b
-
a
;
VECTOR2I
p0
=
dir
.
Perpendicular
().
Resize
(
d
);
VECTOR2I
p0
=
dir
.
Perpendicular
().
Resize
(
d
);
VECTOR2I
ds
=
dir
.
Perpendicular
().
Resize
(
x
/
2
);
VECTOR2I
ds
=
dir
.
Perpendicular
().
Resize
(
x
/
2
);
VECTOR2I
pd
=
dir
.
Resize
(
x
/
2
);
VECTOR2I
pd
=
dir
.
Resize
(
x
/
2
);
VECTOR2I
dp
=
dir
.
Resize
(
d
);
VECTOR2I
dp
=
dir
.
Resize
(
d
);
SHAPE_LINE_CHAIN
s
;
SHAPE_LINE_CHAIN
s
;
s
.
SetClosed
(
true
);
s
.
SetClosed
(
true
);
s
.
Append
(
b
+
p0
+
pd
);
s
.
Append
(
b
+
dp
+
ds
);
s
.
Append
(
b
+
dp
-
ds
);
s
.
Append
(
b
-
p0
+
pd
);
s
.
Append
(
a
-
p0
-
pd
);
s
.
Append
(
a
-
dp
-
ds
);
s
.
Append
(
a
-
dp
+
ds
);
s
.
Append
(
a
+
p0
-
pd
);
// make sure the hull outline is always clockwise
if
(
s
.
CSegment
(
0
).
Side
(
a
)
<
0
)
return
s
.
Reverse
();
else
return
s
;
s
.
Append
(
b
+
p0
+
pd
);
s
.
Append
(
b
+
dp
+
ds
);
s
.
Append
(
b
+
dp
-
ds
);
s
.
Append
(
b
-
p0
+
pd
);
s
.
Append
(
a
-
p0
-
pd
);
s
.
Append
(
a
-
dp
-
ds
);
s
.
Append
(
a
-
dp
+
ds
);
s
.
Append
(
a
+
p0
-
pd
);
// make sure the hull outline is always clockwise
if
(
s
.
CSegment
(
0
).
Side
(
a
)
<
0
)
return
s
.
Reverse
();
else
return
s
;
}
}
bool
PNS_LINE
::
Is45Degree
()
bool
PNS_LINE
::
Is45Degree
()
{
{
for
(
int
i
=
0
;
i
<
m_line
.
SegmentCount
();
i
++
)
for
(
int
i
=
0
;
i
<
m_line
.
SegmentCount
();
i
++
)
{
{
const
SEG
&
s
=
m_line
.
CSegment
(
i
);
const
SEG
&
s
=
m_line
.
CSegment
(
i
);
double
angle
=
180.0
/
M_PI
*
atan2
((
double
)
s
.
b
.
y
-
(
double
)
s
.
a
.
y
,
(
double
)
s
.
b
.
x
-
(
double
)
s
.
a
.
x
);
double
angle
=
180.0
/
M_PI
*
atan2
(
(
double
)
s
.
b
.
y
-
(
double
)
s
.
a
.
y
,
if
(
angle
<
0
)
(
double
)
s
.
b
.
x
-
(
double
)
s
.
a
.
x
);
angle
+=
360.0
;
if
(
angle
<
0
)
double
angle_a
=
fabs
(
fmod
(
angle
,
45.0
));
angle
+=
360.0
;
if
(
angle_a
>
1.0
&&
angle_a
<
44.0
)
return
false
;
double
angle_a
=
fabs
(
fmod
(
angle
,
45.0
)
);
}
return
true
;
if
(
angle_a
>
1.0
&&
angle_a
<
44.0
)
return
false
;
}
return
true
;
}
}
const
PNS_LINE
PNS_LINE
::
ClipToNearestObstacle
(
PNS_NODE
*
aNode
)
const
const
PNS_LINE
PNS_LINE
::
ClipToNearestObstacle
(
PNS_NODE
*
aNode
)
const
{
{
PNS_LINE
l
(
*
this
);
PNS_LINE
l
(
*
this
);
PNS_NODE
::
OptObstacle
obs
=
aNode
->
NearestObstacle
(
&
l
);
PNS_NODE
::
OptObstacle
obs
=
aNode
->
NearestObstacle
(
&
l
);
if
(
obs
)
if
(
obs
)
{
{
l
.
RemoveVia
();
l
.
RemoveVia
();
int
p
=
l
.
GetLine
().
Split
(
obs
->
ip_first
);
int
p
=
l
.
GetLine
().
Split
(
obs
->
ip_first
);
l
.
GetLine
().
Remove
(
p
+
1
,
-
1
);
l
.
GetLine
().
Remove
(
p
+
1
,
-
1
);
}
}
return
l
;
return
l
;
}
}
void
PNS_LINE
::
ShowLinks
()
void
PNS_LINE
::
ShowLinks
()
{
{
if
(
!
m_segmentRefs
)
if
(
!
m_segmentRefs
)
{
{
printf
(
"line %p: no links
\n
"
,
this
);
printf
(
"line %p: no links
\n
"
,
this
);
return
;
return
;
}
}
printf
(
"line %p: %d linked segs
\n
"
,
this
,
m_segmentRefs
->
size
());
for
(
int
i
=
0
;
i
<
(
int
)
m_segmentRefs
->
size
();
i
++
)
printf
(
"seg %d: %p
\n
"
,
i
,
(
*
m_segmentRefs
)[
i
])
;
printf
(
"line %p: %d linked segs
\n
"
,
this
,
m_segmentRefs
->
size
()
);
for
(
int
i
=
0
;
i
<
(
int
)
m_segmentRefs
->
size
();
i
++
)
printf
(
"seg %d: %p
\n
"
,
i
,
(
*
m_segmentRefs
)[
i
]
);
}
}
pcbnew/router/pns_line.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -38,214 +38,227 @@ class PNS_VIA;
...
@@ -38,214 +38,227 @@ class PNS_VIA;
/**
/**
* Class PNS_LINE
* Class PNS_LINE
*
*
* Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,
* Represents a track on a PCB, connecting two non-trivial joints (that is,
* junctions between multiple traces or two traces different widths and combinations of these).
* vias, pads, junctions between multiple traces or two traces different widths
* PNS_LINEs are NOT stored in the model (PNS_NODE) - instead, they are assembled on-the-fly, based on
* and combinations of these). PNS_LINEs are NOT stored in the model (PNS_NODE).
* a via/pad/segment that belongs/begins them.
* Instead, they are assembled on-the-fly, based on a via/pad/segment that
* belongs/begins them.
*
*
* PNS_LINEs can be either loose (consisting of segments that do not belong to any PNS_NODE) or owned (with segments
* PNS_LINEs can be either loose (consisting of segments that do not belong to
* taken from a PNS_NODE) - these are returned by PNS_NODE::AssembleLine and friends.
* any PNS_NODE) or owned (with segments taken from a PNS_NODE) - these are
*
* returned by PNS_NODE::AssembleLine and friends.
* A PNS_LINE may have a PNS_VIA attached at its and - this is used by via dragging/force propagation stuff.
*
* A PNS_LINE may have a PNS_VIA attached at its and - this is used by via
* dragging/force propagation stuff.
*/
*/
class
PNS_LINE
:
public
PNS_ITEM
class
PNS_LINE
:
public
PNS_ITEM
{
{
public
:
public
:
typedef
std
::
vector
<
PNS_SEGMENT
*>
LinkedSegments
;
typedef
std
::
vector
<
PNS_SEGMENT
*>
LinkedSegments
;
PNS_LINE
()
:
PNS_LINE
()
:
PNS_ITEM
(
LINE
)
PNS_ITEM
(
LINE
)
{
{
m_segmentRefs
=
NULL
;
m_segmentRefs
=
NULL
;
m_hasVia
=
false
;
m_hasVia
=
false
;
m_affectedRangeStart
=
-
1
;
m_affectedRangeStart
=
-
1
;
};
};
PNS_LINE
(
int
aLayer
,
int
aWidth
,
const
SHAPE_LINE_CHAIN
&
aLine
)
:
PNS_LINE
(
int
aLayer
,
int
aWidth
,
const
SHAPE_LINE_CHAIN
&
aLine
)
:
PNS_ITEM
(
LINE
)
PNS_ITEM
(
LINE
)
{
{
m_line
=
aLine
;
m_line
=
aLine
;
m_width
=
aWidth
;
m_width
=
aWidth
;
m_segmentRefs
=
NULL
;
m_segmentRefs
=
NULL
;
m_hasVia
=
false
;
m_hasVia
=
false
;
m_affectedRangeStart
=
-
1
;
m_affectedRangeStart
=
-
1
;
SetLayer
(
aLayer
);
SetLayer
(
aLayer
);
}
}
PNS_LINE
(
const
PNS_LINE
&
aOther
)
:
PNS_LINE
(
const
PNS_LINE
&
aOther
)
:
PNS_ITEM
(
aOther
),
PNS_ITEM
(
aOther
),
m_line
(
aOther
.
m_line
),
m_line
(
aOther
.
m_line
),
m_width
(
aOther
.
m_width
)
m_width
(
aOther
.
m_width
)
{
{
m_net
=
aOther
.
m_net
;
m_net
=
aOther
.
m_net
;
m_movable
=
aOther
.
m_movable
;
m_movable
=
aOther
.
m_movable
;
m_world
=
aOther
.
m_world
;
m_world
=
aOther
.
m_world
;
m_layers
=
aOther
.
m_layers
;
m_layers
=
aOther
.
m_layers
;
m_segmentRefs
=
NULL
;
m_segmentRefs
=
NULL
;
m_via
=
aOther
.
m_via
;
m_via
=
aOther
.
m_via
;
m_hasVia
=
aOther
.
m_hasVia
;
m_hasVia
=
aOther
.
m_hasVia
;
m_affectedRangeStart
=
-
1
;
m_affectedRangeStart
=
-
1
;
}
}
/**
/**
* Constructor
* Constructor
* copies properties (net, layers from a base line), and replaces the shape
* copies properties (net, layers from a base line), and replaces the shape
* by aLine
* by aLine
**/
**/
PNS_LINE
(
const
PNS_LINE
&
aBase
,
const
SHAPE_LINE_CHAIN
&
aLine
)
:
PNS_LINE
(
const
PNS_LINE
&
aBase
,
const
SHAPE_LINE_CHAIN
&
aLine
)
:
PNS_ITEM
(
aBase
),
PNS_ITEM
(
aBase
),
m_line
(
aLine
),
m_line
(
aLine
),
m_width
(
aBase
.
m_width
)
m_width
(
aBase
.
m_width
)
{
{
m_net
=
aBase
.
m_net
;
m_net
=
aBase
.
m_net
;
m_layers
=
aBase
.
m_layers
;
m_layers
=
aBase
.
m_layers
;
m_segmentRefs
=
NULL
;
m_segmentRefs
=
NULL
;
m_hasVia
=
false
;
m_hasVia
=
false
;
m_affectedRangeStart
=
-
1
;
m_affectedRangeStart
=
-
1
;
}
}
~
PNS_LINE
()
~
PNS_LINE
()
{
{
if
(
m_segmentRefs
)
if
(
m_segmentRefs
)
delete
m_segmentRefs
;
delete
m_segmentRefs
;
};
};
virtual
PNS_LINE
*
Clone
()
const
;
virtual
PNS_LINE
*
Clone
()
const
;
///> clones the line without cloning the shape
///> clones the line without cloning the shape (just the properties - net, width, layers, etc.)
///> (just the properties - net, width, layers, etc.)
PNS_LINE
*
CloneProperties
()
const
;
PNS_LINE
*
CloneProperties
()
const
;
int
GetLayer
()
const
{
return
GetLayers
().
Start
();
}
int
GetLayer
()
const
{
return
GetLayers
().
Start
();
}
///> Geometry accessors
///> Geometry accessors
void
SetShape
(
const
SHAPE_LINE_CHAIN
&
aLine
)
{
m_line
=
aLine
;
}
void
SetShape
(
const
SHAPE_LINE_CHAIN
&
aLine
)
{
m_line
=
aLine
;
}
const
SHAPE
*
GetShape
()
const
{
return
&
m_line
;
}
const
SHAPE
*
GetShape
()
const
{
return
&
m_line
;
}
SHAPE_LINE_CHAIN
&
GetLine
()
{
return
m_line
;
}
SHAPE_LINE_CHAIN
&
GetLine
()
{
return
m_line
;
}
const
SHAPE_LINE_CHAIN
&
GetCLine
()
const
{
return
m_line
;
}
const
SHAPE_LINE_CHAIN
&
GetCLine
()
const
{
return
m_line
;
}
///> Width accessors
///> Width accessors
void
SetWidth
(
int
aWidth
)
{
m_width
=
aWidth
;
}
void
SetWidth
(
int
aWidth
)
{
m_width
=
aWidth
;
}
int
GetWidth
()
const
{
return
m_width
;
}
int
GetWidth
()
const
{
return
m_width
;
}
///> Links a segment from a PNS_NODE to this line, making it owned by the node
///> Links a segment from a PNS_NODE to this line, making it owned by the node
void
LinkSegment
(
PNS_SEGMENT
*
aSeg
)
void
LinkSegment
(
PNS_SEGMENT
*
aSeg
)
{
{
if
(
!
m_segmentRefs
)
if
(
!
m_segmentRefs
)
m_segmentRefs
=
new
std
::
vector
<
PNS_SEGMENT
*>
();
m_segmentRefs
=
new
std
::
vector
<
PNS_SEGMENT
*>
();
m_segmentRefs
->
push_back
(
aSeg
);
}
m_segmentRefs
->
push_back
(
aSeg
);
}
///> Returns a list of segments from the owning node that constitute this line (or NULL if
///> the line is loose)
///> Returns a list of segments from the owning node that constitute this
LinkedSegments
*
GetLinkedSegments
()
///> line (or NULL if the line is loose)
{
LinkedSegments
*
GetLinkedSegments
()
return
m_segmentRefs
;
{
}
return
m_segmentRefs
;
}
bool
ContainsSegment
(
PNS_SEGMENT
*
aSeg
)
const
{
bool
ContainsSegment
(
PNS_SEGMENT
*
aSeg
)
const
if
(
!
m_segmentRefs
)
{
return
false
;
if
(
!
m_segmentRefs
)
return
false
;
return
std
::
find
(
m_segmentRefs
->
begin
(),
m_segmentRefs
->
end
(),
aSeg
)
!=
m_segmentRefs
->
end
();
}
return
std
::
find
(
m_segmentRefs
->
begin
(),
m_segmentRefs
->
end
(),
aSeg
)
!=
m_segmentRefs
->
end
();
///> Returns this line, but clipped to the nearest obstacle along, to avoid collision.
}
const
PNS_LINE
ClipToNearestObstacle
(
PNS_NODE
*
aNode
)
const
;
///> Returns this line, but clipped to the nearest obstacle
///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER)
///> along, to avoid collision.
bool
MergeObtuseSegments
();
const
PNS_LINE
ClipToNearestObstacle
(
PNS_NODE
*
aNode
)
const
;
bool
MergeSegments
();
///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER)
///> Returns the number of corners of angles specified by mask aAngles.
bool
MergeObtuseSegments
();
int
CountCorners
(
int
aAngles
);
bool
MergeSegments
();
///> Returns the number of corners of angles specified by mask aAngles.
///> Calculates a line thightly wrapping a convex hull of an obstacle object (aObstacle).
int
CountCorners
(
int
aAngles
);
///> aPrePath = path from origin to the obstacle
///> aWalkaroundPath = path around the obstacle
///> Calculates a line thightly wrapping a convex hull
///> aPostPath = past from obstacle till the end
///> of an obstacle object (aObstacle).
///> aCW = whether to walkaround in clockwise or counter-clockwise direction.
///> aPrePath = path from origin to the obstacle
void
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
///> aWalkaroundPath = path around the obstacle
SHAPE_LINE_CHAIN
&
aPrePath
,
///> aPostPath = past from obstacle till the end
SHAPE_LINE_CHAIN
&
aWalkaroundPath
,
///> aCW = whether to walkaround in clockwise or counter-clockwise direction.
SHAPE_LINE_CHAIN
&
aPostPath
,
void
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
bool
aCw
)
const
;
SHAPE_LINE_CHAIN
&
aPrePath
,
SHAPE_LINE_CHAIN
&
aWalkaroundPath
,
void
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
SHAPE_LINE_CHAIN
&
aPostPath
,
SHAPE_LINE_CHAIN
&
aPath
,
bool
aCw
)
const
;
bool
aCw
)
const
;
void
NewWalkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
SHAPE_LINE_CHAIN
&
aPath
,
bool
Walkaround
(
SHAPE_LINE_CHAIN
obstacle
,
SHAPE_LINE_CHAIN
&
pre
,
SHAPE_LINE_CHAIN
&
walk
,
SHAPE_LINE_CHAIN
&
post
,
bool
cw
)
const
;
bool
aCw
)
const
;
void
Walkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
SHAPE_LINE_CHAIN
&
aPath
,
bool
Walkaround
(
SHAPE_LINE_CHAIN
obstacle
,
bool
aCw
)
const
;
SHAPE_LINE_CHAIN
&
pre
,
SHAPE_LINE_CHAIN
&
walk
,
SHAPE_LINE_CHAIN
&
post
,
bool
Is45Degree
();
bool
cw
)
const
;
///> Prints out all linked segments
void
Walkaround
(
const
SHAPE_LINE_CHAIN
&
aObstacle
,
void
ShowLinks
();
SHAPE_LINE_CHAIN
&
aPath
,
bool
aCw
)
const
;
bool
EndsWithVia
()
const
{
return
m_hasVia
;
}
bool
Is45Degree
();
void
AppendVia
(
const
PNS_VIA
&
aVia
)
{
m_hasVia
=
true
;
///> Prints out all linked segments
m_via
=
aVia
;
void
ShowLinks
();
m_via
.
SetNet
(
m_net
)
;
}
bool
EndsWithVia
()
const
{
return
m_hasVia
;
}
void
RemoveVia
()
{
m_hasVia
=
false
;
}
void
AppendVia
(
const
PNS_VIA
&
aVia
)
const
PNS_VIA
&
GetVia
()
const
{
return
m_via
;
}
{
m_hasVia
=
true
;
void
SetAffectedRange
(
int
aStart
,
int
aEnd
)
m_via
=
aVia
;
{
m_via
.
SetNet
(
m_net
);
m_affectedRangeStart
=
aStart
;
}
m_affectedRangeEnd
=
aEnd
;
}
void
RemoveVia
()
{
m_hasVia
=
false
;
}
const
PNS_VIA
&
GetVia
()
const
{
return
m_via
;
}
void
ClearAffectedRange
(
)
{
void
SetAffectedRange
(
int
aStart
,
int
aEnd
)
m_affectedRangeStart
=
-
1
;
{
}
m_affectedRangeStart
=
aStart
;
m_affectedRangeEnd
=
aEnd
;
bool
GetAffectedRange
(
int
&
aStart
,
int
&
aEnd
)
}
{
if
(
m_affectedRangeStart
>=
0
)
void
ClearAffectedRange
()
{
{
aStart
=
m_affectedRangeStart
;
m_affectedRangeStart
=
-
1
;
aEnd
=
m_affectedRangeEnd
;
}
return
true
;
}
else
{
bool
GetAffectedRange
(
int
&
aStart
,
int
&
aEnd
)
aStart
=
0
;
{
aEnd
=
m_line
.
PointCount
();
if
(
m_affectedRangeStart
>=
0
)
return
false
;
{
}
aStart
=
m_affectedRangeStart
;
}
aEnd
=
m_affectedRangeEnd
;
return
true
;
}
else
{
aStart
=
0
;
aEnd
=
m_line
.
PointCount
();
return
false
;
}
}
private
:
private
:
bool
onEdge
(
const
SHAPE_LINE_CHAIN
&
obstacle
,
VECTOR2I
p
,
int
&
ei
,
bool
&
is_vertex
)
const
;
bool
onEdge
(
const
SHAPE_LINE_CHAIN
&
obstacle
,
VECTOR2I
p
,
int
&
ei
,
bool
&
is_vertex
)
const
;
bool
walkScan
(
const
SHAPE_LINE_CHAIN
&
line
,
const
SHAPE_LINE_CHAIN
&
obstacle
,
bool
reverse
,
VECTOR2I
&
ip
,
int
&
index_o
,
int
&
index_l
,
bool
&
is_vertex
)
const
;
bool
walkScan
(
const
SHAPE_LINE_CHAIN
&
line
,
const
SHAPE_LINE_CHAIN
&
obstacle
,
bool
reverse
,
VECTOR2I
&
ip
,
int
&
index_o
,
int
&
index_l
,
bool
&
is_vertex
)
const
;
///> List of semgments in a PNS_NODE (PNS_ITEM::m_owner) that constitute this line.
LinkedSegments
*
m_segmentRefs
;
///> Shape of the line
SHAPE_LINE_CHAIN
m_line
;
int
m_width
;
///> Via at the end and a flag indicating if it's enabled.
PNS_VIA
m_via
;
bool
m_hasVia
;
int
m_affectedRangeStart
;
int
m_affectedRangeEnd
;
};
///> List of semgments in a PNS_NODE (PNS_ITEM::m_owner) that constitute this line.
LinkedSegments
*
m_segmentRefs
;
///> Shape of the line
SHAPE_LINE_CHAIN
m_line
;
int
m_width
;
///> Via at the end and a flag indicating if it's enabled.
PNS_VIA
m_via
;
bool
m_hasVia
;
int
m_affectedRangeStart
;
int
m_affectedRangeEnd
;
};
#endif // __PNS_LINE_H
#endif
// __PNS_LINE_H
pcbnew/router/pns_line_placer.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -33,683 +33,648 @@
...
@@ -33,683 +33,648 @@
using
namespace
std
;
using
namespace
std
;
using
boost
::
optional
;
using
boost
::
optional
;
PNS_LINE_PLACER
::
PNS_LINE_PLACER
(
PNS_NODE
*
aWorld
)
PNS_LINE_PLACER
::
PNS_LINE_PLACER
(
PNS_NODE
*
aWorld
)
{
{
m_initial_direction
=
DIRECTION_45
(
DIRECTION_45
::
N
);
m_initial_direction
=
DIRECTION_45
(
DIRECTION_45
::
N
);
m_follow_mouse
=
false
;
m_follow_mouse
=
false
;
m_smoothing_step
=
100000
;
m_smoothing_step
=
100000
;
m_smooth_mouse
=
false
;
m_smooth_mouse
=
false
;
m_iteration
=
0
;
m_iteration
=
0
;
m_world
=
aWorld
;
m_world
=
aWorld
;
m_mode
=
RM_Smart
;
m_mode
=
RM_Smart
;
m_follow_mouse
=
true
;
m_follow_mouse
=
true
;
m_shove
=
NULL
;
m_shove
=
NULL
;
};
};
PNS_LINE_PLACER
::~
PNS_LINE_PLACER
()
PNS_LINE_PLACER
::~
PNS_LINE_PLACER
()
{
{
if
(
m_shove
)
if
(
m_shove
)
delete
m_shove
;
delete
m_shove
;
}
}
void
PNS_LINE_PLACER
::
ApplySettings
(
const
PNS_ROUTING_SETTINGS
&
aSettings
)
void
PNS_LINE_PLACER
::
ApplySettings
(
const
PNS_ROUTING_SETTINGS
&
aSettings
)
{
{
m_follow_mouse
=
aSettings
.
m_followMouse
;
m_follow_mouse
=
aSettings
.
m_followMouse
;
m_mode
=
aSettings
.
m_routingMode
;
m_mode
=
aSettings
.
m_routingMode
;
m_walkaroundIterationLimit
=
aSettings
.
m_walkaroundIterationLimit
;
m_walkaroundIterationLimit
=
aSettings
.
m_walkaroundIterationLimit
;
m_smartPads
=
aSettings
.
m_smartPads
;
m_smartPads
=
aSettings
.
m_smartPads
;
}
}
void
PNS_LINE_PLACER
::
StartPlacement
(
const
VECTOR2I
&
aStart
,
int
aNet
,
int
aWidth
,
int
aLayer
)
void
PNS_LINE_PLACER
::
StartPlacement
(
const
VECTOR2I
&
aStart
,
int
aNet
,
int
aWidth
,
int
aLayer
)
{
{
m_direction
=
m_initial_direction
;
m_direction
=
m_initial_direction
;
TRACE
(
1
,
"world %p, intitial-direction %s layer %d
\n
"
,
m_world
%
m_direction
.
Format
().
c_str
()
%
aLayer
);
TRACE
(
1
,
"world %p, intitial-direction %s layer %d
\n
"
,
m_head
.
SetNet
(
aNet
);
m_world
%
m_direction
.
Format
().
c_str
()
%
aLayer
);
m_tail
.
SetNet
(
aNet
);
m_head
.
SetNet
(
aNet
);
m_head
.
SetWidth
(
aWidth
);
m_tail
.
SetNet
(
aNet
);
m_tail
.
SetWidth
(
aWidth
);
m_head
.
SetWidth
(
aWidth
);
m_head
.
GetLine
().
Clear
();
m_tail
.
SetWidth
(
aWidth
);
m_tail
.
GetLine
().
Clear
();
m_head
.
GetLine
().
Clear
();
m_head
.
SetLayer
(
aLayer
);
m_tail
.
GetLine
().
Clear
();
m_tail
.
SetLayer
(
aLayer
);
m_head
.
SetLayer
(
aLayer
);
m_iteration
=
0
;
m_tail
.
SetLayer
(
aLayer
);
m_p_start
=
aStart
;
m_iteration
=
0
;
m_currentNode
=
m_world
->
Branch
();
m_p_start
=
aStart
;
m_head
.
SetWorld
(
m_currentNode
);
m_currentNode
=
m_world
->
Branch
();
m_tail
.
SetWorld
(
m_currentNode
);
m_head
.
SetWorld
(
m_currentNode
);
//if(m_shove)
m_tail
.
SetWorld
(
m_currentNode
);
// delete m_shove;
// if(m_shove)
m_shove
=
new
PNS_SHOVE
(
m_currentNode
);
// delete m_shove;
m_placingVia
=
false
;
m_shove
=
new
PNS_SHOVE
(
m_currentNode
);
m_placingVia
=
false
;
}
}
void
PNS_LINE_PLACER
::
SetInitialDirection
(
const
DIRECTION_45
&
aDirection
)
void
PNS_LINE_PLACER
::
SetInitialDirection
(
const
DIRECTION_45
&
aDirection
)
{
{
m_initial_direction
=
aDirection
;
m_initial_direction
=
aDirection
;
if
(
m_tail
.
GetCLine
().
SegmentCount
()
==
0
)
if
(
m_tail
.
GetCLine
().
SegmentCount
()
==
0
)
m_direction
=
aDirection
;
m_direction
=
aDirection
;
}
}
/**
* Function handleSelfIntersections()
bool
PNS_LINE_PLACER
::
handleSelfIntersections
()
*
* Checks if the head of the track intersects its tail. If so, cuts the tail up to the
* intersecting segment and fixes the head direction to match the last segment before the cut.
* @return true if the line has been changed.
*/
bool
PNS_LINE_PLACER
::
handleSelfIntersections
()
{
{
SHAPE_LINE_CHAIN
::
Intersections
ips
;
SHAPE_LINE_CHAIN
::
Intersections
ips
;
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
// if there is no tail, there is nothing to intersect with
// if there is no tail, there is nothing to intersect with
if
(
tail
.
PointCount
()
<
2
)
if
(
tail
.
PointCount
()
<
2
)
return
false
;
return
false
;
tail
.
Intersect
(
head
,
ips
);
tail
.
Intersect
(
head
,
ips
);
// no intesection points - nothing to reduce
// no intesection points - nothing to reduce
if
(
ips
.
empty
())
if
(
ips
.
empty
()
)
return
false
;
return
false
;
int
n
=
INT_MAX
;
int
n
=
INT_MAX
;
VECTOR2I
ipoint
;
VECTOR2I
ipoint
;
// if there is more than one intersection, find the one that is
// if there is more than one intersection, find the one that is
// closest to the beginning of the tail.
// closest to the beginning of the tail.
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
::
Intersection
i
,
ips
)
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
::
Intersection
i
,
ips
)
{
{
if
(
i
.
our
.
Index
()
<
n
)
if
(
i
.
our
.
Index
()
<
n
)
{
{
n
=
i
.
our
.
Index
();
n
=
i
.
our
.
Index
();
ipoint
=
i
.
p
;
ipoint
=
i
.
p
;
}
}
}
}
// ignore the point where head and tail meet
// ignore the point where head and tail meet
if
(
ipoint
==
head
.
CPoint
(
0
)
||
ipoint
==
tail
.
CPoint
(
-
1
))
if
(
ipoint
==
head
.
CPoint
(
0
)
||
ipoint
==
tail
.
CPoint
(
-
1
)
)
return
false
;
return
false
;
// Intersection point is on the first or the second segment: just start routing
// Intersection point is on the first or the second segment: just start routing
// from the beginning
// from the beginning
if
(
n
<
2
)
if
(
n
<
2
)
{
{
m_p_start
=
tail
.
Point
(
0
);
m_p_start
=
tail
.
Point
(
0
);
m_direction
=
m_initial_direction
;
m_direction
=
m_initial_direction
;
tail
.
Clear
();
tail
.
Clear
();
head
.
Clear
();
head
.
Clear
();
return
true
;
return
true
;
}
else
{
}
// Clip till the last tail segment before intersection.
else
// Set the direction to the one of this segment.
{
const
SEG
last
=
tail
.
CSegment
(
n
-
1
);
// Clip till the last tail segment before intersection.
m_p_start
=
last
.
a
;
// Set the direction to the one of this segment.
m_direction
=
DIRECTION_45
(
last
);
const
SEG
last
=
tail
.
CSegment
(
n
-
1
);
tail
.
Remove
(
n
,
-
1
);
m_p_start
=
last
.
a
;
return
true
;
m_direction
=
DIRECTION_45
(
last
);
}
tail
.
Remove
(
n
,
-
1
);
return
false
;
return
true
;
}
}
/**
return
false
;
* Function handlePullback()
}
*
* Deals with pull-back: reduces the tail if head trace is moved backwards wrs
* to the current tail direction.
bool
PNS_LINE_PLACER
::
handlePullback
()
* @return true if the line has been changed.
*/
bool
PNS_LINE_PLACER
::
handlePullback
()
{
{
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
int
n
=
tail
.
PointCount
();
int
n
=
tail
.
PointCount
();
if
(
n
==
0
)
if
(
n
==
0
)
return
false
;
return
false
;
else
if
(
n
==
1
)
else
if
(
n
==
1
)
{
{
m_p_start
=
tail
.
CPoint
(
0
);
m_p_start
=
tail
.
CPoint
(
0
);
tail
.
Clear
();
tail
.
Clear
();
return
true
;
return
true
;
}
}
DIRECTION_45
first_head
(
head
.
Segment
(
0
));
DIRECTION_45
first_head
(
head
.
Segment
(
0
)
);
DIRECTION_45
last_tail
(
tail
.
Segment
(
-
1
));
DIRECTION_45
last_tail
(
tail
.
Segment
(
-
1
)
);
DIRECTION_45
::
AngleType
angle
=
first_head
.
Angle
(
last_tail
);
DIRECTION_45
::
AngleType
angle
=
first_head
.
Angle
(
last_tail
);
// case 1: we have a defined routing direction, and the currently computed head
// case 1: we have a defined routing direction, and the currently computed
// goes in different one.
// head goes in different one.
bool
pullback_1
=
false
;
//(m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head);
bool
pullback_1
=
false
;
// (m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head);
// case 2: regardless of the current routing direction, if the tail/head extremities form
// case 2: regardless of the current routing direction, if the tail/head
// an acute or right angle, reduce the tail by one segment (and hope that further iterations)
// extremities form an acute or right angle, reduce the tail by one segment
// will result with a cleaner trace
// (and hope that further iterations) will result with a cleaner trace
bool
pullback_2
=
(
angle
==
DIRECTION_45
::
ANG_RIGHT
||
angle
==
DIRECTION_45
::
ANG_ACUTE
);
bool
pullback_2
=
(
angle
==
DIRECTION_45
::
ANG_RIGHT
||
angle
==
DIRECTION_45
::
ANG_ACUTE
);
if
(
pullback_1
||
pullback_2
)
{
if
(
pullback_1
||
pullback_2
)
{
const
SEG
last
=
tail
.
CSegment
(
-
1
);
const
SEG
last
=
tail
.
CSegment
(
-
1
);
m_direction
=
DIRECTION_45
(
last
);
m_direction
=
DIRECTION_45
(
last
);
m_p_start
=
last
.
a
;
m_p_start
=
last
.
a
;
TRACE
(
0
,
"Placer: pullback triggered [%d] [%s %s]"
,
TRACE
(
0
,
"Placer: pullback triggered [%d] [%s %s]"
,
n
%
last_tail
.
Format
().
c_str
()
%
first_head
.
Format
().
c_str
());
n
%
last_tail
.
Format
().
c_str
()
%
first_head
.
Format
().
c_str
()
);
// erase the last point in the tail, hoping that the next iteration will result with a head
// trace that starts with a segment following our current direction.
// erase the last point in the tail, hoping that the next iteration will
if
(
n
<
2
)
// result with a head trace that starts with a segment following our
tail
.
Clear
();
// don't leave a single-point tail
// current direction.
else
if
(
n
<
2
)
tail
.
Remove
(
-
1
,
-
1
);
tail
.
Clear
();
// don't leave a single-point tail
else
if
(
!
tail
.
SegmentCount
()
)
tail
.
Remove
(
-
1
,
-
1
);
m_direction
=
m_initial_direction
;
if
(
!
tail
.
SegmentCount
()
)
return
true
;
m_direction
=
m_initial_direction
;
}
return
true
;
return
false
;
}
return
false
;
}
}
/**
* Function reduceTail()
bool
PNS_LINE_PLACER
::
reduceTail
(
const
VECTOR2I
&
aEnd
)
*
* Attempts to reduce the numer of segments in the tail by trying to replace a certain number
* of latest tail segments with a direct trace leading to aEnd that does not collide with anything.
* @param aEnd: current routing destination point.
* @return true if the line has been changed.
*/
bool
PNS_LINE_PLACER
::
reduceTail
(
const
VECTOR2I
&
aEnd
)
{
{
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
int
n
=
tail
.
SegmentCount
();
int
n
=
tail
.
SegmentCount
();
// Don't attempt this for too short tails
// Don't attempt this for too short tails
if
(
n
<
2
)
if
(
n
<
2
)
return
false
;
return
false
;
// Start from the segment farthest from the end of the tail
// Start from the segment farthest from the end of the tail
//int start_index = std::max(n - 1 - ReductionDepth, 0);
// int start_index = std::max(n - 1 - ReductionDepth, 0);
DIRECTION_45
new_direction
;
DIRECTION_45
new_direction
;
VECTOR2I
new_start
;
VECTOR2I
new_start
;
int
reduce_index
=
-
1
;
int
reduce_index
=
-
1
;
DIRECTION_45
head_dir
(
head
.
Segment
(
0
)
);
DIRECTION_45
head_dir
(
head
.
Segment
(
0
)
);
for
(
int
i
=
tail
.
SegmentCount
()
-
1
;
i
>=
0
;
i
--
)
for
(
int
i
=
tail
.
SegmentCount
()
-
1
;
i
>=
0
;
i
--
)
{
{
const
SEG
s
=
tail
.
CSegment
(
i
);
const
SEG
s
=
tail
.
CSegment
(
i
);
DIRECTION_45
dir
(
s
);
DIRECTION_45
dir
(
s
);
// calculate a replacement route and check if it matches the direction of the segment to be replaced
// calculate a replacement route and check if it matches
SHAPE_LINE_CHAIN
replacement
=
dir
.
BuildInitialTrace
(
s
.
a
,
aEnd
);
// the direction of the segment to be replaced
SHAPE_LINE_CHAIN
replacement
=
dir
.
BuildInitialTrace
(
s
.
a
,
aEnd
);
PNS_LINE
tmp
(
m_tail
,
replacement
);
PNS_LINE
tmp
(
m_tail
,
replacement
);
if
(
m_currentNode
->
CheckColliding
(
&
tmp
,
PNS_ITEM
::
ANY
))
break
;
if
(
m_currentNode
->
CheckColliding
(
&
tmp
,
PNS_ITEM
::
ANY
)
)
break
;
if
(
DIRECTION_45
(
replacement
.
Segment
(
0
))
==
dir
)
{
if
(
DIRECTION_45
(
replacement
.
Segment
(
0
)
)
==
dir
)
new_start
=
s
.
a
;
{
new_direction
=
dir
;
new_start
=
s
.
a
;
reduce_index
=
i
;
new_direction
=
dir
;
}
reduce_index
=
i
;
}
}
}
if
(
reduce_index
>=
0
)
{
if
(
reduce_index
>=
0
)
{
TRACE
(
0
,
"Placer: reducing tail: %d"
,
reduce_index
);
TRACE
(
0
,
"Placer: reducing tail: %d"
,
reduce_index
);
SHAPE_LINE_CHAIN
reducedLine
=
new_direction
.
BuildInitialTrace
(
new_start
,
aEnd
);
SHAPE_LINE_CHAIN
reducedLine
=
new_direction
.
BuildInitialTrace
(
new_start
,
aEnd
);
m_p_start
=
new_start
;
m_p_start
=
new_start
;
m_direction
=
new_direction
;
m_direction
=
new_direction
;
tail
.
Remove
(
reduce_index
+
1
,
-
1
);
tail
.
Remove
(
reduce_index
+
1
,
-
1
);
head
.
Clear
();
head
.
Clear
();
return
true
;
return
true
;
}
}
if
(
!
tail
.
SegmentCount
()
)
if
(
!
tail
.
SegmentCount
()
)
m_direction
=
m_initial_direction
;
m_direction
=
m_initial_direction
;
return
false
;
return
false
;
}
}
/**
bool
PNS_LINE_PLACER
::
checkObtusity
(
const
SEG
&
a
,
const
SEG
&
b
)
const
* Function checkObtusity()
*
* Helper that checks if segments a and b form an obtuse angle (in 45-degree regime).
* @return true, if angle (a, b) is obtuse
*/
bool
PNS_LINE_PLACER
::
checkObtusity
(
const
SEG
&
a
,
const
SEG
&
b
)
const
{
{
const
DIRECTION_45
dir_a
(
a
);
const
DIRECTION_45
dir_a
(
a
);
const
DIRECTION_45
dir_b
(
b
);
const
DIRECTION_45
dir_b
(
b
);
return
dir_a
.
IsObtuse
(
dir_b
)
||
dir_a
==
dir_b
;
return
dir_a
.
IsObtuse
(
dir_b
)
||
dir_a
==
dir_b
;
}
}
/**
* Function mergeHead()
*
* Moves "estabished" segments from the head to the tail if certain conditions are met.
* @return true, if the line has been changed.
*/
bool
PNS_LINE_PLACER
::
mergeHead
()
bool
PNS_LINE_PLACER
::
mergeHead
()
{
{
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
const
int
ForbiddenAngles
=
DIRECTION_45
::
ANG_ACUTE
|
DIRECTION_45
::
ANG_HALF_FULL
|
DIRECTION_45
::
ANG_UNDEFINED
;
const
int
ForbiddenAngles
=
DIRECTION_45
::
ANG_ACUTE
|
DIRECTION_45
::
ANG_HALF_FULL
|
DIRECTION_45
::
ANG_UNDEFINED
;
head
.
Simplify
();
tail
.
Simplify
();
head
.
Simplify
();
int
n_head
=
head
.
SegmentCount
();
tail
.
Simplify
();
int
n_tail
=
tail
.
SegmentCount
();
int
n_head
=
head
.
SegmentCount
();
if
(
n_head
<
3
)
int
n_tail
=
tail
.
SegmentCount
();
{
TRACEn
(
4
,
"Merge failed: not enough head segs."
);
return
false
;
}
if
(
n_head
<
3
)
if
(
n_tail
&&
head
.
CPoint
(
0
)
!=
tail
.
CPoint
(
-
1
)
)
{
{
TRACEn
(
4
,
"Merge failed: not enough head segs."
);
TRACEn
(
4
,
"Merge failed: head and tail discontinuous."
);
return
false
;
return
false
;
}
}
if
(
n_tail
&&
head
.
CPoint
(
0
)
!=
tail
.
CPoint
(
-
1
))
if
(
m_head
.
CountCorners
(
ForbiddenAngles
)
!=
0
)
{
return
false
;
TRACEn
(
4
,
"Merge failed: head and tail discontinuous."
);
return
false
;
}
if
(
m_head
.
CountCorners
(
ForbiddenAngles
)
!=
0
)
DIRECTION_45
dir_tail
,
dir_head
;
return
false
;
DIRECTION_45
dir_tail
,
dir_head
;
dir_head
=
DIRECTION_45
(
head
.
CSegment
(
0
)
)
;
dir_head
=
DIRECTION_45
(
head
.
CSegment
(
0
));
if
(
n_tail
)
{
dir_tail
=
DIRECTION_45
(
tail
.
CSegment
(
-
1
)
);
if
(
n_tail
)
if
(
dir_head
.
Angle
(
dir_tail
)
&
ForbiddenAngles
)
{
return
false
;
dir_tail
=
DIRECTION_45
(
tail
.
CSegment
(
-
1
));
}
if
(
dir_head
.
Angle
(
dir_tail
)
&
ForbiddenAngles
)
return
false
;
}
if
(
!
n_tail
)
if
(
!
n_tail
)
tail
.
Append
(
head
.
CSegment
(
0
).
a
);
tail
.
Append
(
head
.
CSegment
(
0
).
a
);
for
(
int
i
=
0
;
i
<
n_head
-
2
;
i
++
)
for
(
int
i
=
0
;
i
<
n_head
-
2
;
i
++
)
{
{
tail
.
Append
(
head
.
CSegment
(
i
).
b
);
tail
.
Append
(
head
.
CSegment
(
i
).
b
);
}
}
tail
.
Simplify
();
tail
.
Simplify
();
SEG
last
=
tail
.
CSegment
(
-
1
);
SEG
last
=
tail
.
CSegment
(
-
1
);
m_p_start
=
last
.
b
;
m_direction
=
DIRECTION_45
(
last
).
Right
();
m_p_start
=
last
.
b
;
m_direction
=
DIRECTION_45
(
last
).
Right
();
head
.
Remove
(
0
,
n_head
-
2
);
head
.
Remove
(
0
,
n_head
-
2
);
TRACE
(
0
,
"Placer: merge %d, new direction: %s"
,
n_head
%
m_direction
.
Format
().
c_str
());
TRACE
(
0
,
"Placer: merge %d, new direction: %s"
,
n_head
%
m_direction
.
Format
().
c_str
()
);
head
.
Simplify
();
head
.
Simplify
();
tail
.
Simplify
();
tail
.
Simplify
();
return
true
;
return
true
;
}
}
bool
PNS_LINE_PLACER
::
handleViaPlacement
(
PNS_LINE
&
aHead
)
bool
PNS_LINE_PLACER
::
handleViaPlacement
(
PNS_LINE
&
aHead
)
{
{
if
(
!
m_placingVia
)
if
(
!
m_placingVia
)
return
true
;
return
true
;
PNS_LAYERSET
allLayers
(
0
,
15
);
PNS_LAYERSET
allLayers
(
0
,
15
);
PNS_VIA
v
(
aHead
.
GetCLine
().
CPoint
(
-
1
),
allLayers
,
m_viaDiameter
,
aHead
.
GetNet
());
PNS_VIA
v
(
aHead
.
GetCLine
().
CPoint
(
-
1
),
allLayers
,
m_viaDiameter
,
aHead
.
GetNet
()
);
v
.
SetDrill
(
m_viaDrill
);
v
.
SetDrill
(
m_viaDrill
);
VECTOR2I
force
;
VECTOR2I
force
;
VECTOR2I
lead
=
aHead
.
GetCLine
().
CPoint
(
-
1
)
-
aHead
.
GetCLine
().
CPoint
(
0
);
VECTOR2I
lead
=
aHead
.
GetCLine
().
CPoint
(
-
1
)
-
aHead
.
GetCLine
().
CPoint
(
0
);
if
(
v
.
PushoutForce
(
m_shove
->
GetCurrentNode
(),
lead
,
force
,
true
,
20
)
)
if
(
v
.
PushoutForce
(
m_shove
->
GetCurrentNode
(),
lead
,
force
,
true
,
20
)
)
{
{
SHAPE_LINE_CHAIN
line
=
m_direction
.
BuildInitialTrace
(
SHAPE_LINE_CHAIN
line
=
m_direction
.
BuildInitialTrace
(
aHead
.
GetCLine
().
CPoint
(
0
),
aHead
.
GetCLine
().
CPoint
(
-
1
)
+
force
);
aHead
.
GetCLine
().
CPoint
(
0
),
aHead
=
PNS_LINE
(
aHead
,
line
);
aHead
.
GetCLine
().
CPoint
(
-
1
)
+
force
);
aHead
=
PNS_LINE
(
aHead
,
line
);
v
.
SetPos
(
v
.
GetPos
()
+
force
);
return
true
;
v
.
SetPos
(
v
.
GetPos
()
+
force
);
}
return
true
;
}
return
false
;
return
false
;
}
}
/**
* Function routeHead()
bool
PNS_LINE_PLACER
::
routeHead
(
const
VECTOR2I
&
aP
,
PNS_LINE
&
aNewHead
,
*
bool
aCwWalkaround
)
* Computes the head trace between the current start point (m_p_start) and point aP,
* starting with direction defined in m_direction. The trace walks around all
* colliding solid or non-movable items. Movable segments are ignored, as they'll be handled
* later by the shove algorithm.
*/
bool
PNS_LINE_PLACER
::
routeHead
(
const
VECTOR2I
&
aP
,
PNS_LINE
&
aNewHead
,
bool
aCwWalkaround
)
{
{
// STAGE 1: route a simple two-segment trace between m_p_start and aP...
// STAGE 1: route a simple two-segment trace between m_p_start and aP...
SHAPE_LINE_CHAIN
line
=
m_direction
.
BuildInitialTrace
(
m_p_start
,
aP
);
SHAPE_LINE_CHAIN
line
=
m_direction
.
BuildInitialTrace
(
m_p_start
,
aP
);
PNS_LINE
initTrack
(
m_head
,
line
);
PNS_LINE
initTrack
(
m_head
,
line
);
PNS_LINE
walkFull
,
walkSolids
;
PNS_LINE
walkFull
,
walkSolids
;
if
(
m_mode
==
RM_Ignore
)
{
aNewHead
=
initTrack
;
return
true
;
}
if
(
m_mode
==
RM_Ignore
)
handleViaPlacement
(
initTrack
);
{
aNewHead
=
initTrack
;
return
true
;
}
handleViaPlacement
(
initTrack
);
m_currentNode
=
m_shove
->
GetCurrentNode
();
m_currentNode
=
m_shove
->
GetCurrentNode
();
PNS_OPTIMIZER
optimizer
(
m_currentNode
);
PNS_OPTIMIZER
optimizer
(
m_currentNode
);
PNS_WALKAROUND
walkaround
(
m_currentNode
);
PNS_WALKAROUND
walkaround
(
m_currentNode
);
walkaround
.
SetSolidsOnly
(
false
);
walkaround
.
SetSolidsOnly
(
false
);
walkaround
.
SetIterationLimit
(
m_mode
==
RM_Walkaround
?
8
:
5
);
walkaround
.
SetIterationLimit
(
m_mode
==
RM_Walkaround
?
8
:
5
);
//
walkaround.SetApproachCursor(true, aP);
//
walkaround.SetApproachCursor(true, aP);
PNS_WALKAROUND
::
WalkaroundStatus
wf
=
walkaround
.
Route
(
initTrack
,
walkFull
);
PNS_WALKAROUND
::
WalkaroundStatus
wf
=
walkaround
.
Route
(
initTrack
,
walkFull
);
#if 0
#if 0
if(m_mode == RM_Walkaround)
if( m_mode == RM_Walkaround )
{
{
// walkaround.
// walkaround.
// PNSDisplayDebugLine (walkFull.GetCLine(), 4);
// PNSDisplayDebugLine (walkFull.GetCLine(), 4);
if(wf == PNS_WALKAROUND::STUCK)
if( wf == PNS_WALKAROUND::STUCK )
{
{
aNewHead = m_head;
aNewHead = m_head;
aNewHead.SetShape(walkFull.GetCLine());
aNewHead.SetShape( walkFull.GetCLine() );
aNewHead = aNewHead.ClipToNearestObstacle(m_currentNode);
aNewHead = aNewHead.ClipToNearestObstacle( m_currentNode );
return false;
return false;
}
}
aNewHead = m_head;
aNewHead = m_head;
aNewHead.SetShape(walkFull.GetCLine());
aNewHead.SetShape( walkFull.GetCLine() );
// printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start());
// printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start());
return true;
return true;
}
}
#endif
#endif
PNS_COST_ESTIMATOR
cost_walk
,
cost_orig
;
PNS_COST_ESTIMATOR
cost_walk
,
cost_orig
;
walkaround
.
SetApproachCursor
(
false
,
aP
);
walkaround
.
SetApproachCursor
(
false
,
aP
);
walkaround
.
SetSolidsOnly
(
true
);
walkaround
.
SetSolidsOnly
(
true
);
walkaround
.
SetIterationLimit
(
10
);
walkaround
.
SetIterationLimit
(
10
);
PNS_WALKAROUND
::
WalkaroundStatus
stat_solids
=
walkaround
.
Route
(
initTrack
,
walkSolids
);
PNS_WALKAROUND
::
WalkaroundStatus
stat_solids
=
walkaround
.
Route
(
initTrack
,
walkSolids
);
optimizer
.
SetEffortLevel
(
PNS_OPTIMIZER
::
MERGE_SEGMENTS
);
optimizer
.
SetEffortLevel
(
PNS_OPTIMIZER
::
MERGE_SEGMENTS
);
optimizer
.
SetCollisionMask
(
PNS_ITEM
::
SOLID
);
optimizer
.
SetCollisionMask
(
PNS_ITEM
::
SOLID
);
optimizer
.
Optimize
(
&
walkSolids
);
optimizer
.
Optimize
(
&
walkSolids
);
#if 0
#if 0
optimizer.SetCollisionMask (-1
);
optimizer.SetCollisionMask( -1
);
optimizer.Optimize(&walkFull
);
optimizer.Optimize( &walkFull
);
#endif
#endif
cost_orig
.
Add
(
initTrack
);
cost_orig
.
Add
(
initTrack
);
cost_walk
.
Add
(
walkFull
);
cost_walk
.
Add
(
walkFull
);
if
(
m_mode
==
RM_Smart
||
m_mode
==
RM_Shove
)
if
(
m_mode
==
RM_Smart
||
m_mode
==
RM_Shove
)
{
{
PNS_LINE
l2
;
PNS_LINE
l2
;
bool
walk_better
=
cost_orig
.
IsBetter
(
cost_walk
,
1.5
,
10.0
);
bool
walk_better
=
cost_orig
.
IsBetter
(
cost_walk
,
1.5
,
10.0
);
walk_better
=
false
;
walk_better
=
false
;
#if 0
#if 0
printf("RtTrk width %d %d %d", initTrack.GetWidth(), walkFull.GetWidth(), walkSolids.GetWidth());
printf( "RtTrk width %d %d %d", initTrack.GetWidth(),
printf("init-coll %d\n", m_currentNode->CheckColliding(&initTrack)? 1: 0);
walkFull.GetWidth(), walkSolids.GetWidth() );
printf("total cost: walk cor %.0f len %.0f orig cor %.0f len %.0f walk-better %d\n",
printf( "init-coll %d\n", m_currentNode->CheckColliding( &initTrack ) ? 1 : 0 );
cost_walk.GetCornerCost(), cost_walk.GetLengthCost(),
printf( "total cost: walk cor %.0f len %.0f orig cor %.0f len %.0f walk-better %d\n",
cost_orig.GetCornerCost(), cost_orig.GetLengthCost(),
cost_walk.GetCornerCost(), cost_walk.GetLengthCost(),
walk_better );
cost_orig.GetCornerCost(), cost_orig.GetLengthCost(),
walk_better );
#endif
#endif
if
(
m_mode
==
RM_Smart
&&
wf
==
PNS_WALKAROUND
::
DONE
&&
walk_better
&&
walkFull
.
GetCLine
().
CPoint
(
-
1
)
==
initTrack
.
GetCLine
().
CPoint
(
-
1
))
if
(
m_mode
==
RM_Smart
&&
wf
==
PNS_WALKAROUND
::
DONE
&&
walk_better
l2
=
walkFull
;
&&
walkFull
.
GetCLine
().
CPoint
(
-
1
)
==
initTrack
.
GetCLine
().
CPoint
(
-
1
)
)
else
if
(
stat_solids
==
PNS_WALKAROUND
::
DONE
)
l2
=
walkFull
;
l2
=
walkSolids
;
else
if
(
stat_solids
==
PNS_WALKAROUND
::
DONE
)
else
l2
=
walkSolids
;
l2
=
initTrack
.
ClipToNearestObstacle
(
m_shove
->
GetCurrentNode
());
else
l2
=
initTrack
.
ClipToNearestObstacle
(
m_shove
->
GetCurrentNode
()
);
PNS_LINE
l
(
m_tail
);
l
.
GetLine
().
Append
(
l2
.
GetCLine
()
);
PNS_LINE
l
(
m_tail
);
l
.
GetLine
().
Simplify
();
l
.
GetLine
().
Append
(
l2
.
GetCLine
()
);
l
.
GetLine
().
Simplify
();
if
(
m_placingVia
)
{
if
(
m_placingVia
)
PNS_LAYERSET
allLayers
(
0
,
15
);
{
PNS_VIA
v1
(
l
.
GetCLine
().
CPoint
(
-
1
),
allLayers
,
m_viaDiameter
);
PNS_LAYERSET
allLayers
(
0
,
15
);
PNS_VIA
v2
(
l2
.
GetCLine
().
CPoint
(
-
1
),
allLayers
,
m_viaDiameter
);
PNS_VIA
v1
(
l
.
GetCLine
().
CPoint
(
-
1
),
allLayers
,
m_viaDiameter
);
v1
.
SetDrill
(
m_viaDrill
);
PNS_VIA
v2
(
l2
.
GetCLine
().
CPoint
(
-
1
),
allLayers
,
m_viaDiameter
);
v2
.
SetDrill
(
m_viaDrill
);
v1
.
SetDrill
(
m_viaDrill
);
v2
.
SetDrill
(
m_viaDrill
);
l
.
AppendVia
(
v1
);
l2
.
AppendVia
(
v2
);
l
.
AppendVia
(
v1
);
}
l2
.
AppendVia
(
v2
);
}
PNS_SHOVE
::
ShoveStatus
status
=
m_shove
->
ShoveLines
(
&
l
);
m_currentNode
=
m_shove
->
GetCurrentNode
();
PNS_SHOVE
::
ShoveStatus
status
=
m_shove
->
ShoveLines
(
&
l
);
m_currentNode
=
m_shove
->
GetCurrentNode
();
if
(
status
==
PNS_SHOVE
::
SH_OK
)
{
if
(
status
==
PNS_SHOVE
::
SH_OK
)
{
optimizer
.
SetWorld
(
m_currentNode
);
optimizer
.
SetWorld
(
m_currentNode
);
optimizer
.
ClearCache
();
optimizer
.
ClearCache
();
optimizer
.
SetEffortLevel
(
PNS_OPTIMIZER
::
MERGE_OBTUSE
|
PNS_OPTIMIZER
::
SMART_PADS
);
optimizer
.
SetEffortLevel
(
PNS_OPTIMIZER
::
MERGE_OBTUSE
|
PNS_OPTIMIZER
::
SMART_PADS
);
optimizer
.
SetCollisionMask
(
-
1
);
optimizer
.
SetCollisionMask
(
-
1
);
optimizer
.
Optimize
(
&
l2
);
optimizer
.
Optimize
(
&
l2
);
aNewHead
=
l2
;
aNewHead
=
l2
;
return
true
;
return
true
;
}
else
{
}
walkaround
.
SetWorld
(
m_currentNode
);
else
walkaround
.
SetSolidsOnly
(
false
);
{
walkaround
.
SetIterationLimit
(
10
);
walkaround
.
SetWorld
(
m_currentNode
);
walkaround
.
SetApproachCursor
(
true
,
aP
);
walkaround
.
SetSolidsOnly
(
false
);
walkaround
.
Route
(
initTrack
,
l2
);
walkaround
.
SetIterationLimit
(
10
);
aNewHead
=
l2
.
ClipToNearestObstacle
(
m_shove
->
GetCurrentNode
());
walkaround
.
SetApproachCursor
(
true
,
aP
);
//aNewHead = l2;
walkaround
.
Route
(
initTrack
,
l2
);
aNewHead
=
l2
.
ClipToNearestObstacle
(
m_shove
->
GetCurrentNode
()
);
return
false
;
// aNewHead = l2;
}
return
false
;
}
}
}
return
false
;
return
false
;
}
}
/**
* Function optimizeTailHeadTransition()
*
* Tries to reduce the corner count of the most recent part of tail/head by merging
* obtuse/collinear segments.
* @return true, if the line has been changed.
*/
bool
PNS_LINE_PLACER
::
optimizeTailHeadTransition
()
bool
PNS_LINE_PLACER
::
optimizeTailHeadTransition
()
{
{
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
head
=
m_head
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
SHAPE_LINE_CHAIN
&
tail
=
m_tail
.
GetLine
();
const
int
TailLookbackSegments
=
5
;
const
int
TailLookbackSegments
=
5
;
int
threshold
=
min
(
tail
.
PointCount
(),
TailLookbackSegments
+
1
);
if
(
tail
.
SegmentCount
()
<
3
)
return
false
;
// assemble TailLookbackSegments tail segments with the current head
int
threshold
=
min
(
tail
.
PointCount
(),
TailLookbackSegments
+
1
);
SHAPE_LINE_CHAIN
opt_line
=
tail
.
Slice
(
-
threshold
,
-
1
);
opt_line
.
Append
(
head
);
if
(
tail
.
SegmentCount
()
<
3
)
// opt_line.Simplify()
;
return
false
;
PNS_LINE
new_head
(
m_tail
,
opt_line
);
// assemble TailLookbackSegments tail segments with the current head
SHAPE_LINE_CHAIN
opt_line
=
tail
.
Slice
(
-
threshold
,
-
1
);
// and see if it could be made simpler by merging obtuse/collnear segments. If so,
// replace the (threshold) last tail points and the head with the optimized line
//if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS))
opt_line
.
Append
(
head
);
// opt_line.Simplify();
PNS_LINE
new_head
(
m_tail
,
opt_line
);
if
(
new_head
.
MergeSegments
())
// and see if it could be made simpler by merging obtuse/collnear segments.
{
// If so, replace the (threshold) last tail points and the head with
PNS_LINE
tmp
(
m_tail
,
opt_line
);
// the optimized line
TRACE
(
0
,
"Placer: optimize tail-head [%d]"
,
threshold
);
head
.
Clear
();
tail
.
Replace
(
-
threshold
,
-
1
,
new_head
.
GetCLine
());
tail
.
Simplify
();
m_p_start
=
new_head
.
GetCLine
().
CPoint
(
-
1
);
// if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS))
m_direction
=
DIRECTION_45
(
new_head
.
GetCLine
().
CSegment
(
-
1
));
return
true
;
if
(
new_head
.
MergeSegments
()
)
}
{
PNS_LINE
tmp
(
m_tail
,
opt_line
);
return
false
;
TRACE
(
0
,
"Placer: optimize tail-head [%d]"
,
threshold
);
}
/**
head
.
Clear
();
* Function routeStep()
tail
.
Replace
(
-
threshold
,
-
1
,
new_head
.
GetCLine
()
);
*
tail
.
Simplify
();
* Performs a single routing alorithm step, for the end point aP.
* @param aP ending point of current route
* @return true, if the line has been changed.
*/
m_p_start
=
new_head
.
GetCLine
().
CPoint
(
-
1
);
m_direction
=
DIRECTION_45
(
new_head
.
GetCLine
().
CSegment
(
-
1
)
);
void
PNS_LINE_PLACER
::
routeStep
(
const
VECTOR2I
&
aP
)
return
true
;
{
}
bool
fail
=
false
;
bool
go_back
=
false
;
return
false
;
int
i
,
n_iter
=
1
;
PNS_LINE
new_head
;
m_follow_mouse
=
true
;
TRACE
(
2
,
"INIT-DIR: %s head: %d, tail: %d segs
\n
"
,
m_initial_direction
.
Format
().
c_str
()
%
m_head
.
GetCLine
().
SegmentCount
()
%
m_tail
.
GetCLine
().
SegmentCount
());
for
(
i
=
0
;
i
<
n_iter
;
i
++
)
{
if
(
!
go_back
&&
m_follow_mouse
)
reduceTail
(
aP
);
go_back
=
false
;
if
(
!
routeHead
(
aP
,
new_head
,
true
))
fail
=
true
;
if
(
!
new_head
.
Is45Degree
())
fail
=
true
;
if
(
!
m_follow_mouse
)
return
;
m_head
=
new_head
;
if
(
handleSelfIntersections
())
{
n_iter
++
;
go_back
=
true
;
}
if
(
!
go_back
&&
handlePullback
())
{
n_iter
++
;
go_back
=
true
;
}
}
if
(
!
fail
)
{
if
(
optimizeTailHeadTransition
())
return
;
mergeHead
();
}
}
}
/**
* Function Route()
void
PNS_LINE_PLACER
::
routeStep
(
const
VECTOR2I
&
aP
)
*
* Re-routes the current track to point aP. Returns true, when routing has completed
* successfully (i.e. the trace end has reached point aP), and false if the trace was stuck somewhere
* on the way. May call routeStep() repetitively due to mouse smoothing.
* @param aP ending point of current route.
* @return true, if the routing is complete.
*/
bool
PNS_LINE_PLACER
::
Route
(
const
VECTOR2I
&
aP
)
{
{
if
(
m_smooth_mouse
)
bool
fail
=
false
;
{
bool
go_back
=
false
;
VECTOR2I
p_cur
=
m_p_start
;
VECTOR2I
step
=
(
aP
-
m_p_start
).
Resize
(
m_smoothing_step
);
int
i
,
n_iter
=
1
;
PNS_LINE
new_head
;
m_follow_mouse
=
true
;
TRACE
(
2
,
"INIT-DIR: %s head: %d, tail: %d segs
\n
"
,
m_initial_direction
.
Format
().
c_str
()
%
m_head
.
GetCLine
().
SegmentCount
()
%
m_tail
.
GetCLine
().
SegmentCount
()
);
for
(
i
=
0
;
i
<
n_iter
;
i
++
)
{
if
(
!
go_back
&&
m_follow_mouse
)
reduceTail
(
aP
);
go_back
=
false
;
if
(
!
routeHead
(
aP
,
new_head
,
true
)
)
fail
=
true
;
if
(
!
new_head
.
Is45Degree
()
)
fail
=
true
;
if
(
!
m_follow_mouse
)
return
;
m_head
=
new_head
;
do
if
(
handleSelfIntersections
()
)
{
{
if
((
p_cur
-
aP
).
EuclideanNorm
()
<=
m_smoothing_step
)
n_iter
++
;
p_cur
=
aP
;
go_back
=
true
;
else
}
p_cur
+=
step
;
routeStep
(
p_cur
);
if
(
!
go_back
&&
handlePullback
()
)
{
n_iter
++
;
go_back
=
true
;
}
}
}
while
(
p_cur
!=
aP
);
if
(
!
fail
)
}
else
{
routeStep
(
aP
);
if
(
optimizeTailHeadTransition
()
)
return
;
return
CurrentEnd
()
==
aP
;
mergeHead
();
}
}
bool
PNS_LINE_PLACER
::
Route
(
const
VECTOR2I
&
aP
)
{
if
(
m_smooth_mouse
)
{
VECTOR2I
p_cur
=
m_p_start
;
VECTOR2I
step
=
(
aP
-
m_p_start
).
Resize
(
m_smoothing_step
);
do
{
if
(
(
p_cur
-
aP
).
EuclideanNorm
()
<=
m_smoothing_step
)
p_cur
=
aP
;
else
p_cur
+=
step
;
routeStep
(
p_cur
);
}
while
(
p_cur
!=
aP
);
}
else
routeStep
(
aP
);
return
CurrentEnd
()
==
aP
;
}
}
const
PNS_LINE
PNS_LINE_PLACER
::
GetTrace
()
const
const
PNS_LINE
PNS_LINE_PLACER
::
GetTrace
()
const
{
{
PNS_LINE
tmp
(
m_head
);
PNS_LINE
tmp
(
m_head
);
tmp
.
SetShape
(
m_tail
.
GetCLine
()
);
tmp
.
GetLine
().
Append
(
m_head
.
GetCLine
()
);
tmp
.
SetShape
(
m_tail
.
GetCLine
()
);
tmp
.
GetLine
().
Simplify
();
tmp
.
GetLine
().
Append
(
m_head
.
GetCLine
()
);
return
tmp
;
tmp
.
GetLine
().
Simplify
();
return
tmp
;
}
}
void
PNS_LINE_PLACER
::
FlipPosture
()
void
PNS_LINE_PLACER
::
FlipPosture
()
{
{
m_initial_direction
=
m_initial_direction
.
Right
();
m_initial_direction
=
m_initial_direction
.
Right
();
m_direction
=
m_direction
.
Right
();
m_direction
=
m_direction
.
Right
();
}
}
void
PNS_LINE_PLACER
::
GetUpdatedItems
(
PNS_NODE
::
ItemVector
&
aRemoved
,
PNS_NODE
::
ItemVector
&
aAdded
)
void
PNS_LINE_PLACER
::
GetUpdatedItems
(
PNS_NODE
::
ItemVector
&
aRemoved
,
PNS_NODE
::
ItemVector
&
aAdded
)
{
{
return
m_shove
->
GetCurrentNode
()
->
GetUpdatedItems
(
aRemoved
,
aAdded
);
return
m_shove
->
GetCurrentNode
()
->
GetUpdatedItems
(
aRemoved
,
aAdded
);
}
}
PNS_NODE
*
PNS_LINE_PLACER
::
GetCurrentNode
()
const
PNS_NODE
*
PNS_LINE_PLACER
::
GetCurrentNode
()
const
{
{
return
m_shove
->
GetCurrentNode
();
return
m_shove
->
GetCurrentNode
();
}
}
\ No newline at end of file
pcbnew/router/pns_line_placer.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
#include "pns_via.h"
#include "pns_via.h"
#include "pns_line.h"
#include "pns_line.h"
#include "pns_routing_settings.h"
#include "pns_routing_settings.h"
class
PNS_ROUTER
;
class
PNS_ROUTER
;
class
PNS_SHOVE
;
class
PNS_SHOVE
;
class
PNS_OPTIMIZER
;
class
PNS_OPTIMIZER
;
...
@@ -39,118 +39,217 @@ class PNS_ROUTER_BASE;
...
@@ -39,118 +39,217 @@ class PNS_ROUTER_BASE;
/**
/**
* Class PNS_LINE_PLACER
* Class PNS_LINE_PLACER
*
*
* Interactively routes a single track. Runs shove and walkaround algorithms when needed.
* Interactively routes a single track. Runs shove and walkaround
* algorithms when needed.
*/
*/
class
PNS_LINE_PLACER
class
PNS_LINE_PLACER
{
{
public
:
public
:
PNS_LINE_PLACER
(
PNS_NODE
*
aWorld
);
PNS_LINE_PLACER
(
PNS_NODE
*
aWorld
);
~
PNS_LINE_PLACER
();
~
PNS_LINE_PLACER
();
///> Appends a via at the end of currently placed line.
///> Appends a via at the end of currently placed line.
void
AddVia
(
bool
aEnabled
,
int
aDiameter
,
int
aDrill
)
void
AddVia
(
bool
aEnabled
,
int
aDiameter
,
int
aDrill
)
{
{
m_viaDiameter
=
aDiameter
;
m_viaDiameter
=
aDiameter
;
m_viaDrill
=
aDrill
;
m_viaDrill
=
aDrill
;
m_placingVia
=
aEnabled
;
m_placingVia
=
aEnabled
;
}
}
///> Starts placement of a line at point aStart.
///> Starts placement of a line at point aStart.
void
StartPlacement
(
const
VECTOR2I
&
aStart
,
int
aNet
,
int
aWidth
,
int
aLayer
);
void
StartPlacement
(
const
VECTOR2I
&
aStart
,
int
aNet
,
int
aWidth
,
int
aLayer
);
///> Updates the routed line with a new ending point.
/**
bool
Route
(
const
VECTOR2I
&
aP
);
* Function Route()
*
///> Sets initial routing direction/posture
* Re-routes the current track to point aP. Returns true, when routing has
void
SetInitialDirection
(
const
DIRECTION_45
&
aDirection
);
* completed successfully (i.e. the trace end has reached point aP), and false
* if the trace was stuck somewhere on the way. May call routeStep()
void
ApplySettings
(
const
PNS_ROUTING_SETTINGS
&
aSettings
);
* repetitively due to mouse smoothing.
* @param aP ending point of current route.
///> Returns the "head" of the line being placed, that is the volatile part that has not been settled yet
* @return true, if the routing is complete.
const
PNS_LINE
&
GetHead
()
const
{
return
m_head
;
}
*/
///> Returns the "tail" of the line being placed the part that has been fixed already (follow mouse mode only)
bool
Route
(
const
VECTOR2I
&
aP
);
const
PNS_LINE
&
GetTail
()
const
{
return
m_tail
;
}
///> Sets initial routing direction/posture
///> Returns the whole routed line
void
SetInitialDirection
(
const
DIRECTION_45
&
aDirection
);
const
PNS_LINE
GetTrace
()
const
;
void
ApplySettings
(
const
PNS_ROUTING_SETTINGS
&
aSettings
);
///> Returns the current end of the line being placed. It may not be equal to the cursor position due to collisions.
const
VECTOR2I
&
CurrentEnd
()
const
///> Returns the "head" of the line being placed, that is the volatile part
{
///> that has not been settled yet
if
(
m_head
.
GetCLine
().
PointCount
()
>
0
)
const
PNS_LINE
&
GetHead
()
const
{
return
m_head
;
}
return
m_head
.
GetCLine
().
CPoint
(
-
1
);
///> Returns the "tail" of the line being placed the part that has been
else
if
(
m_tail
.
GetCLine
().
PointCount
()
>
0
)
///> fixed already (follow mouse mode only)
return
m_tail
.
GetCLine
().
CPoint
(
-
1
);
const
PNS_LINE
&
GetTail
()
const
{
return
m_tail
;
}
else
return
m_p_start
;
///> Returns the whole routed line
}
const
PNS_LINE
GetTrace
()
const
;
///> Returns the current end of the line being placed. It may not be equal
///> Returns all items in the world that have been affected by the routing operation. Used
///> to the cursor position due to collisions.
/// to update data structures of the host application
const
VECTOR2I
&
CurrentEnd
()
const
void
GetUpdatedItems
(
PNS_NODE
::
ItemVector
&
aRemoved
,
PNS_NODE
::
ItemVector
&
aAdded
);
{
if
(
m_head
.
GetCLine
().
PointCount
()
>
0
)
///> Toggles the current posture (straight/diagonal) of the trace head.
return
m_head
.
GetCLine
().
CPoint
(
-
1
);
void
FlipPosture
();
else
if
(
m_tail
.
GetCLine
().
PointCount
()
>
0
)
return
m_tail
.
GetCLine
().
CPoint
(
-
1
);
///> Returns the most recent world state
else
PNS_NODE
*
GetCurrentNode
()
const
;
return
m_p_start
;
}
private
:
///> Returns all items in the world that have been affected by the routing
static
const
double
m_shoveLengthThreshold
=
1
.
7
;
///> operation. Used to update data structures of the host application
void
GetUpdatedItems
(
PNS_NODE
::
ItemVector
&
aRemoved
,
bool
handleViaPlacement
(
PNS_LINE
&
aHead
);
PNS_NODE
::
ItemVector
&
aAdded
);
bool
checkObtusity
(
const
SEG
&
a
,
const
SEG
&
b
)
const
;
///> Toggles the current posture (straight/diagonal) of the trace head.
bool
handleSelfIntersections
();
void
FlipPosture
();
bool
handlePullback
();
bool
mergeHead
();
///> Returns the most recent world state
bool
reduceTail
(
const
VECTOR2I
&
aEnd
);
PNS_NODE
*
GetCurrentNode
()
const
;
void
fixHeadPosture
();
bool
optimizeTailHeadTransition
();
private
:
static
const
double
m_shoveLengthThreshold
=
1
.
7
;
bool
routeHead
(
const
VECTOR2I
&
aP
,
PNS_LINE
&
aNewHead
,
bool
aCwWalkaround
=
true
);
void
routeStep
(
const
VECTOR2I
&
aP
);
bool
handleViaPlacement
(
PNS_LINE
&
aHead
);
///> routing mode (walkaround, shove, etc.)
/**
PNS_MODE
m_mode
;
* Function checkObtusity()
///> follow mouse trail by attaching new segments to the head as the cursor moves
*
bool
m_follow_mouse
;
* Helper that checks if segments a and b form an obtuse angle
///> mouse smoothing active
* (in 45-degree regime).
bool
m_smooth_mouse
;
* @return true, if angle (a, b) is obtuse
///> mouse smoothing step (in world units)
*/
int
m_smoothing_step
;
bool
checkObtusity
(
const
SEG
&
a
,
const
SEG
&
b
)
const
;
///> current routing direction
DIRECTION_45
m_direction
;
/**
///> routing direction for new traces
* Function handleSelfIntersections()
DIRECTION_45
m_initial_direction
;
*
///> routing "head": volatile part of the track from the previously
* Checks if the head of the track intersects its tail. If so, cuts the
/// analyzed point to the current routing destination
* tail up to the intersecting segment and fixes the head direction to match
PNS_LINE
m_head
;
* the last segment before the cut.
///> routing "tail": part of the track that has been already fixed due to collisions with obstacles
* @return true if the line has been changed.
PNS_LINE
m_tail
;
*/
///> current algorithm iteration
bool
handleSelfIntersections
();
int
m_iteration
;
///> pointer to world to search colliding items
/**
PNS_NODE
*
m_world
;
* Function handlePullback()
///> current routing start point (end of tail, beginning of head)
*
VECTOR2I
m_p_start
;
* Deals with pull-back: reduces the tail if head trace is moved backwards
///> The shove engine
* wrs to the current tail direction.
PNS_SHOVE
*
m_shove
;
* @return true if the line has been changed.
///> Current world state
*/
PNS_NODE
*
m_currentNode
;
bool
handlePullback
();
///> Are we placing a via?
bool
m_placingVia
;
/**
///> current via diameter
* Function mergeHead()
int
m_viaDiameter
;
*
///> current via drill
* Moves "estabished" segments from the head to the tail if certain
int
m_viaDrill
;
* conditions are met.
///> walkaround algorithm iteration limit
* @return true, if the line has been changed.
int
m_walkaroundIterationLimit
;
*/
///> smart pads optimizer enabled.
bool
mergeHead
();
bool
m_smartPads
;
/**
* Function reduceTail()
*
* Attempts to reduce the numer of segments in the tail by trying to replace a
* certain number of latest tail segments with a direct trace leading to aEnd
* that does not collide with anything.
* @param aEnd: current routing destination point.
* @return true if the line has been changed.
*/
bool
reduceTail
(
const
VECTOR2I
&
aEnd
);
void
fixHeadPosture
();
/**
* Function optimizeTailHeadTransition()
*
* Tries to reduce the corner count of the most recent part of tail/head by
* merging obtuse/collinear segments.
* @return true, if the line has been changed.
*/
bool
optimizeTailHeadTransition
();
/**
* Function routeHead()
*
* Computes the head trace between the current start point (m_p_start) and
* point aP, starting with direction defined in m_direction. The trace walks
* around all colliding solid or non-movable items. Movable segments are
* ignored, as they'll be handled later by the shove algorithm.
*/
bool
routeHead
(
const
VECTOR2I
&
aP
,
PNS_LINE
&
aNewHead
,
bool
aCwWalkaround
=
true
);
/**
* Function routeStep()
*
* Performs a single routing alorithm step, for the end point aP.
* @param aP ending point of current route
* @return true, if the line has been changed.
*/
void
routeStep
(
const
VECTOR2I
&
aP
);
///> routing mode (walkaround, shove, etc.)
PNS_MODE
m_mode
;
///> follow mouse trail by attaching new segments to the head
///> as the cursor moves
bool
m_follow_mouse
;
///> mouse smoothing active
bool
m_smooth_mouse
;
///> mouse smoothing step (in world units)
int
m_smoothing_step
;
///> current routing direction
DIRECTION_45
m_direction
;
///> routing direction for new traces
DIRECTION_45
m_initial_direction
;
///> routing "head": volatile part of the track from the previously
/// analyzed point to the current routing destination
PNS_LINE
m_head
;
///> routing "tail": part of the track that has been already fixed due to collisions with obstacles
PNS_LINE
m_tail
;
///> current algorithm iteration
int
m_iteration
;
///> pointer to world to search colliding items
PNS_NODE
*
m_world
;
///> current routing start point (end of tail, beginning of head)
VECTOR2I
m_p_start
;
///> The shove engine
PNS_SHOVE
*
m_shove
;
///> Current world state
PNS_NODE
*
m_currentNode
;
///> Are we placing a via?
bool
m_placingVia
;
///> current via diameter
int
m_viaDiameter
;
///> current via drill
int
m_viaDrill
;
///> walkaround algorithm iteration limit
int
m_walkaroundIterationLimit
;
///> smart pads optimizer enabled.
bool
m_smartPads
;
};
};
#endif // __PNS_LINE_PLACER_H
#endif // __PNS_LINE_PLACER_H
pcbnew/router/pns_node.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -42,860 +42,946 @@ using namespace std;
...
@@ -42,860 +42,946 @@ using namespace std;
using
boost
::
unordered_set
;
using
boost
::
unordered_set
;
using
boost
::
unordered_map
;
using
boost
::
unordered_map
;
static
boost
::
unordered_set
<
PNS_NODE
*>
allocNodes
;
static
boost
::
unordered_set
<
PNS_NODE
*>
allocNodes
;
PNS_NODE
::
PNS_NODE
()
PNS_NODE
::
PNS_NODE
()
{
{
//
printf("MakeNode [%p, total = %d]\n", this, allocNodes.size());
//
printf("MakeNode [%p, total = %d]\n", this, allocNodes.size());
m_root
=
this
;
m_root
=
this
;
m_parent
=
NULL
;
m_parent
=
NULL
;
m_maxClearance
=
800000
;
// fixme: depends on how thick traces are.
m_maxClearance
=
800000
;
// fixme: depends on how thick traces are.
m_index
=
new
PNS_INDEX
;
m_index
=
new
PNS_INDEX
;
allocNodes
.
insert
(
this
);
allocNodes
.
insert
(
this
);
}
}
PNS_NODE
::~
PNS_NODE
()
PNS_NODE
::~
PNS_NODE
()
{
{
if
(
!
m_children
.
empty
()
)
if
(
!
m_children
.
empty
()
)
{
{
TRACEn
(
0
,
"attempting to free a node that has kids.
\n
"
);
TRACEn
(
0
,
"attempting to free a node that has kids.
\n
"
);
assert
(
false
);
assert
(
false
);
}
}
if
(
allocNodes
.
find
(
this
)
==
allocNodes
.
end
()
)
if
(
allocNodes
.
find
(
this
)
==
allocNodes
.
end
()
)
{
{
TRACEn
(
0
,
"attempting to free an already-free'd node.
\n
"
);
TRACEn
(
0
,
"attempting to free an already-free'd node.
\n
"
);
assert
(
false
);
assert
(
false
);
}
}
allocNodes
.
erase
(
this
);
allocNodes
.
erase
(
this
);
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
m_index
->
begin
();
i
!=
m_index
->
end
();
++
i
)
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
m_index
->
begin
();
if
(
(
*
i
)
->
BelongsTo
(
this
))
i
!=
m_index
->
end
();
++
i
)
delete
*
i
;
if
(
(
*
i
)
->
BelongsTo
(
this
)
)
delete
*
i
;
unlinkParent
();
unlinkParent
();
delete
m_index
;
delete
m_index
;
}
}
int
PNS_NODE
::
GetClearance
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
const
int
PNS_NODE
::
GetClearance
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
const
{
{
int
clearance
=
(
*
m_clearanceFunctor
)
(
a
,
b
);
int
clearance
=
(
*
m_clearanceFunctor
)(
a
,
b
);
if
(
a
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
if
(
a
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
clearance
+=
static_cast
<
const
PNS_SEGMENT
*>
(
a
)
->
GetWidth
()
/
2
;
clearance
+=
static_cast
<
const
PNS_SEGMENT
*>
(
a
)
->
GetWidth
()
/
2
;
if
(
a
->
OfKind
(
PNS_ITEM
::
LINE
)
)
if
(
a
->
OfKind
(
PNS_ITEM
::
LINE
)
)
clearance
+=
static_cast
<
const
PNS_LINE
*>
(
a
)
->
GetWidth
()
/
2
;
clearance
+=
static_cast
<
const
PNS_LINE
*>
(
a
)
->
GetWidth
()
/
2
;
if
(
b
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
if
(
b
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
clearance
+=
static_cast
<
const
PNS_SEGMENT
*>
(
b
)
->
GetWidth
()
/
2
;
clearance
+=
static_cast
<
const
PNS_SEGMENT
*>
(
b
)
->
GetWidth
()
/
2
;
if
(
b
->
OfKind
(
PNS_ITEM
::
LINE
)
)
if
(
b
->
OfKind
(
PNS_ITEM
::
LINE
)
)
clearance
+=
static_cast
<
const
PNS_LINE
*>
(
b
)
->
GetWidth
()
/
2
;
clearance
+=
static_cast
<
const
PNS_LINE
*>
(
b
)
->
GetWidth
()
/
2
;
return
clearance
;
return
clearance
;
}
}
PNS_NODE
*
PNS_NODE
::
Branch
()
PNS_NODE
*
PNS_NODE
::
Branch
()
{
{
PNS_NODE
*
child
=
new
PNS_NODE
;
PNS_NODE
*
child
=
new
PNS_NODE
;
m_children
.
push_back
(
child
);
child
->
m_parent
=
this
;
child
->
m_clearanceFunctor
=
m_clearanceFunctor
;
child
->
m_root
=
isRoot
()
?
this
:
m_root
;
// immmediate offspring of the root branch needs not copy anything. For the rest,
// deep-copy joints, overridden item map and pointers to stored items.
if
(
!
isRoot
())
{
JointMap
::
iterator
j
;
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
m_index
->
begin
();
i
!=
m_index
->
end
();
++
i
)
child
->
m_index
->
Add
(
*
i
);
child
->
m_joints
=
m_joints
;
child
->
m_override
=
m_override
;
}
TRACE
(
2
,
"%d items, %d joints, %d overrides"
,
child
->
m_index
->
Size
()
%
child
->
m_joints
.
size
()
%
child
->
m_override
.
size
());
return
child
;
}
void
PNS_NODE
::
unlinkParent
(
)
{
if
(
isRoot
()
)
return
;
for
(
vector
<
PNS_NODE
*>::
iterator
i
=
m_parent
->
m_children
.
begin
();
i
!=
m_parent
->
m_children
.
end
();
++
i
)
{
if
(
*
i
==
this
)
{
m_parent
->
m_children
.
erase
(
i
);
return
;
}
}
}
// function object that visits potential obstacles and performs the actual collision refining
struct
PNS_NODE
::
obstacleVisitor
{
///> node we are searching in (either root or a branch)
PNS_NODE
*
m_node
;
///> node that overrides root entries
PNS_NODE
*
m_override
;
///> list of encountered obstacles
Obstacles
&
m_tab
;
///> the item we are looking for collisions with
const
PNS_ITEM
*
m_item
;
///> acccepted kinds of colliding items (solids, vias, segments, etc...)
int
m_kindMask
;
///> max number of hits
int
m_limitCount
;
///> number of items found so far
int
m_matchCount
;
obstacleVisitor
(
PNS_NODE
::
Obstacles
&
aTab
,
const
PNS_ITEM
*
aItem
,
int
aKindMask
)
:
m_tab
(
aTab
),
m_item
(
aItem
),
m_kindMask
(
aKindMask
),
m_limitCount
(
-
1
),
m_matchCount
(
0
)
{
};
void
SetCountLimit
(
int
aLimit
)
{
m_limitCount
=
aLimit
;
}
void
SetWorld
(
PNS_NODE
*
aNode
,
PNS_NODE
*
aOverride
=
NULL
)
{
m_node
=
aNode
;
m_override
=
aOverride
;
}
bool
operator
()(
PNS_ITEM
*
aItem
)
{
if
(
!
aItem
->
OfKind
(
m_kindMask
))
return
true
;
// check if there is a more recent branch with a newer (possibily modified) version of this item.
if
(
m_override
&&
m_override
->
overrides
(
aItem
)
)
return
true
;
int
clearance
=
m_node
->
GetClearance
(
aItem
,
m_item
);
if
(
!
aItem
->
Collide
(
m_item
,
clearance
))
return
true
;
PNS_OBSTACLE
obs
;
obs
.
item
=
aItem
;
m_tab
.
push_back
(
obs
);
m_matchCount
++
;
if
(
m_limitCount
>
0
&&
m_matchCount
>=
m_limitCount
)
return
false
;
return
true
;
};
};
int
PNS_NODE
::
QueryColliding
(
const
PNS_ITEM
*
aItem
,
PNS_NODE
::
Obstacles
&
aObstacles
,
int
aKindMask
,
int
aLimitCount
)
{
obstacleVisitor
visitor
(
aObstacles
,
aItem
,
aKindMask
);
assert
(
allocNodes
.
find
(
this
)
!=
allocNodes
.
end
());
visitor
.
SetCountLimit
(
aLimitCount
);
visitor
.
SetWorld
(
this
,
NULL
);
// first, look for colliding items ourselves
m_index
->
Query
(
aItem
,
m_maxClearance
,
visitor
);
// if we haven't found enough items, look in the root branch as well.
if
(
!
isRoot
()
&&
(
visitor
.
m_matchCount
<
aLimitCount
||
aLimitCount
<
0
)
)
{
visitor
.
SetWorld
(
m_root
,
this
);
m_root
->
m_index
->
Query
(
aItem
,
m_maxClearance
,
visitor
);
}
return
aObstacles
.
size
();
}
PNS_NODE
::
OptObstacle
PNS_NODE
::
NearestObstacle
(
const
PNS_LINE
*
aItem
,
int
aKindMask
)
{
Obstacles
obs_list
;
bool
found_isects
=
false
;
const
SHAPE_LINE_CHAIN
&
line
=
aItem
->
GetCLine
();
obs_list
.
reserve
(
100
);
int
n
=
0
;
for
(
int
i
=
0
;
i
<
line
.
SegmentCount
();
i
++
)
{
const
PNS_SEGMENT
s
(
*
aItem
,
line
.
CSegment
(
i
));
n
+=
QueryColliding
(
&
s
,
obs_list
,
aKindMask
);
}
if
(
aItem
->
EndsWithVia
()
)
n
+=
QueryColliding
(
&
aItem
->
GetVia
(),
obs_list
,
aKindMask
);
//if(! QueryColliding ( aItem, obs_list, aKindMask ))
if
(
!
n
)
return
OptObstacle
();
PNS_LINE
&
aLine
=
(
PNS_LINE
&
)
*
aItem
;
PNS_OBSTACLE
nearest
;
nearest
.
item
=
NULL
;
nearest
.
dist_first
=
INT_MAX
;
BOOST_FOREACH
(
PNS_OBSTACLE
obs
,
obs_list
)
{
VECTOR2I
ip_first
,
ip_last
;
int
dist_max
=
INT_MIN
;
vector
<
SHAPE_LINE_CHAIN
::
Intersection
>
isect_list
;
int
clearance
=
GetClearance
(
obs
.
item
,
&
aLine
);
SHAPE_LINE_CHAIN
hull
=
obs
.
item
->
Hull
(
clearance
);
if
(
aLine
.
EndsWithVia
())
{
int
clearance
=
GetClearance
(
obs
.
item
,
&
aLine
.
GetVia
());
SHAPE_LINE_CHAIN
viaHull
=
aLine
.
GetVia
().
Hull
(
clearance
);
viaHull
.
Intersect
(
hull
,
isect_list
);
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
::
Intersection
isect
,
isect_list
)
{
int
dist
=
aLine
.
GetCLine
().
Length
()
+
(
isect
.
p
-
aLine
.
GetVia
().
GetPos
()).
EuclideanNorm
();
if
(
dist
<
nearest
.
dist_first
)
{
found_isects
=
true
;
nearest
.
dist_first
=
dist
;
nearest
.
ip_first
=
isect
.
p
;
nearest
.
item
=
obs
.
item
;
nearest
.
hull
=
hull
;
}
if
(
dist
>
dist_max
)
{
dist_max
=
dist
;
ip_last
=
isect
.
p
;
}
}
}
isect_list
.
clear
();
m_children
.
push_back
(
child
);
hull
.
Intersect
(
aLine
.
GetCLine
(),
isect_list
);
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
::
Intersection
isect
,
isect_list
)
{
int
dist
=
aLine
.
GetCLine
().
PathLength
(
isect
.
p
);
child
->
m_parent
=
this
;
child
->
m_clearanceFunctor
=
m_clearanceFunctor
;
child
->
m_root
=
isRoot
()
?
this
:
m_root
;
if
(
dist
<
nearest
.
dist_first
)
// immmediate offspring of the root branch needs not copy anything.
{
// For the rest, deep-copy joints, overridden item map and pointers
found_isects
=
true
;
// to stored items.
nearest
.
dist_first
=
dist
;
if
(
!
isRoot
()
)
nearest
.
ip_first
=
isect
.
p
;
{
nearest
.
item
=
obs
.
item
;
JointMap
::
iterator
j
;
nearest
.
hull
=
hull
;
}
if
(
dist
>
dist_max
)
{
dist_max
=
dist
;
ip_last
=
isect
.
p
;
}
}
nearest
.
ip_last
=
ip_last
;
nearest
.
dist_last
=
dist_max
;
}
return
found_isects
?
nearest
:
OptObstacle
();
}
PNS_NODE
::
OptObstacle
PNS_NODE
::
CheckColliding
(
const
PNS_ITEM
*
aItemA
,
int
aKindMask
)
{
Obstacles
obs
;
obs
.
reserve
(
100
);
if
(
aItemA
->
GetKind
()
==
PNS_ITEM
::
LINE
)
{
int
n
=
0
;
const
PNS_LINE
*
line
=
static_cast
<
const
PNS_LINE
*>
(
aItemA
);
const
SHAPE_LINE_CHAIN
&
l
=
line
->
GetCLine
();
for
(
int
i
=
0
;
i
<
l
.
SegmentCount
();
i
++
)
{
const
PNS_SEGMENT
s
(
*
line
,
l
.
CSegment
(
i
));
n
+=
QueryColliding
(
&
s
,
obs
,
aKindMask
,
1
);
if
(
n
)
return
OptObstacle
(
obs
[
0
]);
}
if
(
line
->
EndsWithVia
()
)
{
n
+=
QueryColliding
(
&
line
->
GetVia
(),
obs
,
aKindMask
,
1
);
if
(
n
)
return
OptObstacle
(
obs
[
0
]);
}
}
else
if
(
QueryColliding
(
aItemA
,
obs
,
aKindMask
,
1
)
>
0
)
return
OptObstacle
(
obs
[
0
]);
return
OptObstacle
();
}
bool
PNS_NODE
::
CheckColliding
(
const
PNS_ITEM
*
aItemA
,
const
PNS_ITEM
*
aItemB
,
int
aKindMask
)
{
Obstacles
dummy
;
assert
(
aItemB
);
// return QueryColliding(aItemA, dummy, aKindMask, 1) > 0;
return
aItemA
->
Collide
(
aItemB
,
GetClearance
(
aItemA
,
aItemB
));
}
struct
hitVisitor
{
PNS_ITEMSET
&
m_items
;
const
VECTOR2I
&
m_point
;
PNS_NODE
*
m_world
;
hitVisitor
(
PNS_ITEMSET
&
aTab
,
const
VECTOR2I
&
aPoint
,
PNS_NODE
*
aWorld
)
:
m_items
(
aTab
),
m_point
(
aPoint
),
m_world
(
aWorld
)
{
};
bool
operator
()(
PNS_ITEM
*
aItem
)
{
SHAPE_CIRCLE
cp
(
m_point
,
0
);
int
cl
=
0
;
if
(
aItem
->
GetKind
()
==
PNS_ITEM
::
SEGMENT
)
cl
+=
static_cast
<
PNS_SEGMENT
*>
(
aItem
)
->
GetWidth
()
/
2
;
if
(
aItem
->
GetShape
()
->
Collide
(
&
cp
,
cl
))
m_items
.
Add
(
aItem
);
return
true
;
}
};
const
PNS_ITEMSET
PNS_NODE
::
HitTest
(
const
VECTOR2I
&
aPoint
)
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
m_index
->
begin
();
i
!=
m_index
->
end
();
++
i
)
child
->
m_index
->
Add
(
*
i
);
child
->
m_joints
=
m_joints
;
child
->
m_override
=
m_override
;
}
TRACE
(
2
,
"%d items, %d joints, %d overrides"
,
child
->
m_index
->
Size
()
%
child
->
m_joints
.
size
()
%
child
->
m_override
.
size
()
);
return
child
;
}
void
PNS_NODE
::
unlinkParent
()
{
if
(
isRoot
()
)
return
;
for
(
vector
<
PNS_NODE
*>::
iterator
i
=
m_parent
->
m_children
.
begin
();
i
!=
m_parent
->
m_children
.
end
();
++
i
)
{
if
(
*
i
==
this
)
{
m_parent
->
m_children
.
erase
(
i
);
return
;
}
}
}
// function object that visits potential obstacles and performs
// the actual collision refining
struct
PNS_NODE
::
obstacleVisitor
{
///> node we are searching in (either root or a branch)
PNS_NODE
*
m_node
;
///> node that overrides root entries
PNS_NODE
*
m_override
;
///> list of encountered obstacles
Obstacles
&
m_tab
;
///> the item we are looking for collisions with
const
PNS_ITEM
*
m_item
;
///> acccepted kinds of colliding items (solids, vias, segments, etc...)
int
m_kindMask
;
///> max number of hits
int
m_limitCount
;
///> number of items found so far
int
m_matchCount
;
obstacleVisitor
(
PNS_NODE
::
Obstacles
&
aTab
,
const
PNS_ITEM
*
aItem
,
int
aKindMask
)
:
m_tab
(
aTab
),
m_item
(
aItem
),
m_kindMask
(
aKindMask
),
m_limitCount
(
-
1
),
m_matchCount
(
0
)
{};
void
SetCountLimit
(
int
aLimit
)
{
m_limitCount
=
aLimit
;
}
void
SetWorld
(
PNS_NODE
*
aNode
,
PNS_NODE
*
aOverride
=
NULL
)
{
m_node
=
aNode
;
m_override
=
aOverride
;
}
bool
operator
()(
PNS_ITEM
*
aItem
)
{
if
(
!
aItem
->
OfKind
(
m_kindMask
)
)
return
true
;
// check if there is a more recent branch with a newer
// (possibily modified) version of this item.
if
(
m_override
&&
m_override
->
overrides
(
aItem
)
)
return
true
;
int
clearance
=
m_node
->
GetClearance
(
aItem
,
m_item
);
if
(
!
aItem
->
Collide
(
m_item
,
clearance
)
)
return
true
;
PNS_OBSTACLE
obs
;
obs
.
item
=
aItem
;
m_tab
.
push_back
(
obs
);
m_matchCount
++
;
if
(
m_limitCount
>
0
&&
m_matchCount
>=
m_limitCount
)
return
false
;
return
true
;
};
};
int
PNS_NODE
::
QueryColliding
(
const
PNS_ITEM
*
aItem
,
PNS_NODE
::
Obstacles
&
aObstacles
,
int
aKindMask
,
int
aLimitCount
)
{
obstacleVisitor
visitor
(
aObstacles
,
aItem
,
aKindMask
);
assert
(
allocNodes
.
find
(
this
)
!=
allocNodes
.
end
()
);
visitor
.
SetCountLimit
(
aLimitCount
);
visitor
.
SetWorld
(
this
,
NULL
);
// first, look for colliding items ourselves
m_index
->
Query
(
aItem
,
m_maxClearance
,
visitor
);
// if we haven't found enough items, look in the root branch as well.
if
(
!
isRoot
()
&&
(
visitor
.
m_matchCount
<
aLimitCount
||
aLimitCount
<
0
)
)
{
visitor
.
SetWorld
(
m_root
,
this
);
m_root
->
m_index
->
Query
(
aItem
,
m_maxClearance
,
visitor
);
}
return
aObstacles
.
size
();
}
PNS_NODE
::
OptObstacle
PNS_NODE
::
NearestObstacle
(
const
PNS_LINE
*
aItem
,
int
aKindMask
)
{
{
PNS_ITEMSET
items
;
Obstacles
obs_list
;
SHAPE_CIRCLE
s
(
aPoint
,
0
);
// fixme: we treat a point as an infinitely small circle - this is inefficient.
bool
found_isects
=
false
;
hitVisitor
visitor
(
items
,
aPoint
,
this
);
const
SHAPE_LINE_CHAIN
&
line
=
aItem
->
GetCLine
();
m_index
->
Query
(
&
s
,
m_maxClearance
,
visitor
);
obs_list
.
reserve
(
100
);
if
(
!
isRoot
()
)
// fixme: could be made cleaner
{
int
n
=
0
;
PNS_ITEMSET
items_root
;
hitVisitor
visitor_root
(
items_root
,
aPoint
,
m_root
);
for
(
int
i
=
0
;
i
<
line
.
SegmentCount
();
i
++
)
m_root
->
m_index
->
Query
(
&
s
,
m_maxClearance
,
visitor_root
);
{
const
PNS_SEGMENT
s
(
*
aItem
,
line
.
CSegment
(
i
)
);
n
+=
QueryColliding
(
&
s
,
obs_list
,
aKindMask
);
}
if
(
aItem
->
EndsWithVia
()
)
n
+=
QueryColliding
(
&
aItem
->
GetVia
(),
obs_list
,
aKindMask
);
// if(! QueryColliding ( aItem, obs_list, aKindMask ))
if
(
!
n
)
return
OptObstacle
();
PNS_LINE
&
aLine
=
(
PNS_LINE
&
)
*
aItem
;
PNS_OBSTACLE
nearest
;
nearest
.
item
=
NULL
;
nearest
.
dist_first
=
INT_MAX
;
BOOST_FOREACH
(
PNS_OBSTACLE
obs
,
obs_list
)
{
VECTOR2I
ip_first
,
ip_last
;
int
dist_max
=
INT_MIN
;
vector
<
SHAPE_LINE_CHAIN
::
Intersection
>
isect_list
;
int
clearance
=
GetClearance
(
obs
.
item
,
&
aLine
);
SHAPE_LINE_CHAIN
hull
=
obs
.
item
->
Hull
(
clearance
);
if
(
aLine
.
EndsWithVia
()
)
{
int
clearance
=
GetClearance
(
obs
.
item
,
&
aLine
.
GetVia
()
);
SHAPE_LINE_CHAIN
viaHull
=
aLine
.
GetVia
().
Hull
(
clearance
);
viaHull
.
Intersect
(
hull
,
isect_list
);
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
::
Intersection
isect
,
isect_list
)
{
int
dist
=
aLine
.
GetCLine
().
Length
()
+
(
isect
.
p
-
aLine
.
GetVia
().
GetPos
()
).
EuclideanNorm
();
if
(
dist
<
nearest
.
dist_first
)
{
found_isects
=
true
;
nearest
.
dist_first
=
dist
;
nearest
.
ip_first
=
isect
.
p
;
nearest
.
item
=
obs
.
item
;
nearest
.
hull
=
hull
;
}
if
(
dist
>
dist_max
)
{
dist_max
=
dist
;
ip_last
=
isect
.
p
;
}
}
}
isect_list
.
clear
();
hull
.
Intersect
(
aLine
.
GetCLine
(),
isect_list
);
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
::
Intersection
isect
,
isect_list
)
{
int
dist
=
aLine
.
GetCLine
().
PathLength
(
isect
.
p
);
BOOST_FOREACH
(
PNS_ITEM
*
item
,
items_root
.
Items
())
if
(
dist
<
nearest
.
dist_first
)
{
{
if
(
!
overrides
(
item
))
found_isects
=
true
;
items
.
Add
(
item
);
nearest
.
dist_first
=
dist
;
}
nearest
.
ip_first
=
isect
.
p
;
}
nearest
.
item
=
obs
.
item
;
nearest
.
hull
=
hull
;
}
return
items
;
if
(
dist
>
dist_max
)
{
dist_max
=
dist
;
ip_last
=
isect
.
p
;
}
}
nearest
.
ip_last
=
ip_last
;
nearest
.
dist_last
=
dist_max
;
}
return
found_isects
?
nearest
:
OptObstacle
();
}
}
void
PNS_NODE
::
addSolid
(
PNS_SOLID
*
aSolid
)
PNS_NODE
::
OptObstacle
PNS_NODE
::
CheckColliding
(
const
PNS_ITEM
*
aItemA
,
int
aKindMask
)
{
{
linkJoint
(
aSolid
->
GetCenter
(),
aSolid
->
GetLayers
(),
aSolid
->
GetNet
(),
aSolid
);
Obstacles
obs
;
m_index
->
Add
(
aSolid
);
obs
.
reserve
(
100
);
if
(
aItemA
->
GetKind
()
==
PNS_ITEM
::
LINE
)
{
int
n
=
0
;
const
PNS_LINE
*
line
=
static_cast
<
const
PNS_LINE
*>
(
aItemA
);
const
SHAPE_LINE_CHAIN
&
l
=
line
->
GetCLine
();
for
(
int
i
=
0
;
i
<
l
.
SegmentCount
();
i
++
)
{
const
PNS_SEGMENT
s
(
*
line
,
l
.
CSegment
(
i
)
);
n
+=
QueryColliding
(
&
s
,
obs
,
aKindMask
,
1
);
if
(
n
)
return
OptObstacle
(
obs
[
0
]
);
}
if
(
line
->
EndsWithVia
()
)
{
n
+=
QueryColliding
(
&
line
->
GetVia
(),
obs
,
aKindMask
,
1
);
if
(
n
)
return
OptObstacle
(
obs
[
0
]
);
}
}
else
if
(
QueryColliding
(
aItemA
,
obs
,
aKindMask
,
1
)
>
0
)
return
OptObstacle
(
obs
[
0
]
);
return
OptObstacle
();
}
}
void
PNS_NODE
::
addVia
(
PNS_VIA
*
aVia
)
bool
PNS_NODE
::
CheckColliding
(
const
PNS_ITEM
*
aItemA
,
const
PNS_ITEM
*
aItemB
,
int
aKindMask
)
{
{
linkJoint
(
aVia
->
GetPos
(),
aVia
->
GetLayers
(),
aVia
->
GetNet
(),
aVia
);
Obstacles
dummy
;
m_index
->
Add
(
aVia
);
assert
(
aItemB
);
// return QueryColliding(aItemA, dummy, aKindMask, 1) > 0;
return
aItemA
->
Collide
(
aItemB
,
GetClearance
(
aItemA
,
aItemB
)
);
}
}
void
PNS_NODE
::
addLine
(
PNS_LINE
*
aLine
)
struct
hitVisitor
{
PNS_ITEMSET
&
m_items
;
const
VECTOR2I
&
m_point
;
PNS_NODE
*
m_world
;
hitVisitor
(
PNS_ITEMSET
&
aTab
,
const
VECTOR2I
&
aPoint
,
PNS_NODE
*
aWorld
)
:
m_items
(
aTab
),
m_point
(
aPoint
),
m_world
(
aWorld
)
{};
bool
operator
()(
PNS_ITEM
*
aItem
)
{
SHAPE_CIRCLE
cp
(
m_point
,
0
);
int
cl
=
0
;
if
(
aItem
->
GetKind
()
==
PNS_ITEM
::
SEGMENT
)
cl
+=
static_cast
<
PNS_SEGMENT
*>
(
aItem
)
->
GetWidth
()
/
2
;
if
(
aItem
->
GetShape
()
->
Collide
(
&
cp
,
cl
)
)
m_items
.
Add
(
aItem
);
return
true
;
}
};
const
PNS_ITEMSET
PNS_NODE
::
HitTest
(
const
VECTOR2I
&
aPoint
)
{
{
const
SHAPE_LINE_CHAIN
&
l
=
aLine
->
GetLine
();
PNS_ITEMSET
items
;
// fixme: we treat a point as an infinitely small circle - this is inefficient.
SHAPE_CIRCLE
s
(
aPoint
,
0
);
hitVisitor
visitor
(
items
,
aPoint
,
this
);
m_index
->
Query
(
&
s
,
m_maxClearance
,
visitor
);
if
(
!
isRoot
()
)
// fixme: could be made cleaner
{
PNS_ITEMSET
items_root
;
hitVisitor
visitor_root
(
items_root
,
aPoint
,
m_root
);
m_root
->
m_index
->
Query
(
&
s
,
m_maxClearance
,
visitor_root
);
for
(
int
i
=
0
;
i
<
l
.
SegmentCount
();
i
++
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
items_root
.
Items
()
)
{
{
SEG
s
=
l
.
CSegment
(
i
);
if
(
!
overrides
(
item
)
)
items
.
Add
(
item
);
}
}
if
(
s
.
a
!=
s
.
b
)
return
items
;
{
}
PNS_SEGMENT
*
pseg
=
new
PNS_SEGMENT
(
*
aLine
,
s
);
pseg
->
SetOwner
(
this
);
linkJoint
(
s
.
a
,
pseg
->
GetLayers
(),
aLine
->
GetNet
(),
pseg
);
void
PNS_NODE
::
addSolid
(
PNS_SOLID
*
aSolid
)
linkJoint
(
s
.
b
,
pseg
->
GetLayers
(),
aLine
->
GetNet
(),
pseg
);
{
linkJoint
(
aSolid
->
GetCenter
(),
aSolid
->
GetLayers
(),
aSolid
->
GetNet
(),
aSolid
);
m_index
->
Add
(
aSolid
);
}
aLine
->
LinkSegment
(
pseg
);
m_index
->
Add
(
pseg
);
void
PNS_NODE
::
addVia
(
PNS_VIA
*
aVia
)
}
{
}
linkJoint
(
aVia
->
GetPos
(),
aVia
->
GetLayers
(),
aVia
->
GetNet
(),
aVia
);
m_index
->
Add
(
aVia
);
}
}
void
PNS_NODE
::
addSegment
(
PNS_SEGMENT
*
aSeg
)
void
PNS_NODE
::
addLine
(
PNS_LINE
*
aLine
)
{
{
if
(
aSeg
->
GetSeg
().
a
==
aSeg
->
GetSeg
().
b
)
const
SHAPE_LINE_CHAIN
&
l
=
aLine
->
GetLine
();
{
TRACEn
(
0
,
"attempting to add a segment with same end coordinates, ignoring."
)
for
(
int
i
=
0
;
i
<
l
.
SegmentCount
();
i
++
)
return
;
{
}
SEG
s
=
l
.
CSegment
(
i
);
aSeg
->
SetOwner
(
this
);
if
(
s
.
a
!=
s
.
b
)
{
PNS_SEGMENT
*
pseg
=
new
PNS_SEGMENT
(
*
aLine
,
s
);
pseg
->
SetOwner
(
this
);
linkJoint
(
s
.
a
,
pseg
->
GetLayers
(),
aLine
->
GetNet
(),
pseg
);
linkJoint
(
s
.
b
,
pseg
->
GetLayers
(),
aLine
->
GetNet
(),
pseg
);
linkJoint
(
aSeg
->
GetSeg
().
a
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
aLine
->
LinkSegment
(
pseg
);
linkJoint
(
aSeg
->
GetSeg
().
b
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
m_index
->
Add
(
aSeg
);
m_index
->
Add
(
pseg
);
}
}
}
}
void
PNS_NODE
::
Add
(
PNS_ITEM
*
aItem
)
void
PNS_NODE
::
addSegment
(
PNS_SEGMENT
*
aSeg
)
{
{
if
(
aSeg
->
GetSeg
().
a
==
aSeg
->
GetSeg
().
b
)
{
TRACEn
(
0
,
"attempting to add a segment with same end coordinates, ignoring."
)
return
;
}
aSeg
->
SetOwner
(
this
);
linkJoint
(
aSeg
->
GetSeg
().
a
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
linkJoint
(
aSeg
->
GetSeg
().
b
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
aItem
->
SetOwner
(
this
);
m_index
->
Add
(
aSeg
);
}
switch
(
aItem
->
GetKind
())
{
case
PNS_ITEM
:
:
SOLID
:
addSolid
(
static_cast
<
PNS_SOLID
*>
(
aItem
));
break
;
case
PNS_ITEM
:
:
SEGMENT
:
void
PNS_NODE
::
Add
(
PNS_ITEM
*
aItem
)
addSegment
(
static_cast
<
PNS_SEGMENT
*>
(
aItem
));
{
break
;
aItem
->
SetOwner
(
this
)
;
case
PNS_ITEM
:
:
LINE
:
switch
(
aItem
->
GetKind
()
)
addLine
(
static_cast
<
PNS_LINE
*>
(
aItem
));
{
break
;
case
PNS_ITEM
:
:
SOLID
:
addSolid
(
static_cast
<
PNS_SOLID
*>
(
aItem
)
);
break
;
case
PNS_ITEM
:
:
VIA
:
case
PNS_ITEM
:
:
SEGMENT
:
addVia
(
static_cast
<
PNS_VIA
*>
(
aItem
)
);
addSegment
(
static_cast
<
PNS_SEGMENT
*>
(
aItem
)
);
break
;
break
;
default
:
case
PNS_ITEM
:
:
LINE
:
assert
(
false
);
addLine
(
static_cast
<
PNS_LINE
*>
(
aItem
)
);
}
break
;
}
case
PNS_ITEM
:
:
VIA
:
addVia
(
static_cast
<
PNS_VIA
*>
(
aItem
)
);
break
;
void
PNS_NODE
::
doRemove
(
PNS_ITEM
*
aItem
)
default
:
assert
(
false
);
}
}
void
PNS_NODE
::
doRemove
(
PNS_ITEM
*
aItem
)
{
{
// case 1: removing an item that is stored in the root node from any branch: mark it as overridden, but do not remove
// case 1: removing an item that is stored in the root node from any branch:
if
(
aItem
->
BelongsTo
(
m_root
)
&&
!
isRoot
()
)
// mark it as overridden, but do not remove
m_override
.
insert
(
aItem
);
if
(
aItem
->
BelongsTo
(
m_root
)
&&
!
isRoot
()
)
m_override
.
insert
(
aItem
);
// case 2: the item belongs to this branch or a parent, non-root branch, or the root itself and we are the root: remove from the index
// case 2: the item belongs to this branch or a parent, non-root branch,
else
if
(
!
aItem
->
BelongsTo
(
m_root
)
||
isRoot
()
)
// or the root itself and we are the root: remove from the index
m_index
->
Remove
(
aItem
);
else
if
(
!
aItem
->
BelongsTo
(
m_root
)
||
isRoot
()
)
m_index
->
Remove
(
aItem
);
// the item belongs to this particular branch: un-reference it
// the item belongs to this particular branch: un-reference it
if
(
aItem
->
BelongsTo
(
this
)
)
if
(
aItem
->
BelongsTo
(
this
)
)
aItem
->
SetOwner
(
NULL
);
aItem
->
SetOwner
(
NULL
);
}
}
void
PNS_NODE
::
removeSegment
(
PNS_SEGMENT
*
aSeg
)
void
PNS_NODE
::
removeSegment
(
PNS_SEGMENT
*
aSeg
)
{
{
unlinkJoint
(
aSeg
->
GetSeg
().
a
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
unlinkJoint
(
aSeg
->
GetSeg
().
a
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
unlinkJoint
(
aSeg
->
GetSeg
().
b
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
unlinkJoint
(
aSeg
->
GetSeg
().
b
,
aSeg
->
GetLayers
(),
aSeg
->
GetNet
(),
aSeg
);
doRemove
(
aSeg
);
doRemove
(
aSeg
);
}
}
void
PNS_NODE
::
removeLine
(
PNS_LINE
*
aLine
)
void
PNS_NODE
::
removeLine
(
PNS_LINE
*
aLine
)
{
{
vector
<
PNS_SEGMENT
*>
*
segRefs
=
aLine
->
GetLinkedSegments
();
vector
<
PNS_SEGMENT
*>*
segRefs
=
aLine
->
GetLinkedSegments
();
if
(
!
segRefs
)
if
(
!
segRefs
)
return
;
return
;
assert
(
aLine
->
GetOwner
()
);
assert
(
aLine
->
GetOwner
()
);
BOOST_FOREACH
(
PNS_SEGMENT
*
seg
,
*
segRefs
)
BOOST_FOREACH
(
PNS_SEGMENT
*
seg
,
*
segRefs
)
{
{
removeSegment
(
seg
);
removeSegment
(
seg
);
}
}
aLine
->
SetOwner
(
NULL
);
aLine
->
SetOwner
(
NULL
);
}
}
void
PNS_NODE
::
removeVia
(
PNS_VIA
*
aVia
)
void
PNS_NODE
::
removeVia
(
PNS_VIA
*
aVia
)
{
{
unlinkJoint
(
aVia
->
GetPos
(),
aVia
->
GetLayers
(),
aVia
->
GetNet
(),
aVia
);
unlinkJoint
(
aVia
->
GetPos
(),
aVia
->
GetLayers
(),
aVia
->
GetNet
(),
aVia
);
doRemove
(
aVia
);
doRemove
(
aVia
);
}
}
void
PNS_NODE
::
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
)
void
PNS_NODE
::
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
)
{
{
Remove
(
aOldItem
);
Remove
(
aOldItem
);
Add
(
aNewItem
);
Add
(
aNewItem
);
}
}
void
PNS_NODE
::
Remove
(
PNS_ITEM
*
aItem
)
void
PNS_NODE
::
Remove
(
PNS_ITEM
*
aItem
)
{
{
switch
(
aItem
->
GetKind
()
)
switch
(
aItem
->
GetKind
())
{
{
case
PNS_ITEM
:
:
SOLID
:
case
PNS_ITEM
:
:
SOLID
:
assert
(
false
);
assert
(
false
);
break
;
break
;
case
PNS_ITEM
:
:
SEGMENT
:
case
PNS_ITEM
:
:
SEGMENT
:
removeSegment
(
static_cast
<
PNS_SEGMENT
*>
(
aItem
));
removeSegment
(
static_cast
<
PNS_SEGMENT
*>
(
aItem
)
);
break
;
break
;
case
PNS_ITEM
:
:
LINE
:
removeLine
(
static_cast
<
PNS_LINE
*>
(
aItem
));
case
PNS_ITEM
:
:
LINE
:
break
;
removeLine
(
static_cast
<
PNS_LINE
*>
(
aItem
)
);
case
PNS_ITEM
:
:
VIA
:
break
;
removeVia
(
static_cast
<
PNS_VIA
*>
(
aItem
));
break
;
case
PNS_ITEM
:
:
VIA
:
removeVia
(
static_cast
<
PNS_VIA
*>
(
aItem
)
);
default
:
break
;
break
;
}
default
:
break
;
}
}
}
void
PNS_NODE
::
followLine
(
PNS_SEGMENT
*
current
,
bool
scanDirection
,
int
&
pos
,
int
limit
,
VECTOR2I
*
corners
,
PNS_SEGMENT
**
segments
)
void
PNS_NODE
::
followLine
(
PNS_SEGMENT
*
current
,
bool
scanDirection
,
int
&
pos
,
int
limit
,
VECTOR2I
*
corners
,
PNS_SEGMENT
**
segments
)
{
{
bool
prevReversed
=
false
;
bool
prevReversed
=
false
;
for
(;;)
for
(
;
;
)
{
{
const
VECTOR2I
p
=
(
scanDirection
^
prevReversed
)
?
current
->
GetSeg
().
b
:
current
->
GetSeg
().
a
;
const
VECTOR2I
p
=
const
OptJoint
jt
=
FindJoint
(
p
,
current
->
GetLayer
(),
current
->
GetNet
());
(
scanDirection
^
prevReversed
)
?
current
->
GetSeg
().
b
:
current
->
GetSeg
().
a
;
const
OptJoint
jt
=
FindJoint
(
p
,
current
->
GetLayer
(),
current
->
GetNet
()
);
assert
(
jt
);
assert
(
jt
);
assert
(
pos
>
0
&&
pos
<
limit
);
assert
(
pos
>
0
&&
pos
<
limit
);
corners
[
pos
]
=
jt
->
GetPos
();
corners
[
pos
]
=
jt
->
GetPos
();
segments
[
pos
]
=
current
;
segments
[
pos
]
=
current
;
pos
+=
(
scanDirection
?
1
:
-
1
);
pos
+=
(
scanDirection
?
1
:
-
1
);
if
(
!
jt
->
IsLineCorner
())
break
;
current
=
jt
->
NextSegment
(
current
);
if
(
!
jt
->
IsLineCorner
()
)
prevReversed
=
(
jt
->
GetPos
()
==
(
scanDirection
?
current
->
GetSeg
().
b
:
current
->
GetSeg
().
a
));
break
;
}
current
=
jt
->
NextSegment
(
current
);
prevReversed
=
(
jt
->
GetPos
()
==
(
scanDirection
?
current
->
GetSeg
().
b
:
current
->
GetSeg
().
a
)
);
}
}
}
PNS_LINE
*
PNS_NODE
::
AssembleLine
(
PNS_SEGMENT
*
aSeg
,
const
OptJoint
&
a
,
const
OptJoint
&
b
)
PNS_LINE
*
PNS_NODE
::
AssembleLine
(
PNS_SEGMENT
*
aSeg
,
const
OptJoint
&
a
,
const
OptJoint
&
b
)
{
{
const
int
MaxVerts
=
1024
;
const
int
MaxVerts
=
1024
;
VECTOR2I
corners
[
MaxVerts
+
1
];
VECTOR2I
corners
[
MaxVerts
+
1
];
PNS_SEGMENT
*
segs
[
MaxVerts
+
1
];
PNS_SEGMENT
*
segs
[
MaxVerts
+
1
];
PNS_LINE
*
pl
=
new
PNS_LINE
;
PNS_LINE
*
pl
=
new
PNS_LINE
;
int
i_start
=
MaxVerts
/
2
,
i_end
=
i_start
+
1
;
int
i_start
=
MaxVerts
/
2
,
i_end
=
i_start
+
1
;
pl
->
SetWidth
(
aSeg
->
GetWidth
()
);
pl
->
SetWidth
(
aSeg
->
GetWidth
()
);
pl
->
SetLayers
(
aSeg
->
GetLayers
()
);
pl
->
SetLayers
(
aSeg
->
GetLayers
()
);
pl
->
SetNet
(
aSeg
->
GetNet
()
);
pl
->
SetNet
(
aSeg
->
GetNet
()
);
pl
->
SetOwner
(
this
);
pl
->
SetOwner
(
this
);
//pl->LinkSegment(aSeg);
// pl->LinkSegment(aSeg);
followLine
(
aSeg
,
false
,
i_start
,
MaxVerts
,
corners
,
segs
);
followLine
(
aSeg
,
true
,
i_end
,
MaxVerts
,
corners
,
segs
);
followLine
(
aSeg
,
false
,
i_start
,
MaxVerts
,
corners
,
segs
);
followLine
(
aSeg
,
true
,
i_end
,
MaxVerts
,
corners
,
segs
);
int
clip_start
=
-
1
,
clip_end
=
-
1
;
for
(
int
i
=
i_start
+
1
;
i
<
i_end
;
i
++
)
{
const
VECTOR2I
&
p
=
corners
[
i
];
if
(
a
&&
(
p
==
a
->
GetPos
()
||
p
==
b
->
GetPos
()
)
)
{
clip_start
=
std
::
min
(
clip_start
,
i
);
clip_end
=
std
::
max
(
clip_end
,
i
);
}
pl
->
GetLine
().
Append
(
p
);
int
clip_start
=
-
1
,
clip_end
=
-
1
;
if
(
segs
[
i
-
1
]
!=
segs
[
i
])
pl
->
LinkSegment
(
segs
[
i
]);
}
return
pl
;
for
(
int
i
=
i_start
+
1
;
i
<
i_end
;
i
++
)
{
const
VECTOR2I
&
p
=
corners
[
i
];
if
(
a
&&
(
p
==
a
->
GetPos
()
||
p
==
b
->
GetPos
()
)
)
{
clip_start
=
std
::
min
(
clip_start
,
i
);
clip_end
=
std
::
max
(
clip_end
,
i
);
}
pl
->
GetLine
().
Append
(
p
);
if
(
segs
[
i
-
1
]
!=
segs
[
i
]
)
pl
->
LinkSegment
(
segs
[
i
]
);
}
return
pl
;
}
}
void
PNS_NODE
::
FindLineEnds
(
PNS_LINE
*
aLine
,
PNS_JOINT
&
a
,
PNS_JOINT
&
b
)
void
PNS_NODE
::
FindLineEnds
(
PNS_LINE
*
aLine
,
PNS_JOINT
&
a
,
PNS_JOINT
&
b
)
{
{
a
=
*
FindJoint
(
aLine
->
GetCLine
().
CPoint
(
0
),
aLine
->
GetLayers
().
Start
(),
aLine
->
GetNet
()
);
a
=
*
FindJoint
(
aLine
->
GetCLine
().
CPoint
(
0
),
aLine
->
GetLayers
().
Start
(),
aLine
->
GetNet
()
);
b
=
*
FindJoint
(
aLine
->
GetCLine
().
CPoint
(
-
1
),
aLine
->
GetLayers
().
Start
(),
aLine
->
GetNet
());
b
=
*
FindJoint
(
aLine
->
GetCLine
().
CPoint
(
-
1
),
aLine
->
GetLayers
().
Start
(),
aLine
->
GetNet
()
);
}
}
int
PNS_NODE
::
FindLinesBetweenJoints
(
PNS_JOINT
&
a
,
PNS_JOINT
&
b
,
vector
<
PNS_LINE
*>
&
aLines
)
int
PNS_NODE
::
FindLinesBetweenJoints
(
PNS_JOINT
&
a
,
PNS_JOINT
&
b
,
vector
<
PNS_LINE
*>&
aLines
)
{
{
BOOST_FOREACH
(
PNS_ITEM
*
item
,
a
.
GetLinkList
())
BOOST_FOREACH
(
PNS_ITEM
*
item
,
a
.
GetLinkList
()
)
{
{
if
(
item
->
GetKind
()
==
PNS_ITEM
::
SEGMENT
)
if
(
item
->
GetKind
()
==
PNS_ITEM
::
SEGMENT
)
{
{
PNS_SEGMENT
*
seg
=
static_cast
<
PNS_SEGMENT
*>
(
item
);
PNS_SEGMENT
*
seg
=
static_cast
<
PNS_SEGMENT
*>
(
item
);
PNS_LINE
*
line
=
AssembleLine
(
seg
);
PNS_LINE
*
line
=
AssembleLine
(
seg
);
PNS_JOINT
j_start
,
j_end
;
FindLineEnds
(
line
,
j_start
,
j_end
);
PNS_JOINT
j_start
,
j_end
;
if
(
(
j_start
==
a
&&
j_end
==
b
)
||
(
j_end
==
a
&&
j_start
==
b
)
)
FindLineEnds
(
line
,
j_start
,
j_end
);
aLines
.
push_back
(
line
);
if
(
(
j_start
==
a
&&
j_end
==
b
)
||
(
j_end
==
a
&&
j_start
==
b
))
else
aLines
.
push_back
(
line
);
delete
line
;
else
}
delete
line
;
}
}
}
return
0
;
return
0
;
}
}
const
PNS_NODE
::
OptJoint
PNS_NODE
::
FindJoint
(
const
VECTOR2I
&
aPos
,
int
aLayer
,
int
aNet
)
const
PNS_NODE
::
OptJoint
PNS_NODE
::
FindJoint
(
const
VECTOR2I
&
aPos
,
int
aLayer
,
int
aNet
)
{
{
PNS_JOINT
::
HashTag
tag
;
PNS_JOINT
::
HashTag
tag
;
tag
.
net
=
aNet
;
tag
.
pos
=
aPos
;
tag
.
net
=
aNet
;
JointMap
::
iterator
f
=
m_joints
.
find
(
tag
),
end
=
m_joints
.
end
();
tag
.
pos
=
aPos
;
JointMap
::
iterator
f
=
m_joints
.
find
(
tag
),
end
=
m_joints
.
end
();
if
(
f
==
end
&&
!
isRoot
()
)
{
end
=
m_root
->
m_joints
.
end
();
f
=
m_root
->
m_joints
.
find
(
tag
);
// m_root->FindJoint(aPos, aLayer, aNet);
}
if
(
f
==
end
&&
!
isRoot
())
if
(
f
==
end
)
{
return
OptJoint
();
end
=
m_root
->
m_joints
.
end
();
f
=
m_root
->
m_joints
.
find
(
tag
);
//m_root->FindJoint(aPos, aLayer, aNet);
}
if
(
f
==
end
)
while
(
f
!=
end
)
return
OptJoint
();
{
if
(
f
->
second
.
GetLayers
().
Overlaps
(
aLayer
)
)
return
f
->
second
;
while
(
f
!=
end
)
++
f
;
{
}
if
(
f
->
second
.
GetLayers
().
Overlaps
(
aLayer
))
return
f
->
second
;
return
OptJoint
();
++
f
;
}
return
OptJoint
();
}
}
PNS_JOINT
&
PNS_NODE
::
touchJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
)
PNS_JOINT
&
PNS_NODE
::
touchJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
)
{
{
PNS_JOINT
::
HashTag
tag
;
PNS_JOINT
::
HashTag
tag
;
tag
.
pos
=
aPos
;
tag
.
pos
=
aPos
;
tag
.
net
=
aNet
;
tag
.
net
=
aNet
;
// try to find the joint in this node.
// try to find the joint in this node.
JointMap
::
iterator
f
=
m_joints
.
find
(
tag
);
JointMap
::
iterator
f
=
m_joints
.
find
(
tag
);
pair
<
JointMap
::
iterator
,
JointMap
::
iterator
>
range
;
pair
<
JointMap
::
iterator
,
JointMap
::
iterator
>
range
;
// not found and we are not root? find in the root and copy results here.
// not found and we are not root? find in the root and copy results here.
if
(
f
==
m_joints
.
end
()
&&
!
isRoot
())
if
(
f
==
m_joints
.
end
()
&&
!
isRoot
()
)
{
{
range
=
m_root
->
m_joints
.
equal_range
(
tag
);
range
=
m_root
->
m_joints
.
equal_range
(
tag
);
for
(
f
=
range
.
first
;
f
!=
range
.
second
;
++
f
)
m_joints
.
insert
(
*
f
);
for
(
f
=
range
.
first
;
f
!=
range
.
second
;
++
f
)
}
m_joints
.
insert
(
*
f
);
}
// now insert and combine overlapping joints
PNS_JOINT
jt
(
aPos
,
aLayers
,
aNet
);
// now insert and combine overlapping joints
PNS_JOINT
jt
(
aPos
,
aLayers
,
aNet
);
bool
merged
;
bool
merged
;
do
{
do
merged
=
false
;
{
range
=
m_joints
.
equal_range
(
tag
);
merged
=
false
;
range
=
m_joints
.
equal_range
(
tag
);
if
(
range
.
first
==
m_joints
.
end
())
break
;
if
(
range
.
first
==
m_joints
.
end
()
)
break
;
for
(
f
=
range
.
first
;
f
!=
range
.
second
;
++
f
)
{
for
(
f
=
range
.
first
;
f
!=
range
.
second
;
++
f
)
if
(
aLayers
.
Overlaps
(
f
->
second
.
GetLayers
()))
{
{
if
(
aLayers
.
Overlaps
(
f
->
second
.
GetLayers
()
)
)
jt
.
Merge
(
f
->
second
);
{
m_joints
.
erase
(
f
);
jt
.
Merge
(
f
->
second
);
merged
=
true
;
m_joints
.
erase
(
f
);
break
;
merged
=
true
;
}
break
;
}
}
}
while
(
merged
);
}
}
while
(
merged
);
return
m_joints
.
insert
(
TagJointPair
(
tag
,
jt
)
)
->
second
;
return
m_joints
.
insert
(
TagJointPair
(
tag
,
jt
)
)
->
second
;
}
}
void
PNS_JOINT
::
Dump
()
const
void
PNS_JOINT
::
Dump
()
const
{
{
printf
(
"joint layers %d-%d, net %d, pos %s, links: %d
\n
"
,
m_layers
.
Start
(),
m_layers
.
End
(),
m_tag
.
net
,
m_tag
.
pos
.
Format
().
c_str
(),
LinkCount
()
);
printf
(
"joint layers %d-%d, net %d, pos %s, links: %d
\n
"
,
m_layers
.
Start
(),
m_layers
.
End
(),
m_tag
.
net
,
m_tag
.
pos
.
Format
().
c_str
(),
LinkCount
()
);
}
}
void
PNS_NODE
::
linkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
,
PNS_ITEM
*
aWhere
)
void
PNS_NODE
::
linkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
,
PNS_ITEM
*
aWhere
)
{
{
PNS_JOINT
&
jt
=
touchJoint
(
aPos
,
aLayers
,
aNet
);
PNS_JOINT
&
jt
=
touchJoint
(
aPos
,
aLayers
,
aNet
);
jt
.
Link
(
aWhere
);
jt
.
Link
(
aWhere
);
}
}
void
PNS_NODE
::
unlinkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
,
PNS_ITEM
*
aWhere
)
void
PNS_NODE
::
unlinkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
,
PNS_ITEM
*
aWhere
)
{
{
// fixme: remove dangling joints
// fixme: remove dangling joints
PNS_JOINT
&
jt
=
touchJoint
(
aPos
,
aLayers
,
aNet
);
PNS_JOINT
&
jt
=
touchJoint
(
aPos
,
aLayers
,
aNet
);
jt
.
Unlink
(
aWhere
);
jt
.
Unlink
(
aWhere
);
}
}
void
PNS_NODE
::
Dump
(
bool
aLong
)
void
PNS_NODE
::
Dump
(
bool
aLong
)
{
{
#if 0
#if 0
boost::unordered_set<PNS_SEGMENT *> all_segs;
boost::unordered_set<PNS_SEGMENT*> all_segs;
SHAPE_INDEX_LIST<PNS_ITEM *>::iterator i;
SHAPE_INDEX_LIST<PNS_ITEM*>::iterator i;
for(i = m_items.begin(); i != m_items.end() ; i++)
for( i = m_items.begin(); i != m_items.end(); i++ )
{
{
if((*i)->GetKind() == PNS_ITEM::SEGMENT)
if( (*i)->GetKind() == PNS_ITEM::SEGMENT )
all_segs.insert(static_cast<PNS_SEGMENT*>(*i));
all_segs.insert( static_cast<PNS_SEGMENT*>(*i) );
}
}
if(!isRoot())
if( !isRoot() )
for(i = m_root->m_items.begin(); i != m_root->m_items.end() ; i++)
for( i = m_root->m_items.begin(); i != m_root->m_items.end(); i++ )
{
{
if((*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides(*i))
if( (*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides( *i ) )
all_segs.insert(static_cast<PNS_SEGMENT*>(*i));
all_segs.insert( static_cast<PNS_SEGMENT*>(*i) );
}
}
JointMap::iterator j;
JointMap::iterator j;
if(aLong)
if( aLong )
for(j=m_joints.begin(); j!=m_joints.end(); ++j)
for( j = m_joints.begin(); j!=m_joints.end(); ++j )
{
{
printf("joint : %s, links : %d\n", j->second.GetPos().Format().c_str(), j->second.LinkCount());
printf( "joint : %s, links : %d\n",
PNS_JOINT::LinkedItems::const_iterator k;
j->second.GetPos().Format().c_str(), j->second.LinkCount() );
for(k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k)
PNS_JOINT::LinkedItems::const_iterator k;
{
const PNS_ITEM *item = *k;
for( k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k )
{
switch(item->GetKind())
const PNS_ITEM* item = *k;
{
case PNS_ITEM::SEGMENT:
switch( item->GetKind() )
{
{
const PNS_SEGMENT *seg = static_cast<const PNS_SEGMENT *>(item);
case PNS_ITEM::SEGMENT:
printf(" -> seg %s %s\n", seg->GetSeg().a.Format().c_str(), seg->GetSeg().b.Format().c_str());
{
break;
const PNS_SEGMENT* seg = static_cast<const PNS_SEGMENT*>(item);
}
printf( " -> seg %s %s\n", seg->GetSeg().a.Format().c_str(),
default:
seg->GetSeg().b.Format().c_str() );
break;
break;
}
}
}
}
default:
break;
int lines_count = 0;
}
while(!all_segs.empty())
}
{
}
PNS_SEGMENT *s = *all_segs.begin();
PNS_LINE *l = AssembleLine(s);
PNS_LINE::LinkedSegments* seg_refs = l->GetLinkedSegments();
int lines_count = 0;
if(aLong)
while( !all_segs.empty() )
printf("Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() );
{
PNS_SEGMENT* s = *all_segs.begin();
PNS_LINE* l = AssembleLine( s );
for(vector<PNS_SEGMENT *>::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j)
{
PNS_LINE::LinkedSegments* seg_refs = l->GetLinkedSegments();
printf("%s ", (*j)->GetSeg().a.Format().c_str() );
if(j+1 == seg_refs->end())
if( aLong )
printf("%s\n", (*j)->GetSeg().b.Format().c_str() );
printf( "Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() );
all_segs.erase(*j);
}
lines_count++;
for( vector<PNS_SEGMENT*>::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j )
}
{
printf( "%s ", (*j)->GetSeg().a.Format().c_str() );
printf("Local joints: %d, lines : %d \n", m_joints.size(), lines_count);
if( j + 1 == seg_refs->end() )
printf( "%s\n", (*j)->GetSeg().b.Format().c_str() );
all_segs.erase( *j );
}
lines_count++;
}
printf( "Local joints: %d, lines : %d \n", m_joints.size(), lines_count );
#endif
#endif
}
}
void
PNS_NODE
::
GetUpdatedItems
(
ItemVector
&
aRemoved
,
ItemVector
&
aAdded
)
void
PNS_NODE
::
GetUpdatedItems
(
ItemVector
&
aRemoved
,
ItemVector
&
aAdded
)
{
{
aRemoved
.
reserve
(
m_override
.
size
());
aRemoved
.
reserve
(
m_override
.
size
()
);
aAdded
.
reserve
(
m_index
->
Size
());
aAdded
.
reserve
(
m_index
->
Size
()
);
if
(
isRoot
()
)
return
;
if
(
isRoot
()
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_override
)
return
;
aRemoved
.
push_back
(
item
)
;
BOOST_FOREACH
(
PNS_ITEM
*
item
,
m_override
)
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
m_index
->
begin
();
i
!=
m_index
->
end
();
++
i
)
aRemoved
.
push_back
(
item
);
aAdded
.
push_back
(
*
i
);
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
m_index
->
begin
();
i
!=
m_index
->
end
();
++
i
)
aAdded
.
push_back
(
*
i
);
}
}
void
PNS_NODE
::
releaseChildren
()
void
PNS_NODE
::
releaseChildren
()
{
{
// copy the kids as the PNS_NODE destructor erases the item from the parent node.
// copy the kids as the PNS_NODE destructor erases the item from the parent node.
vector
<
PNS_NODE
*>
kids
=
m_children
;
vector
<
PNS_NODE
*>
kids
=
m_children
;
BOOST_FOREACH
(
PNS_NODE
*
node
,
kids
)
BOOST_FOREACH
(
PNS_NODE
*
node
,
kids
)
{
{
node
->
releaseChildren
();
node
->
releaseChildren
();
delete
node
;
delete
node
;
}
}
}
}
void
PNS_NODE
::
Commit
(
PNS_NODE
*
aNode
)
{
if
(
aNode
->
isRoot
())
void
PNS_NODE
::
Commit
(
PNS_NODE
*
aNode
)
return
;
{
if
(
aNode
->
isRoot
()
)
return
;
BOOST_FOREACH
(
PNS_ITEM
*
item
,
aNode
->
m_override
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
aNode
->
m_override
)
Remove
(
item
);
Remove
(
item
);
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
aNode
->
m_index
->
begin
();
i
!=
aNode
->
m_index
->
end
();
++
i
)
for
(
PNS_INDEX
::
ItemSet
::
iterator
i
=
aNode
->
m_index
->
begin
();
Add
(
*
i
);
i
!=
aNode
->
m_index
->
end
();
++
i
)
Add
(
*
i
);
releaseChildren
();
releaseChildren
();
}
}
void
PNS_NODE
::
KillChildren
()
void
PNS_NODE
::
KillChildren
()
{
{
assert
(
isRoot
()
);
assert
(
isRoot
()
);
releaseChildren
();
releaseChildren
();
}
}
void
PNS_NODE
::
AllItemsInNet
(
int
aNet
,
std
::
list
<
PNS_ITEM
*>&
aItems
)
void
PNS_NODE
::
AllItemsInNet
(
int
aNet
,
std
::
list
<
PNS_ITEM
*>&
aItems
)
{
{
PNS_INDEX
::
NetItemsList
*
l_cur
=
m_index
->
GetItemsForNet
(
aNet
);
PNS_INDEX
::
NetItemsList
*
l_cur
=
m_index
->
GetItemsForNet
(
aNet
);
if
(
!
l_cur
)
return
;
std
::
copy
(
aItems
.
begin
(),
l_cur
->
begin
(),
l_cur
->
end
()
);
if
(
!
l_cur
)
if
(
!
isRoot
()
)
return
;
{
PNS_INDEX
::
NetItemsList
*
l_root
=
m_root
->
m_index
->
GetItemsForNet
(
aNet
);
std
::
copy
(
aItems
.
begin
(),
l_cur
->
begin
(),
l_cur
->
end
()
);
for
(
PNS_INDEX
::
NetItemsList
::
iterator
i
=
l_root
->
begin
();
i
!=
l_root
->
end
();
++
i
)
if
(
!
isRoot
()
)
if
(
!
overrides
(
*
i
)
)
{
aItems
.
push_back
(
*
i
);
PNS_INDEX
::
NetItemsList
*
l_root
=
m_root
->
m_index
->
GetItemsForNet
(
aNet
);
for
(
PNS_INDEX
::
NetItemsList
::
iterator
i
=
l_root
->
begin
();
i
!=
l_root
->
end
();
++
i
)
if
(
!
overrides
(
*
i
))
}
aItems
.
push_back
(
*
i
);
}
}
}
pcbnew/router/pns_node.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -45,9 +45,10 @@ class PNS_INDEX;
...
@@ -45,9 +45,10 @@ class PNS_INDEX;
using
boost
::
shared_ptr
;
using
boost
::
shared_ptr
;
class
PNS_CLEARANCE_FUNC
{
class
PNS_CLEARANCE_FUNC
public
:
{
virtual
int
operator
()
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
=
0
;
public
:
virtual
int
operator
()(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
=
0
;
};
};
/**
/**
...
@@ -56,205 +57,225 @@ class PNS_CLEARANCE_FUNC {
...
@@ -56,205 +57,225 @@ class PNS_CLEARANCE_FUNC {
* Holds an object colliding with another object, along with
* Holds an object colliding with another object, along with
* some useful data about the collision.
* some useful data about the collision.
**/
**/
struct
PNS_OBSTACLE
struct
PNS_OBSTACLE
{
{
///> Item we search collisions with
///> Item we search collisions with
PNS_ITEM
*
head
;
PNS_ITEM
*
head
;
///> Item found to be colliding with head
///> Item found to be colliding with head
PNS_ITEM
*
item
;
PNS_ITEM
*
item
;
///> Hull of the colliding item
///> Hull of the colliding item
SHAPE_LINE_CHAIN
hull
;
SHAPE_LINE_CHAIN
hull
;
///> First and last intersection point between the head item and the hull of the
///> First and last intersection point between the head item and the hull
////
colliding item
///> of the
colliding item
VECTOR2I
ip_first
,
ip_last
;
VECTOR2I
ip_first
,
ip_last
;
///> ... and the distance thereof
///> ... and the distance thereof
int
dist_first
,
dist_last
;
int
dist_first
,
dist_last
;
};
};
/**
/**
* Class PNS_NODE
* Class PNS_NODE
*
*
* Keeps the router "world" - i.e. all the tracks, vias, solids in a hierarchical and indexed way.
* Keeps the router "world" - i.e. all the tracks, vias, solids in a
* hierarchical and indexed way.
* Features:
* Features:
* - spatial-indexed container for PCB item shapes
* - spatial-indexed container for PCB item shapes
* - collision search (with clearance checking)
* - collision search (with clearance checking)
* - assembly of lines connecting joints, finding loops and unique paths
* - assembly of lines connecting joints, finding loops and unique paths
* - lightweight cloning/branching (for recursive optimization and shove springback)
* - lightweight cloning/branching (for recursive optimization and shove
* springback)
**/
**/
class
PNS_NODE
{
class
PNS_NODE
{
public
:
public
:
typedef
boost
::
optional
<
PNS_OBSTACLE
>
OptObstacle
;
typedef
boost
::
optional
<
PNS_OBSTACLE
>
OptObstacle
;
typedef
std
::
vector
<
PNS_ITEM
*>
ItemVector
;
typedef
std
::
vector
<
PNS_ITEM
*>
ItemVector
;
typedef
std
::
vector
<
PNS_OBSTACLE
>
Obstacles
;
typedef
std
::
vector
<
PNS_OBSTACLE
>
Obstacles
;
typedef
boost
::
optional
<
PNS_JOINT
>
OptJoint
;
typedef
boost
::
optional
<
PNS_JOINT
>
OptJoint
;
PNS_NODE
();
PNS_NODE
();
~
PNS_NODE
();
~
PNS_NODE
();
///> Returns the expected clearance between items a and b.
///> Returns the expected clearance between items a and b.
int
GetClearance
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
const
;
int
GetClearance
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
const
;
///> Returns the pre-set worst case clearance between any pair of items
int
GetMaxClearance
()
const
{
return
m_maxClearance
;
}
void
SetMaxClearance
(
int
aClearance
)
///> Returns the pre-set worst case clearance between any pair of items
{
int
GetMaxClearance
()
const
m_maxClearance
=
aClearance
;
{
}
return
m_maxClearance
;
}
void
SetClearanceFunctor
(
PNS_CLEARANCE_FUNC
*
aFunc
)
void
SetMaxClearance
(
int
aClearance
)
{
{
m_clearanceFunctor
=
aFunc
;
m_maxClearance
=
aClearance
;
}
}
///> Finds items that collide with aItem and stores collision information in aObstacles.
void
SetClearanceFunctor
(
PNS_CLEARANCE_FUNC
*
aFunc
)
int
QueryColliding
(
const
PNS_ITEM
*
aItem
,
Obstacles
&
aObstacles
,
int
aKindMask
=
PNS_ITEM
::
ANY
,
int
aLimitCount
=
-
1
);
{
m_clearanceFunctor
=
aFunc
;
}
///> Finds the nearest item that collides with aItem.
///> Finds items that collide with aItem and stores collision information
OptObstacle
NearestObstacle
(
const
PNS_LINE
*
aItem
,
int
aKindMask
=
PNS_ITEM
::
ANY
);
///> in aObstacles.
int
QueryColliding
(
const
PNS_ITEM
*
aItem
,
Obstacles
&
aObstacles
,
int
aKindMask
=
PNS_ITEM
::
ANY
,
int
aLimitCount
=
-
1
);
///> Checks if the item collides with anything else in the world, and returns it if so
.
///> Finds the nearest item that collides with aItem
.
OptObstacle
CheckColliding
(
const
PNS_ITEM
*
aItem
,
int
aKindMask
=
PNS_ITEM
::
ANY
);
OptObstacle
NearestObstacle
(
const
PNS_LINE
*
aItem
,
int
aKindMask
=
PNS_ITEM
::
ANY
);
///> Checks if two items collide [deprecated].
///> Checks if the item collides with anything else in the world,
bool
CheckColliding
(
const
PNS_ITEM
*
aItemA
,
const
PNS_ITEM
*
aItemB
,
int
aKindMask
=
PNS_ITEM
::
ANY
);
///> and returns it if so.
OptObstacle
CheckColliding
(
const
PNS_ITEM
*
aItem
,
int
aKindMask
=
PNS_ITEM
::
ANY
);
///> Hit detection
///> Checks if two items collide [deprecated].
const
PNS_ITEMSET
HitTest
(
const
VECTOR2I
&
aPoint
);
bool
CheckColliding
(
const
PNS_ITEM
*
aItemA
,
const
PNS_ITEM
*
aItemB
,
int
aKindMask
=
PNS_ITEM
::
ANY
);
void
Add
(
PNS_ITEM
*
aItem
);
///> Hit detection
void
Remove
(
PNS_ITEM
*
aItem
);
const
PNS_ITEMSET
HitTest
(
const
VECTOR2I
&
aPoint
);
void
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
);
///> Creates a lightweight copy ("branch") of self. Note that if there are any branches
void
Add
(
PNS_ITEM
*
aItem
);
/// in use, their parents must NOT be deleted.
void
Remove
(
PNS_ITEM
*
aItem
);
PNS_NODE
*
Branch
(
);
void
Replace
(
PNS_ITEM
*
aOldItem
,
PNS_ITEM
*
aNewItem
);
///> Assembles a line connecting two non-trivial joints the segment aSeg belongs to.
///> Creates a lightweight copy ("branch") of self. Note that if there are
PNS_LINE
*
AssembleLine
(
PNS_SEGMENT
*
aSeg
,
const
OptJoint
&
a
=
OptJoint
(),
const
OptJoint
&
b
=
OptJoint
());
///> any branches in use, their parents must NOT be deleted.
PNS_NODE
*
Branch
();
///> Dumps the contents and joints structure
void
Dump
(
bool
aLong
=
false
);
///> Returns the number of joints
///> Assembles a line connecting two non-trivial joints the
int
JointCount
()
const
///> segment aSeg belongs to.
{
PNS_LINE
*
AssembleLine
(
PNS_SEGMENT
*
aSeg
,
return
m_joints
.
size
();
const
OptJoint
&
a
=
OptJoint
(),
const
OptJoint
&
b
=
OptJoint
()
);
}
///> Returns the lists of items removed and added in this branch, with respect
///> Dumps the contents and joints structure
///> to the root.
void
Dump
(
bool
aLong
=
false
);
void
GetUpdatedItems
(
ItemVector
&
aRemoved
,
ItemVector
&
aAdded
);
///> Copies the changes from a given branch (aNode) to the root. Called on
///> Returns the number of joints
///> a non-root branch will fail.
int
JointCount
()
const
void
Commit
(
PNS_NODE
*
aNode
);
{
return
m_joints
.
size
();
}
///> finds a joint at a given position, layer and nets
///> Returns the lists of items removed and added in this branch, with
const
OptJoint
FindJoint
(
const
VECTOR2I
&
aPos
,
int
aLayer
,
int
aNet
);
///> respect to the root.
void
GetUpdatedItems
(
ItemVector
&
aRemoved
,
ItemVector
&
aAdded
);
///> finds all linest between a pair of joints. Used by the loop removal engine.
///> Copies the changes from a given branch (aNode) to the root. Called on
int
FindLinesBetweenJoints
(
PNS_JOINT
&
a
,
PNS_JOINT
&
b
,
std
::
vector
<
PNS_LINE
*>
&
aLines
);
///> a non-root branch will fail.
void
Commit
(
PNS_NODE
*
aNode
);
///> finds the joints corresponding to the ends of line aLine
///> finds a joint at a given position, layer and nets
void
FindLineEnds
(
PNS_LINE
*
aLine
,
PNS_JOINT
&
a
,
PNS_JOINT
&
b
);
const
OptJoint
FindJoint
(
const
VECTOR2I
&
aPos
,
int
aLayer
,
int
aNet
);
///> finds all joints that have an (in)direct connection(s) (i.e. segments/vias) with the joint aJoint.
///> finds all linest between a pair of joints. Used by the loop removal engine.
void
FindConnectedJoints
(
const
PNS_JOINT
&
aJoint
,
std
::
vector
<
PNS_JOINT
*>
&
aConnectedJoints
);
int
FindLinesBetweenJoints
(
PNS_JOINT
&
a
,
PNS_JOINT
&
b
,
std
::
vector
<
PNS_LINE
*>&
aLines
);
///> Destroys all child nodes. Applicable only to the root node.
///> finds the joints corresponding to the ends of line aLine
void
KillChildren
(
);
void
FindLineEnds
(
PNS_LINE
*
aLine
,
PNS_JOINT
&
a
,
PNS_JOINT
&
b
);
void
AllItemsInNet
(
int
aNet
,
std
::
list
<
PNS_ITEM
*>&
aItems
);
///> finds all joints that have an (in)direct connection(s)
///> (i.e. segments/vias) with the joint aJoint.
void
FindConnectedJoints
(
const
PNS_JOINT
&
aJoint
,
std
::
vector
<
PNS_JOINT
*>&
aConnectedJoints
);
private
:
///> Destroys all child nodes. Applicable only to the root node.
void
KillChildren
();
void
AllItemsInNet
(
int
aNet
,
std
::
list
<
PNS_ITEM
*>&
aItems
);
struct
obstacleVisitor
;
private
:
typedef
boost
::
unordered_multimap
<
PNS_JOINT
::
HashTag
,
PNS_JOINT
>
JointMap
;
struct
obstacleVisitor
;
typedef
JointMap
::
value_type
TagJointPair
;
typedef
boost
::
unordered_multimap
<
PNS_JOINT
::
HashTag
,
PNS_JOINT
>
JointMap
;
typedef
JointMap
::
value_type
TagJointPair
;
/// nodes are not copyable
PNS_NODE
(
const
PNS_NODE
&
b
);
/// nodes are not copyable
PNS_NODE
&
operator
=
(
const
PNS_NODE
&
b
);
PNS_NODE
(
const
PNS_NODE
&
b
);
PNS_NODE
&
operator
=
(
const
PNS_NODE
&
b
);
///> tries to find matching joint and creates a new one if not found
PNS_JOINT
&
touchJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
);
///> tries to find matching joint and creates a new one if not found
PNS_JOINT
&
touchJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
///> touches a joint and links it to an item
int
aNet
);
void
linkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
,
PNS_ITEM
*
aWhere
);
///> touches a joint and links it to an item
///> unlinks an item from a joint
void
linkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
void
unlinkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aNet
,
PNS_ITEM
*
aWhere
);
int
aNet
,
PNS_ITEM
*
aWhere
);
///> helpers for adding/removing items
///> unlinks an item from a joint
void
unlinkJoint
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
void
addSolid
(
PNS_SOLID
*
aSeg
);
int
aNet
,
PNS_ITEM
*
aWhere
);
void
addSegment
(
PNS_SEGMENT
*
aSeg
);
void
addLine
(
PNS_LINE
*
aLine
);
///> helpers for adding/removing items
void
addVia
(
PNS_VIA
*
aVia
);
void
addSolid
(
PNS_SOLID
*
aSeg
);
void
removeSolid
(
PNS_SOLID
*
aSeg
);
void
addSegment
(
PNS_SEGMENT
*
aSeg
);
void
removeLine
(
PNS_LINE
*
aLine
);
void
addLine
(
PNS_LINE
*
aLine
);
void
removeSegment
(
PNS_SEGMENT
*
aSeg
);
void
addVia
(
PNS_VIA
*
aVia
);
void
removeVia
(
PNS_VIA
*
aVia
);
void
removeSolid
(
PNS_SOLID
*
aSeg
);
void
removeLine
(
PNS_LINE
*
aLine
);
void
doRemove
(
PNS_ITEM
*
aItem
);
void
removeSegment
(
PNS_SEGMENT
*
aSeg
);
void
unlinkParent
(
);
void
removeVia
(
PNS_VIA
*
aVia
);
void
releaseChildren
();
void
doRemove
(
PNS_ITEM
*
aItem
);
bool
isRoot
()
const
void
unlinkParent
();
{
void
releaseChildren
();
return
m_parent
==
NULL
;
}
bool
isRoot
()
const
{
///> checks if this branch contains an updated version of the item from the root branch.
return
m_parent
==
NULL
;
bool
overrides
(
PNS_ITEM
*
aItem
)
const
}
{
return
m_override
.
find
(
aItem
)
!=
m_override
.
end
();
///> checks if this branch contains an updated version of the item
}
///> from the root branch.
bool
overrides
(
PNS_ITEM
*
aItem
)
const
///> scans the joint map, forming a line starting from segment (current).
{
void
followLine
(
PNS_SEGMENT
*
current
,
bool
scanDirection
,
int
&
pos
,
int
limit
,
VECTOR2I
*
corners
,
PNS_SEGMENT
**
segments
);
return
m_override
.
find
(
aItem
)
!=
m_override
.
end
();
}
///> spatial index of all items
//SHAPE_INDEX_LIST<PNS_ITEM *> m_items;
///> scans the joint map, forming a line starting from segment (current).
void
followLine
(
PNS_SEGMENT
*
current
,
///> hash table with the joints, linking the items. Joints are hashed by their
bool
scanDirection
,
///> position, layer set and net.
int
&
pos
,
JointMap
m_joints
;
int
limit
,
VECTOR2I
*
corners
,
///> node this node was branched from
PNS_SEGMENT
**
segments
);
PNS_NODE
*
m_parent
;
///> spatial index of all items
///> root node of the whole hierarchy
// SHAPE_INDEX_LIST<PNS_ITEM *> m_items;
PNS_NODE
*
m_root
;
///> hash table with the joints, linking the items. Joints are hashed by
///> list of nodes branched from this one
///> their position, layer set and net.
std
::
vector
<
PNS_NODE
*>
m_children
;
JointMap
m_joints
;
///> hash of root's items that are more recent in this node
///> node this node was branched from
boost
::
unordered_set
<
PNS_ITEM
*>
m_override
;
PNS_NODE
*
m_parent
;
///> worst case item-item clearance
///> root node of the whole hierarchy
int
m_maxClearance
;
PNS_NODE
*
m_root
;
///> Clearance resolution functor
///> list of nodes branched from this one
PNS_CLEARANCE_FUNC
*
m_clearanceFunctor
;
std
::
vector
<
PNS_NODE
*>
m_children
;
///> Geometric/Net index of the items
///> hash of root's items that are more recent in this node
PNS_INDEX
*
m_index
;
boost
::
unordered_set
<
PNS_ITEM
*>
m_override
;
///> list of currently processed obstacles.
///> worst case item-item clearance
Obstacles
m_obstacleList
;
int
m_maxClearance
;
///> Clearance resolution functor
PNS_CLEARANCE_FUNC
*
m_clearanceFunctor
;
///> Geometric/Net index of the items
PNS_INDEX
*
m_index
;
///> list of currently processed obstacles.
Obstacles
m_obstacleList
;
};
};
#endif
#endif
pcbnew/router/pns_optimizer.cpp
View file @
5598acb6
...
@@ -3,20 +3,21 @@
...
@@ -3,20 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#include <boost/foreach.hpp>
#include <boost/foreach.hpp>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_line_chain.h>
...
@@ -27,678 +28,737 @@
...
@@ -27,678 +28,737 @@
#include "pns_optimizer.h"
#include "pns_optimizer.h"
#include "pns_utils.h"
#include "pns_utils.h"
using
namespace
std
;
using
namespace
std
;
/**
/**
*
* Cost Estimator Methods
*
**/
Cost Estimator Methods
int
PNS_COST_ESTIMATOR
::
CornerCost
(
const
SEG
&
a
,
const
SEG
&
b
)
{
DIRECTION_45
dir_a
(
a
),
dir_b
(
b
);
**/
switch
(
dir_a
.
Angle
(
dir_b
)
)
{
case
DIRECTION_45
:
:
ANG_OBTUSE
:
return
1
;
int
PNS_COST_ESTIMATOR
::
CornerCost
(
const
SEG
&
a
,
const
SEG
&
b
)
case
DIRECTION_45
:
:
ANG_STRAIGHT
:
{
return
0
;
DIRECTION_45
dir_a
(
a
),
dir_b
(
b
);
case
DIRECTION_45
:
:
ANG_ACUTE
:
switch
(
dir_a
.
Angle
(
dir_b
))
return
50
;
{
case
DIRECTION_45
:
:
ANG_OBTUSE
:
case
DIRECTION_45
:
:
ANG_RIGHT
:
return
1
;
return
30
;
case
DIRECTION_45
:
:
ANG_STRAIGHT
:
return
0
;
case
DIRECTION_45
:
:
ANG_HALF_FULL
:
case
DIRECTION_45
:
:
ANG_ACUTE
:
return
60
;
return
50
;
case
DIRECTION_45
:
:
ANG_RIGHT
:
default
:
return
30
;
return
100
;
case
DIRECTION_45
:
:
ANG_HALF_FULL
:
}
return
60
;
default
:
return
100
;
}
}
}
int
PNS_COST_ESTIMATOR
::
CornerCost
(
const
SHAPE_LINE_CHAIN
&
aLine
)
int
PNS_COST_ESTIMATOR
::
CornerCost
(
const
SHAPE_LINE_CHAIN
&
aLine
)
{
{
int
total
=
0
;
int
total
=
0
;
for
(
int
i
=
0
;
i
<
aLine
.
SegmentCount
()
-
1
;
++
i
)
total
+=
CornerCost
(
aLine
.
CSegment
(
i
),
aLine
.
CSegment
(
i
+
1
));
for
(
int
i
=
0
;
i
<
aLine
.
SegmentCount
()
-
1
;
++
i
)
return
total
;
total
+=
CornerCost
(
aLine
.
CSegment
(
i
),
aLine
.
CSegment
(
i
+
1
)
);
return
total
;
}
}
int
PNS_COST_ESTIMATOR
::
CornerCost
(
const
PNS_LINE
&
aLine
)
int
PNS_COST_ESTIMATOR
::
CornerCost
(
const
PNS_LINE
&
aLine
)
{
{
return
CornerCost
(
aLine
.
GetCLine
()
);
return
CornerCost
(
aLine
.
GetCLine
()
);
}
}
void
PNS_COST_ESTIMATOR
::
Add
(
PNS_LINE
&
aLine
)
void
PNS_COST_ESTIMATOR
::
Add
(
PNS_LINE
&
aLine
)
{
{
m_lengthCost
+=
aLine
.
GetCLine
().
Length
();
m_lengthCost
+=
aLine
.
GetCLine
().
Length
();
m_cornerCost
+=
CornerCost
(
aLine
);
m_cornerCost
+=
CornerCost
(
aLine
);
}
}
void
PNS_COST_ESTIMATOR
::
Remove
(
PNS_LINE
&
aLine
)
void
PNS_COST_ESTIMATOR
::
Remove
(
PNS_LINE
&
aLine
)
{
{
m_lengthCost
-=
aLine
.
GetCLine
().
Length
();
m_lengthCost
-=
aLine
.
GetCLine
().
Length
();
m_cornerCost
-=
CornerCost
(
aLine
);
m_cornerCost
-=
CornerCost
(
aLine
);
}
}
void
PNS_COST_ESTIMATOR
::
Replace
(
PNS_LINE
&
aOldLine
,
PNS_LINE
&
aNewLine
)
void
PNS_COST_ESTIMATOR
::
Replace
(
PNS_LINE
&
aOldLine
,
PNS_LINE
&
aNewLine
)
{
{
m_lengthCost
-=
aOldLine
.
GetCLine
().
Length
();
m_lengthCost
-=
aOldLine
.
GetCLine
().
Length
();
m_cornerCost
-=
CornerCost
(
aOldLine
);
m_cornerCost
-=
CornerCost
(
aOldLine
);
m_lengthCost
+=
aNewLine
.
GetCLine
().
Length
();
m_lengthCost
+=
aNewLine
.
GetCLine
().
Length
();
m_cornerCost
+=
CornerCost
(
aNewLine
);
m_cornerCost
+=
CornerCost
(
aNewLine
);
}
}
bool
PNS_COST_ESTIMATOR
::
IsBetter
(
PNS_COST_ESTIMATOR
&
aOther
,
double
aLengthTollerance
,
double
aCornerTollerance
)
const
bool
PNS_COST_ESTIMATOR
::
IsBetter
(
PNS_COST_ESTIMATOR
&
aOther
,
double
aLengthTollerance
,
double
aCornerTollerance
)
const
{
{
if
(
aOther
.
m_cornerCost
<
m_cornerCost
&&
aOther
.
m_lengthCost
<
m_lengthCost
)
if
(
aOther
.
m_cornerCost
<
m_cornerCost
&&
aOther
.
m_lengthCost
<
m_lengthCost
)
return
true
;
return
true
;
else
if
(
aOther
.
m_cornerCost
<
m_cornerCost
*
aCornerTollerance
&&
aOther
.
m_lengthCost
<
m_lengthCost
*
aLengthTollerance
)
return
true
;
else
if
(
aOther
.
m_cornerCost
<
m_cornerCost
*
aCornerTollerance
&&
aOther
.
m_lengthCost
<
m_lengthCost
*
aLengthTollerance
)
return
false
;
return
true
;
return
false
;
}
}
/**
/**
*
Optimizer
* Optimizer
*
**/
**/
PNS_OPTIMIZER
::
PNS_OPTIMIZER
(
PNS_NODE
*
aWorld
)
:
m_world
(
aWorld
),
m_collisionKindMask
(
PNS_ITEM
::
ANY
),
m_effortLevel
(
MERGE_SEGMENTS
)
PNS_OPTIMIZER
::
PNS_OPTIMIZER
(
PNS_NODE
*
aWorld
)
:
m_world
(
aWorld
),
m_collisionKindMask
(
PNS_ITEM
::
ANY
),
m_effortLevel
(
MERGE_SEGMENTS
)
{
// m_cache = new SHAPE_INDEX_LIST<PNS_ITEM*>();
}
PNS_OPTIMIZER
::~
PNS_OPTIMIZER
(
)
{
{
//delete m_cache
;
// m_cache = new SHAPE_INDEX_LIST<PNS_ITEM*>()
;
}
}
struct
PNS_OPTIMIZER
::
CacheVisitor
PNS_OPTIMIZER
::~
PNS_OPTIMIZER
()
{
{
// delete m_cache;
}
CacheVisitor
(
const
PNS_ITEM
*
aOurItem
,
PNS_NODE
*
aNode
,
int
aMask
)
:
m_ourItem
(
aOurItem
),
m_collidingItem
(
NULL
),
m_node
(
aNode
),
m_mask
(
aMask
)
{};
bool
operator
()
(
PNS_ITEM
*
aOtherItem
)
{
if
(
!
m_mask
&
aOtherItem
->
GetKind
())
return
true
;
int
clearance
=
m_node
->
GetClearance
(
aOtherItem
,
m_ourItem
);
if
(
!
aOtherItem
->
Collide
(
m_ourItem
,
clearance
))
return
true
;
m_collidingItem
=
aOtherItem
;
return
false
;
}
const
PNS_ITEM
*
m_ourItem
;
struct
PNS_OPTIMIZER
::
CacheVisitor
PNS_ITEM
*
m_collidingItem
;
{
PNS_NODE
*
m_node
;
CacheVisitor
(
const
PNS_ITEM
*
aOurItem
,
PNS_NODE
*
aNode
,
int
aMask
)
:
int
m_mask
;
m_ourItem
(
aOurItem
),
m_collidingItem
(
NULL
),
m_node
(
aNode
),
m_mask
(
aMask
)
{};
bool
operator
()(
PNS_ITEM
*
aOtherItem
)
{
if
(
!
m_mask
&
aOtherItem
->
GetKind
()
)
return
true
;
int
clearance
=
m_node
->
GetClearance
(
aOtherItem
,
m_ourItem
);
if
(
!
aOtherItem
->
Collide
(
m_ourItem
,
clearance
)
)
return
true
;
m_collidingItem
=
aOtherItem
;
return
false
;
}
const
PNS_ITEM
*
m_ourItem
;
PNS_ITEM
*
m_collidingItem
;
PNS_NODE
*
m_node
;
int
m_mask
;
};
};
void
PNS_OPTIMIZER
::
cacheAdd
(
PNS_ITEM
*
aItem
,
bool
aIsStatic
=
false
)
void
PNS_OPTIMIZER
::
cacheAdd
(
PNS_ITEM
*
aItem
,
bool
aIsStatic
=
false
)
{
{
if
(
m_cacheTags
.
find
(
aItem
)
!=
m_cacheTags
.
end
()
)
if
(
m_cacheTags
.
find
(
aItem
)
!=
m_cacheTags
.
end
()
)
return
;
return
;
m_cache
.
Add
(
aItem
);
m_cache
.
Add
(
aItem
);
m_cacheTags
[
aItem
].
hits
=
1
;
m_cacheTags
[
aItem
].
hits
=
1
;
m_cacheTags
[
aItem
].
isStatic
=
aIsStatic
;
m_cacheTags
[
aItem
].
isStatic
=
aIsStatic
;
}
}
void
PNS_OPTIMIZER
::
removeCachedSegments
(
PNS_LINE
*
aLine
,
int
aStartVertex
,
int
aEndVertex
)
void
PNS_OPTIMIZER
::
removeCachedSegments
(
PNS_LINE
*
aLine
,
int
aStartVertex
,
int
aEndVertex
)
{
{
std
::
vector
<
PNS_SEGMENT
*>
*
segs
=
aLine
->
GetLinkedSegments
();
std
::
vector
<
PNS_SEGMENT
*>*
segs
=
aLine
->
GetLinkedSegments
();
if
(
!
segs
)
if
(
!
segs
)
return
;
return
;
if
(
aEndVertex
<
0
)
if
(
aEndVertex
<
0
)
aEndVertex
+=
aLine
->
GetCLine
().
PointCount
();
aEndVertex
+=
aLine
->
GetCLine
().
PointCount
();
for
(
int
i
=
aStartVertex
;
i
<
aEndVertex
-
1
;
i
++
)
for
(
int
i
=
aStartVertex
;
i
<
aEndVertex
-
1
;
i
++
)
{
{
PNS_SEGMENT
*
s
=
(
*
segs
)[
i
];
PNS_SEGMENT
*
s
=
(
*
segs
)[
i
];
m_cacheTags
.
erase
(
s
);
m_cacheTags
.
erase
(
s
);
m_cache
.
Remove
(
s
);
m_cache
.
Remove
(
s
);
}
//
*cacheRemove( (*segs)[i] );
}
//
*cacheRemove( (*segs)[i] );
}
}
void
PNS_OPTIMIZER
::
CacheRemove
(
PNS_ITEM
*
aItem
)
void
PNS_OPTIMIZER
::
CacheRemove
(
PNS_ITEM
*
aItem
)
{
{
if
(
aItem
->
GetKind
()
==
PNS_ITEM
::
LINE
)
if
(
aItem
->
GetKind
()
==
PNS_ITEM
::
LINE
)
removeCachedSegments
(
static_cast
<
PNS_LINE
*>
(
aItem
)
);
removeCachedSegments
(
static_cast
<
PNS_LINE
*>
(
aItem
)
);
}
}
void
PNS_OPTIMIZER
::
CacheStaticItem
(
PNS_ITEM
*
aItem
)
void
PNS_OPTIMIZER
::
CacheStaticItem
(
PNS_ITEM
*
aItem
)
{
{
cacheAdd
(
aItem
,
true
);
cacheAdd
(
aItem
,
true
);
}
}
void
PNS_OPTIMIZER
::
ClearCache
(
bool
aStaticOnly
)
void
PNS_OPTIMIZER
::
ClearCache
(
bool
aStaticOnly
)
{
{
if
(
!
aStaticOnly
)
if
(
!
aStaticOnly
)
{
{
m_cacheTags
.
clear
();
m_cacheTags
.
clear
();
m_cache
.
Clear
();
m_cache
.
Clear
();
return
;
return
;
}
}
for
(
CachedItemTags
::
iterator
i
=
m_cacheTags
.
begin
();
i
!=
m_cacheTags
.
end
();
++
i
)
for
(
CachedItemTags
::
iterator
i
=
m_cacheTags
.
begin
();
i
!=
m_cacheTags
.
end
();
++
i
)
{
{
if
(
i
->
second
.
isStatic
)
if
(
i
->
second
.
isStatic
)
{
{
m_cache
.
Remove
(
i
->
first
);
m_cache
.
Remove
(
i
->
first
);
m_cacheTags
.
erase
(
i
->
first
);
m_cacheTags
.
erase
(
i
->
first
);
}
}
}
}
}
}
bool
PNS_OPTIMIZER
::
checkColliding
(
PNS_ITEM
*
aItem
,
bool
aUpdateCache
)
bool
PNS_OPTIMIZER
::
checkColliding
(
PNS_ITEM
*
aItem
,
bool
aUpdateCache
)
{
{
CacheVisitor
v
(
aItem
,
m_world
,
m_collisionKindMask
);
CacheVisitor
v
(
aItem
,
m_world
,
m_collisionKindMask
);
return
m_world
->
CheckColliding
(
aItem
);
return
m_world
->
CheckColliding
(
aItem
);
// something is wrong with the cache, need to investigate.
// something is wrong with the cache, need to investigate.
m_cache
.
Query
(
aItem
->
GetShape
(),
m_world
->
GetMaxClearance
(),
v
,
false
);
m_cache
.
Query
(
aItem
->
GetShape
(),
m_world
->
GetMaxClearance
(),
v
,
false
);
if
(
!
v
.
m_collidingItem
)
if
(
!
v
.
m_collidingItem
)
{
{
PNS_NODE
::
OptObstacle
obs
=
m_world
->
CheckColliding
(
aItem
);
PNS_NODE
::
OptObstacle
obs
=
m_world
->
CheckColliding
(
aItem
);
if
(
obs
)
{
if
(
obs
)
{
if
(
aUpdateCache
)
if
(
aUpdateCache
)
cacheAdd
(
obs
->
item
);
cacheAdd
(
obs
->
item
);
return
true
;
}
return
true
;
}
else
{
}
m_cacheTags
[
v
.
m_collidingItem
].
hits
++
;
}
return
true
;
else
}
{
m_cacheTags
[
v
.
m_collidingItem
].
hits
++
;
return
false
;
return
true
;
}
return
false
;
}
}
bool
PNS_OPTIMIZER
::
checkColliding
(
PNS_LINE
*
aLine
,
const
SHAPE_LINE_CHAIN
&
aOptPath
)
bool
PNS_OPTIMIZER
::
checkColliding
(
PNS_LINE
*
aLine
,
const
SHAPE_LINE_CHAIN
&
aOptPath
)
{
{
PNS_LINE
tmp
(
*
aLine
,
aOptPath
);
PNS_LINE
tmp
(
*
aLine
,
aOptPath
);
return
checkColliding
(
&
tmp
);
return
checkColliding
(
&
tmp
);
}
}
bool
PNS_OPTIMIZER
::
mergeObtuse
(
PNS_LINE
*
aLine
)
bool
PNS_OPTIMIZER
::
mergeObtuse
(
PNS_LINE
*
aLine
)
{
{
SHAPE_LINE_CHAIN
&
line
=
aLine
->
GetLine
();
SHAPE_LINE_CHAIN
&
line
=
aLine
->
GetLine
();
int
step
=
line
.
PointCount
()
-
3
;
int
step
=
line
.
PointCount
()
-
3
;
int
iter
=
0
;
int
iter
=
0
;
int
segs_pre
=
line
.
SegmentCount
();
int
segs_pre
=
line
.
SegmentCount
();
if
(
step
<
0
)
if
(
step
<
0
)
return
false
;
return
false
;
SHAPE_LINE_CHAIN
current_path
(
line
);
SHAPE_LINE_CHAIN
current_path
(
line
);
while
(
1
)
while
(
1
)
{
{
iter
++
;
iter
++
;
int
n_segs
=
current_path
.
SegmentCount
();
int
n_segs
=
current_path
.
SegmentCount
();
int
max_step
=
n_segs
-
2
;
int
max_step
=
n_segs
-
2
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
<
2
)
{
if
(
step
<
2
)
line
=
current_path
;
{
return
current_path
.
SegmentCount
()
<
segs_pre
;
line
=
current_path
;
}
return
current_path
.
SegmentCount
()
<
segs_pre
;
}
bool
found_anything
=
false
;
int
n
=
0
;
bool
found_anything
=
false
;
int
n
=
0
;
while
(
n
<
n_segs
-
step
)
{
while
(
n
<
n_segs
-
step
)
const
SEG
s1
=
current_path
.
CSegment
(
n
);
{
const
SEG
s2
=
current_path
.
CSegment
(
n
+
step
);
const
SEG
s1
=
current_path
.
CSegment
(
n
);
SEG
s1opt
,
s2opt
;
const
SEG
s2
=
current_path
.
CSegment
(
n
+
step
);
SEG
s1opt
,
s2opt
;
if
(
DIRECTION_45
(
s1
).
IsObtuse
(
DIRECTION_45
(
s2
)))
{
if
(
DIRECTION_45
(
s1
).
IsObtuse
(
DIRECTION_45
(
s2
)
)
)
VECTOR2I
ip
=
*
s1
.
IntersectLines
(
s2
);
{
VECTOR2I
ip
=
*
s1
.
IntersectLines
(
s2
);
if
(
s1
.
Distance
(
ip
)
<=
1
||
s2
.
Distance
(
ip
)
<=
1
)
{
if
(
s1
.
Distance
(
ip
)
<=
1
||
s2
.
Distance
(
ip
)
<=
1
)
s1opt
=
SEG
(
s1
.
a
,
ip
);
{
s2opt
=
SEG
(
ip
,
s2
.
b
);
s1opt
=
SEG
(
s1
.
a
,
ip
);
}
else
{
s2opt
=
SEG
(
ip
,
s2
.
b
);
s1opt
=
SEG
(
s1
.
a
,
ip
);
}
s2opt
=
SEG
(
ip
,
s2
.
b
);
else
}
{
s1opt
=
SEG
(
s1
.
a
,
ip
);
s2opt
=
SEG
(
ip
,
s2
.
b
);
if
(
DIRECTION_45
(
s1opt
).
IsObtuse
(
DIRECTION_45
(
s2opt
)))
}
{
SHAPE_LINE_CHAIN
opt_path
;
opt_path
.
Append
(
s1opt
.
a
);
if
(
DIRECTION_45
(
s1opt
).
IsObtuse
(
DIRECTION_45
(
s2opt
)
)
)
opt_path
.
Append
(
s1opt
.
b
);
{
opt_path
.
Append
(
s2opt
.
b
);
SHAPE_LINE_CHAIN
opt_path
;
opt_path
.
Append
(
s1opt
.
a
);
PNS_LINE
opt_track
(
*
aLine
,
opt_path
);
opt_path
.
Append
(
s1opt
.
b
);
opt_path
.
Append
(
s2opt
.
b
);
if
(
!
checkColliding
(
&
opt_track
))
{
PNS_LINE
opt_track
(
*
aLine
,
opt_path
);
current_path
.
Replace
(
s1
.
Index
()
+
1
,
s2
.
Index
(),
ip
);
//removeCachedSegments(aLine, s1.Index(), s2.Index());
if
(
!
checkColliding
(
&
opt_track
)
)
n_segs
=
current_path
.
SegmentCount
();
{
found_anything
=
true
;
current_path
.
Replace
(
s1
.
Index
()
+
1
,
s2
.
Index
(),
ip
);
break
;
// removeCachedSegments(aLine, s1.Index(), s2.Index());
}
n_segs
=
current_path
.
SegmentCount
();
}
found_anything
=
true
;
}
break
;
n
++
;
}
}
}
}
if
(
!
found_anything
)
{
n
++
;
if
(
step
<=
2
)
}
{
line
=
current_path
;
if
(
!
found_anything
)
return
line
.
SegmentCount
()
<
segs_pre
;
{
}
if
(
step
<=
2
)
step
--
;
{
}
line
=
current_path
;
}
return
line
.
SegmentCount
()
<
segs_pre
;
return
line
.
SegmentCount
()
<
segs_pre
;
}
step
--
;
}
}
return
line
.
SegmentCount
()
<
segs_pre
;
}
}
bool
PNS_OPTIMIZER
::
mergeFull
(
PNS_LINE
*
aLine
)
bool
PNS_OPTIMIZER
::
mergeFull
(
PNS_LINE
*
aLine
)
{
{
SHAPE_LINE_CHAIN
&
line
=
aLine
->
GetLine
();
SHAPE_LINE_CHAIN
&
line
=
aLine
->
GetLine
();
int
step
=
line
.
SegmentCount
()
-
1
;
int
step
=
line
.
SegmentCount
()
-
1
;
int
segs_pre
=
line
.
SegmentCount
();
line
.
Simplify
();
int
segs_pre
=
line
.
SegmentCount
();
if
(
step
<
0
)
line
.
Simplify
();
return
false
;
SHAPE_LINE_CHAIN
current_path
(
line
);
if
(
step
<
0
)
return
false
;
while
(
1
)
SHAPE_LINE_CHAIN
current_path
(
line
);
{
int
n_segs
=
current_path
.
SegmentCount
();
int
max_step
=
n_segs
-
2
;
if
(
step
>
max_step
)
step
=
max_step
;
if
(
step
<
1
)
while
(
1
)
break
;
{
int
n_segs
=
current_path
.
SegmentCount
();
bool
found_anything
=
mergeStep
(
aLine
,
current_path
,
step
);
int
max_step
=
n_segs
-
2
;
if
(
!
found_anything
)
step
--
;
if
(
step
>
max_step
)
step
=
max_step
;
}
if
(
step
<
1
)
break
;
aLine
->
SetShape
(
current_path
);
bool
found_anything
=
mergeStep
(
aLine
,
current_path
,
step
);
return
current_path
.
SegmentCount
()
<
segs_pre
;
if
(
!
found_anything
)
step
--
;
}
aLine
->
SetShape
(
current_path
);
return
current_path
.
SegmentCount
()
<
segs_pre
;
}
}
bool
PNS_OPTIMIZER
::
Optimize
(
PNS_LINE
*
aLine
,
PNS_LINE
*
aResult
,
int
aStartVertex
,
int
aEndVertex
)
bool
PNS_OPTIMIZER
::
Optimize
(
PNS_LINE
*
aLine
,
PNS_LINE
*
aResult
,
int
aStartVertex
,
int
aEndVertex
)
{
{
if
(
!
aResult
)
if
(
!
aResult
)
aResult
=
aLine
;
aResult
=
aLine
;
else
else
*
aResult
=
*
aLine
;
*
aResult
=
*
aLine
;
m_keepPostures
=
false
;
m_keepPostures
=
false
;
bool
rv
=
false
;
bool
rv
=
false
;
if
(
m_effortLevel
&
MERGE_SEGMENTS
)
rv
|=
mergeFull
(
aResult
);
if
(
m_effortLevel
&
MERGE_SEGMENTS
)
if
(
m_effortLevel
&
MERGE_OBTUSE
)
rv
|=
mergeFull
(
aResult
);
rv
|=
mergeObtuse
(
aResult
);
if
(
m_effortLevel
&
SMART_PADS
)
if
(
m_effortLevel
&
MERGE_OBTUSE
)
rv
|=
runSmartPads
(
aResult
);
rv
|=
mergeObtuse
(
aResult
);
return
rv
;
if
(
m_effortLevel
&
SMART_PADS
)
rv
|=
runSmartPads
(
aResult
);
return
rv
;
}
}
bool
PNS_OPTIMIZER
::
mergeStep
(
PNS_LINE
*
aLine
,
SHAPE_LINE_CHAIN
&
aCurrentPath
,
int
step
)
bool
PNS_OPTIMIZER
::
mergeStep
(
PNS_LINE
*
aLine
,
SHAPE_LINE_CHAIN
&
aCurrentPath
,
int
step
)
{
{
int
n
=
0
;
int
n
=
0
;
int
n_segs
=
aCurrentPath
.
SegmentCount
();
int
n_segs
=
aCurrentPath
.
SegmentCount
();
int
cost_orig
=
PNS_COST_ESTIMATOR
::
CornerCost
(
aCurrentPath
);
int
cost_orig
=
PNS_COST_ESTIMATOR
::
CornerCost
(
aCurrentPath
);
if
(
aLine
->
GetCLine
().
SegmentCount
()
<
4
)
if
(
aLine
->
GetCLine
().
SegmentCount
()
<
4
)
return
false
;
return
false
;
DIRECTION_45
orig_start
(
aLine
->
GetCLine
().
CSegment
(
0
));
DIRECTION_45
orig_start
(
aLine
->
GetCLine
().
CSegment
(
0
)
);
DIRECTION_45
orig_end
(
aLine
->
GetCLine
().
CSegment
(
-
1
));
DIRECTION_45
orig_end
(
aLine
->
GetCLine
().
CSegment
(
-
1
)
);
while
(
n
<
n_segs
-
step
)
while
(
n
<
n_segs
-
step
)
{
{
const
SEG
s1
=
aCurrentPath
.
CSegment
(
n
);
const
SEG
s1
=
aCurrentPath
.
CSegment
(
n
);
const
SEG
s2
=
aCurrentPath
.
CSegment
(
n
+
step
);
const
SEG
s2
=
aCurrentPath
.
CSegment
(
n
+
step
);
SHAPE_LINE_CHAIN
path
[
2
],
*
picked
=
NULL
;
SHAPE_LINE_CHAIN
path
[
2
],
*
picked
=
NULL
;
int
cost
[
2
];
int
cost
[
2
];
for
(
int
i
=
0
;
i
<
2
;
i
++
)
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
{
bool
postureMatch
=
true
;
bool
postureMatch
=
true
;
SHAPE_LINE_CHAIN
bypass
=
DIRECTION_45
().
BuildInitialTrace
(
s1
.
a
,
s2
.
b
,
i
);
SHAPE_LINE_CHAIN
bypass
=
DIRECTION_45
().
BuildInitialTrace
(
s1
.
a
,
s2
.
b
,
i
);
cost
[
i
]
=
INT_MAX
;
cost
[
i
]
=
INT_MAX
;
if
(
n
==
0
&&
orig_start
!=
DIRECTION_45
(
bypass
.
CSegment
(
0
)
)
)
if
(
n
==
0
&&
orig_start
!=
DIRECTION_45
(
bypass
.
CSegment
(
0
)
)
)
postureMatch
=
false
;
postureMatch
=
false
;
else
if
(
n
==
n_segs
-
step
&&
orig_end
!=
DIRECTION_45
(
bypass
.
CSegment
(
-
1
)))
else
if
(
n
==
n_segs
-
step
&&
orig_end
!=
DIRECTION_45
(
bypass
.
CSegment
(
-
1
)
)
)
postureMatch
=
false
;
postureMatch
=
false
;
if
((
postureMatch
||
!
m_keepPostures
)
&&
!
checkColliding
(
aLine
,
bypass
))
if
(
(
postureMatch
||
!
m_keepPostures
)
&&
!
checkColliding
(
aLine
,
bypass
)
)
{
{
path
[
i
]
=
aCurrentPath
;
path
[
i
]
=
aCurrentPath
;
path
[
i
].
Replace
(
s1
.
Index
(),
s2
.
Index
(),
bypass
);
path
[
i
].
Replace
(
s1
.
Index
(),
s2
.
Index
(),
bypass
);
path
[
i
].
Simplify
();
path
[
i
].
Simplify
();
cost
[
i
]
=
PNS_COST_ESTIMATOR
::
CornerCost
(
path
[
i
]);
cost
[
i
]
=
PNS_COST_ESTIMATOR
::
CornerCost
(
path
[
i
]
);
}
}
}
}
if
(
cost
[
0
]
<
cost_orig
&&
cost
[
0
]
<
cost
[
1
])
if
(
cost
[
0
]
<
cost_orig
&&
cost
[
0
]
<
cost
[
1
]
)
picked
=
&
path
[
0
];
picked
=
&
path
[
0
];
else
if
(
cost
[
1
]
<
cost_orig
)
else
if
(
cost
[
1
]
<
cost_orig
)
picked
=
&
path
[
1
];
picked
=
&
path
[
1
];
if
(
picked
)
if
(
picked
)
{
{
n_segs
=
aCurrentPath
.
SegmentCount
();
n_segs
=
aCurrentPath
.
SegmentCount
();
aCurrentPath
=
*
picked
;
aCurrentPath
=
*
picked
;
return
true
;
return
true
;
}
}
n
++
;
}
n
++
;
}
return
false
;
return
false
;
}
}
PNS_OPTIMIZER
::
BreakoutList
PNS_OPTIMIZER
::
circleBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
PNS_OPTIMIZER
::
BreakoutList
PNS_OPTIMIZER
::
circleBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
{
{
BreakoutList
breakouts
;
BreakoutList
breakouts
;
for
(
int
angle
=
0
;
angle
<
360
;
angle
+=
45
)
for
(
int
angle
=
0
;
angle
<
360
;
angle
+=
45
)
{
{
const
SHAPE_CIRCLE
*
cir
=
static_cast
<
const
SHAPE_CIRCLE
*>
(
aShape
);
const
SHAPE_CIRCLE
*
cir
=
static_cast
<
const
SHAPE_CIRCLE
*>
(
aShape
);
SHAPE_LINE_CHAIN
l
;
SHAPE_LINE_CHAIN
l
;
VECTOR2I
p0
=
cir
->
GetCenter
();
VECTOR2I
p0
=
cir
->
GetCenter
();
VECTOR2I
v0
(
cir
->
GetRadius
()
*
M_SQRT2
,
0
);
VECTOR2I
v0
(
cir
->
GetRadius
()
*
M_SQRT2
,
0
);
l
.
Append
(
p0
);
l
.
Append
(
p0
);
l
.
Append
(
p0
+
v0
.
Rotate
(
angle
*
M_PI
/
180.0
)
);
l
.
Append
(
p0
+
v0
.
Rotate
(
angle
*
M_PI
/
180.0
)
);
breakouts
.
push_back
(
l
);
breakouts
.
push_back
(
l
);
}
}
return
breakouts
;
return
breakouts
;
}
}
PNS_OPTIMIZER
::
BreakoutList
PNS_OPTIMIZER
::
rectBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
PNS_OPTIMIZER
::
BreakoutList
PNS_OPTIMIZER
::
rectBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
{
{
const
SHAPE_RECT
*
rect
=
static_cast
<
const
SHAPE_RECT
*>
(
aShape
);
const
SHAPE_RECT
*
rect
=
static_cast
<
const
SHAPE_RECT
*>
(
aShape
);
VECTOR2I
s
=
rect
->
GetSize
(),
c
=
rect
->
GetPosition
()
+
VECTOR2I
(
s
.
x
/
2
,
s
.
y
/
2
);
VECTOR2I
s
=
rect
->
GetSize
(),
c
=
rect
->
GetPosition
()
+
VECTOR2I
(
s
.
x
/
2
,
s
.
y
/
2
);
BreakoutList
breakouts
;
BreakoutList
breakouts
;
VECTOR2I
d_offset
;
VECTOR2I
d_offset
;
d_offset
.
x
=
(
s
.
x
>
s
.
y
)
?
(
s
.
x
-
s
.
y
)
/
2
:
0
;
d_offset
.
x
=
(
s
.
x
>
s
.
y
)
?
(
s
.
x
-
s
.
y
)
/
2
:
0
;
d_offset
.
y
=
(
s
.
x
<
s
.
y
)
?
(
s
.
y
-
s
.
x
)
/
2
:
0
;
d_offset
.
y
=
(
s
.
x
<
s
.
y
)
?
(
s
.
y
-
s
.
x
)
/
2
:
0
;
VECTOR2I
d_vert
=
VECTOR2I
(
0
,
s
.
y
/
2
+
aWidth
);
VECTOR2I
d_vert
=
VECTOR2I
(
0
,
s
.
y
/
2
+
aWidth
);
VECTOR2I
d_horiz
=
VECTOR2I
(
s
.
x
/
2
+
aWidth
,
0
);
VECTOR2I
d_horiz
=
VECTOR2I
(
s
.
x
/
2
+
aWidth
,
0
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_horiz
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_horiz
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_horiz
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_horiz
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_vert
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_vert
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_vert
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_vert
)
);
if
(
aPermitDiagonal
)
if
(
aPermitDiagonal
)
{
{
int
l
=
aWidth
+
std
::
min
(
s
.
x
,
s
.
y
)
/
2
;
int
l
=
aWidth
+
std
::
min
(
s
.
x
,
s
.
y
)
/
2
;
VECTOR2I
d_diag
;
VECTOR2I
d_diag
;
if
(
s
.
x
>=
s
.
y
)
if
(
s
.
x
>=
s
.
y
)
{
{
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
c
+
d_offset
+
VECTOR2I
(
l
,
l
)));
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
c
+
d_offset
-
VECTOR2I
(
-
l
,
l
)));
c
+
d_offset
+
VECTOR2I
(
l
,
l
)
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
c
-
d_offset
+
VECTOR2I
(
-
l
,
l
)));
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
c
-
d_offset
-
VECTOR2I
(
l
,
l
)));
c
+
d_offset
-
VECTOR2I
(
-
l
,
l
)
)
);
}
else
{
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
// fixme: this could be done more efficiently
c
-
d_offset
+
VECTOR2I
(
-
l
,
l
)
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
c
+
d_offset
+
VECTOR2I
(
l
,
l
)));
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
c
-
d_offset
-
VECTOR2I
(
-
l
,
l
)));
c
-
d_offset
-
VECTOR2I
(
l
,
l
)
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
c
+
d_offset
+
VECTOR2I
(
-
l
,
l
)));
}
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
c
-
d_offset
-
VECTOR2I
(
l
,
l
)));
else
{
}
// fixme: this could be done more efficiently
}
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
c
+
d_offset
+
VECTOR2I
(
l
,
l
)
)
);
return
breakouts
;
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
c
-
d_offset
-
VECTOR2I
(
-
l
,
l
)
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
+
d_offset
,
c
+
d_offset
+
VECTOR2I
(
-
l
,
l
)
)
);
breakouts
.
push_back
(
SHAPE_LINE_CHAIN
(
c
,
c
-
d_offset
,
c
-
d_offset
-
VECTOR2I
(
l
,
l
)
)
);
}
}
return
breakouts
;
}
}
PNS_OPTIMIZER
::
BreakoutList
PNS_OPTIMIZER
::
computeBreakouts
(
int
aWidth
,
const
PNS_ITEM
*
aItem
,
bool
aPermitDiagonal
)
const
PNS_OPTIMIZER
::
BreakoutList
PNS_OPTIMIZER
::
computeBreakouts
(
int
aWidth
,
const
PNS_ITEM
*
aItem
,
bool
aPermitDiagonal
)
const
{
{
switch
(
aItem
->
GetKind
())
switch
(
aItem
->
GetKind
()
)
{
{
case
PNS_ITEM
:
:
VIA
:
case
PNS_ITEM
:
:
VIA
:
{
{
const
PNS_VIA
*
via
=
static_cast
<
const
PNS_VIA
*>
(
aItem
);
const
PNS_VIA
*
via
=
static_cast
<
const
PNS_VIA
*>
(
aItem
);
return
circleBreakouts
(
aWidth
,
via
->
GetShape
(),
aPermitDiagonal
);
return
circleBreakouts
(
aWidth
,
via
->
GetShape
(),
aPermitDiagonal
);
}
}
case
PNS_ITEM
:
:
SOLID
:
case
PNS_ITEM
:
:
SOLID
:
{
{
const
SHAPE
*
shape
=
aItem
->
GetShape
();
const
SHAPE
*
shape
=
aItem
->
GetShape
();
switch
(
shape
->
Type
())
{
switch
(
shape
->
Type
()
)
case
SH_RECT
:
{
return
rectBreakouts
(
aWidth
,
shape
,
aPermitDiagonal
);
case
SH_RECT
:
case
SH_CIRCLE
:
return
rectBreakouts
(
aWidth
,
shape
,
aPermitDiagonal
);
return
circleBreakouts
(
aWidth
,
shape
,
aPermitDiagonal
);
default
:
case
SH_CIRCLE
:
break
;
return
circleBreakouts
(
aWidth
,
shape
,
aPermitDiagonal
);
}
}
default
:
default
:
break
;
break
;
}
}
}
return
BreakoutList
();
default
:
break
;
}
return
BreakoutList
();
}
}
PNS_ITEM
*
PNS_OPTIMIZER
::
findPadOrVia
(
int
aLayer
,
int
aNet
,
const
VECTOR2I
&
aP
)
const
PNS_ITEM
*
PNS_OPTIMIZER
::
findPadOrVia
(
int
aLayer
,
int
aNet
,
const
VECTOR2I
&
aP
)
const
{
{
PNS_NODE
::
OptJoint
jt
=
m_world
->
FindJoint
(
aP
,
aLayer
,
aNet
);
PNS_NODE
::
OptJoint
jt
=
m_world
->
FindJoint
(
aP
,
aLayer
,
aNet
);
if
(
!
jt
)
return
NULL
;
if
(
!
jt
)
return
NULL
;
BOOST_FOREACH
(
PNS_ITEM
*
item
,
jt
->
GetLinkList
()
)
{
BOOST_FOREACH
(
PNS_ITEM
*
item
,
jt
->
GetLinkList
()
)
if
(
item
->
GetKind
()
==
PNS_ITEM
::
VIA
||
item
->
GetKind
()
==
PNS_ITEM
::
SOLID
)
{
return
item
;
if
(
item
->
GetKind
()
==
PNS_ITEM
::
VIA
||
item
->
GetKind
()
==
PNS_ITEM
::
SOLID
)
}
return
item
;
return
NULL
;
}
return
NULL
;
}
}
int
PNS_OPTIMIZER
::
smartPadsSingle
(
PNS_LINE
*
aLine
,
PNS_ITEM
*
aPad
,
bool
aEnd
,
int
aEndVertex
)
int
PNS_OPTIMIZER
::
smartPadsSingle
(
PNS_LINE
*
aLine
,
PNS_ITEM
*
aPad
,
bool
aEnd
,
int
aEndVertex
)
{
{
int
min_cost
=
INT_MAX
;
//PNS_COST_ESTIMATOR::CornerCost( line );
int
min_cost
=
INT_MAX
;
// PNS_COST_ESTIMATOR::CornerCost( line );
int
min_len
=
INT_MAX
;
int
min_len
=
INT_MAX
;
DIRECTION_45
dir
;
DIRECTION_45
dir
;
const
int
ForbiddenAngles
=
DIRECTION_45
::
ANG_ACUTE
|
DIRECTION_45
::
ANG_RIGHT
|
DIRECTION_45
::
ANG_HALF_FULL
|
DIRECTION_45
::
ANG_UNDEFINED
;
const
int
ForbiddenAngles
=
DIRECTION_45
::
ANG_ACUTE
|
DIRECTION_45
::
ANG_RIGHT
|
DIRECTION_45
::
ANG_HALF_FULL
|
DIRECTION_45
::
ANG_UNDEFINED
;
typedef
pair
<
int
,
SHAPE_LINE_CHAIN
>
RtVariant
;
vector
<
RtVariant
>
variants
;
typedef
pair
<
int
,
SHAPE_LINE_CHAIN
>
RtVariant
;
vector
<
RtVariant
>
variants
;
BreakoutList
breakouts
=
computeBreakouts
(
aLine
->
GetWidth
(),
aPad
,
true
);
BreakoutList
breakouts
=
computeBreakouts
(
aLine
->
GetWidth
(),
aPad
,
true
);
SHAPE_LINE_CHAIN
line
=
(
aEnd
?
aLine
->
GetCLine
().
Reverse
()
:
aLine
->
GetCLine
());
SHAPE_LINE_CHAIN
line
=
(
aEnd
?
aLine
->
GetCLine
().
Reverse
()
:
aLine
->
GetCLine
()
);
//bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal();
// bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal();
int
p_end
=
min
(
aEndVertex
,
min
(
3
,
line
.
PointCount
()
-
1
));
int
p_end
=
min
(
aEndVertex
,
min
(
3
,
line
.
PointCount
()
-
1
)
);
for
(
int
p
=
1
;
p
<=
p_end
;
p
++
)
{
for
(
int
p
=
1
;
p
<=
p_end
;
p
++
)
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
&
l
,
breakouts
)
{
{
BOOST_FOREACH
(
SHAPE_LINE_CHAIN
&
l
,
breakouts
)
{
//PNSDisplayDebugLine (l, 0);
// PNSDisplayDebugLine (l, 0);
for
(
int
diag
=
0
;
diag
<
2
;
diag
++
)
for
(
int
diag
=
0
;
diag
<
2
;
diag
++
)
{
{
SHAPE_LINE_CHAIN
v
;
SHAPE_LINE_CHAIN
v
;
SHAPE_LINE_CHAIN
connect
=
dir
.
BuildInitialTrace
(
l
.
CPoint
(
-
1
),
line
.
CPoint
(
p
),
diag
==
0
);
SHAPE_LINE_CHAIN
connect
=
dir
.
BuildInitialTrace
(
l
.
CPoint
(
-
1
),
line
.
CPoint
(
p
),
diag
==
0
);
DIRECTION_45
dir_bkout
(
l
.
CSegment
(
-
1
));
//DIRECTION_45 dir_head ( line.CSegment(p + 1));
DIRECTION_45
dir_bkout
(
l
.
CSegment
(
-
1
)
);
// DIRECTION_45 dir_head ( line.CSegment(p + 1));
int
ang1
=
dir_bkout
.
Angle
(
DIRECTION_45
(
connect
.
CSegment
(
0
)
));
int
ang2
=
0
;
int
ang1
=
dir_bkout
.
Angle
(
DIRECTION_45
(
connect
.
CSegment
(
0
)
)
);
//int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) ));
int
ang2
=
0
;
// int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) ));
if
(
(
ang1
|
ang2
)
&
ForbiddenAngles
)
continue
;
if
(
(
ang1
|
ang2
)
&
ForbiddenAngles
)
continue
;
if
(
l
.
Length
()
>
line
.
Length
())
continue
;
v
=
l
;
v
.
Append
(
connect
);
for
(
int
i
=
p
+
1
;
i
<
line
.
PointCount
();
i
++
)
v
.
Append
(
line
.
CPoint
(
i
)
);
PNS_LINE
tmp
(
*
aLine
,
v
);
//tmp.GetLine().Simplify();
int
cc
=
tmp
.
CountCorners
(
ForbiddenAngles
);
if
(
cc
==
0
)
{
RtVariant
vp
;
vp
.
first
=
p
;
vp
.
second
=
aEnd
?
v
.
Reverse
()
:
v
;
vp
.
second
.
Simplify
();
variants
.
push_back
(
vp
);
}
}
}
}
SHAPE_LINE_CHAIN
l_best
;
bool
found
=
false
;
int
p_best
=
-
1
;
BOOST_FOREACH
(
RtVariant
&
vp
,
variants
)
{
PNS_LINE
tmp
(
*
aLine
,
vp
.
second
);
int
cost
=
PNS_COST_ESTIMATOR
::
CornerCost
(
vp
.
second
);
int
len
=
vp
.
second
.
Length
();
if
(
!
checkColliding
(
&
tmp
))
{
if
(
l
.
Length
()
>
line
.
Length
()
)
continue
;
v
=
l
;
v
.
Append
(
connect
);
for
(
int
i
=
p
+
1
;
i
<
line
.
PointCount
();
i
++
)
v
.
Append
(
line
.
CPoint
(
i
)
);
PNS_LINE
tmp
(
*
aLine
,
v
);
// tmp.GetLine().Simplify();
int
cc
=
tmp
.
CountCorners
(
ForbiddenAngles
);
if
(
cc
==
0
)
{
RtVariant
vp
;
vp
.
first
=
p
;
vp
.
second
=
aEnd
?
v
.
Reverse
()
:
v
;
vp
.
second
.
Simplify
();
variants
.
push_back
(
vp
);
}
}
}
}
SHAPE_LINE_CHAIN
l_best
;
bool
found
=
false
;
int
p_best
=
-
1
;
BOOST_FOREACH
(
RtVariant
&
vp
,
variants
)
{
PNS_LINE
tmp
(
*
aLine
,
vp
.
second
);
int
cost
=
PNS_COST_ESTIMATOR
::
CornerCost
(
vp
.
second
);
int
len
=
vp
.
second
.
Length
();
if
(
!
checkColliding
(
&
tmp
)
)
{
/* if(aEnd)
/* if(aEnd)
PNSDisplayDebugLine (l_best, 6);
* PNSDisplayDebugLine (l_best, 6);
else
* else
PNSDisplayDebugLine (l_best, 5);*/
* PNSDisplayDebugLine (l_best, 5);*/
if
(
cost
<
min_cost
||
(
cost
==
min_cost
&&
len
<
min_len
))
if
(
cost
<
min_cost
||
(
cost
==
min_cost
&&
len
<
min_len
)
)
{
{
l_best
=
vp
.
second
;
l_best
=
vp
.
second
;
p_best
=
vp
.
first
;
p_best
=
vp
.
first
;
found
=
true
;
found
=
true
;
//if(cost == min_cost)
// if(cost == min_cost)
if
(
cost
==
min_cost
)
if
(
cost
==
min_cost
)
min_len
=
std
::
min
(
len
,
min_len
);
min_len
=
std
::
min
(
len
,
min_len
);
min_cost
=
std
::
min
(
cost
,
min_cost
);
}
min_cost
=
std
::
min
(
cost
,
min_cost
);
}
}
}
}
}
if
(
found
)
if
(
found
)
{
{
// printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount());
// printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount());
// if(!aEnd)
// if(!aEnd)
// PNSDisplayDebugLine (l_best, 5);
// PNSDisplayDebugLine (l_best, 5);
// else
// else
aLine
->
SetShape
(
l_best
);
aLine
->
SetShape
(
l_best
);
return
p_best
;
return
p_best
;
}
}
return
-
1
;
return
-
1
;
}
}
bool
PNS_OPTIMIZER
::
runSmartPads
(
PNS_LINE
*
aLine
)
bool
PNS_OPTIMIZER
::
runSmartPads
(
PNS_LINE
*
aLine
)
{
{
SHAPE_LINE_CHAIN
&
line
=
aLine
->
GetLine
();
SHAPE_LINE_CHAIN
&
line
=
aLine
->
GetLine
();
if
(
line
.
PointCount
()
<
3
)
return
false
;
if
(
line
.
PointCount
()
<
3
)
VECTOR2I
p_start
=
line
.
CPoint
(
0
),
p_end
=
line
.
CPoint
(
-
1
);
return
false
;
VECTOR2I
p_start
=
line
.
CPoint
(
0
),
p_end
=
line
.
CPoint
(
-
1
);
PNS_ITEM
*
startPad
=
findPadOrVia
(
aLine
->
GetLayer
(),
aLine
->
GetNet
(),
p_start
);
PNS_ITEM
*
endPad
=
findPadOrVia
(
aLine
->
GetLayer
(),
aLine
->
GetNet
(),
p_end
);
PNS_ITEM
*
startPad
=
findPadOrVia
(
aLine
->
GetLayer
(),
aLine
->
GetNet
(),
p_start
);
int
vtx
=
-
1
;
PNS_ITEM
*
endPad
=
findPadOrVia
(
aLine
->
GetLayer
(),
aLine
->
GetNet
(),
p_end
);
int
vtx
=
-
1
;
if
(
startPad
)
vtx
=
smartPadsSingle
(
aLine
,
startPad
,
false
,
3
);
if
(
startPad
)
if
(
endPad
)
vtx
=
smartPadsSingle
(
aLine
,
startPad
,
false
,
3
);
smartPadsSingle
(
aLine
,
endPad
,
true
,
if
(
endPad
)
vtx
<
0
?
line
.
PointCount
()
-
1
:
line
.
PointCount
()
-
1
-
vtx
);
smartPadsSingle
(
aLine
,
endPad
,
true
,
vtx
<
0
?
line
.
PointCount
()
-
1
:
line
.
PointCount
()
-
1
-
vtx
);
aLine
->
GetLine
().
Simplify
();
aLine
->
GetLine
().
Simplify
();
return
true
;
return
true
;
}
}
bool
PNS_OPTIMIZER
::
Optimize
(
PNS_LINE
*
aLine
,
int
aEffortLevel
,
PNS_NODE
*
aWorld
)
bool
PNS_OPTIMIZER
::
Optimize
(
PNS_LINE
*
aLine
,
int
aEffortLevel
,
PNS_NODE
*
aWorld
)
{
{
PNS_OPTIMIZER
opt
(
aWorld
?
aWorld
:
aLine
->
GetWorld
()
);
PNS_OPTIMIZER
opt
(
aWorld
?
aWorld
:
aLine
->
GetWorld
()
);
opt
.
SetEffortLevel
(
aEffortLevel
);
opt
.
SetCollisionMask
(
-
1
);
opt
.
SetEffortLevel
(
aEffortLevel
);
return
opt
.
Optimize
(
aLine
);
opt
.
SetCollisionMask
(
-
1
);
return
opt
.
Optimize
(
aLine
);
}
}
pcbnew/router/pns_optimizer.h
View file @
5598acb6
...
@@ -3,20 +3,21 @@
...
@@ -3,20 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#ifndef __PNS_OPTIMIZER_H
#ifndef __PNS_OPTIMIZER_H
#define __PNS_OPTIMIZER_H
#define __PNS_OPTIMIZER_H
...
@@ -30,135 +31,137 @@ class PNS_NODE;
...
@@ -30,135 +31,137 @@ class PNS_NODE;
class
PNS_LINE
;
class
PNS_LINE
;
class
PNS_ROUTER
;
class
PNS_ROUTER
;
/**
/**
* Class PNS_COST_ESTIMATOR
* Class PNS_COST_ESTIMATOR
*
*
* Calculates the cost of a given line, taking corner angles and total length into account.
* Calculates the cost of a given line, taking corner angles and total length into account.
**/
**/
class
PNS_COST_ESTIMATOR
class
PNS_COST_ESTIMATOR
{
{
public
:
public
:
PNS_COST_ESTIMATOR
()
:
PNS_COST_ESTIMATOR
()
:
m_lengthCost
(
0
),
m_lengthCost
(
0
),
m_cornerCost
(
0
)
m_cornerCost
(
0
)
{};
{};
PNS_COST_ESTIMATOR
(
const
PNS_COST_ESTIMATOR
&
b
)
:
PNS_COST_ESTIMATOR
(
const
PNS_COST_ESTIMATOR
&
b
)
:
m_lengthCost
(
b
.
m_lengthCost
),
m_lengthCost
(
b
.
m_lengthCost
),
m_cornerCost
(
b
.
m_cornerCost
)
m_cornerCost
(
b
.
m_cornerCost
)
{};
{};
~
PNS_COST_ESTIMATOR
()
{};
~
PNS_COST_ESTIMATOR
()
{};
static
int
CornerCost
(
const
SEG
&
a
,
const
SEG
&
b
);
static
int
CornerCost
(
const
SEG
&
a
,
const
SEG
&
b
);
static
int
CornerCost
(
const
SHAPE_LINE_CHAIN
&
aLine
);
static
int
CornerCost
(
const
SHAPE_LINE_CHAIN
&
aLine
);
static
int
CornerCost
(
const
PNS_LINE
&
aLine
);
static
int
CornerCost
(
const
PNS_LINE
&
aLine
);
void
Add
(
PNS_LINE
&
aLine
);
void
Add
(
PNS_LINE
&
aLine
);
void
Remove
(
PNS_LINE
&
aLine
);
void
Remove
(
PNS_LINE
&
aLine
);
void
Replace
(
PNS_LINE
&
aOldLine
,
PNS_LINE
&
aNewLine
);
void
Replace
(
PNS_LINE
&
aOldLine
,
PNS_LINE
&
aNewLine
);
bool
IsBetter
(
PNS_COST_ESTIMATOR
&
aOther
,
double
aLengthTollerance
,
double
aCornerTollerace
)
const
;
bool
IsBetter
(
PNS_COST_ESTIMATOR
&
aOther
,
double
aLengthTollerance
,
double
aCornerTollerace
)
const
;
double
GetLengthCost
()
const
{
return
m_lengthCost
;
}
double
GetCornerCost
()
const
{
return
m_cornerCost
;
}
double
GetLengthCost
()
const
{
return
m_lengthCost
;
}
double
GetCornerCost
()
const
{
return
m_cornerCost
;
}
private
:
double
m_lengthCost
;
private
:
int
m_cornerCost
;
double
m_lengthCost
;
int
m_cornerCost
;
};
};
/**
/**
* Class PNS_OPTIMIZER
* Class PNS_OPTIMIZER
*
*
* Performs various optimizations of the lines being routed, attempting to make the lines shorter
* Performs various optimizations of the lines being routed, attempting to make the lines shorter
* and less cornery. There are 3 kinds of optimizations so far:
* and less cornery. There are 3 kinds of optimizations so far:
* - Merging obtuse segments (MERGE_OBTUSE): tries to join together as many
* - Merging obtuse segments (MERGE_OBTUSE): tries to join together as many
* obtuse segments as possible without causing collisions
* obtuse segments as possible without causing collisions
* - Rerouting path between pair of line corners with a 2-segment "\__" line and iteratively repeating
* - Rerouting path between pair of line corners with a 2-segment "\__" line and iteratively repeating
* the procedure as long as the total cost of the line keeps decreasing
* the procedure as long as the total cost of the line keeps decreasing
* - "Smart Pads" - that is, rerouting pad/via exits to make them look nice (SMART_PADS).
* - "Smart Pads" - that is, rerouting pad/via exits to make them look nice (SMART_PADS).
**/
**/
class
PNS_OPTIMIZER
class
PNS_OPTIMIZER
{
{
public
:
public
:
enum
OptimizationEffort
{
MERGE_SEGMENTS
=
0x01
,
SMART_PADS
=
0x02
,
MERGE_OBTUSE
=
0x04
};
enum
OptimizationEffort
{
PNS_OPTIMIZER
(
PNS_NODE
*
aWorld
);
MERGE_SEGMENTS
=
0x1
,
~
PNS_OPTIMIZER
();
SMART_PADS
=
0x2
,
MERGE_OBTUSE
=
0x4
};
PNS_OPTIMIZER
(
PNS_NODE
*
aWorld
);
///> a quick shortcut to optmize a line without creating and setting up an optimizer
~
PNS_OPTIMIZER
(
);
static
bool
Optimize
(
PNS_LINE
*
aLine
,
int
aEffortLevel
,
PNS_NODE
*
aWorld
=
NULL
);
///> a quick shortcut to optmize a line without creating and setting up an optimizer
bool
Optimize
(
PNS_LINE
*
aLine
,
PNS_LINE
*
aResult
=
NULL
,
static
bool
Optimize
(
PNS_LINE
*
aLine
,
int
aEffortLevel
,
PNS_NODE
*
aWorld
=
NULL
);
int
aStartVertex
=
0
,
int
aEndVertex
=
-
1
);
bool
Optimize
(
PNS_LINE
*
aLine
,
PNS_LINE
*
aResult
=
NULL
,
int
aStartVertex
=
0
,
int
aEndVertex
=
-
1
);
void
SetWorld
(
PNS_NODE
*
aNode
)
{
m_world
=
aNode
;
}
void
CacheStaticItem
(
PNS_ITEM
*
aItem
);
void
CacheRemove
(
PNS_ITEM
*
aItem
);
void
ClearCache
(
bool
aStaticOnly
=
false
);
void
SetWorld
(
PNS_NODE
*
aNode
)
{
m_world
=
aNode
;
}
void
SetCollisionMask
(
int
aMask
)
void
CacheStaticItem
(
PNS_ITEM
*
aItem
);
{
void
CacheRemove
(
PNS_ITEM
*
aItem
)
;
m_collisionKindMask
=
aMask
;
void
ClearCache
(
bool
aStaticOnly
=
false
);
}
void
SetCollisionMask
(
int
aMask
)
void
SetEffortLevel
(
int
aEffort
)
{
{
m_collisionKindMask
=
aMask
;
m_effortLevel
=
aEffort
;
}
}
void
SetEffortLevel
(
int
aEffort
)
private
:
{
static
const
int
MaxCachedItems
=
256
;
m_effortLevel
=
aEffort
;
}
private
:
static
const
int
MaxCachedItems
=
256
;
typedef
std
::
vector
<
SHAPE_LINE_CHAIN
>
BreakoutList
;
typedef
std
::
vector
<
SHAPE_LINE_CHAIN
>
BreakoutList
;
struct
CacheVisitor
;
struct
CacheVisitor
;
struct
CachedItem
{
struct
CachedItem
int
hits
;
{
bool
isStatic
;
int
hits
;
};
bool
isStatic
;
};
bool
mergeObtuse
(
PNS_LINE
*
aLine
);
bool
mergeObtuse
(
PNS_LINE
*
aLine
);
bool
mergeFull
(
PNS_LINE
*
aLine
);
bool
mergeFull
(
PNS_LINE
*
aLine
);
bool
removeUglyCorners
(
PNS_LINE
*
aLine
);
bool
removeUglyCorners
(
PNS_LINE
*
aLine
);
bool
runSmartPads
(
PNS_LINE
*
aLine
);
bool
runSmartPads
(
PNS_LINE
*
aLine
);
bool
mergeStep
(
PNS_LINE
*
aLine
,
SHAPE_LINE_CHAIN
&
aCurrentLine
,
int
step
);
bool
mergeStep
(
PNS_LINE
*
aLine
,
SHAPE_LINE_CHAIN
&
aCurrentLine
,
int
step
);
bool
checkColliding
(
PNS_ITEM
*
aItem
,
bool
aUpdateCache
=
true
);
bool
checkColliding
(
PNS_ITEM
*
aItem
,
bool
aUpdateCache
=
true
);
bool
checkColliding
(
PNS_LINE
*
aLine
,
const
SHAPE_LINE_CHAIN
&
aOptPath
);
bool
checkColliding
(
PNS_LINE
*
aLine
,
const
SHAPE_LINE_CHAIN
&
aOptPath
);
void
cacheAdd
(
PNS_ITEM
*
aItem
,
bool
aIsStatic
);
void
cacheAdd
(
PNS_ITEM
*
aItem
,
bool
aIsStatic
);
void
removeCachedSegments
(
PNS_LINE
*
aLine
,
int
aStartVertex
=
0
,
int
aEndVertex
=
-
1
);
void
removeCachedSegments
(
PNS_LINE
*
aLine
,
int
aStartVertex
=
0
,
int
aEndVertex
=
-
1
);
BreakoutList
circleBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
;
BreakoutList
circleBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
;
BreakoutList
rectBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
;
BreakoutList
rectBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
;
BreakoutList
ovalBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
;
BreakoutList
ovalBreakouts
(
int
aWidth
,
const
SHAPE
*
aShape
,
bool
aPermitDiagonal
)
const
;
BreakoutList
computeBreakouts
(
int
aWidth
,
const
PNS_ITEM
*
aItem
,
bool
aPermitDiagonal
)
const
;
BreakoutList
computeBreakouts
(
int
aWidth
,
const
PNS_ITEM
*
aItem
,
bool
aPermitDiagonal
)
const
;
int
smartPadsSingle
(
PNS_LINE
*
aLine
,
PNS_ITEM
*
aPad
,
bool
aEnd
,
int
aEndVertex
);
int
smartPadsSingle
(
PNS_LINE
*
aLine
,
PNS_ITEM
*
aPad
,
bool
aEnd
,
int
aEndVertex
);
PNS_ITEM
*
findPadOrVia
(
int
aLayer
,
int
aNet
,
const
VECTOR2I
&
aP
)
const
;
PNS_ITEM
*
findPadOrVia
(
int
aLayer
,
int
aNet
,
const
VECTOR2I
&
aP
)
const
;
SHAPE_INDEX_LIST
<
PNS_ITEM
*>
m_cache
;
SHAPE_INDEX_LIST
<
PNS_ITEM
*>
m_cache
;
typedef
boost
::
unordered_map
<
PNS_ITEM
*
,
CachedItem
>
CachedItemTags
;
typedef
boost
::
unordered_map
<
PNS_ITEM
*
,
CachedItem
>
CachedItemTags
;
CachedItemTags
m_cacheTags
;
CachedItemTags
m_cacheTags
;
PNS_NODE
*
m_world
;
PNS_NODE
*
m_world
;
int
m_collisionKindMask
;
int
m_collisionKindMask
;
int
m_effortLevel
;
int
m_effortLevel
;
bool
m_keepPostures
;
bool
m_keepPostures
;
};
};
#endif
#endif
pcbnew/router/pns_router.cpp
View file @
5598acb6
...
@@ -3,20 +3,21 @@
...
@@ -3,20 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#include <cstdio>
#include <cstdio>
#include <vector>
#include <vector>
...
@@ -33,7 +34,7 @@
...
@@ -33,7 +34,7 @@
#include <geometry/shape_line_chain.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_circle.h>
#include "trace.h"
#include "trace.h"
#include "pns_node.h"
#include "pns_node.h"
#include "pns_line_placer.h"
#include "pns_line_placer.h"
...
@@ -48,727 +49,765 @@
...
@@ -48,727 +49,765 @@
#include <class_board_item.h>
#include <class_board_item.h>
#include <class_pad.h>
#include <class_pad.h>
#include <class_track.h>
#include <class_track.h>
#include <layers_id_colors_and_visibility.h>
#include <layers_id_colors_and_visibility.h>
using
namespace
std
;
using
namespace
std
;
// an ugly singleton for drawing debug items within the router context. To be fixed sometime in the future.
// an ugly singleton for drawing debug items within the router context.
static
PNS_ROUTER
*
theRouter
;
// To be fixed sometime in the future.
static
PNS_ROUTER
*
theRouter
;
class
PCBNEW_CLEARANCE_FUNC
:
public
PNS_CLEARANCE_FUNC
{
class
PCBNEW_CLEARANCE_FUNC
:
public
PNS_CLEARANCE_FUNC
public
:
{
PCBNEW_CLEARANCE_FUNC
(
BOARD
*
aBoard
)
public
:
{
PCBNEW_CLEARANCE_FUNC
(
BOARD
*
aBoard
)
m_clearanceCache
.
resize
(
aBoard
->
GetNetCount
());
{
m_clearanceCache
.
resize
(
aBoard
->
GetNetCount
()
);
for
(
unsigned
int
i
=
0
;
i
<
aBoard
->
GetNetCount
();
i
++
)
{
for
(
unsigned
int
i
=
0
;
i
<
aBoard
->
GetNetCount
();
i
++
)
NETINFO_ITEM
*
ni
=
aBoard
->
FindNet
(
i
);
{
wxString
netClassName
=
ni
->
GetClassName
();
NETINFO_ITEM
*
ni
=
aBoard
->
FindNet
(
i
);
NETCLASS
*
nc
=
aBoard
->
m_NetClasses
.
Find
(
netClassName
);
wxString
netClassName
=
ni
->
GetClassName
();
int
clearance
=
nc
->
GetClearance
();
NETCLASS
*
nc
=
aBoard
->
m_NetClasses
.
Find
(
netClassName
);
m_clearanceCache
[
i
]
=
clearance
;
int
clearance
=
nc
->
GetClearance
();
TRACE
(
1
,
"Add net %d netclass %s clearance %d"
,
i
%
netClassName
.
mb_str
()
%
clearance
);
m_clearanceCache
[
i
]
=
clearance
;
}
TRACE
(
1
,
"Add net %d netclass %s clearance %d"
,
i
%
netClassName
.
mb_str
()
%
clearance
);
m_defaultClearance
=
254000
;
//aBoard->m_NetClasses.Find ("Default clearance")->GetClearance();
}
}
m_defaultClearance
=
254000
;
// aBoard->m_NetClasses.Find ("Default clearance")->GetClearance();
int
operator
()
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
}
{
int
net_a
=
a
->
GetNet
();
int
operator
()(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
int
cl_a
=
(
net_a
>=
0
?
m_clearanceCache
[
net_a
]
:
m_defaultClearance
);
{
int
net_b
=
b
->
GetNet
();
int
net_a
=
a
->
GetNet
();
int
cl_b
=
(
net_b
>=
0
?
m_clearanceCache
[
net_b
]
:
m_defaultClearance
);
int
cl_a
=
(
net_a
>=
0
?
m_clearanceCache
[
net_a
]
:
m_defaultClearance
);
return
std
::
max
(
cl_a
,
cl_b
);
int
net_b
=
b
->
GetNet
();
}
int
cl_b
=
(
net_b
>=
0
?
m_clearanceCache
[
net_b
]
:
m_defaultClearance
);
private
:
return
std
::
max
(
cl_a
,
cl_b
);
}
vector
<
int
>
m_clearanceCache
;
int
m_defaultClearance
;
private
:
vector
<
int
>
m_clearanceCache
;
int
m_defaultClearance
;
};
};
PNS_ITEM
*
PNS_ROUTER
::
syncPad
(
D_PAD
*
aPad
)
PNS_ITEM
*
PNS_ROUTER
::
syncPad
(
D_PAD
*
aPad
)
{
{
PNS_LAYERSET
layers
;
PNS_LAYERSET
layers
;
switch
(
aPad
->
GetAttribute
())
switch
(
aPad
->
GetAttribute
()
)
{
{
case
PAD_STANDARD
:
case
PAD_STANDARD
:
layers
=
PNS_LAYERSET
(
0
,
15
);
layers
=
PNS_LAYERSET
(
0
,
15
);
break
;
break
;
case
PAD_SMD
:
case
PAD_CONN
:
case
PAD_SMD
:
{
case
PAD_CONN
:
LAYER_MSK
lmsk
=
aPad
->
GetLayerMask
();
{
int
i
;
LAYER_MSK
lmsk
=
aPad
->
GetLayerMask
();
int
i
;
for
(
i
=
FIRST_COPPER_LAYER
;
i
<=
LAST_COPPER_LAYER
;
i
++
)
if
(
lmsk
&
(
1
<<
i
))
for
(
i
=
FIRST_COPPER_LAYER
;
i
<=
LAST_COPPER_LAYER
;
i
++
)
{
if
(
lmsk
&
(
1
<<
i
)
)
layers
=
PNS_LAYERSET
(
i
);
{
break
;
layers
=
PNS_LAYERSET
(
i
);
}
break
;
break
;
}
}
default
:
TRACE
(
0
,
"unsupported pad type 0x%x"
,
aPad
->
GetAttribute
());
break
;
return
NULL
;
}
}
default
:
PNS_SOLID
*
solid
=
new
PNS_SOLID
;
TRACE
(
0
,
"unsupported pad type 0x%x"
,
aPad
->
GetAttribute
()
);
return
NULL
;
solid
->
SetLayers
(
layers
);
}
solid
->
SetNet
(
aPad
->
GetNet
()
);
wxPoint
wx_c
=
aPad
->
GetPosition
();
PNS_SOLID
*
solid
=
new
PNS_SOLID
;
wxSize
wx_sz
=
aPad
->
GetSize
();
solid
->
SetLayers
(
layers
);
VECTOR2I
c
(
wx_c
.
x
,
wx_c
.
y
);
solid
->
SetNet
(
aPad
->
GetNet
()
);
VECTOR2I
sz
(
wx_sz
.
x
,
wx_sz
.
y
);
wxPoint
wx_c
=
aPad
->
GetPosition
();
wxSize
wx_sz
=
aPad
->
GetSize
();
solid
->
SetCenter
(
c
);
VECTOR2I
c
(
wx_c
.
x
,
wx_c
.
y
);
VECTOR2I
sz
(
wx_sz
.
x
,
wx_sz
.
y
);
double
orient
=
aPad
->
GetOrientation
()
/
10.0
;
solid
->
SetCenter
(
c
);
if
(
orient
==
90.0
||
orient
==
270.0
)
sz
=
VECTOR2I
(
sz
.
y
,
sz
.
x
);
double
orient
=
aPad
->
GetOrientation
()
/
10.0
;
else
if
(
orient
!=
0.0
&&
orient
!=
180.0
)
{
if
(
orient
==
90.0
||
orient
==
270.0
)
TRACEn
(
0
,
"non-orthogonal pad rotations not supported yet"
);
sz
=
VECTOR2I
(
sz
.
y
,
sz
.
x
);
delete
solid
;
else
if
(
orient
!=
0.0
&&
orient
!=
180.0
)
return
NULL
;
{
}
TRACEn
(
0
,
"non-orthogonal pad rotations not supported yet"
);
delete
solid
;
switch
(
aPad
->
GetShape
())
return
NULL
;
{
}
case
PAD_CIRCLE
:
solid
->
SetShape
(
new
SHAPE_CIRCLE
(
c
,
sz
.
x
/
2
)
);
switch
(
aPad
->
GetShape
()
)
break
;
{
case
PAD_OVAL
:
case
PAD_CIRCLE
:
if
(
sz
.
x
==
sz
.
y
)
solid
->
SetShape
(
new
SHAPE_CIRCLE
(
c
,
sz
.
x
/
2
)
);
solid
->
SetShape
(
new
SHAPE_CIRCLE
(
c
,
sz
.
x
/
2
)
);
break
;
else
solid
->
SetShape
(
new
SHAPE_RECT
(
c
-
sz
/
2
,
sz
.
x
,
sz
.
y
)
);
case
PAD_OVAL
:
break
;
if
(
sz
.
x
==
sz
.
y
)
solid
->
SetShape
(
new
SHAPE_CIRCLE
(
c
,
sz
.
x
/
2
)
);
case
PAD_RECT
:
else
solid
->
SetShape
(
new
SHAPE_RECT
(
c
-
sz
/
2
,
sz
.
x
,
sz
.
y
)
);
solid
->
SetShape
(
new
SHAPE_RECT
(
c
-
sz
/
2
,
sz
.
x
,
sz
.
y
)
);
break
;
break
;
default
:
case
PAD_RECT
:
TRACEn
(
0
,
"unsupported pad shape"
);
solid
->
SetShape
(
new
SHAPE_RECT
(
c
-
sz
/
2
,
sz
.
x
,
sz
.
y
)
);
delete
solid
;
break
;
return
NULL
;
}
default
:
TRACEn
(
0
,
"unsupported pad shape"
);
delete
solid
;
solid
->
SetParent
(
aPad
);
return
NULL
;
return
solid
;
}
solid
->
SetParent
(
aPad
);
return
solid
;
}
}
PNS_ITEM
*
PNS_ROUTER
::
syncTrack
(
TRACK
*
aTrack
)
PNS_ITEM
*
PNS_ROUTER
::
syncTrack
(
TRACK
*
aTrack
)
{
{
PNS_SEGMENT
*
s
=
new
PNS_SEGMENT
(
SEG
(
aTrack
->
GetStart
(),
aTrack
->
GetEnd
()
),
aTrack
->
GetNet
()
);
PNS_SEGMENT
*
s
=
new
PNS_SEGMENT
(
SEG
(
aTrack
->
GetStart
(),
aTrack
->
GetEnd
()
),
aTrack
->
GetNet
()
);
s
->
SetWidth
(
aTrack
->
GetWidth
()
);
s
->
SetLayers
(
PNS_LAYERSET
(
aTrack
->
GetLayer
()
)
);
s
->
SetWidth
(
aTrack
->
GetWidth
()
);
s
->
SetParent
(
aTrack
);
s
->
SetLayers
(
PNS_LAYERSET
(
aTrack
->
GetLayer
()));
return
s
;
s
->
SetParent
(
aTrack
);
return
s
;
}
}
PNS_ITEM
*
PNS_ROUTER
::
syncVia
(
SEGVIA
*
aVia
)
{
PNS_VIA
*
v
=
new
PNS_VIA
(
aVia
->
GetPosition
(),
PNS_LAYERSET
(
0
,
15
),
aVia
->
GetWidth
(),
aVia
->
GetNet
());
v
->
SetParent
(
aVia
);
PNS_ITEM
*
PNS_ROUTER
::
syncVia
(
SEGVIA
*
aVia
)
return
v
;
{
PNS_VIA
*
v
=
new
PNS_VIA
(
aVia
->
GetPosition
(),
PNS_LAYERSET
(
0
,
15
),
aVia
->
GetWidth
(),
aVia
->
GetNet
()
);
v
->
SetParent
(
aVia
);
return
v
;
}
}
void
PNS_ROUTER
::
SetBoard
(
BOARD
*
aBoard
)
void
PNS_ROUTER
::
SetBoard
(
BOARD
*
aBoard
)
{
{
m_board
=
aBoard
;
m_board
=
aBoard
;
TRACE
(
1
,
"m_board = %p
\n
"
,
m_board
);
TRACE
(
1
,
"m_board = %p
\n
"
,
m_board
);
}
}
int
PNS_ROUTER
::
NextCopperLayer
(
bool
aUp
)
int
PNS_ROUTER
::
NextCopperLayer
(
bool
aUp
)
{
{
LAYER_MSK
mask
=
m_board
->
GetEnabledLayers
()
&
m_board
->
GetVisibleLayers
();
LAYER_MSK
mask
=
m_board
->
GetEnabledLayers
()
&
m_board
->
GetVisibleLayers
();
LAYER_NUM
l
=
m_currentLayer
;
LAYER_NUM
l
=
m_currentLayer
;
do
{
l
+=
(
aUp
?
1
:
-
1
);
if
(
l
>
LAST_COPPER_LAYER
)
l
=
FIRST_COPPER_LAYER
;
do
{
if
(
l
<
FIRST_COPPER_LAYER
)
l
+=
(
aUp
?
1
:
-
1
);
l
=
LAST_COPPER_LAYER
;
if
(
l
>
LAST_COPPER_LAYER
)
l
=
FIRST_COPPER_LAYER
;
if
(
l
<
FIRST_COPPER_LAYER
)
l
=
LAST_COPPER_LAYER
;
if
(
mask
&
GetLayerMask
(
l
))
if
(
mask
&
GetLayerMask
(
l
)
)
return
l
;
return
l
;
}
while
(
l
!=
m_currentLayer
);
}
while
(
l
!=
m_currentLayer
);
return
l
;
return
l
;
}
}
void
PNS_ROUTER
::
SyncWorld
()
void
PNS_ROUTER
::
SyncWorld
()
{
{
vector
<
D_PAD
*>
pads
;
vector
<
D_PAD
*>
pads
;
if
(
!
m_board
)
if
(
!
m_board
)
{
{
TRACEn
(
0
,
"No board attached, aborting sync."
);
TRACEn
(
0
,
"No board attached, aborting sync."
);
return
;
return
;
}
}
ClearWorld
();
ClearWorld
();
m_clearanceFunc
=
new
PCBNEW_CLEARANCE_FUNC
(
m_board
);
m_clearanceFunc
=
new
PCBNEW_CLEARANCE_FUNC
(
m_board
);
m_world
=
new
PNS_NODE
();
m_world
=
new
PNS_NODE
();
m_world
->
SetClearanceFunctor
(
m_clearanceFunc
);
m_world
->
SetClearanceFunctor
(
m_clearanceFunc
);
m_world
->
SetMaxClearance
(
1000000
);
//m_board->GetBiggestClearanceValue());
m_world
->
SetMaxClearance
(
1000000
);
// m_board->GetBiggestClearanceValue());
pads
=
m_board
->
GetPads
();
pads
=
m_board
->
GetPads
();
BOOST_FOREACH
(
D_PAD
*
pad
,
pads
)
BOOST_FOREACH
(
D_PAD
*
pad
,
pads
)
{
{
PNS_ITEM
*
solid
=
syncPad
(
pad
);
PNS_ITEM
*
solid
=
syncPad
(
pad
);
if
(
solid
)
if
(
solid
)
m_world
->
Add
(
solid
);
m_world
->
Add
(
solid
);
}
}
for
(
TRACK
*
t
=
m_board
->
m_Track
;
t
;
t
=
t
->
Next
())
for
(
TRACK
*
t
=
m_board
->
m_Track
;
t
;
t
=
t
->
Next
()
)
{
{
KICAD_T
type
=
t
->
Type
();
KICAD_T
type
=
t
->
Type
();
PNS_ITEM
*
item
=
NULL
;
PNS_ITEM
*
item
=
NULL
;
if
(
type
==
PCB_TRACE_T
)
item
=
syncTrack
(
t
);
if
(
type
==
PCB_TRACE_T
)
else
if
(
type
==
PCB_VIA_T
)
item
=
syncTrack
(
t
);
item
=
syncVia
(
static_cast
<
SEGVIA
*>
(
t
));
else
if
(
type
==
PCB_VIA_T
)
item
=
syncVia
(
static_cast
<
SEGVIA
*>
(
t
)
);
if
(
item
)
m_world
->
Add
(
item
);
if
(
item
)
}
m_world
->
Add
(
item
);
}
m_placer
=
new
PNS_LINE_PLACER
(
m_world
);
m_placer
=
new
PNS_LINE_PLACER
(
m_world
);
}
}
PNS_ROUTER
::
PNS_ROUTER
()
PNS_ROUTER
::
PNS_ROUTER
()
{
{
theRouter
=
this
;
theRouter
=
this
;
m_clearanceFunc
=
NULL
;
m_clearanceFunc
=
NULL
;
m_currentLayer
=
1
;
m_currentLayer
=
1
;
m_placingVia
=
false
;
m_placingVia
=
false
;
m_currentNet
=
-
1
;
m_currentNet
=
-
1
;
m_state
=
IDLE
;
m_state
=
IDLE
;
m_world
=
NULL
;
m_world
=
NULL
;
m_placer
=
NULL
;
m_placer
=
NULL
;
m_previewItems
=
NULL
;
m_previewItems
=
NULL
;
m_start_diagonal
=
false
;
m_start_diagonal
=
false
;
m_board
=
NULL
;
m_board
=
NULL
;
TRACE
(
1
,
"m_board = %p
\n
"
,
m_board
);
TRACE
(
1
,
"m_board = %p
\n
"
,
m_board
);
}
}
void
PNS_ROUTER
::
SetView
(
KiGfx
::
VIEW
*
aView
)
void
PNS_ROUTER
::
SetView
(
KiGfx
::
VIEW
*
aView
)
{
{
if
(
m_previewItems
)
if
(
m_previewItems
)
{
{
m_previewItems
->
FreeItems
();
m_previewItems
->
FreeItems
();
delete
m_previewItems
;
delete
m_previewItems
;
}
}
m_view
=
aView
;
m_view
=
aView
;
m_previewItems
=
new
KiGfx
::
VIEW_GROUP
(
m_view
);
m_previewItems
=
new
KiGfx
::
VIEW_GROUP
(
m_view
);
m_previewItems
->
SetLayer
(
ITEM_GAL_LAYER
(
GP_OVERLAY
));
m_previewItems
->
SetLayer
(
ITEM_GAL_LAYER
(
GP_OVERLAY
)
);
m_view
->
Add
(
m_previewItems
);
m_view
->
Add
(
m_previewItems
);
m_previewItems
->
ViewSetVisible
(
true
);
m_previewItems
->
ViewSetVisible
(
true
);
}
}
PNS_ROUTER
*
PNS_ROUTER
::
GetInstance
()
PNS_ROUTER
*
PNS_ROUTER
::
GetInstance
()
{
{
return
theRouter
;
return
theRouter
;
}
}
PNS_ROUTER
::~
PNS_ROUTER
()
PNS_ROUTER
::~
PNS_ROUTER
()
{
{
ClearWorld
();
ClearWorld
();
theRouter
=
NULL
;
theRouter
=
NULL
;
}
}
void
PNS_ROUTER
::
ClearWorld
()
void
PNS_ROUTER
::
ClearWorld
()
{
{
if
(
m_world
)
if
(
m_world
)
delete
m_world
;
delete
m_world
;
if
(
m_clearanceFunc
)
delete
m_clearanceFunc
;
if
(
m_clearanceFunc
)
if
(
m_placer
)
delete
m_clearanceFunc
;
delete
m_placer
;
if
(
m_placer
)
delete
m_placer
;
m_clearanceFunc
=
NULL
;
m_clearanceFunc
=
NULL
;
m_world
=
NULL
;
m_world
=
NULL
;
m_placer
=
NULL
;
m_placer
=
NULL
;
}
}
void
PNS_ROUTER
::
SetCurrentWidth
(
int
w
)
void
PNS_ROUTER
::
SetCurrentWidth
(
int
w
)
{
{
// fixme: change width while routing
// fixme: change width while routing
m_currentWidth
=
w
;
m_currentWidth
=
w
;
}
}
bool
PNS_ROUTER
::
RoutingInProgress
()
const
bool
PNS_ROUTER
::
RoutingInProgress
()
const
{
{
return
m_state
!=
IDLE
;
return
m_state
!=
IDLE
;
}
}
const
PNS_ITEMSET
PNS_ROUTER
::
QueryHoverItems
(
const
VECTOR2I
&
aP
)
const
PNS_ITEMSET
PNS_ROUTER
::
QueryHoverItems
(
const
VECTOR2I
&
aP
)
{
{
if
(
m_state
==
IDLE
)
if
(
m_state
==
IDLE
)
return
m_world
->
HitTest
(
aP
);
return
m_world
->
HitTest
(
aP
);
else
else
return
m_placer
->
GetCurrentNode
()
->
HitTest
(
aP
);
return
m_placer
->
GetCurrentNode
()
->
HitTest
(
aP
);
}
}
const
VECTOR2I
PNS_ROUTER
::
SnapToItem
(
PNS_ITEM
*
item
,
VECTOR2I
aP
,
bool
&
aSplitsSegment
)
const
VECTOR2I
PNS_ROUTER
::
SnapToItem
(
PNS_ITEM
*
item
,
VECTOR2I
aP
,
bool
&
aSplitsSegment
)
{
{
VECTOR2I
anchor
;
VECTOR2I
anchor
;
if
(
!
item
)
if
(
!
item
)
{
{
aSplitsSegment
=
false
;
aSplitsSegment
=
false
;
return
aP
;
return
aP
;
}
}
switch
(
item
->
GetKind
())
switch
(
item
->
GetKind
()
)
{
{
case
PNS_ITEM
:
:
SOLID
:
case
PNS_ITEM
:
:
SOLID
:
anchor
=
static_cast
<
PNS_SOLID
*>
(
item
)
->
GetCenter
();
anchor
=
static_cast
<
PNS_SOLID
*>
(
item
)
->
GetCenter
();
aSplitsSegment
=
false
;
aSplitsSegment
=
false
;
break
;
break
;
case
PNS_ITEM
:
:
VIA
:
anchor
=
static_cast
<
PNS_VIA
*>
(
item
)
->
GetPos
();
case
PNS_ITEM
:
:
VIA
:
aSplitsSegment
=
false
;
anchor
=
static_cast
<
PNS_VIA
*>
(
item
)
->
GetPos
();
break
;
aSplitsSegment
=
false
;
case
PNS_ITEM
:
:
SEGMENT
:
break
;
{
PNS_SEGMENT
*
seg
=
static_cast
<
PNS_SEGMENT
*>
(
item
);
case
PNS_ITEM
:
:
SEGMENT
:
const
SEG
&
s
=
seg
->
GetSeg
();
{
int
w
=
seg
->
GetWidth
();
PNS_SEGMENT
*
seg
=
static_cast
<
PNS_SEGMENT
*>
(
item
);
const
SEG
&
s
=
seg
->
GetSeg
();
aSplitsSegment
=
false
;
int
w
=
seg
->
GetWidth
();
if
((
aP
-
s
.
a
).
EuclideanNorm
()
<
w
/
2
)
aSplitsSegment
=
false
;
anchor
=
s
.
a
;
else
if
((
aP
-
s
.
b
).
EuclideanNorm
()
<
w
/
2
)
if
(
(
aP
-
s
.
a
).
EuclideanNorm
()
<
w
/
2
)
anchor
=
s
.
b
;
anchor
=
s
.
a
;
else
{
else
if
(
(
aP
-
s
.
b
).
EuclideanNorm
()
<
w
/
2
)
anchor
=
s
.
NearestPoint
(
aP
);
anchor
=
s
.
b
;
aSplitsSegment
=
true
;
else
}
{
break
;
anchor
=
s
.
NearestPoint
(
aP
);
}
aSplitsSegment
=
true
;
default
:
}
break
;
}
break
;
return
anchor
;
}
default
:
break
;
}
return
anchor
;
}
}
void
PNS_ROUTER
::
StartRouting
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aStartItem
)
void
PNS_ROUTER
::
StartRouting
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aStartItem
)
{
{
VECTOR2I
p
;
VECTOR2I
p
;
static
int
unknowNetIdx
=
0
;
//-10000;
m_placingVia
=
false
;
m_startsOnVia
=
false
;
m_currentNet
=
-
1
;
bool
splitSeg
=
false
;
static
int
unknowNetIdx
=
0
;
// -10000
;
p
=
SnapToItem
(
aStartItem
,
aP
,
splitSeg
);
m_placingVia
=
false
;
m_startsOnVia
=
false
;
m_currentNet
=
-
1
;
if
(
!
aStartItem
||
aStartItem
->
GetNet
()
<
0
)
bool
splitSeg
=
false
;
m_currentNet
=
unknowNetIdx
--
;
else
m_currentNet
=
aStartItem
->
GetNet
();
m_currentStart
=
p
;
p
=
SnapToItem
(
aStartItem
,
aP
,
splitSeg
);
m_originalStart
=
p
;
m_currentEnd
=
p
;
m_placer
->
SetInitialDirection
(
m_start_diagonal
?
DIRECTION_45
(
DIRECTION_45
::
NE
)
:
DIRECTION_45
(
DIRECTION_45
::
N
));
if
(
!
aStartItem
||
aStartItem
->
GetNet
()
<
0
)
m_placer
->
StartPlacement
(
m_originalStart
,
m_currentNet
,
m_currentWidth
,
m_currentLayer
);
m_currentNet
=
unknowNetIdx
--
;
m_state
=
ROUTE_TRACK
;
else
m_currentNet
=
aStartItem
->
GetNet
();
if
(
splitSeg
)
m_currentStart
=
p
;
splitAdjacentSegments
(
m_placer
->
GetCurrentNode
(),
aStartItem
,
p
);
m_originalStart
=
p
;
m_currentEnd
=
p
;
m_placer
->
SetInitialDirection
(
m_start_diagonal
?
DIRECTION_45
(
DIRECTION_45
::
NE
)
:
DIRECTION_45
(
DIRECTION_45
::
N
)
);
m_placer
->
StartPlacement
(
m_originalStart
,
m_currentNet
,
m_currentWidth
,
m_currentLayer
);
m_state
=
ROUTE_TRACK
;
if
(
splitSeg
)
splitAdjacentSegments
(
m_placer
->
GetCurrentNode
(),
aStartItem
,
p
);
}
}
const
VECTOR2I
PNS_ROUTER
::
GetCurrentEnd
(
)
const
const
VECTOR2I
PNS_ROUTER
::
GetCurrentEnd
()
const
{
{
return
m_currentEnd
;
return
m_currentEnd
;
}
}
void
PNS_ROUTER
::
EraseView
()
void
PNS_ROUTER
::
EraseView
()
{
{
BOOST_FOREACH
(
BOARD_ITEM
*
item
,
m_hiddenItems
)
BOOST_FOREACH
(
BOARD_ITEM
*
item
,
m_hiddenItems
)
{
{
item
->
ViewSetVisible
(
true
);
item
->
ViewSetVisible
(
true
);
}
}
if
(
m_previewItems
)
if
(
m_previewItems
)
m_previewItems
->
FreeItems
();
m_previewItems
->
FreeItems
();
m_previewItems
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
);
m_previewItems
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
);
}
}
void
PNS_ROUTER
::
DisplayItem
(
const
PNS_ITEM
*
aItem
,
bool
aIsHead
)
void
PNS_ROUTER
::
DisplayItem
(
const
PNS_ITEM
*
aItem
,
bool
aIsHead
)
{
{
ROUTER_PREVIEW_ITEM
*
pitem
=
new
ROUTER_PREVIEW_ITEM
(
aItem
,
m_previewItems
);
ROUTER_PREVIEW_ITEM
*
pitem
=
new
ROUTER_PREVIEW_ITEM
(
aItem
,
m_previewItems
);
m_previewItems
->
Add
(
pitem
);
m_previewItems
->
Add
(
pitem
);
if
(
aIsHead
)
pitem
->
MarkAsHead
();
pitem
->
ViewSetVisible
(
true
);
if
(
aIsHead
)
m_previewItems
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
|
KiGfx
::
VIEW_ITEM
::
APPEARANCE
);
pitem
->
MarkAsHead
();
pitem
->
ViewSetVisible
(
true
);
m_previewItems
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
|
KiGfx
::
VIEW_ITEM
::
APPEARANCE
);
}
}
void
PNS_ROUTER
::
DisplayDebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aType
,
int
aWidth
)
void
PNS_ROUTER
::
DisplayDebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aType
,
int
aWidth
)
{
{
ROUTER_PREVIEW_ITEM
*
pitem
=
new
ROUTER_PREVIEW_ITEM
(
NULL
,
m_previewItems
);
ROUTER_PREVIEW_ITEM
*
pitem
=
new
ROUTER_PREVIEW_ITEM
(
NULL
,
m_previewItems
);
pitem
->
DebugLine
(
aLine
,
aWidth
,
aType
);
pitem
->
DebugLine
(
aLine
,
aWidth
,
aType
);
m_previewItems
->
Add
(
pitem
);
m_previewItems
->
Add
(
pitem
);
pitem
->
ViewSetVisible
(
true
);
pitem
->
ViewSetVisible
(
true
);
m_previewItems
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
|
KiGfx
::
VIEW_ITEM
::
APPEARANCE
);
m_previewItems
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
|
KiGfx
::
VIEW_ITEM
::
APPEARANCE
);
}
}
void
PNS_ROUTER
::
DisplayDebugBox
(
const
BOX2I
&
aBox
,
int
aType
,
int
aWidth
)
{
void
PNS_ROUTER
::
DisplayDebugBox
(
const
BOX2I
&
aBox
,
int
aType
,
int
aWidth
)
{
}
}
void
PNS_ROUTER
::
Move
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
endItem
)
void
PNS_ROUTER
::
Move
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
endItem
)
{
{
PNS_NODE
::
ItemVector
removed
,
added
;
PNS_NODE
::
ItemVector
removed
,
added
;
VECTOR2I
p
=
aP
;
VECTOR2I
p
=
aP
;
if
(
m_state
==
IDLE
)
if
(
m_state
==
IDLE
)
return
;
return
;
if
(
m_state
==
START_ROUTING
)
// TODO is something missing here?
{
if
(
m_state
==
START_ROUTING
)
{
}
}
EraseView
();
EraseView
();
m_currentEnd
=
p
;
m_currentEnd
=
p
;
m_placer
->
Route
(
p
);
m_placer
->
Route
(
p
);
PNS_LINE
current
=
m_placer
->
GetTrace
();
PNS_LINE
current
=
m_placer
->
GetTrace
();
DisplayItem
(
&
current
,
true
);
DisplayItem
(
&
current
,
true
);
if
(
current
.
EndsWithVia
()
)
if
(
current
.
EndsWithVia
()
)
DisplayItem
(
&
current
.
GetVia
(),
true
);
DisplayItem
(
&
current
.
GetVia
(),
true
);
m_placer
->
GetCurrentNode
()
->
GetUpdatedItems
(
removed
,
added
);
m_placer
->
GetCurrentNode
()
->
GetUpdatedItems
(
removed
,
added
);
BOOST_FOREACH
(
PNS_ITEM
*
item
,
added
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
added
)
{
{
DisplayItem
(
item
);
DisplayItem
(
item
);
}
}
BOOST_FOREACH
(
PNS_ITEM
*
item
,
removed
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
removed
)
{
{
BOARD_ITEM
*
parent
=
item
->
GetParent
();
BOARD_ITEM
*
parent
=
item
->
GetParent
();
if
(
parent
)
if
(
parent
)
{
{
if
(
parent
->
ViewIsVisible
()
)
if
(
parent
->
ViewIsVisible
()
)
m_hiddenItems
.
insert
(
parent
);
m_hiddenItems
.
insert
(
parent
);
parent
->
ViewSetVisible
(
false
);
parent
->
ViewSetVisible
(
false
);
parent
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
APPEARANCE
);
parent
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
APPEARANCE
);
}
}
}
}
}
}
void
PNS_ROUTER
::
splitAdjacentSegments
(
PNS_NODE
*
aNode
,
PNS_ITEM
*
aSeg
,
const
VECTOR2I
&
aP
)
void
PNS_ROUTER
::
splitAdjacentSegments
(
PNS_NODE
*
aNode
,
PNS_ITEM
*
aSeg
,
const
VECTOR2I
&
aP
)
{
{
if
(
aSeg
&&
aSeg
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
if
(
aSeg
&&
aSeg
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
{
{
PNS_NODE
::
OptJoint
jt
=
aNode
->
FindJoint
(
aP
,
aSeg
->
GetLayers
().
Start
(),
aSeg
->
GetNet
()
);
PNS_NODE
::
OptJoint
jt
=
aNode
->
FindJoint
(
aP
,
aSeg
->
GetLayers
().
Start
(),
aSeg
->
GetNet
()
);
if
(
jt
&&
jt
->
LinkCount
()
>=
1
)
if
(
jt
&&
jt
->
LinkCount
()
>=
1
)
return
;
return
;
PNS_SEGMENT
*
s_old
=
static_cast
<
PNS_SEGMENT
*>
(
aSeg
);
PNS_SEGMENT
*
s_new
[
2
];
s_new
[
0
]
=
s_old
->
Clone
(
);
PNS_SEGMENT
*
s_old
=
static_cast
<
PNS_SEGMENT
*>
(
aSeg
);
s_new
[
1
]
=
s_old
->
Clone
()
;
PNS_SEGMENT
*
s_new
[
2
]
;
s_new
[
0
]
->
SetEnds
(
s_old
->
GetSeg
().
a
,
aP
);
s_new
[
0
]
=
s_old
->
Clone
(
);
s_new
[
1
]
->
SetEnds
(
aP
,
s_old
->
GetSeg
().
b
);
s_new
[
1
]
=
s_old
->
Clone
(
);
s_new
[
0
]
->
SetEnds
(
s_old
->
GetSeg
().
a
,
aP
);
s_new
[
1
]
->
SetEnds
(
aP
,
s_old
->
GetSeg
().
b
);
aNode
->
Remove
(
s_old
);
aNode
->
Remove
(
s_old
);
aNode
->
Add
(
s_new
[
0
]
);
aNode
->
Add
(
s_new
[
0
]
);
aNode
->
Add
(
s_new
[
1
]
);
aNode
->
Add
(
s_new
[
1
]
);
}
}
}
}
void
PNS_ROUTER
::
commitRouting
(
PNS_NODE
*
aNode
)
{
void
PNS_ROUTER
::
commitRouting
(
PNS_NODE
*
aNode
)
PNS_NODE
::
ItemVector
removed
,
added
;
{
PNS_NODE
::
ItemVector
removed
,
added
;
aNode
->
GetUpdatedItems
(
removed
,
added
);
aNode
->
GetUpdatedItems
(
removed
,
added
);
for
(
unsigned
int
i
=
0
;
i
<
removed
.
size
();
i
++
)
{
for
(
unsigned
int
i
=
0
;
i
<
removed
.
size
();
i
++
)
BOARD_ITEM
*
parent
=
removed
[
i
]
->
GetParent
();
{
BOARD_ITEM
*
parent
=
removed
[
i
]
->
GetParent
();
if
(
parent
)
{
if
(
parent
)
m_view
->
Remove
(
parent
);
{
m_board
->
Remove
(
parent
);
m_view
->
Remove
(
parent
);
}
m_board
->
Remove
(
parent
);
}
}
}
BOOST_FOREACH
(
PNS_ITEM
*
item
,
added
)
{
BOOST_FOREACH
(
PNS_ITEM
*
item
,
added
)
BOARD_ITEM
*
newBI
=
NULL
;
{
switch
(
item
->
GetKind
())
BOARD_ITEM
*
newBI
=
NULL
;
{
case
PNS_ITEM
:
:
SEGMENT
:
switch
(
item
->
GetKind
()
)
{
{
PNS_SEGMENT
*
seg
=
static_cast
<
PNS_SEGMENT
*>
(
item
);
case
PNS_ITEM
:
:
SEGMENT
:
TRACK
*
track
=
new
TRACK
(
m_board
);
{
const
SEG
&
s
=
seg
->
GetSeg
();
PNS_SEGMENT
*
seg
=
static_cast
<
PNS_SEGMENT
*>
(
item
);
TRACK
*
track
=
new
TRACK
(
m_board
);
track
->
SetStart
(
wxPoint
(
s
.
a
.
x
,
s
.
a
.
y
));
const
SEG
&
s
=
seg
->
GetSeg
();
track
->
SetEnd
(
wxPoint
(
s
.
b
.
x
,
s
.
b
.
y
));
track
->
SetWidth
(
seg
->
GetWidth
());
track
->
SetStart
(
wxPoint
(
s
.
a
.
x
,
s
.
a
.
y
)
);
track
->
SetLayer
(
seg
->
GetLayers
().
Start
());
track
->
SetEnd
(
wxPoint
(
s
.
b
.
x
,
s
.
b
.
y
)
);
track
->
SetNet
(
seg
->
GetNet
());
track
->
SetWidth
(
seg
->
GetWidth
()
);
newBI
=
track
;
track
->
SetLayer
(
seg
->
GetLayers
().
Start
()
);
break
;
track
->
SetNet
(
seg
->
GetNet
()
);
}
newBI
=
track
;
break
;
case
PNS_ITEM
:
:
VIA
:
}
{
SEGVIA
*
via_board
=
new
SEGVIA
(
m_board
);
case
PNS_ITEM
:
:
VIA
:
PNS_VIA
*
via
=
static_cast
<
PNS_VIA
*>
(
item
);
{
via_board
->
SetPosition
(
wxPoint
(
via
->
GetPos
().
x
,
via
->
GetPos
().
y
));
SEGVIA
*
via_board
=
new
SEGVIA
(
m_board
);
via_board
->
SetWidth
(
via
->
GetDiameter
()
);
PNS_VIA
*
via
=
static_cast
<
PNS_VIA
*>
(
item
);
via_board
->
SetNet
(
via
->
GetNet
()
);
via_board
->
SetPosition
(
wxPoint
(
via
->
GetPos
().
x
,
via
->
GetPos
().
y
)
);
newBI
=
via_board
;
via_board
->
SetWidth
(
via
->
GetDiameter
()
);
break
;
via_board
->
SetNet
(
via
->
GetNet
()
);
}
newBI
=
via_board
;
break
;
default
:
}
break
;
}
default
:
break
;
if
(
newBI
)
}
{
item
->
SetParent
(
newBI
);
if
(
newBI
)
newBI
->
ClearFlags
();
{
m_view
->
Add
(
newBI
);
item
->
SetParent
(
newBI
);
m_board
->
Add
(
newBI
);
newBI
->
ClearFlags
();
newBI
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
);
m_view
->
Add
(
newBI
);
}
m_board
->
Add
(
newBI
);
}
newBI
->
ViewUpdate
(
KiGfx
::
VIEW_ITEM
::
GEOMETRY
);
}
m_world
->
Commit
(
aNode
);
}
m_world
->
Commit
(
aNode
);
}
}
PNS_VIA
*
PNS_ROUTER
::
checkLoneVia
(
PNS_JOINT
*
aJoint
)
const
PNS_VIA
*
PNS_ROUTER
::
checkLoneVia
(
PNS_JOINT
*
aJoint
)
const
{
{
PNS_VIA
*
theVia
=
NULL
;
PNS_VIA
*
theVia
=
NULL
;
PNS_LAYERSET
l
;
PNS_LAYERSET
l
;
BOOST_FOREACH
(
PNS_ITEM
*
item
,
aJoint
->
GetLinkList
()
)
{
if
(
item
->
GetKind
()
==
PNS_ITEM
::
VIA
)
theVia
=
static_cast
<
PNS_VIA
*>
(
item
);
BOOST_FOREACH
(
PNS_ITEM
*
item
,
aJoint
->
GetLinkList
())
l
.
Merge
(
item
->
GetLayers
()
);
{
}
if
(
item
->
GetKind
()
==
PNS_ITEM
::
VIA
)
theVia
=
static_cast
<
PNS_VIA
*>
(
item
);
if
(
l
.
Start
()
==
l
.
End
()
)
l
.
Merge
(
item
->
GetLayers
());
return
theVia
;
}
if
(
l
.
Start
()
==
l
.
End
())
return
NULL
;
return
theVia
;
return
NULL
;
}
}
PNS_NODE
*
PNS_ROUTER
::
removeLoops
(
PNS_NODE
*
aNode
,
PNS_SEGMENT
*
aLatestSeg
)
{
PNS_NODE
*
PNS_ROUTER
::
removeLoops
(
PNS_NODE
*
aNode
,
PNS_SEGMENT
*
aLatestSeg
)
PNS_LINE
*
ourLine
=
aNode
->
AssembleLine
(
aLatestSeg
);
{
PNS_NODE
*
cleaned
=
aNode
->
Branch
();
PNS_LINE
*
ourLine
=
aNode
->
AssembleLine
(
aLatestSeg
);
PNS_JOINT
a
,
b
;
PNS_NODE
*
cleaned
=
aNode
->
Branch
();
vector
<
PNS_LINE
*>
lines
;
PNS_JOINT
a
,
b
;
vector
<
PNS_LINE
*>
lines
;
cleaned
->
FindLineEnds
(
ourLine
,
a
,
b
);
cleaned
->
FindLinesBetweenJoints
(
a
,
b
,
lines
);
cleaned
->
FindLineEnds
(
ourLine
,
a
,
b
);
cleaned
->
FindLinesBetweenJoints
(
a
,
b
,
lines
);
BOOST_FOREACH
(
PNS_LINE
*
line
,
lines
)
{
BOOST_FOREACH
(
PNS_LINE
*
line
,
lines
)
if
(
!
(
line
->
ContainsSegment
(
aLatestSeg
)
)
)
{
{
if
(
!
(
line
->
ContainsSegment
(
aLatestSeg
)
)
)
cleaned
->
Remove
(
line
);
{
}
cleaned
->
Remove
(
line
);
}
}
}
return
cleaned
;
return
cleaned
;
}
}
bool
PNS_ROUTER
::
FixRoute
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aEndItem
)
{
bool
real_end
=
false
;
PNS_LINE
pl
=
m_placer
->
GetTrace
();
const
SHAPE_LINE_CHAIN
&
l
=
pl
.
GetCLine
();
if
(
!
l
.
SegmentCount
()
)
return
true
;
VECTOR2I
p_pre_last
=
l
.
CPoint
(
-
1
);
const
VECTOR2I
p_last
=
l
.
CPoint
(
-
1
);
DIRECTION_45
d_last
(
l
.
CSegment
(
-
1
)
);
if
(
l
.
PointCount
()
>
2
)
p_pre_last
=
l
.
CPoint
(
-
2
);
bool
PNS_ROUTER
::
FixRoute
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aEndItem
)
if
(
aEndItem
&&
m_currentNet
>=
0
&&
m_currentNet
==
aEndItem
->
GetNet
()
)
{
real_end
=
true
;
bool
real_end
=
false
;
int
last
=
(
real_end
||
m_placingVia
)
?
l
.
SegmentCount
()
:
max
(
1
,
l
.
SegmentCount
()
-
1
);
PNS_LINE
pl
=
m_placer
->
GetTrace
();
const
SHAPE_LINE_CHAIN
&
l
=
pl
.
GetCLine
();
PNS_NODE
*
latest
=
m_placer
->
GetCurrentNode
();
if
(
!
l
.
SegmentCount
())
if
(
real_end
)
return
true
;
splitAdjacentSegments
(
latest
,
aEndItem
,
aP
);
VECTOR2I
p_pre_last
=
l
.
CPoint
(
-
1
);
PNS_SEGMENT
*
lastSeg
=
NULL
;
const
VECTOR2I
p_last
=
l
.
CPoint
(
-
1
);
DIRECTION_45
d_last
(
l
.
CSegment
(
-
1
));
for
(
int
i
=
0
;
i
<
last
;
i
++
)
{
if
(
l
.
PointCount
()
>
2
)
const
SEG
&
s
=
pl
.
GetCLine
().
CSegment
(
i
);
p_pre_last
=
l
.
CPoint
(
-
2
);
PNS_SEGMENT
*
seg
=
new
PNS_SEGMENT
(
s
,
m_currentNet
);
seg
->
SetWidth
(
pl
.
GetWidth
()
);
if
(
aEndItem
&&
m_currentNet
>=
0
&&
m_currentNet
==
aEndItem
->
GetNet
())
seg
->
SetLayer
(
m_currentLayer
);
real_end
=
true
;
latest
->
Add
(
seg
);
lastSeg
=
seg
;
int
last
=
(
real_end
||
m_placingVia
)
?
l
.
SegmentCount
()
:
max
(
1
,
l
.
SegmentCount
()
-
1
);
}
PNS_NODE
*
latest
=
m_placer
->
GetCurrentNode
();
if
(
pl
.
EndsWithVia
()
)
latest
->
Add
(
pl
.
GetVia
().
Clone
()
);
if
(
real_end
)
splitAdjacentSegments
(
latest
,
aEndItem
,
aP
);
if
(
real_end
)
latest
=
removeLoops
(
latest
,
lastSeg
);
PNS_SEGMENT
*
lastSeg
=
NULL
;
for
(
int
i
=
0
;
i
<
last
;
i
++
)
commitRouting
(
latest
);
{
const
SEG
&
s
=
pl
.
GetCLine
().
CSegment
(
i
);
EraseView
();
PNS_SEGMENT
*
seg
=
new
PNS_SEGMENT
(
s
,
m_currentNet
);
seg
->
SetWidth
(
pl
.
GetWidth
());
if
(
real_end
)
seg
->
SetLayer
(
m_currentLayer
);
{
latest
->
Add
(
seg
);
m_state
=
IDLE
;
lastSeg
=
seg
;
// m_world->KillChildren();
}
}
else
if
(
pl
.
EndsWithVia
()
)
{
latest
->
Add
(
pl
.
GetVia
().
Clone
());
m_state
=
ROUTE_TRACK
;
m_placer
->
SetInitialDirection
(
d_last
);
if
(
real_end
)
m_currentStart
=
m_placingVia
?
p_last
:
p_pre_last
;
latest
=
removeLoops
(
latest
,
lastSeg
);
if
(
m_placingVia
)
commitRouting
(
latest
);
m_currentLayer
=
NextCopperLayer
(
true
);
EraseView
();
m_placer
->
StartPlacement
(
m_currentStart
,
m_currentNet
,
m_currentWidth
,
m_currentLayer
);
if
(
real_end
)
m_startsOnVia
=
m_placingVia
;
{
m_placingVia
=
false
;
m_state
=
IDLE
;
}
//m_world->KillChildren();
}
else
{
return
real_end
;
m_state
=
ROUTE_TRACK
;
m_placer
->
SetInitialDirection
(
d_last
);
m_currentStart
=
m_placingVia
?
p_last
:
p_pre_last
;
if
(
m_placingVia
)
m_currentLayer
=
NextCopperLayer
(
true
);
m_placer
->
StartPlacement
(
m_currentStart
,
m_currentNet
,
m_currentWidth
,
m_currentLayer
);
m_startsOnVia
=
m_placingVia
;
m_placingVia
=
false
;
}
return
real_end
;
}
}
void
PNS_ROUTER
::
StopRouting
()
void
PNS_ROUTER
::
StopRouting
()
{
{
if
(
!
RoutingInProgress
())
if
(
!
RoutingInProgress
()
)
return
;
return
;
// highlightCurrent(false);
EraseView
();
//highlightCurrent(false);
m_state
=
IDLE
;
m_world
->
KillChildren
();
EraseView
();
m_state
=
IDLE
;
m_world
->
KillChildren
();
}
}
void
PNS_ROUTER
::
FlipPosture
()
void
PNS_ROUTER
::
FlipPosture
()
{
{
if
(
m_placer
->
GetTail
().
GetCLine
().
SegmentCount
()
==
0
)
if
(
m_placer
->
GetTail
().
GetCLine
().
SegmentCount
()
==
0
)
{
{
m_start_diagonal
=
!
m_start_diagonal
;
m_start_diagonal
=
!
m_start_diagonal
;
m_placer
->
SetInitialDirection
(
m_start_diagonal
?
DIRECTION_45
(
DIRECTION_45
::
NE
)
:
DIRECTION_45
(
DIRECTION_45
::
N
));
m_placer
->
SetInitialDirection
(
m_start_diagonal
?
DIRECTION_45
(
}
else
DIRECTION_45
::
NE
)
:
DIRECTION_45
(
DIRECTION_45
::
N
)
);
m_placer
->
FlipPosture
();
}
else
Move
(
m_currentEnd
,
NULL
);
m_placer
->
FlipPosture
();
Move
(
m_currentEnd
,
NULL
);
}
}
void
PNS_ROUTER
::
SwitchLayer
(
int
layer
)
{
void
PNS_ROUTER
::
SwitchLayer
(
int
layer
)
switch
(
m_state
)
{
{
switch
(
m_state
)
case
IDLE
:
{
m_currentLayer
=
layer
;
case
IDLE
:
break
;
m_currentLayer
=
layer
;
case
ROUTE_TRACK
:
break
;
if
(
m_startsOnVia
)
{
case
ROUTE_TRACK
:
m_currentLayer
=
layer
;
if
(
m_startsOnVia
)
m_placer
->
StartPlacement
(
m_currentStart
,
m_currentNet
,
m_currentWidth
,
m_currentLayer
);
{
}
m_currentLayer
=
layer
;
default
:
m_placer
->
StartPlacement
(
m_currentStart
,
m_currentNet
,
m_currentWidth
,
break
;
m_currentLayer
);
}
}
default
:
break
;
}
}
}
void
PNS_ROUTER
::
ToggleViaPlacement
()
void
PNS_ROUTER
::
ToggleViaPlacement
()
{
{
if
(
m_state
==
ROUTE_TRACK
)
if
(
m_state
==
ROUTE_TRACK
)
{
{
m_placingVia
=
!
m_placingVia
;
m_placingVia
=
!
m_placingVia
;
m_placer
->
AddVia
(
m_placingVia
,
m_currentViaDiameter
,
m_currentViaDrill
);
m_placer
->
AddVia
(
m_placingVia
,
m_currentViaDiameter
,
m_currentViaDrill
);
}
}
}
}
pcbnew/router/pns_router.h
View file @
5598acb6
...
@@ -3,20 +3,21 @@
...
@@ -3,20 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#ifndef __PNS_ROUTER_H
#ifndef __PNS_ROUTER_H
#define __PNS_ROUTER_H
#define __PNS_ROUTER_H
...
@@ -48,150 +49,146 @@ class PNS_CLEARANCE_FUNC;
...
@@ -48,150 +49,146 @@ class PNS_CLEARANCE_FUNC;
class
VIEW_GROUP
;
class
VIEW_GROUP
;
namespace
KiGfx
{
namespace
KiGfx
{
class
VIEW
;
class
VIEW
;
class
VIEW_GROUP
;
class
VIEW_GROUP
;
};
};
/**
/**
* Class PNS_ROUTER
* Class PNS_ROUTER
*
*
* Main router class.
* Main router class.
*/
*/
class
PNS_ROUTER
{
class
PNS_ROUTER
{
private
:
private
:
enum
RouterState
{
enum
RouterState
IDLE
,
{
START_ROUTING
,
IDLE
,
ROUTE_TRACK
,
START_ROUTING
,
FINISH_TRACK
ROUTE_TRACK
,
};
FINISH_TRACK
};
public
:
public
:
PNS_ROUTER
();
~
PNS_ROUTER
();
PNS_ROUTER
();
static
PNS_ROUTER
*
GetInstance
();
~
PNS_ROUTER
();
static
PNS_ROUTER
*
GetInstance
();
void
ClearWorld
();
void
ClearWorld
();
void
SetBoard
(
BOARD
*
aBoard
);
void
SetBoard
(
BOARD
*
aBoard
);
void
SyncWorld
();
void
SyncWorld
();
void
SetView
(
KiGfx
::
VIEW
*
aView
);
void
SetView
(
KiGfx
::
VIEW
*
aView
);
bool
RoutingInProgress
()
const
;
bool
RoutingInProgress
()
const
;
void
StartRouting
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aItem
);
void
StartRouting
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aItem
);
void
Move
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aItem
);
void
Move
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aItem
);
bool
FixRoute
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aItem
);
bool
FixRoute
(
const
VECTOR2I
&
aP
,
PNS_ITEM
*
aItem
);
void
StopRouting
();
void
StopRouting
();
const
VECTOR2I
GetCurrentEnd
()
const
;
const
VECTOR2I
GetCurrentEnd
()
const
;
int
GetClearance
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
const
;
int
GetClearance
(
const
PNS_ITEM
*
a
,
const
PNS_ITEM
*
b
)
const
;
PNS_NODE
*
GetWorld
()
const
PNS_NODE
*
GetWorld
()
const
{
{
return
m_world
;
return
m_world
;
}
}
void
FlipPosture
();
void
FlipPosture
();
void
DisplayItem
(
const
PNS_ITEM
*
aItem
,
bool
aIsHead
=
false
);
void
DisplayDebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aType
=
0
,
int
aWidth
=
0
);
void
DisplayDebugBox
(
const
BOX2I
&
aBox
,
int
aType
=
0
,
int
aWidth
=
0
);
void
EraseView
(
);
void
SwitchLayer
(
int
layer
);
int
GetCurrentLayer
()
const
{
return
m_currentLayer
;
}
void
ToggleViaPlacement
();
void
SetCurrentWidth
(
int
w
);
void
DisplayItem
(
const
PNS_ITEM
*
aItem
,
bool
aIsHead
=
false
);
void
SetCurrentViaDiameter
(
int
d
)
{
m_currentViaDiameter
=
d
;}
void
DisplayDebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aType
=
0
,
int
aWidth
=
0
);
void
SetCurrentViaDrill
(
int
d
)
{
m_currentViaDrill
=
d
;}
void
DisplayDebugBox
(
const
BOX2I
&
aBox
,
int
aType
=
0
,
int
aWidth
=
0
);
int
GetCurrentWidth
()
const
{
return
m_currentWidth
;
}
int
GetCurrentViaDiameter
()
const
{
return
m_currentViaDiameter
;
}
int
GetCurrentViaDrill
()
const
{
return
m_currentViaDrill
;
}
int
GetCurrentNet
()
const
{
return
m_currentNet
;
}
PNS_CLEARANCE_FUNC
*
GetClearanceFunc
()
const
void
EraseView
();
{
void
SwitchLayer
(
int
layer
);
return
m_clearanceFunc
;
}
bool
IsPlacingVia
()
const
int
GetCurrentLayer
()
const
{
return
m_currentLayer
;
}
{
void
ToggleViaPlacement
();
return
m_placingVia
;
}
void
SetCurrentWidth
(
int
w
);
int
NextCopperLayer
(
bool
aUp
);
void
SetCurrentViaDiameter
(
int
d
)
{
m_currentViaDiameter
=
d
;
}
void
SetCurrentViaDrill
(
int
d
)
{
m_currentViaDrill
=
d
;
}
int
GetCurrentWidth
()
const
{
return
m_currentWidth
;
}
int
GetCurrentViaDiameter
()
const
{
return
m_currentViaDiameter
;
}
int
GetCurrentViaDrill
()
const
{
return
m_currentViaDrill
;
}
int
GetCurrentNet
()
const
{
return
m_currentNet
;
}
//typedef boost::optional<hoverItem> optHoverItem;
PNS_CLEARANCE_FUNC
*
GetClearanceFunc
()
const
{
return
m_clearanceFunc
;
}
const
PNS_ITEMSET
QueryHoverItems
(
const
VECTOR2I
&
aP
);
bool
IsPlacingVia
()
const
const
VECTOR2I
SnapToItem
(
PNS_ITEM
*
item
,
VECTOR2I
aP
,
bool
&
aSplitsSegment
);
{
return
m_placingVia
;
}
int
NextCopperLayer
(
bool
aUp
);
private
:
// typedef boost::optional<hoverItem> optHoverItem;
const
PNS_ITEMSET
QueryHoverItems
(
const
VECTOR2I
&
aP
);
const
VECTOR2I
SnapToItem
(
PNS_ITEM
*
item
,
VECTOR2I
aP
,
bool
&
aSplitsSegment
);
private
:
void
clearViewFlags
();
void
clearViewFlags
();
// optHoverItem queryHoverItemEx(const VECTOR2I& aP);
//optHoverItem queryHoverItemEx(const VECTOR2I& aP);
PNS_ITEM
*
pickSingleItem
(
PNS_ITEMSET
&
aItems
)
const
;
//std::vector<PNS_ITEM*> aItems) const;
void
splitAdjacentSegments
(
PNS_NODE
*
aNode
,
PNS_ITEM
*
aSeg
,
const
VECTOR2I
&
aP
);
//optHoverItem& aItem);
void
commitRouting
(
PNS_NODE
*
aNode
);
PNS_NODE
*
removeLoops
(
PNS_NODE
*
aNode
,
PNS_SEGMENT
*
aLatestSeg
);
PNS_NODE
*
removeLoops
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aNewLine
);
PNS_VIA
*
checkLoneVia
(
PNS_JOINT
*
aJoint
)
const
;
PNS_ITEM
*
syncPad
(
D_PAD
*
aPad
);
PNS_ITEM
*
pickSingleItem
(
PNS_ITEMSET
&
aItems
)
const
;
// std::vector<PNS_ITEM*> aItems) const;
PNS_ITEM
*
syncTrack
(
TRACK
*
aTrack
);
void
splitAdjacentSegments
(
PNS_NODE
*
aNode
,
PNS_ITEM
*
aSeg
,
const
VECTOR2I
&
aP
);
// optHoverItem& aItem);
PNS_ITEM
*
syncVia
(
SEGVIA
*
aVia
);
void
commitRouting
(
PNS_NODE
*
aNode
);
PNS_NODE
*
removeLoops
(
PNS_NODE
*
aNode
,
PNS_SEGMENT
*
aLatestSeg
);
PNS_NODE
*
removeLoops
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aNewLine
);
PNS_VIA
*
checkLoneVia
(
PNS_JOINT
*
aJoint
)
const
;
void
commitPad
(
PNS_SOLID
*
aPad
);
PNS_ITEM
*
syncPad
(
D_PAD
*
aPad
);
void
commitSegment
(
PNS_SEGMENT
*
aTrack
);
PNS_ITEM
*
syncTrack
(
TRACK
*
aTrack
);
void
commitVia
(
PNS_VIA
*
aVia
);
PNS_ITEM
*
syncVia
(
SEGVIA
*
aVia
);
void
highlightCurrent
(
bool
enabled
);
void
commitPad
(
PNS_SOLID
*
aPad
);
void
commitSegment
(
PNS_SEGMENT
*
aTrack
);
void
commitVia
(
PNS_VIA
*
aVia
);
void
highlightCurrent
(
bool
enabled
);
int
m_currentLayer
;
int
m_currentLayer
;
int
m_currentNet
;
int
m_currentNet
;
int
m_currentWidth
;
int
m_currentWidth
;
int
m_currentViaDiameter
;
int
m_currentViaDiameter
;
int
m_currentViaDrill
;
int
m_currentViaDrill
;
bool
m_start_diagonal
;
bool
m_start_diagonal
;
RouterState
m_state
;
RouterState
m_state
;
BOARD
*
m_board
;
BOARD
*
m_board
;
PNS_NODE
*
m_world
;
PNS_NODE
*
m_world
;
PNS_LINE_PLACER
*
m_placer
;
PNS_LINE_PLACER
*
m_placer
;
KiGfx
::
VIEW
*
m_view
;
KiGfx
::
VIEW
*
m_view
;
KiGfx
::
VIEW_GROUP
*
m_previewItems
;
KiGfx
::
VIEW_GROUP
*
m_previewItems
;
VECTOR2I
m_currentEnd
;
VECTOR2I
m_currentEnd
;
VECTOR2I
m_currentStart
;
VECTOR2I
m_currentStart
;
VECTOR2I
m_originalStart
;
VECTOR2I
m_originalStart
;
bool
m_placingVia
;
bool
m_placingVia
;
bool
m_startsOnVia
;
bool
m_startsOnVia
;
// optHoverItem m_startItem, m_endItem;
// optHoverItem m_startItem, m_endItem;
PNS_ROUTING_SETTINGS
m_settings
;
PNS_CLEARANCE_FUNC
*
m_clearanceFunc
;
boost
::
unordered_set
<
BOARD_ITEM
*>
m_hiddenItems
;
PNS_ROUTING_SETTINGS
m_settings
;
PNS_CLEARANCE_FUNC
*
m_clearanceFunc
;
boost
::
unordered_set
<
BOARD_ITEM
*>
m_hiddenItems
;
};
};
#endif
#endif
\ No newline at end of file
pcbnew/router/pns_routing_settings.h
View file @
5598acb6
...
@@ -3,50 +3,51 @@
...
@@ -3,50 +3,51 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#ifndef __PNS_ROUTER_SETTINGS
#ifndef __PNS_ROUTER_SETTINGS
#define __PNS_ROUTER_SETTINGS
#define __PNS_ROUTER_SETTINGS
///> Routing modes
///> Routing modes
enum
PNS_MODE
{
enum
PNS_MODE
RM_Ignore
=
0
,
///> Ignore collisions
{
RM_Shove
,
///> Only shove
RM_Ignore
=
0
,
///> Ignore collisions
RM_Walkaround
,
///> Only walkaround
RM_Shove
,
///> Only shove
RM_Smart
///> Guess what's better
RM_Walkaround
,
///> Only walkaround
RM_Smart
///> Guess what's better
};
};
class
PNS_ROUTING_SETTINGS
class
PNS_ROUTING_SETTINGS
{
{
public
:
public
:
PNS_MODE
m_routingMode
;
PNS_MODE
m_routingMode
;
bool
m_removeLoops
;
bool
m_removeLoops
;
bool
m_smartPads
;
bool
m_smartPads
;
bool
m_suggestEnding
;
bool
m_suggestEnding
;
bool
m_shoveOnRequest
;
bool
m_shoveOnRequest
;
bool
m_changePostures
;
bool
m_changePostures
;
bool
m_followMouse
;
bool
m_followMouse
;
int
m_lineWidth
;
int
m_lineWidth
;
int
m_viaDiameter
;
int
m_viaDiameter
;
int
m_viaDrill
;
int
m_viaDrill
;
int
m_preferredLayer
;
int
m_preferredLayer
;
int
m_walkaroundIterationLimit
;
int
m_walkaroundIterationLimit
;
int
m_shoveIterationLimit
;
int
m_shoveIterationLimit
;
};
};
#endif
#endif
...
...
pcbnew/router/pns_segment.h
View file @
5598acb6
...
@@ -3,21 +3,21 @@
...
@@ -3,21 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#ifndef __PNS_SEGMENT_H
#ifndef __PNS_SEGMENT_H
#define __PNS_SEGMENT_H
#define __PNS_SEGMENT_H
...
@@ -32,88 +32,94 @@
...
@@ -32,88 +32,94 @@
class
PNS_NODE
;
class
PNS_NODE
;
class
PNS_SEGMENT
:
public
PNS_ITEM
{
class
PNS_SEGMENT
:
public
PNS_ITEM
{
public
:
public
:
PNS_SEGMENT
()
:
PNS_SEGMENT
()
:
PNS_ITEM
(
SEGMENT
)
PNS_ITEM
(
SEGMENT
)
{};
{};
PNS_SEGMENT
(
const
SEG
&
aSeg
,
int
aNet
)
:
PNS_SEGMENT
(
const
SEG
&
aSeg
,
int
aNet
)
:
PNS_ITEM
(
SEGMENT
)
PNS_ITEM
(
SEGMENT
)
{
{
m_net
=
aNet
;
m_net
=
aNet
;
m_shape
.
Clear
();
m_shape
.
Clear
();
m_shape
.
Append
(
aSeg
.
a
);
m_shape
.
Append
(
aSeg
.
a
);
m_shape
.
Append
(
aSeg
.
b
);
m_shape
.
Append
(
aSeg
.
b
);
};
};
PNS_SEGMENT
(
const
PNS_LINE
&
aParentLine
,
const
SEG
&
aSeg
)
:
PNS_SEGMENT
(
const
PNS_LINE
&
aParentLine
,
const
SEG
&
aSeg
)
:
PNS_ITEM
(
SEGMENT
)
PNS_ITEM
(
SEGMENT
)
{
{
m_net
=
aParentLine
.
GetNet
();
m_net
=
aParentLine
.
GetNet
();
m_layers
=
aParentLine
.
GetLayers
();
m_layers
=
aParentLine
.
GetLayers
();
m_width
=
aParentLine
.
GetWidth
();
m_width
=
aParentLine
.
GetWidth
();
m_shape
.
Clear
();
m_shape
.
Clear
();
m_shape
.
Append
(
aSeg
.
a
);
m_shape
.
Append
(
aSeg
.
a
);
m_shape
.
Append
(
aSeg
.
b
);
m_shape
.
Append
(
aSeg
.
b
);
};
};
PNS_SEGMENT
*
Clone
()
const
;
PNS_SEGMENT
*
Clone
()
const
;
const
SHAPE
*
GetShape
()
const
{
const
SHAPE
*
GetShape
()
const
return
static_cast
<
const
SHAPE
*>
(
&
m_shape
);
{
}
return
static_cast
<
const
SHAPE
*>
(
&
m_shape
);
}
void
SetLayer
(
int
aLayer
)
{
void
SetLayer
(
int
aLayer
)
SetLayers
(
PNS_LAYERSET
(
aLayer
));
{
}
SetLayers
(
PNS_LAYERSET
(
aLayer
)
);
}
int
GetLayer
()
const
{
int
GetLayer
()
const
return
GetLayers
().
Start
();
{
}
return
GetLayers
().
Start
();
}
const
SHAPE_LINE_CHAIN
&
GetCLine
()
const
{
const
SHAPE_LINE_CHAIN
&
GetCLine
()
const
return
m_shape
;
{
}
return
m_shape
;
}
void
SetWidth
(
int
aWidth
)
{
void
SetWidth
(
int
aWidth
)
m_width
=
aWidth
;
{
}
m_width
=
aWidth
;
}
int
GetWidth
()
const
{
return
m_width
;
int
GetWidth
()
const
}
{
return
m_width
;
const
SEG
GetSeg
()
const
{
}
assert
(
m_shape
.
PointCount
()
>=
1
);
if
(
m_shape
.
PointCount
()
==
1
)
const
SEG
GetSeg
()
const
return
SEG
(
m_shape
.
CPoint
(
0
),
m_shape
.
CPoint
(
0
));
{
return
SEG
(
m_shape
.
CPoint
(
0
),
m_shape
.
CPoint
(
1
));
assert
(
m_shape
.
PointCount
()
>=
1
);
}
if
(
m_shape
.
PointCount
()
==
1
)
void
SetEnds
(
const
VECTOR2I
&
a
,
const
VECTOR2I
&
b
)
return
SEG
(
m_shape
.
CPoint
(
0
),
m_shape
.
CPoint
(
0
)
);
{
m_shape
.
Clear
();
return
SEG
(
m_shape
.
CPoint
(
0
),
m_shape
.
CPoint
(
1
)
);
m_shape
.
Append
(
a
);
}
m_shape
.
Append
(
b
);
}
void
SetEnds
(
const
VECTOR2I
&
a
,
const
VECTOR2I
&
b
)
{
void
SwapEnds
()
m_shape
.
Clear
();
{
m_shape
.
Append
(
a
);
m_shape
=
m_shape
.
Reverse
();
m_shape
.
Append
(
b
);
}
}
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
;
void
SwapEnds
()
{
m_shape
=
m_shape
.
Reverse
();
}
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
;
private
:
private
:
SHAPE_LINE_CHAIN
m_shape
;
SHAPE_LINE_CHAIN
m_shape
;
int
m_width
;
int
m_width
;
};
};
#endif
#endif
pcbnew/router/pns_shove.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -37,433 +37,458 @@
...
@@ -37,433 +37,458 @@
using
namespace
std
;
using
namespace
std
;
PNS_SHOVE
::
PNS_SHOVE
(
PNS_NODE
*
aWorld
)
PNS_SHOVE
::
PNS_SHOVE
(
PNS_NODE
*
aWorld
)
{
{
m_root
=
aWorld
;
m_root
=
aWorld
;
m_iterLimit
=
100
;
m_iterLimit
=
100
;
};
};
PNS_SHOVE
::~
PNS_SHOVE
()
PNS_SHOVE
::~
PNS_SHOVE
()
{
{
}
}
struct
range
{
range
()
struct
range
{
{
min_v
=
max_v
=
-
1
;
range
()
}
{
min_v
=
max_v
=
-
1
;
void
add
(
int
x
)
}
{
if
(
min_v
<
0
)
min_v
=
x
;
void
add
(
int
x
)
if
(
max_v
<
0
)
max_v
=
x
;
{
if
(
min_v
<
0
)
min_v
=
x
;
if
(
x
<
min_v
)
min_v
=
x
;
if
(
max_v
<
0
)
max_v
=
x
;
else
if
(
x
>
max_v
)
max_v
=
x
;
if
(
x
<
min_v
)
}
min_v
=
x
;
else
if
(
x
>
max_v
)
int
start
()
max_v
=
x
;
{
}
return
min_v
;
}
int
start
()
{
int
end
()
return
min_v
;
{
}
return
max_v
;
}
int
end
()
{
int
min_v
,
max_v
;
return
max_v
;
}
int
min_v
,
max_v
;
};
};
// fixme: this is damn f***ing inefficient. And fails much too often due to broken direction finding algorithm.
// fixme: this is damn f***ing inefficient. And fails much too often due to broken direction finding algorithm.
bool
PNS_SHOVE
::
tryShove
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aHead
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
,
bool
aInvertWinding
)
bool
PNS_SHOVE
::
tryShove
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aHead
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
,
bool
aInvertWinding
)
{
{
const
SHAPE_LINE_CHAIN
&
head
=
aHead
->
GetCLine
();
const
SHAPE_LINE_CHAIN
&
head
=
aHead
->
GetCLine
();
bool
cw
=
false
;
bool
cw
=
false
;
int
i
;
int
i
;
if
(
aHead
->
EndsWithVia
()
&&
!
aHead
->
GetLayers
().
Overlaps
(
aObstacle
->
GetLayers
()))
if
(
aHead
->
EndsWithVia
()
&&
!
aHead
->
GetLayers
().
Overlaps
(
aObstacle
->
GetLayers
()
)
)
{
{
int
clearance
=
aNode
->
GetClearance
(
aHead
,
aObstacle
);
int
clearance
=
aNode
->
GetClearance
(
aHead
,
aObstacle
);
SHAPE_LINE_CHAIN
hull
=
aHead
->
GetVia
().
Hull
(
clearance
-
aObstacle
->
GetWidth
()
/
2
);
SHAPE_LINE_CHAIN
hull
=
aHead
->
GetVia
().
Hull
(
clearance
-
aObstacle
->
GetWidth
()
/
2
);
//SHAPE_LINE_CHAIN path_pre, path_walk_cw, path_walk_ccw, path_post;
// SHAPE_LINE_CHAIN path_pre, path_walk_cw, path_walk_ccw, path_post;
SHAPE_LINE_CHAIN
path_cw
,
path_ccw
,
*
path
;
SHAPE_LINE_CHAIN
path_cw
,
path_ccw
,
*
path
;
aObstacle
->
NewWalkaround
(
hull
,
path_cw
,
true
);
aObstacle
->
NewWalkaround
(
hull
,
path_cw
,
true
);
aObstacle
->
NewWalkaround
(
hull
,
path_ccw
,
false
);
aObstacle
->
NewWalkaround
(
hull
,
path_ccw
,
false
);
path
=
path_ccw
.
Length
()
<
path_cw
.
Length
()
?
&
path_ccw
:
&
path_cw
;
path
=
path_ccw
.
Length
()
<
path_cw
.
Length
()
?
&
path_ccw
:
&
path_cw
;
aResult
->
SetShape
(
*
path
);
aResult
->
SetShape
(
*
path
);
//PNSDisplayDebugLine (*path, 5);
// PNSDisplayDebugLine (*path, 5);
if
(
!
aResult
->
Is45Degree
())
if
(
!
aResult
->
Is45Degree
()
)
{
{
//printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str());
// printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str());
}
}
/*... special case for vias? */
/*... special case for vias? */
return
!
aNode
->
CheckColliding
(
aResult
,
aHead
);
}
return
!
aNode
->
CheckColliding
(
aResult
,
aHead
);
}
int
ns
=
head
.
SegmentCount
();
if
(
aHead
->
EndsWithVia
())
int
ns
=
head
.
SegmentCount
();
ns
++
;
if
(
aHead
->
EndsWithVia
()
)
for
(
i
=
0
;
i
<
head
.
SegmentCount
();
i
++
)
ns
++
;
{
const
PNS_SEGMENT
hs
(
*
aHead
,
head
.
CSegment
(
i
));
for
(
i
=
0
;
i
<
head
.
SegmentCount
();
i
++
)
{
const
PNS_SEGMENT
hs
(
*
aHead
,
head
.
CSegment
(
i
)
);
if
(
aNode
->
CheckColliding
(
&
hs
,
aObstacle
))
{
if
(
aNode
->
CheckColliding
(
&
hs
,
aObstacle
)
)
VECTOR2I
v1
=
hs
.
GetSeg
().
b
-
hs
.
GetSeg
().
a
;
{
VECTOR2I
v2
=
aObstacleSeg
.
GetSeg
().
b
-
aObstacleSeg
.
GetSeg
().
a
;
VECTOR2I
v1
=
hs
.
GetSeg
().
b
-
hs
.
GetSeg
().
a
;
VECTOR2I
v2
=
aObstacleSeg
.
GetSeg
().
b
-
aObstacleSeg
.
GetSeg
().
a
;
VECTOR2I
::
extended_type
det
=
v1
.
Cross
(
v2
);
VECTOR2I
::
extended_type
det
=
v1
.
Cross
(
v2
);
if
(
det
>
0
)
cw
=
true
;
if
(
det
>
0
)
else
cw
=
true
;
cw
=
false
;
else
cw
=
false
;
break
;
}
break
;
}
}
}
if
(
aInvertWinding
)
{
if
(
aInvertWinding
)
if
(
cw
)
{
cw
=
false
;
if
(
cw
)
else
cw
=
false
;
cw
=
true
;
else
}
cw
=
true
;
}
PNS_LINE
shoved
(
*
aObstacle
);
PNS_LINE
shoved
(
*
aObstacle
);
int
clearance
=
aNode
->
GetClearance
(
aHead
,
aObstacle
);
int
clearance
=
aNode
->
GetClearance
(
aHead
,
aObstacle
);
range
r
;
range
r
;
for
(
i
=
0
;
i
<
ns
;
i
++
)
{
for
(
i
=
0
;
i
<
ns
;
i
++
)
SHAPE_LINE_CHAIN
hull
;
{
SHAPE_LINE_CHAIN
hull
;
if
(
i
<
head
.
SegmentCount
())
{
if
(
i
<
head
.
SegmentCount
()
)
const
PNS_SEGMENT
hs
(
*
aHead
,
head
.
CSegment
(
i
));
{
hull
=
hs
.
Hull
(
clearance
,
0
);
const
PNS_SEGMENT
hs
(
*
aHead
,
head
.
CSegment
(
i
)
);
}
else
hull
=
hs
.
Hull
(
clearance
,
0
);
hull
=
aHead
->
GetVia
().
Hull
(
clearance
-
aObstacle
->
GetWidth
()
/
2
);
}
else
SHAPE_LINE_CHAIN
path_pre
,
path_walk
,
path_post
,
tmp
;
hull
=
aHead
->
GetVia
().
Hull
(
clearance
-
aObstacle
->
GetWidth
()
/
2
);
SHAPE_LINE_CHAIN
path_pre2
,
path_walk2
,
path_post2
;
SHAPE_LINE_CHAIN
path_pre
,
path_walk
,
path_post
,
tmp
;
//shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw);
SHAPE_LINE_CHAIN
path_pre2
,
path_walk2
,
path_post2
;
shoved
.
NewWalkaround
(
hull
,
path_pre
,
path_walk
,
path_post
,
cw
);
// shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw);
/*if(path_pre != path_pre2 || path_post != path_post2 || path_walk != path_walk2 )
shoved
.
NewWalkaround
(
hull
,
path_pre
,
path_walk
,
path_post
,
cw
);
{
TRACE(5, "polyset orig\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre.Format().c_str() % path_walk.Format().c_str() % path_post.Format().c_str());
/*if(path_pre != path_pre2 || path_post != path_post2 || path_walk != path_walk2 )
TRACE(5, "polyset err\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre2.Format().c_str() % path_walk2.Format().c_str() % path_post2.Format().c_str());
* {
}*/
* TRACE(5, "polyset orig\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre.Format().c_str() % path_walk.Format().c_str() % path_post.Format().c_str());
* TRACE(5, "polyset err\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre2.Format().c_str() % path_walk2.Format().c_str() % path_post2.Format().c_str());
tmp
=
shoved
.
GetCLine
();
* }*/
if
(
path_walk
.
SegmentCount
())
r
.
add
(
i
);
tmp
=
shoved
.
GetCLine
();
path_pre
.
Append
(
path_walk
);
if
(
path_walk
.
SegmentCount
()
)
path_pre
.
Append
(
path_post
);
r
.
add
(
i
);
path_pre
.
Simplify
();
shoved
.
SetShape
(
path_pre
);
path_pre
.
Append
(
path_walk
);
// shoved.SetAffectedRange ( start, end );
path_pre
.
Append
(
path_post
);
*
aResult
=
shoved
;
path_pre
.
Simplify
();
shoved
.
SetShape
(
path_pre
);
if
(
!
aResult
->
Is45Degree
())
// shoved.SetAffectedRange ( start, end );
{
*
aResult
=
shoved
;
//TRACE(5, "polyset non-45\npoly %s\npoly %s\npoly %s\nendpolyset\n", tmp.Format().c_str() % hull.Format().c_str() % aResult->GetCLine().Format().c_str());
}
if
(
!
aResult
->
Is45Degree
()
)
{
}
// TRACE(5, "polyset non-45\npoly %s\npoly %s\npoly %s\nendpolyset\n", tmp.Format().c_str() % hull.Format().c_str() % aResult->GetCLine().Format().c_str());
}
TRACE
(
2
,
"CW %d affectedRange %d-%d [total %d]"
,
(
cw
?
1
:
0
)
%
r
.
start
()
%
r
.
end
()
%
ns
);
}
return
!
aNode
->
CheckColliding
(
aResult
,
aHead
);
TRACE
(
2
,
"CW %d affectedRange %d-%d [total %d]"
,
(
cw
?
1
:
0
)
%
r
.
start
()
%
r
.
end
()
%
ns
);
return
!
aNode
->
CheckColliding
(
aResult
,
aHead
);
}
}
PNS_SHOVE
::
ShoveStatus
PNS_SHOVE
::
shoveSingleLine
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aCurrent
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
)
PNS_SHOVE
::
ShoveStatus
PNS_SHOVE
::
shoveSingleLine
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aCurrent
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
)
{
{
bool
rv
=
tryShove
(
aNode
,
aCurrent
,
aObstacle
,
aObstacleSeg
,
aResult
,
false
);
bool
rv
=
tryShove
(
aNode
,
aCurrent
,
aObstacle
,
aObstacleSeg
,
aResult
,
false
);
if
(
!
rv
)
if
(
!
rv
)
rv
=
tryShove
(
aNode
,
aCurrent
,
aObstacle
,
aObstacleSeg
,
aResult
,
true
);
rv
=
tryShove
(
aNode
,
aCurrent
,
aObstacle
,
aObstacleSeg
,
aResult
,
true
);
if
(
!
rv
)
if
(
!
rv
)
{
{
TRACEn
(
2
,
"Shove failed"
);
TRACEn
(
2
,
"Shove failed"
);
return
SH_INCOMPLETE
;
return
SH_INCOMPLETE
;
}
}
aResult
->
GetLine
().
Simplify
();
aResult
->
GetLine
().
Simplify
();
const
SHAPE_LINE_CHAIN
&
sh_shoved
=
aResult
->
GetCLine
();
const
SHAPE_LINE_CHAIN
&
sh_shoved
=
aResult
->
GetCLine
();
const
SHAPE_LINE_CHAIN
&
sh_orig
=
aObstacle
->
GetCLine
();
const
SHAPE_LINE_CHAIN
&
sh_orig
=
aObstacle
->
GetCLine
();
if
(
sh_shoved
.
SegmentCount
()
>
1
&&
sh_shoved
.
CPoint
(
0
)
==
sh_orig
.
CPoint
(
0
)
&&
sh_shoved
.
CPoint
(
-
1
)
==
sh_orig
.
CPoint
(
-
1
)
)
if
(
sh_shoved
.
SegmentCount
()
>
1
&&
sh_shoved
.
CPoint
(
0
)
==
sh_orig
.
CPoint
(
0
)
return
SH_OK
;
&&
sh_shoved
.
CPoint
(
-
1
)
==
sh_orig
.
CPoint
(
-
1
)
)
else
if
(
!
sh_shoved
.
SegmentCount
())
return
SH_OK
;
return
SH_NULL
;
else
if
(
!
sh_shoved
.
SegmentCount
()
)
else
return
SH_NULL
;
return
SH_INCOMPLETE
;
else
return
SH_INCOMPLETE
;
}
}
bool
PNS_SHOVE
::
reduceSpringback
(
PNS_LINE
*
aHead
)
bool
PNS_SHOVE
::
reduceSpringback
(
PNS_LINE
*
aHead
)
{
{
bool
rv
=
false
;
bool
rv
=
false
;
while
(
!
m_nodeStack
.
empty
())
while
(
!
m_nodeStack
.
empty
()
)
{
{
SpringbackTag
st_stack
=
m_nodeStack
.
back
();
SpringbackTag
st_stack
=
m_nodeStack
.
back
();
bool
tail_ok
=
true
;
bool
tail_ok
=
true
;
if
(
!
st_stack
.
node
->
CheckColliding
(
aHead
)
&&
tail_ok
)
if
(
!
st_stack
.
node
->
CheckColliding
(
aHead
)
&&
tail_ok
)
{
{
rv
=
true
;
rv
=
true
;
delete
st_stack
.
node
;
delete
st_stack
.
node
;
m_nodeStack
.
pop_back
();
m_nodeStack
.
pop_back
();
}
else
}
break
;
else
}
break
;
}
return
rv
;
return
rv
;
}
}
bool
PNS_SHOVE
::
pushSpringback
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aHead
,
const
PNS_COST_ESTIMATOR
&
aCost
)
bool
PNS_SHOVE
::
pushSpringback
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aHead
,
const
PNS_COST_ESTIMATOR
&
aCost
)
{
{
BOX2I
headBB
=
aHead
->
GetCLine
().
BBox
();
BOX2I
headBB
=
aHead
->
GetCLine
().
BBox
();
SpringbackTag
st
;
SpringbackTag
st
;
st
.
node
=
aNode
;
st
.
node
=
aNode
;
st
.
cost
=
aCost
;
st
.
cost
=
aCost
;
st
.
length
=
std
::
max
(
headBB
.
GetWidth
(),
headBB
.
GetHeight
()
);;
st
.
length
=
std
::
max
(
headBB
.
GetWidth
(),
headBB
.
GetHeight
()
);;
m_nodeStack
.
push_back
(
st
);
m_nodeStack
.
push_back
(
st
);
return
true
;
return
true
;
}
}
const
PNS_COST_ESTIMATOR
PNS_SHOVE
::
TotalCost
()
const
const
PNS_COST_ESTIMATOR
PNS_SHOVE
::
TotalCost
()
const
{
{
if
(
m_nodeStack
.
empty
()
)
if
(
m_nodeStack
.
empty
()
)
return
PNS_COST_ESTIMATOR
();
return
PNS_COST_ESTIMATOR
();
else
else
return
m_nodeStack
.
back
().
cost
;
return
m_nodeStack
.
back
().
cost
;
}
}
PNS_SHOVE
::
ShoveStatus
PNS_SHOVE
::
ShoveLines
(
PNS_LINE
*
aCurrentHead
)
PNS_SHOVE
::
ShoveStatus
PNS_SHOVE
::
ShoveLines
(
PNS_LINE
*
aCurrentHead
)
{
{
stack
<
PNS_LINE
*>
lineStack
;
stack
<
PNS_LINE
*>
lineStack
;
PNS_NODE
*
node
,
*
parent
;
PNS_NODE
*
node
,
*
parent
;
PNS_VIA
*
headVia
=
NULL
;
PNS_VIA
*
headVia
=
NULL
;
bool
fail
=
false
;
bool
fail
=
false
;
int
iter
=
0
;
int
iter
=
0
;
PNS_LINE
*
head
=
aCurrentHead
->
Clone
();
PNS_LINE
*
head
=
aCurrentHead
->
Clone
();
reduceSpringback
(
aCurrentHead
);
reduceSpringback
(
aCurrentHead
);
parent
=
m_nodeStack
.
empty
()
?
m_root
:
m_nodeStack
.
back
().
node
;
parent
=
m_nodeStack
.
empty
()
?
m_root
:
m_nodeStack
.
back
().
node
;
node
=
parent
->
Branch
();
node
=
parent
->
Branch
();
lineStack
.
push
(
head
);
//node->Add(tail);
lineStack
.
push
(
head
);
node
->
Add
(
head
);
if
(
head
->
EndsWithVia
())
// node->Add(tail);
{
node
->
Add
(
head
);
headVia
=
head
->
GetVia
().
Clone
();
node
->
Add
(
headVia
);
}
PNS_OPTIMIZER
optimizer
(
node
);
if
(
head
->
EndsWithVia
()
)
{
headVia
=
head
->
GetVia
().
Clone
();
node
->
Add
(
headVia
);
}
optimizer
.
SetEffortLevel
(
PNS_OPTIMIZER
::
MERGE_SEGMENTS
|
PNS_OPTIMIZER
::
SMART_PADS
);
PNS_OPTIMIZER
optimizer
(
node
);
optimizer
.
SetCollisionMask
(
-
1
);
PNS_NODE
::
OptObstacle
nearest
;
optimizer
.
CacheStaticItem
(
head
);
optimizer
.
SetEffortLevel
(
PNS_OPTIMIZER
::
MERGE_SEGMENTS
|
PNS_OPTIMIZER
::
SMART_PADS
);
if
(
headVia
)
optimizer
.
SetCollisionMask
(
-
1
);
optimizer
.
CacheStaticItem
(
headVia
)
;
PNS_NODE
::
OptObstacle
nearest
;
TRACE
(
1
,
"ShoveStart [root: %d jts, node: %d jts]"
,
m_root
->
JointCount
()
%
node
->
JointCount
());
optimizer
.
CacheStaticItem
(
head
);
//PNS_ITEM *lastWalkSolid = NULL;
prof_counter
totalRealTime
;
wxLongLong
t_start
=
wxGetLocalTimeMillis
();
while
(
!
lineStack
.
empty
())
{
wxLongLong
t_cur
=
wxGetLocalTimeMillis
();
if
((
t_cur
-
t_start
).
ToLong
()
>
ShoveTimeLimit
)
{
fail
=
true
;
break
;
}
iter
++
;
if
(
iter
>
m_iterLimit
)
{
fail
=
true
;
break
;
}
PNS_LINE
*
currentLine
=
lineStack
.
top
();
prof_start
(
&
totalRealTime
,
false
);
nearest
=
node
->
NearestObstacle
(
currentLine
,
PNS_ITEM
::
ANY
);
prof_end
(
&
totalRealTime
);
TRACE
(
2
,
"t-nearestObstacle %lld us"
,
(
totalRealTime
.
value
));
if
(
!
nearest
)
{
if
(
lineStack
.
size
()
>
1
)
{
PNS_LINE
*
original
=
lineStack
.
top
();
PNS_LINE
optimized
;
int
r_start
,
r_end
;
original
->
GetAffectedRange
(
r_start
,
r_end
);
TRACE
(
1
,
"Iter %d optimize-line [range %d-%d, total %d]"
,
iter
%
r_start
%
r_end
%
original
->
GetCLine
().
PointCount
()
);
//lastWalkSolid = NULL;
prof_start
(
&
totalRealTime
,
false
);
if
(
optimizer
.
Optimize
(
original
,
&
optimized
)
)
{
node
->
Remove
(
original
);
optimizer
.
CacheRemove
(
original
);
node
->
Add
(
&
optimized
);
if
(
original
->
BelongsTo
(
node
))
delete
original
;
}
prof_end
(
&
totalRealTime
);
TRACE
(
2
,
"t-optimizeObstacle %lld us"
,
(
totalRealTime
.
value
));
}
lineStack
.
pop
();
}
else
{
switch
(
nearest
->
item
->
GetKind
())
{
case
PNS_ITEM
:
:
SEGMENT
:
{
TRACE
(
1
,
"Iter %d shove-line"
,
iter
);
PNS_SEGMENT
*
pseg
=
static_cast
<
PNS_SEGMENT
*>
(
nearest
->
item
);
if
(
headVia
)
PNS_LINE
*
collidingLine
=
node
->
AssembleLine
(
pseg
);
optimizer
.
CacheStaticItem
(
headVia
);
PNS_LINE
*
shovedLine
=
collidingLine
->
CloneProperties
();
TRACE
(
1
,
"ShoveStart [root: %d jts, node: %d jts]"
,
m_root
->
JointCount
()
%
prof_start
(
&
totalRealTime
,
false
);
node
->
JointCount
()
);
ShoveStatus
st
=
shoveSingleLine
(
node
,
currentLine
,
collidingLine
,
*
pseg
,
shovedLine
);
prof_end
(
&
totalRealTime
);
// PNS_ITEM *lastWalkSolid = NULL;
prof_counter
totalRealTime
;
TRACE
(
2
,
"t-shoveSingle %lld us"
,
(
totalRealTime
.
value
));
wxLongLong
t_start
=
wxGetLocalTimeMillis
();
if
(
st
==
SH_OK
)
{
while
(
!
lineStack
.
empty
()
)
node
->
Replace
(
collidingLine
,
shovedLine
);
{
wxLongLong
t_cur
=
wxGetLocalTimeMillis
();
if
(
collidingLine
->
BelongsTo
(
node
))
delete
collidingLine
;
if
(
(
t_cur
-
t_start
).
ToLong
()
>
ShoveTimeLimit
)
{
optimizer
.
CacheRemove
(
collidingLine
);
fail
=
true
;
lineStack
.
push
(
shovedLine
);
break
;
}
else
}
fail
=
true
;
iter
++
;
//lastWalkSolid = NULL;
if
(
iter
>
m_iterLimit
)
break
;
{
}
// case SEGMENT
fail
=
true
;
break
;
case
PNS_ITEM
:
:
SOLID
:
}
case
PNS_ITEM
:
:
VIA
:
{
PNS_LINE
*
currentLine
=
lineStack
.
top
();
TRACE
(
1
,
"Iter %d walkaround-solid [%p]"
,
iter
%
nearest
->
item
);
prof_start
(
&
totalRealTime
,
false
);
if
(
lineStack
.
size
()
==
1
)
nearest
=
node
->
NearestObstacle
(
currentLine
,
PNS_ITEM
::
ANY
);
{
prof_end
(
&
totalRealTime
);
fail
=
true
;
break
;
TRACE
(
2
,
"t-nearestObstacle %lld us"
,
(
totalRealTime
.
value
)
);
}
if
(
!
nearest
)
{
if
(
lineStack
.
size
()
>
1
)
{
PNS_LINE
*
original
=
lineStack
.
top
();
PNS_LINE
optimized
;
int
r_start
,
r_end
;
original
->
GetAffectedRange
(
r_start
,
r_end
);
TRACE
(
1
,
"Iter %d optimize-line [range %d-%d, total %d]"
,
iter
%
r_start
%
r_end
%
original
->
GetCLine
().
PointCount
()
);
// lastWalkSolid = NULL;
prof_start
(
&
totalRealTime
,
false
);
if
(
optimizer
.
Optimize
(
original
,
&
optimized
)
)
{
node
->
Remove
(
original
);
optimizer
.
CacheRemove
(
original
);
node
->
Add
(
&
optimized
);
if
(
original
->
BelongsTo
(
node
)
)
delete
original
;
}
prof_end
(
&
totalRealTime
);
TRACE
(
2
,
"t-optimizeObstacle %lld us"
,
(
totalRealTime
.
value
)
);
}
lineStack
.
pop
();
}
else
{
switch
(
nearest
->
item
->
GetKind
()
)
{
case
PNS_ITEM
:
:
SEGMENT
:
{
TRACE
(
1
,
"Iter %d shove-line"
,
iter
);
PNS_SEGMENT
*
pseg
=
static_cast
<
PNS_SEGMENT
*>
(
nearest
->
item
);
PNS_LINE
*
collidingLine
=
node
->
AssembleLine
(
pseg
);
PNS_LINE
*
shovedLine
=
collidingLine
->
CloneProperties
();
prof_start
(
&
totalRealTime
,
false
);
ShoveStatus
st
=
shoveSingleLine
(
node
,
currentLine
,
collidingLine
,
*
pseg
,
shovedLine
);
prof_end
(
&
totalRealTime
);
TRACE
(
2
,
"t-shoveSingle %lld us"
,
(
totalRealTime
.
value
)
);
if
(
st
==
SH_OK
)
{
node
->
Replace
(
collidingLine
,
shovedLine
);
if
(
collidingLine
->
BelongsTo
(
node
)
)
delete
collidingLine
;
optimizer
.
CacheRemove
(
collidingLine
);
lineStack
.
push
(
shovedLine
);
}
else
fail
=
true
;
// lastWalkSolid = NULL;
break
;
}
// case SEGMENT
case
PNS_ITEM
:
:
SOLID
:
case
PNS_ITEM
:
:
VIA
:
{
TRACE
(
1
,
"Iter %d walkaround-solid [%p]"
,
iter
%
nearest
->
item
);
if
(
lineStack
.
size
()
==
1
)
{
fail
=
true
;
break
;
}
/* if(lastWalkSolid == nearest->item)
/* if(lastWalkSolid == nearest->item)
{
* {
fail = true;
* fail = true;
break;
* break;
}*/
* }*/
PNS_WALKAROUND
walkaround
(
node
);
PNS_WALKAROUND
walkaround
(
node
);
PNS_LINE
*
walkaroundLine
=
currentLine
->
CloneProperties
();
PNS_LINE
*
walkaroundLine
=
currentLine
->
CloneProperties
();
walkaround
.
SetSolidsOnly
(
true
);
walkaround
.
SetSolidsOnly
(
true
);
walkaround
.
SetSingleDirection
(
true
);
walkaround
.
SetSingleDirection
(
true
);
prof_start
(
&
totalRealTime
,
false
);
prof_start
(
&
totalRealTime
,
false
);
walkaround
.
Route
(
*
currentLine
,
*
walkaroundLine
,
false
);
walkaround
.
Route
(
*
currentLine
,
*
walkaroundLine
,
false
);
prof_end
(
&
totalRealTime
);
prof_end
(
&
totalRealTime
);
TRACE
(
2
,
"t-walkSolid %lld us"
,
(
totalRealTime
.
value
));
TRACE
(
2
,
"t-walkSolid %lld us"
,
(
totalRealTime
.
value
)
);
node
->
Replace
(
currentLine
,
walkaroundLine
);
node
->
Replace
(
currentLine
,
walkaroundLine
);
if
(
currentLine
->
BelongsTo
(
node
))
if
(
currentLine
->
BelongsTo
(
node
)
)
delete
currentLine
;
delete
currentLine
;
optimizer
.
CacheRemove
(
currentLine
);
optimizer
.
CacheRemove
(
currentLine
);
lineStack
.
top
()
=
walkaroundLine
;
lineStack
.
top
()
=
walkaroundLine
;
//lastWalkSolid = nearest->item;
// lastWalkSolid = nearest->item;
break
;
break
;
}
}
default
:
break
;
default
:
}
// switch
break
;
if
(
fail
)
}
// switch
break
;
}
if
(
fail
)
}
break
;
}
node
->
Remove
(
head
);
}
delete
head
;
node
->
Remove
(
head
);
if
(
headVia
)
delete
head
;
{
node
->
Remove
(
headVia
);
if
(
headVia
)
delete
headVia
;
{
}
node
->
Remove
(
headVia
);
delete
headVia
;
TRACE
(
1
,
"Shove status : %s after %d iterations"
,
(
fail
?
"FAILED"
:
"OK"
)
%
iter
);
}
if
(
!
fail
)
{
TRACE
(
1
,
"Shove status : %s after %d iterations"
,
(
fail
?
"FAILED"
:
"OK"
)
%
iter
);
pushSpringback
(
node
,
aCurrentHead
,
PNS_COST_ESTIMATOR
());
return
SH_OK
;
if
(
!
fail
)
}
else
{
{
delete
node
;
pushSpringback
(
node
,
aCurrentHead
,
PNS_COST_ESTIMATOR
()
);
return
SH_INCOMPLETE
;
return
SH_OK
;
}
}
else
{
delete
node
;
return
SH_INCOMPLETE
;
}
}
}
pcbnew/router/pns_shove.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -30,53 +30,57 @@ class PNS_LINE;
...
@@ -30,53 +30,57 @@ class PNS_LINE;
class
PNS_NODE
;
class
PNS_NODE
;
class
PNS_ROUTER
;
class
PNS_ROUTER
;
class
PNS_SHOVE
{
class
PNS_SHOVE
{
public
:
PNS_SHOVE
(
PNS_NODE
*
aWorld
);
~
PNS_SHOVE
();
public
:
enum
ShoveStatus
PNS_SHOVE
(
PNS_NODE
*
aWorld
);
{
~
PNS_SHOVE
();
SH_OK
=
0
,
SH_NULL
,
SH_INCOMPLETE
};
enum
ShoveStatus
{
ShoveStatus
ShoveLines
(
PNS_LINE
*
aCurrentHead
);
SH_OK
=
0
,
SH_NULL
,
SH_INCOMPLETE
};
ShoveStatus
ShoveLines
(
PNS_LINE
*
aCurrentHead
);
PNS_NODE
*
GetCurrentNode
()
{
return
m_nodeStack
.
empty
()
?
m_root
:
m_nodeStack
.
back
().
node
;
}
PNS_NODE
*
GetCurrentNode
()
const
PNS_COST_ESTIMATOR
TotalCost
()
const
;
{
return
m_nodeStack
.
empty
()
?
m_root
:
m_nodeStack
.
back
().
node
;
}
const
PNS_COST_ESTIMATOR
TotalCost
()
const
;
void
Reset
();
void
KillChildNodes
();
void
Reset
();
private
:
void
KillChildNodes
()
;
static
const
int
ShoveTimeLimit
=
3000
;
private
:
bool
tryShove
(
PNS_NODE
*
aWorld
,
PNS_LINE
*
aTrack
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
,
bool
aInvertWinding
);
static
const
int
ShoveTimeLimit
=
3000
;
ShoveStatus
shoveSingleLine
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aCurrent
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
);
bool
tryShove
(
PNS_NODE
*
aWorld
,
PNS_LINE
*
aTrack
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
,
bool
aInvertWinding
);
bool
reduceSpringback
(
PNS_LINE
*
aHead
);
bool
pushSpringback
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aHead
,
const
PNS_COST_ESTIMATOR
&
aCost
);
ShoveStatus
shoveSingleLine
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aCurrent
,
PNS_LINE
*
aObstacle
,
PNS_SEGMENT
&
aObstacleSeg
,
PNS_LINE
*
aResult
);
struct
SpringbackTag
{
int64_t
length
;
int
segments
;
VECTOR2I
p
;
PNS_NODE
*
node
;
PNS_COST_ESTIMATOR
cost
;
};
bool
reduceSpringback
(
PNS_LINE
*
aHead
);
std
::
vector
<
SpringbackTag
>
m_nodeStack
;
bool
pushSpringback
(
PNS_NODE
*
aNode
,
PNS_LINE
*
aHead
,
const
PNS_COST_ESTIMATOR
&
aCost
);
PNS_NODE
*
m_root
;
PNS_NODE
*
m_currentNode
;
struct
SpringbackTag
{
int
m_iterLimit
;
int64_t
length
;
int
segments
;
VECTOR2I
p
;
PNS_NODE
*
node
;
PNS_COST_ESTIMATOR
cost
;
};
std
::
vector
<
SpringbackTag
>
m_nodeStack
;
PNS_NODE
*
m_root
;
PNS_NODE
*
m_currentNode
;
int
m_iterLimit
;
};
};
#endif
#endif
pcbnew/router/pns_solid.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -28,37 +28,36 @@
...
@@ -28,37 +28,36 @@
#include "pns_solid.h"
#include "pns_solid.h"
#include "pns_utils.h"
#include "pns_utils.h"
const
SHAPE_LINE_CHAIN
PNS_SOLID
::
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
const
SHAPE_LINE_CHAIN
PNS_SOLID
::
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
{
{
switch
(
m_shape
->
Type
())
switch
(
m_shape
->
Type
()
)
{
{
case
SH_RECT
:
case
SH_RECT
:
{
{
SHAPE_RECT
*
rect
=
static_cast
<
SHAPE_RECT
*>
(
m_shape
);
SHAPE_RECT
*
rect
=
static_cast
<
SHAPE_RECT
*>
(
m_shape
);
return
OctagonalHull
(
rect
->
GetPosition
(),
return
OctagonalHull
(
rect
->
GetPosition
(),
rect
->
GetSize
(),
rect
->
GetSize
(),
aClearance
+
1
,
0.2
*
aClearance
);
aClearance
+
1
,
}
0.2
*
aClearance
);
}
case
SH_CIRCLE
:
{
SHAPE_CIRCLE
*
circle
=
static_cast
<
SHAPE_CIRCLE
*>
(
m_shape
);
int
r
=
circle
->
GetRadius
();
return
OctagonalHull
(
circle
->
GetCenter
()
-
VECTOR2I
(
r
,
r
),
VECTOR2I
(
2
*
r
,
2
*
r
),
aClearance
+
1
,
0.52
*
(
r
+
aClearance
)
);
}
case
SH_CIRCLE
:
default
:
{
break
;
SHAPE_CIRCLE
*
circle
=
static_cast
<
SHAPE_CIRCLE
*>
(
m_shape
);
}
int
r
=
circle
->
GetRadius
();
return
OctagonalHull
(
circle
->
GetCenter
()
-
VECTOR2I
(
r
,
r
),
VECTOR2I
(
2
*
r
,
2
*
r
),
aClearance
+
1
,
0.52
*
(
r
+
aClearance
)
);
}
default
:
break
;
}
return
SHAPE_LINE_CHAIN
();
return
SHAPE_LINE_CHAIN
();
}
}
PNS_ITEM
*
PNS_SOLID
::
Clone
()
const
PNS_ITEM
*
PNS_SOLID
::
Clone
()
const
{
{
// solids are never cloned as the shove algorithm never moves them
// solids are never cloned as the shove algorithm never moves them
assert
(
false
);
assert
(
false
);
}
}
\ No newline at end of file
pcbnew/router/pns_solid.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -29,41 +29,42 @@
...
@@ -29,41 +29,42 @@
#include "pns_item.h"
#include "pns_item.h"
class
PNS_SOLID
:
public
PNS_ITEM
{
class
PNS_SOLID
:
public
PNS_ITEM
{
public
:
public
:
PNS_SOLID
()
:
PNS_ITEM
(
SOLID
)
PNS_SOLID
()
:
PNS_ITEM
(
SOLID
)
{
{
m_movable
=
false
;
m_movable
=
false
;
m_shape
=
NULL
;
m_shape
=
NULL
;
}
}
PNS_ITEM
*
Clone
()
const
;
const
SHAPE
*
GetShape
()
const
{
return
m_shape
;
}
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
=
0
,
int
aWalkaroundThickness
=
0
)
const
;
PNS_ITEM
*
Clone
(
)
const
;
void
SetShape
(
SHAPE
*
shape
)
const
SHAPE
*
GetShape
()
const
{
return
m_shape
;
}
{
if
(
m_shape
)
delete
m_shape
;
m_shape
=
shape
;
}
const
VECTOR2I
&
GetCenter
()
const
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
=
0
,
int
aWalkaroundThickness
=
0
)
const
;
{
return
m_center
;
}
void
SetCenter
(
const
VECTOR2I
&
aCenter
)
void
SetShape
(
SHAPE
*
shape
)
{
{
m_center
=
aCenter
;
if
(
m_shape
)
}
delete
m_shape
;
private
:
m_shape
=
shape
;
}
VECTOR2I
m_center
;
const
VECTOR2I
&
GetCenter
()
const
SHAPE
*
m_shape
;
{
return
m_center
;
}
void
SetCenter
(
const
VECTOR2I
&
aCenter
)
{
m_center
=
aCenter
;
}
private
:
VECTOR2I
m_center
;
SHAPE
*
m_shape
;
};
};
#endif
#endif
...
...
pcbnew/router/pns_utils.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -22,21 +22,24 @@
...
@@ -22,21 +22,24 @@
#include "pns_line.h"
#include "pns_line.h"
#include "pns_router.h"
#include "pns_router.h"
const
SHAPE_LINE_CHAIN
OctagonalHull
(
const
VECTOR2I
&
aP0
,
const
VECTOR2I
&
aSize
,
int
aClearance
,
int
aChamfer
)
const
SHAPE_LINE_CHAIN
OctagonalHull
(
const
VECTOR2I
&
aP0
,
const
VECTOR2I
&
aSize
,
int
aClearance
,
int
aChamfer
)
{
{
SHAPE_LINE_CHAIN
s
;
SHAPE_LINE_CHAIN
s
;
s
.
SetClosed
(
true
);
s
.
Append
(
aP0
.
x
-
aClearance
,
aP0
.
y
-
aClearance
+
aChamfer
);
s
.
Append
(
aP0
.
x
-
aClearance
+
aChamfer
,
aP0
.
y
-
aClearance
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
-
aChamfer
,
aP0
.
y
-
aClearance
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
,
aP0
.
y
-
aClearance
+
aChamfer
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
,
aP0
.
y
+
aSize
.
y
+
aClearance
-
aChamfer
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
-
aChamfer
,
aP0
.
y
+
aSize
.
y
+
aClearance
);
s
.
Append
(
aP0
.
x
-
aClearance
+
aChamfer
,
aP0
.
y
+
aSize
.
y
+
aClearance
);
s
.
Append
(
aP0
.
x
-
aClearance
,
aP0
.
y
+
aSize
.
y
+
aClearance
-
aChamfer
);
s
.
SetClosed
(
true
);
return
s
;
s
.
Append
(
aP0
.
x
-
aClearance
,
aP0
.
y
-
aClearance
+
aChamfer
);
s
.
Append
(
aP0
.
x
-
aClearance
+
aChamfer
,
aP0
.
y
-
aClearance
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
-
aChamfer
,
aP0
.
y
-
aClearance
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
,
aP0
.
y
-
aClearance
+
aChamfer
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
,
aP0
.
y
+
aSize
.
y
+
aClearance
-
aChamfer
);
s
.
Append
(
aP0
.
x
+
aSize
.
x
+
aClearance
-
aChamfer
,
aP0
.
y
+
aSize
.
y
+
aClearance
);
s
.
Append
(
aP0
.
x
-
aClearance
+
aChamfer
,
aP0
.
y
+
aSize
.
y
+
aClearance
);
s
.
Append
(
aP0
.
x
-
aClearance
,
aP0
.
y
+
aSize
.
y
+
aClearance
-
aChamfer
);
return
s
;
}
}
pcbnew/router/pns_utils.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -24,10 +24,10 @@
...
@@ -24,10 +24,10 @@
#include <math/vector2d.h>
#include <math/vector2d.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_line_chain.h>
/** Various utility functions */
/** Various utility functions */
const
SHAPE_LINE_CHAIN
OctagonalHull
(
const
VECTOR2I
&
aP0
,
const
VECTOR2I
&
aSize
,
int
aClearance
,
int
aChamfer
);
const
SHAPE_LINE_CHAIN
OctagonalHull
(
const
VECTOR2I
&
aP0
,
const
VECTOR2I
&
aSize
,
int
aClearance
,
int
aChamfer
);
#endif // __PNS_UTILS_H
#endif
// __PNS_UTILS_H
pcbnew/router/pns_via.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -26,123 +26,136 @@
...
@@ -26,123 +26,136 @@
static
bool
Circle2Circle
(
VECTOR2I
p1
,
VECTOR2I
p2
,
int
r1
,
int
r2
,
VECTOR2I
&
force
)
static
bool
Circle2Circle
(
VECTOR2I
p1
,
VECTOR2I
p2
,
int
r1
,
int
r2
,
VECTOR2I
&
force
)
{
{
int
mindist
=
r1
+
r2
;
VECTOR2I
delta
=
p2
-
p1
;
int
dist
=
delta
.
EuclideanNorm
();
if
(
dist
>=
mindist
)
return
false
;
int
mindist
=
r1
+
r2
;
force
=
delta
.
Resize
(
abs
(
mindist
-
dist
)
+
1
);
VECTOR2I
delta
=
p2
-
p1
;
return
true
;
int
dist
=
delta
.
EuclideanNorm
();
if
(
dist
>=
mindist
)
return
false
;
force
=
delta
.
Resize
(
abs
(
mindist
-
dist
)
+
1
);
return
true
;
};
};
static
bool
Rect2Circle
(
VECTOR2I
rp0
,
VECTOR2I
rsize
,
VECTOR2I
cc
,
int
cr
,
VECTOR2I
&
force
)
static
bool
Rect2Circle
(
VECTOR2I
rp0
,
VECTOR2I
rsize
,
VECTOR2I
cc
,
int
cr
,
VECTOR2I
&
force
)
{
{
VECTOR2I
vts
[]
=
{
VECTOR2I
(
rp0
.
x
,
rp0
.
y
),
VECTOR2I
vts
[]
=
VECTOR2I
(
rp0
.
x
,
rp0
.
y
+
rsize
.
y
),
{
VECTOR2I
(
rp0
.
x
+
rsize
.
x
,
rp0
.
y
+
rsize
.
y
),
VECTOR2I
(
rp0
.
x
,
rp0
.
y
),
VECTOR2I
(
rp0
.
x
+
rsize
.
x
,
rp0
.
y
),
VECTOR2I
(
rp0
.
x
,
rp0
.
y
+
rsize
.
y
),
VECTOR2I
(
rp0
.
x
,
rp0
.
y
)
};
VECTOR2I
(
rp0
.
x
+
rsize
.
x
,
rp0
.
y
+
rsize
.
y
),
VECTOR2I
(
rp0
.
x
+
rsize
.
x
,
rp0
.
y
),
int
dist
=
INT_MAX
;
VECTOR2I
(
rp0
.
x
,
rp0
.
y
)
VECTOR2I
nearest
;
};
for
(
int
i
=
0
;
i
<
4
;
i
++
)
int
dist
=
INT_MAX
;
{
VECTOR2I
nearest
;
SEG
s
(
vts
[
i
],
vts
[
i
+
1
]);
for
(
int
i
=
0
;
i
<
4
;
i
++
)
VECTOR2I
pn
=
s
.
NearestPoint
(
cc
);
{
SEG
s
(
vts
[
i
],
vts
[
i
+
1
]
);
int
d
=
(
pn
-
cc
).
EuclideanNorm
();
if
(
d
<
dist
)
VECTOR2I
pn
=
s
.
NearestPoint
(
cc
);
{
nearest
=
pn
;
int
d
=
(
pn
-
cc
).
EuclideanNorm
();
dist
=
d
;
}
if
(
d
<
dist
)
}
{
nearest
=
pn
;
bool
inside
=
cc
.
x
>=
rp0
.
x
&&
cc
.
x
<=
(
rp0
.
x
+
rsize
.
x
)
dist
=
d
;
&&
cc
.
y
>=
rp0
.
y
&&
cc
.
y
<=
(
rp0
.
y
+
rsize
.
y
);
}
}
VECTOR2I
delta
=
cc
-
nearest
;
bool
inside
=
cc
.
x
>=
rp0
.
x
&&
cc
.
x
<=
(
rp0
.
x
+
rsize
.
x
)
if
(
dist
>=
cr
&&
!
inside
)
&&
cc
.
y
>=
rp0
.
y
&&
cc
.
y
<=
(
rp0
.
y
+
rsize
.
y
);
return
false
;
VECTOR2I
delta
=
cc
-
nearest
;
if
(
inside
)
force
=
-
delta
.
Resize
(
abs
(
cr
+
dist
)
+
1
);
if
(
dist
>=
cr
&&
!
inside
)
else
return
false
;
force
=
delta
.
Resize
(
abs
(
cr
-
dist
)
+
1
);
if
(
inside
)
return
true
;
force
=
-
delta
.
Resize
(
abs
(
cr
+
dist
)
+
1
);
else
force
=
delta
.
Resize
(
abs
(
cr
-
dist
)
+
1
);
return
true
;
};
};
static
bool
ShPushoutForce
(
const
SHAPE
*
shape
,
VECTOR2I
p
,
int
r
,
VECTOR2I
&
force
,
int
clearance
)
static
bool
ShPushoutForce
(
const
SHAPE
*
shape
,
VECTOR2I
p
,
int
r
,
VECTOR2I
&
force
,
int
clearance
)
{
{
switch
(
shape
->
Type
())
switch
(
shape
->
Type
()
)
{
{
case
SH_CIRCLE
:
case
SH_CIRCLE
:
{
{
const
SHAPE_CIRCLE
*
cir
=
static_cast
<
const
SHAPE_CIRCLE
*>
(
shape
);
const
SHAPE_CIRCLE
*
cir
=
static_cast
<
const
SHAPE_CIRCLE
*>
(
shape
);
return
Circle2Circle
(
cir
->
GetCenter
(),
p
,
cir
->
GetRadius
(),
r
+
clearance
+
1
,
force
);
return
Circle2Circle
(
cir
->
GetCenter
(),
p
,
cir
->
GetRadius
(),
r
+
clearance
+
1
,
force
);
}
}
case
SH_RECT
:
{
case
SH_RECT
:
const
SHAPE_RECT
*
rect
=
static_cast
<
const
SHAPE_RECT
*>
(
shape
);
{
return
Rect2Circle
(
rect
->
GetPosition
(),
rect
->
GetSize
(),
p
,
r
+
clearance
+
1
,
force
);
const
SHAPE_RECT
*
rect
=
static_cast
<
const
SHAPE_RECT
*>
(
shape
);
}
return
Rect2Circle
(
rect
->
GetPosition
(),
rect
->
GetSize
(),
p
,
r
+
clearance
+
1
,
force
);
default:
}
return
false
;
default:
}
return
false
;
return
false
;
}
return
false
;
}
}
bool
PNS_VIA
::
PushoutForce
(
PNS_NODE
*
aNode
,
const
VECTOR2I
&
aDirection
,
VECTOR2I
&
aForce
,
bool
aSolidsOnly
,
int
aMaxIterations
)
bool
PNS_VIA
::
PushoutForce
(
PNS_NODE
*
aNode
,
const
VECTOR2I
&
aDirection
,
VECTOR2I
&
aForce
,
bool
aSolidsOnly
,
int
aMaxIterations
)
{
{
int
iter
=
0
;
int
iter
=
0
;
PNS_VIA
mv
(
*
this
);
PNS_VIA
mv
(
*
this
);
VECTOR2I
force
,
totalForce
;
VECTOR2I
force
,
totalForce
;
while
(
iter
<
aMaxIterations
)
while
(
iter
<
aMaxIterations
)
{
{
PNS_NODE
::
OptObstacle
obs
=
aNode
->
CheckColliding
(
&
mv
,
aSolidsOnly
?
PNS_ITEM
::
SOLID
:
PNS_ITEM
::
ANY
);
PNS_NODE
::
OptObstacle
obs
=
aNode
->
CheckColliding
(
&
mv
,
aSolidsOnly
?
PNS_ITEM
::
SOLID
:
PNS_ITEM
::
ANY
);
if
(
!
obs
)
break
;
int
clearance
=
aNode
->
GetClearance
(
obs
->
item
,
&
mv
);
if
(
!
obs
)
break
;
if
(
iter
>
10
)
int
clearance
=
aNode
->
GetClearance
(
obs
->
item
,
&
mv
);
{
VECTOR2I
l
=
-
aDirection
.
Resize
(
m_diameter
/
4
);
totalForce
+=
l
;
mv
.
SetPos
(
mv
.
GetPos
()
+
l
);
}
if
(
ShPushoutForce
(
obs
->
item
->
GetShape
(),
mv
.
GetPos
(),
mv
.
GetDiameter
()
/
2
,
force
,
clearance
)
)
if
(
iter
>
10
)
{
{
totalForce
+=
force
;
VECTOR2I
l
=
-
aDirection
.
Resize
(
m_diameter
/
4
);
mv
.
SetPos
(
mv
.
GetPos
()
+
force
);
totalForce
+=
l
;
}
mv
.
SetPos
(
mv
.
GetPos
()
+
l
);
}
if
(
ShPushoutForce
(
obs
->
item
->
GetShape
(),
mv
.
GetPos
(),
mv
.
GetDiameter
()
/
2
,
force
,
clearance
)
)
{
totalForce
+=
force
;
mv
.
SetPos
(
mv
.
GetPos
()
+
force
);
}
iter
++
;
}
if
(
iter
==
aMaxIterations
)
iter
++
;
return
false
;
}
aForce
=
totalForce
;
if
(
iter
==
aMaxIterations
)
return
true
;
return
false
;
aForce
=
totalForce
;
return
true
;
}
}
const
SHAPE_LINE_CHAIN
PNS_VIA
::
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
const
SHAPE_LINE_CHAIN
PNS_VIA
::
Hull
(
int
aClearance
,
int
aWalkaroundThickness
)
const
{
{
return
OctagonalHull
(
m_pos
-
VECTOR2I
(
m_diameter
/
2
,
m_diameter
/
2
),
VECTOR2I
(
m_diameter
,
m_diameter
),
aClearance
+
1
,
(
2
*
aClearance
+
m_diameter
)
*
0.26
);
return
OctagonalHull
(
m_pos
-
VECTOR2I
(
m_diameter
/
2
,
m_diameter
/
2
),
VECTOR2I
(
m_diameter
,
m_diameter
),
aClearance
+
1
,
(
2
*
aClearance
+
m_diameter
)
*
0.26
);
}
}
\ No newline at end of file
pcbnew/router/pns_via.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -28,91 +28,96 @@
...
@@ -28,91 +28,96 @@
class
PNS_NODE
;
class
PNS_NODE
;
class
PNS_VIA
:
public
PNS_ITEM
class
PNS_VIA
:
public
PNS_ITEM
{
{
public
:
public
:
PNS_VIA
(
)
:
PNS_VIA
()
:
PNS_ITEM
(
VIA
)
{};
PNS_ITEM
(
VIA
)
{};
PNS_VIA
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aDiameter
,
int
aNet
=
-
1
)
:
PNS_VIA
(
const
VECTOR2I
&
aPos
,
const
PNS_LAYERSET
&
aLayers
,
int
aDiameter
,
int
aNet
=
-
1
)
:
PNS_ITEM
(
VIA
)
{
PNS_ITEM
(
VIA
)
SetNet
(
aNet
);
{
SetLayers
(
aLayers
);
SetNet
(
aNet
);
m_pos
=
aPos
;
SetLayers
(
aLayers
);
m_diameter
=
aDiameter
;
m_pos
=
aPos
;
m_shape
=
SHAPE_CIRCLE
(
aPos
,
aDiameter
/
2
);
m_diameter
=
aDiameter
;
};
m_shape
=
SHAPE_CIRCLE
(
aPos
,
aDiameter
/
2
);
};
PNS_VIA
(
const
PNS_VIA
&
b
)
:
PNS_ITEM
(
VIA
)
{
PNS_VIA
(
const
PNS_VIA
&
b
)
:
PNS_ITEM
(
VIA
)
SetNet
(
b
.
GetNet
());
{
SetLayers
(
b
.
GetLayers
());
SetNet
(
b
.
GetNet
()
);
m_pos
=
b
.
m_pos
;
SetLayers
(
b
.
GetLayers
()
);
m_diameter
=
b
.
m_diameter
;
m_pos
=
b
.
m_pos
;
m_shape
=
SHAPE_CIRCLE
(
m_pos
,
m_diameter
/
2
);
m_diameter
=
b
.
m_diameter
;
}
m_shape
=
SHAPE_CIRCLE
(
m_pos
,
m_diameter
/
2
);
}
const
VECTOR2I
&
GetPos
()
const
{
const
VECTOR2I
&
GetPos
()
const
return
m_pos
;
{
}
return
m_pos
;
}
void
SetPos
(
const
VECTOR2I
&
aPos
)
{
void
SetPos
(
const
VECTOR2I
&
aPos
)
m_pos
=
aPos
;
{
m_shape
.
SetCenter
(
aPos
);
m_pos
=
aPos
;
}
m_shape
.
SetCenter
(
aPos
);
}
int
GetDiameter
()
const
{
int
GetDiameter
()
const
return
m_diameter
;
{
}
return
m_diameter
;
}
void
SetDiameter
(
int
aDiameter
)
{
void
SetDiameter
(
int
aDiameter
)
m_diameter
=
aDiameter
;
{
m_shape
.
SetRadius
(
m_diameter
/
2
);
m_diameter
=
aDiameter
;
}
m_shape
.
SetRadius
(
m_diameter
/
2
);
}
int
GetDrill
()
const
{
int
GetDrill
()
const
return
m_drill
;
{
}
return
m_drill
;
}
void
SetDrill
(
int
aDrill
)
{
void
SetDrill
(
int
aDrill
)
m_drill
=
aDrill
;
{
}
m_drill
=
aDrill
;
}
bool
PushoutForce
(
PNS_NODE
*
aNode
,
const
VECTOR2I
&
aDirection
,
VECTOR2I
&
aForce
,
bool
aSolidsOnly
=
true
,
int
aMaxIterations
=
10
);
bool
PushoutForce
(
PNS_NODE
*
aNode
,
const
SHAPE
*
GetShape
()
const
const
VECTOR2I
&
aDirection
,
{
VECTOR2I
&
aForce
,
return
&
m_shape
;
bool
aSolidsOnly
=
true
,
}
int
aMaxIterations
=
10
);
PNS_VIA
*
Clone
()
const
const
SHAPE
*
GetShape
()
const
{
{
PNS_VIA
*
v
=
new
PNS_VIA
();
return
&
m_shape
;
}
v
->
SetNet
(
GetNet
());
v
->
SetLayers
(
GetLayers
());
PNS_VIA
*
Clone
()
const
v
->
m_pos
=
m_pos
;
{
v
->
m_diameter
=
m_diameter
;
PNS_VIA
*
v
=
new
PNS_VIA
();
v
->
m_shape
=
SHAPE_CIRCLE
(
m_pos
,
m_diameter
/
2
);
v
->
SetNet
(
GetNet
()
);
return
v
;
v
->
SetLayers
(
GetLayers
()
);
}
v
->
m_pos
=
m_pos
;
v
->
m_diameter
=
m_diameter
;
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
=
0
,
int
aWalkaroundThickness
=
0
)
const
;
v
->
m_shape
=
SHAPE_CIRCLE
(
m_pos
,
m_diameter
/
2
);
private
:
return
v
;
}
int
m_diameter
;
int
m_drill
;
const
SHAPE_LINE_CHAIN
Hull
(
int
aClearance
=
0
,
int
aWalkaroundThickness
=
0
)
const
;
VECTOR2I
m_pos
;
SHAPE_CIRCLE
m_shape
;
private
:
int
m_diameter
;
int
m_drill
;
VECTOR2I
m_pos
;
SHAPE_CIRCLE
m_shape
;
};
};
#endif
#endif
pcbnew/router/pns_walkaround.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -35,187 +35,197 @@ using boost::optional;
...
@@ -35,187 +35,197 @@ using boost::optional;
void
PNS_WALKAROUND
::
start
(
const
PNS_LINE
&
aInitialPath
)
void
PNS_WALKAROUND
::
start
(
const
PNS_LINE
&
aInitialPath
)
{
{
m_iteration
=
0
;
m_iteration
=
0
;
m_iteration_limit
=
50
;
m_iteration_limit
=
50
;
}
}
PNS_NODE
::
OptObstacle
PNS_WALKAROUND
::
nearestObstacle
(
const
PNS_LINE
&
aPath
)
PNS_NODE
::
OptObstacle
PNS_WALKAROUND
::
nearestObstacle
(
const
PNS_LINE
&
aPath
)
{
{
return
m_world
->
NearestObstacle
(
&
aPath
,
m_solids_only
?
(
PNS_ITEM
::
SOLID
|
PNS_ITEM
::
VIA
)
:
PNS_ITEM
::
ANY
);
return
m_world
->
NearestObstacle
(
&
aPath
,
m_solids_only
?
(
PNS_ITEM
::
SOLID
|
PNS_ITEM
::
VIA
)
:
PNS_ITEM
::
ANY
);
}
}
PNS_WALKAROUND
::
WalkaroundStatus
PNS_WALKAROUND
::
singleStep
(
PNS_LINE
&
aPath
,
bool
aWindingDirection
)
PNS_WALKAROUND
::
WalkaroundStatus
PNS_WALKAROUND
::
singleStep
(
PNS_LINE
&
aPath
,
bool
aWindingDirection
)
{
{
optional
<
PNS_OBSTACLE
>&
current_obs
=
aWindingDirection
?
m_currentObstacle
[
0
]
:
m_currentObstacle
[
1
];
optional
<
PNS_OBSTACLE
>&
current_obs
=
bool
&
prev_recursive
=
aWindingDirection
?
m_recursiveCollision
[
0
]
:
m_recursiveCollision
[
1
];
aWindingDirection
?
m_currentObstacle
[
0
]
:
m_currentObstacle
[
1
];
bool
&
prev_recursive
=
aWindingDirection
?
m_recursiveCollision
[
0
]
:
m_recursiveCollision
[
1
];
if
(
!
current_obs
)
return
DONE
;
if
(
!
current_obs
)
return
DONE
;
SHAPE_LINE_CHAIN
path_pre
[
2
],
path_walk
[
2
],
path_post
[
2
];
SHAPE_LINE_CHAIN
path_pre
[
2
],
path_walk
[
2
],
path_post
[
2
];
VECTOR2I
last
=
aPath
.
GetCLine
().
CPoint
(
-
1
);
VECTOR2I
last
=
aPath
.
GetCLine
().
CPoint
(
-
1
);
if
((
current_obs
->
hull
).
PointInside
(
last
))
{
if
(
(
current_obs
->
hull
).
PointInside
(
last
)
)
m_recursiveBlockageCount
++
;
{
m_recursiveBlockageCount
++
;
if
(
m_recursiveBlockageCount
<
3
)
aPath
.
GetLine
().
Append
(
current_obs
->
hull
.
NearestPoint
(
last
)
);
if
(
m_recursiveBlockageCount
<
3
)
else
{
aPath
.
GetLine
().
Append
(
current_obs
->
hull
.
NearestPoint
(
last
)
);
aPath
=
aPath
.
ClipToNearestObstacle
(
m_world
);
else
return
STUCK
;
{
}
aPath
=
aPath
.
ClipToNearestObstacle
(
m_world
);
}
return
STUCK
;
}
aPath
.
NewWalkaround
(
current_obs
->
hull
,
path_pre
[
0
],
path_walk
[
0
],
path_post
[
0
],
aWindingDirection
);
}
aPath
.
NewWalkaround
(
current_obs
->
hull
,
path_pre
[
1
],
path_walk
[
1
],
path_post
[
1
],
!
aWindingDirection
);
aPath
.
NewWalkaround
(
current_obs
->
hull
,
path_pre
[
0
],
path_walk
[
0
],
path_post
[
0
],
aWindingDirection
);
int
len_pre
=
path_walk
[
0
].
Length
();
aPath
.
NewWalkaround
(
current_obs
->
hull
,
path_pre
[
1
],
path_walk
[
1
],
int
len_alt
=
path_walk
[
1
].
Length
();
path_post
[
1
],
!
aWindingDirection
);
PNS_LINE
walk_path
(
aPath
,
path_walk
[
1
]);
int
len_pre
=
path_walk
[
0
].
Length
();
int
len_alt
=
path_walk
[
1
].
Length
();
bool
alt_collides
=
m_world
->
CheckColliding
(
&
walk_path
,
m_solids_only
?
PNS_ITEM
::
SOLID
:
PNS_ITEM
::
ANY
);
PNS_LINE
walk_path
(
aPath
,
path_walk
[
1
]
);
SHAPE_LINE_CHAIN
pnew
;
bool
alt_collides
=
m_world
->
CheckColliding
(
&
walk_path
,
if
(
!
m_forceSingleDirection
&&
len_alt
<
len_pre
&&
!
alt_collides
&&
!
prev_recursive
)
m_solids_only
?
PNS_ITEM
::
SOLID
:
PNS_ITEM
::
ANY
);
{
pnew
=
path_pre
[
1
];
SHAPE_LINE_CHAIN
pnew
;
pnew
.
Append
(
path_walk
[
1
]);
pnew
.
Append
(
path_post
[
1
]);
if
(
!
m_forceSingleDirection
&&
len_alt
<
len_pre
&&
!
alt_collides
&&
!
prev_recursive
)
{
current_obs
=
nearestObstacle
(
PNS_LINE
(
aPath
,
path_post
[
1
]));
pnew
=
path_pre
[
1
];
prev_recursive
=
false
;
pnew
.
Append
(
path_walk
[
1
]
);
}
else
{
pnew
.
Append
(
path_post
[
1
]
);
pnew
=
path_pre
[
0
];
pnew
.
Append
(
path_walk
[
0
]);
current_obs
=
nearestObstacle
(
PNS_LINE
(
aPath
,
path_post
[
1
]
)
);
pnew
.
Append
(
path_post
[
0
]);
prev_recursive
=
false
;
}
current_obs
=
nearestObstacle
(
PNS_LINE
(
aPath
,
path_walk
[
0
]));
else
{
if
(
!
current_obs
)
pnew
=
path_pre
[
0
];
{
pnew
.
Append
(
path_walk
[
0
]
);
prev_recursive
=
false
;
pnew
.
Append
(
path_post
[
0
]
);
current_obs
=
nearestObstacle
(
PNS_LINE
(
aPath
,
path_post
[
0
]));
}
else
current_obs
=
nearestObstacle
(
PNS_LINE
(
aPath
,
path_walk
[
0
]
)
);
prev_recursive
=
true
;
}
if
(
!
current_obs
)
{
prev_recursive
=
false
;
pnew
.
Simplify
();
current_obs
=
nearestObstacle
(
PNS_LINE
(
aPath
,
path_post
[
0
]
)
);
aPath
.
SetShape
(
pnew
);
}
else
return
IN_PROGRESS
;
prev_recursive
=
true
;
}
pnew
.
Simplify
();
aPath
.
SetShape
(
pnew
);
return
IN_PROGRESS
;
}
}
PNS_WALKAROUND
::
WalkaroundStatus
PNS_WALKAROUND
::
Route
(
const
PNS_LINE
&
aInitialPath
,
PNS_LINE
&
aWalkPath
,
bool
aOptimize
)
{
PNS_LINE
path_cw
(
aInitialPath
),
path_ccw
(
aInitialPath
);
WalkaroundStatus
s_cw
=
IN_PROGRESS
,
s_ccw
=
IN_PROGRESS
;
SHAPE_LINE_CHAIN
best_path
;
start
(
aInitialPath
);
m_currentObstacle
[
0
]
=
m_currentObstacle
[
1
]
=
nearestObstacle
(
aInitialPath
);
m_recursiveBlockageCount
=
0
;
aWalkPath
=
aInitialPath
;
while
(
m_iteration
<
m_iteration_limit
)
{
if
(
s_cw
!=
STUCK
)
s_cw
=
singleStep
(
path_cw
,
true
);
if
(
s_ccw
!=
STUCK
)
s_ccw
=
singleStep
(
path_ccw
,
false
);
if
((
s_cw
==
DONE
&&
s_ccw
==
DONE
)
||
(
s_cw
==
STUCK
&&
s_ccw
==
STUCK
))
{
int
len_cw
=
path_cw
.
GetCLine
().
Length
();
int
len_ccw
=
path_ccw
.
GetCLine
().
Length
();
if
(
m_forceLongerPath
)
aWalkPath
=
(
len_cw
>
len_ccw
?
path_cw
:
path_ccw
);
else
aWalkPath
=
(
len_cw
<
len_ccw
?
path_cw
:
path_ccw
);
break
;
}
else
if
(
s_cw
==
DONE
&&
!
m_forceLongerPath
)
{
aWalkPath
=
path_cw
;
break
;
}
else
if
(
s_ccw
==
DONE
&&
!
m_forceLongerPath
)
{
aWalkPath
=
path_ccw
;
break
;
}
m_iteration
++
;
}
if
(
m_iteration
==
m_iteration_limit
)
{
int
len_cw
=
path_cw
.
GetCLine
().
Length
();
int
len_ccw
=
path_ccw
.
GetCLine
().
Length
();
PNS_WALKAROUND
::
WalkaroundStatus
PNS_WALKAROUND
::
Route
(
const
PNS_LINE
&
aInitialPath
,
if
(
m_forceLongerPath
)
PNS_LINE
&
aWalkPath
,
aWalkPath
=
(
len_cw
>
len_ccw
?
path_cw
:
path_ccw
);
bool
aOptimize
)
else
{
aWalkPath
=
(
len_cw
<
len_ccw
?
path_cw
:
path_ccw
);
PNS_LINE
path_cw
(
aInitialPath
),
path_ccw
(
aInitialPath
);
WalkaroundStatus
s_cw
=
IN_PROGRESS
,
s_ccw
=
IN_PROGRESS
;
}
SHAPE_LINE_CHAIN
best_path
;
if
(
m_cursorApproachMode
)
start
(
aInitialPath
);
{
//int len_cw = path_cw.GetCLine().Length();
m_currentObstacle
[
0
]
=
m_currentObstacle
[
1
]
=
nearestObstacle
(
aInitialPath
);
//int len_ccw = path_ccw.GetCLine().Length();
m_recursiveBlockageCount
=
0
;
bool
found
=
false
;
aWalkPath
=
aInitialPath
;
SHAPE_LINE_CHAIN
l
=
aWalkPath
.
GetCLine
();
while
(
m_iteration
<
m_iteration_limit
)
{
for
(
int
i
=
0
;
i
<
l
.
SegmentCount
();
i
++
)
if
(
s_cw
!=
STUCK
)
{
s_cw
=
singleStep
(
path_cw
,
true
);
const
SEG
s
=
l
.
Segment
(
i
);
if
(
s_ccw
!=
STUCK
)
VECTOR2I
nearest
=
s
.
NearestPoint
(
m_cursorPos
);
s_ccw
=
singleStep
(
path_ccw
,
false
);
VECTOR2I
::
extended_type
dist_a
=
(
s
.
a
-
m_cursorPos
).
SquaredEuclideanNorm
();
VECTOR2I
::
extended_type
dist_b
=
(
s
.
b
-
m_cursorPos
).
SquaredEuclideanNorm
();
if
(
(
s_cw
==
DONE
&&
s_ccw
==
DONE
)
||
(
s_cw
==
STUCK
&&
s_ccw
==
STUCK
)
)
VECTOR2I
::
extended_type
dist_n
=
(
nearest
-
m_cursorPos
).
SquaredEuclideanNorm
();
{
int
len_cw
=
path_cw
.
GetCLine
().
Length
();
int
len_ccw
=
path_ccw
.
GetCLine
().
Length
();
if
(
dist_n
<=
dist_a
&&
dist_n
<
dist_b
)
if
(
m_forceLongerPath
)
{
aWalkPath
=
(
len_cw
>
len_ccw
?
path_cw
:
path_ccw
);
//PNSDisplayDebugLine(l, 3);
else
l
.
Remove
(
i
+
1
,
-
1
);
aWalkPath
=
(
len_cw
<
len_ccw
?
path_cw
:
path_ccw
);
l
.
Append
(
nearest
);
l
.
Simplify
();
break
;
found
=
true
;
}
break
;
else
if
(
s_cw
==
DONE
&&
!
m_forceLongerPath
)
}
{
}
aWalkPath
=
path_cw
;
if
(
found
)
break
;
{
}
aWalkPath
=
aInitialPath
;
else
if
(
s_ccw
==
DONE
&&
!
m_forceLongerPath
)
aWalkPath
.
SetShape
(
l
);
{
}
aWalkPath
=
path_ccw
;
}
break
;
}
aWalkPath
.
SetWorld
(
m_world
);
m_iteration
++
;
aWalkPath
.
GetLine
().
Simplify
();
}
WalkaroundStatus
st
=
s_ccw
==
DONE
||
s_cw
==
DONE
?
DONE
:
STUCK
;
if
(
m_iteration
==
m_iteration_limit
)
{
if
(
aOptimize
&&
st
==
DONE
)
int
len_cw
=
path_cw
.
GetCLine
().
Length
();
PNS_OPTIMIZER
::
Optimize
(
&
aWalkPath
,
PNS_OPTIMIZER
::
MERGE_OBTUSE
,
m_world
);
int
len_ccw
=
path_ccw
.
GetCLine
().
Length
();
return
st
;
if
(
m_forceLongerPath
)
aWalkPath
=
(
len_cw
>
len_ccw
?
path_cw
:
path_ccw
);
else
aWalkPath
=
(
len_cw
<
len_ccw
?
path_cw
:
path_ccw
);
}
if
(
m_cursorApproachMode
)
{
// int len_cw = path_cw.GetCLine().Length();
// int len_ccw = path_ccw.GetCLine().Length();
bool
found
=
false
;
SHAPE_LINE_CHAIN
l
=
aWalkPath
.
GetCLine
();
for
(
int
i
=
0
;
i
<
l
.
SegmentCount
();
i
++
)
{
const
SEG
s
=
l
.
Segment
(
i
);
VECTOR2I
nearest
=
s
.
NearestPoint
(
m_cursorPos
);
VECTOR2I
::
extended_type
dist_a
=
(
s
.
a
-
m_cursorPos
).
SquaredEuclideanNorm
();
VECTOR2I
::
extended_type
dist_b
=
(
s
.
b
-
m_cursorPos
).
SquaredEuclideanNorm
();
VECTOR2I
::
extended_type
dist_n
=
(
nearest
-
m_cursorPos
).
SquaredEuclideanNorm
();
if
(
dist_n
<=
dist_a
&&
dist_n
<
dist_b
)
{
// PNSDisplayDebugLine(l, 3);
l
.
Remove
(
i
+
1
,
-
1
);
l
.
Append
(
nearest
);
l
.
Simplify
();
found
=
true
;
break
;
}
}
if
(
found
)
{
aWalkPath
=
aInitialPath
;
aWalkPath
.
SetShape
(
l
);
}
}
aWalkPath
.
SetWorld
(
m_world
);
aWalkPath
.
GetLine
().
Simplify
();
WalkaroundStatus
st
=
s_ccw
==
DONE
||
s_cw
==
DONE
?
DONE
:
STUCK
;
if
(
aOptimize
&&
st
==
DONE
)
PNS_OPTIMIZER
::
Optimize
(
&
aWalkPath
,
PNS_OPTIMIZER
::
MERGE_OBTUSE
,
m_world
);
return
st
;
}
}
pcbnew/router/pns_walkaround.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -24,76 +24,75 @@
...
@@ -24,76 +24,75 @@
#include "pns_line.h"
#include "pns_line.h"
#include "pns_node.h"
#include "pns_node.h"
class
PNS_WALKAROUND
{
class
PNS_WALKAROUND
{
static
const
int
DefaultIterationLimit
=
50
;
static
const
int
DefaultIterationLimit
=
50
;
public
:
PNS_WALKAROUND
(
PNS_NODE
*
aWorld
)
:
public
:
m_world
(
aWorld
),
m_iteration_limit
(
DefaultIterationLimit
)
PNS_WALKAROUND
(
PNS_NODE
*
aWorld
)
:
{
m_world
(
aWorld
),
m_iteration_limit
(
DefaultIterationLimit
)
{
m_forceSingleDirection
=
false
;
m_forceSingleDirection
=
false
;
m_forceLongerPath
=
false
;
m_forceLongerPath
=
false
;
m_cursorApproachMode
=
false
;
m_cursorApproachMode
=
false
;
};
};
~
PNS_WALKAROUND
()
{};
~
PNS_WALKAROUND
()
{};
enum
WalkaroundStatus
enum
WalkaroundStatus
{
{
IN_PROGRESS
=
0
,
IN_PROGRESS
=
0
,
DONE
,
DONE
,
STUCK
STUCK
};
};
void
SetWorld
(
PNS_NODE
*
aNode
)
void
SetWorld
(
PNS_NODE
*
aNode
)
{
{
m_world
=
aNode
;
m_world
=
aNode
;
}
}
void
SetIterationLimit
(
const
int
aIterLimit
)
void
SetIterationLimit
(
const
int
aIterLimit
)
{
{
m_iteration_limit
=
aIterLimit
;
m_iteration_limit
=
aIterLimit
;
}
}
void
SetSolidsOnly
(
bool
aSolidsOnly
)
void
SetSolidsOnly
(
bool
aSolidsOnly
)
{
{
m_solids_only
=
aSolidsOnly
;
m_solids_only
=
aSolidsOnly
;
}
}
void
SetSingleDirection
(
bool
aForceSingleDirection
)
void
SetSingleDirection
(
bool
aForceSingleDirection
)
{
{
m_forceSingleDirection
=
aForceSingleDirection
;
m_forceSingleDirection
=
aForceSingleDirection
;
m_forceLongerPath
=
true
;
m_forceLongerPath
=
true
;
}
}
void
SetApproachCursor
(
bool
aEnabled
,
const
VECTOR2I
&
aPos
)
void
SetApproachCursor
(
bool
aEnabled
,
const
VECTOR2I
&
aPos
)
{
{
m_cursorPos
=
aPos
;
m_cursorPos
=
aPos
;
m_cursorApproachMode
=
aEnabled
;
m_cursorApproachMode
=
aEnabled
;
}
}
WalkaroundStatus
Route
(
const
PNS_LINE
&
aInitialPath
,
PNS_LINE
&
aWalkPath
,
bool
aOptimize
=
true
);
WalkaroundStatus
Route
(
const
PNS_LINE
&
aInitialPath
,
PNS_LINE
&
aWalkPath
,
bool
aOptimize
=
true
);
private
:
private
:
void
start
(
const
PNS_LINE
&
aInitialPath
);
void
start
(
const
PNS_LINE
&
aInitialPath
);
WalkaroundStatus
singleStep
(
PNS_LINE
&
aPath
,
bool
aWindingDirection
);
WalkaroundStatus
singleStep
(
PNS_LINE
&
aPath
,
bool
aWindingDirection
);
PNS_NODE
::
OptObstacle
nearestObstacle
(
const
PNS_LINE
&
aPath
);
PNS_NODE
::
OptObstacle
nearestObstacle
(
const
PNS_LINE
&
aPath
);
PNS_NODE
*
m_world
;
PNS_NODE
*
m_world
;
int
m_recursiveBlockageCount
;
int
m_recursiveBlockageCount
;
int
m_iteration
;
int
m_iteration
;
int
m_iteration_limit
;
int
m_iteration_limit
;
bool
m_solids_only
;
bool
m_solids_only
;
bool
m_forceSingleDirection
,
m_forceLongerPath
;
bool
m_forceSingleDirection
,
m_forceLongerPath
;
bool
m_cursorApproachMode
;
bool
m_cursorApproachMode
;
VECTOR2I
m_cursorPos
;
VECTOR2I
m_cursorPos
;
PNS_NODE
::
OptObstacle
m_currentObstacle
[
2
];
PNS_NODE
::
OptObstacle
m_currentObstacle
[
2
];
bool
m_recursiveCollision
[
2
];
bool
m_recursiveCollision
[
2
];
};
};
#endif // __PNS_WALKAROUND_H
#endif
// __PNS_WALKAROUND_H
pcbnew/router/readme.txt
deleted
100644 → 0
View file @
87b3f2e4
You'll see the P&S router sources here, but just not right now.
We are still dealing with some non-technical issues that should be solved by the next week.
Tom
\ No newline at end of file
pcbnew/router/router_preview_item.cpp
View file @
5598acb6
...
@@ -3,21 +3,21 @@
...
@@ -3,21 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#include <gal/color4d.h>
#include <gal/color4d.h>
#include "class_track.h"
#include "class_track.h"
...
@@ -31,167 +31,200 @@
...
@@ -31,167 +31,200 @@
using
namespace
KiGfx
;
using
namespace
KiGfx
;
ROUTER_PREVIEW_ITEM
::
ROUTER_PREVIEW_ITEM
(
const
PNS_ITEM
*
aItem
,
VIEW_GROUP
*
aParent
)
ROUTER_PREVIEW_ITEM
::
ROUTER_PREVIEW_ITEM
(
const
PNS_ITEM
*
aItem
,
VIEW_GROUP
*
aParent
)
:
:
EDA_ITEM
(
NOT_USED
)
EDA_ITEM
(
NOT_USED
)
{
{
m_Flags
=
0
;
m_Flags
=
0
;
m_parent
=
aParent
;
m_parent
=
aParent
;
if
(
aItem
)
Update
(
aItem
);
if
(
aItem
)
}
Update
(
aItem
);
}
ROUTER_PREVIEW_ITEM
::~
ROUTER_PREVIEW_ITEM
()
ROUTER_PREVIEW_ITEM
::~
ROUTER_PREVIEW_ITEM
()
{
{
}
}
void
ROUTER_PREVIEW_ITEM
::
Update
(
const
PNS_ITEM
*
aItem
)
void
ROUTER_PREVIEW_ITEM
::
Update
(
const
PNS_ITEM
*
aItem
)
{
{
m_layer
=
aItem
->
GetLayers
().
Start
();
m_layer
=
aItem
->
GetLayers
().
Start
();
m_color
=
getLayerColor
(
m_layer
);
m_color
=
getLayerColor
(
m_layer
);
m_color
.
a
=
0.8
;
m_color
.
a
=
0.8
;
switch
(
aItem
->
GetKind
()
)
switch
(
aItem
->
GetKind
())
{
{
case
PNS_ITEM
:
:
LINE
:
case
PNS_ITEM
:
:
LINE
:
m_type
=
PR_LINE
;
m_type
=
PR_LINE
;
m_width
=
static_cast
<
const
PNS_LINE
*>
(
aItem
)
->
GetWidth
();
m_width
=
static_cast
<
const
PNS_LINE
*>
(
aItem
)
->
GetWidth
();
m_line
=
*
static_cast
<
const
SHAPE_LINE_CHAIN
*>
(
aItem
->
GetShape
()
);
m_line
=
*
static_cast
<
const
SHAPE_LINE_CHAIN
*>
(
aItem
->
GetShape
());
break
;
break
;
case
PNS_ITEM
:
:
SEGMENT
:
case
PNS_ITEM
:
:
SEGMENT
:
m_type
=
PR_LINE
;
m_type
=
PR_LINE
;
m_width
=
static_cast
<
const
PNS_SEGMENT
*>
(
aItem
)
->
GetWidth
();
m_width
=
static_cast
<
const
PNS_SEGMENT
*>
(
aItem
)
->
GetWidth
();
m_line
=
*
static_cast
<
const
SHAPE_LINE_CHAIN
*>
(
aItem
->
GetShape
()
);
m_line
=
*
static_cast
<
const
SHAPE_LINE_CHAIN
*>
(
aItem
->
GetShape
());
break
;
break
;
case
PNS_ITEM
:
:
VIA
:
case
PNS_ITEM
:
:
VIA
:
m_type
=
PR_VIA
;
m_type
=
PR_VIA
;
m_color
=
COLOR4D
(
0.7
,
0.7
,
0.7
,
0.8
);
m_color
=
COLOR4D
(
0.7
,
0.7
,
0.7
,
0.8
);
m_width
=
static_cast
<
const
PNS_VIA
*>
(
aItem
)
->
GetDiameter
();
m_width
=
static_cast
<
const
PNS_VIA
*>
(
aItem
)
->
GetDiameter
();
m_viaCenter
=
static_cast
<
const
PNS_VIA
*>
(
aItem
)
->
GetPos
();
m_viaCenter
=
static_cast
<
const
PNS_VIA
*>
(
aItem
)
->
GetPos
();
break
;
break
;
default
:
default
:
break
;
break
;
}
}
ViewSetVisible
(
true
);
ViewSetVisible
(
true
);
ViewUpdate
(
GEOMETRY
|
APPEARANCE
);
ViewUpdate
(
GEOMETRY
|
APPEARANCE
);
}
}
void
ROUTER_PREVIEW_ITEM
::
MarkAsHead
(
)
void
ROUTER_PREVIEW_ITEM
::
MarkAsHead
()
{
{
if
(
m_type
!=
PR_VIA
)
if
(
m_type
!=
PR_VIA
)
m_color
.
Saturate
(
1.0
);
m_color
.
Saturate
(
1.0
);
}
}
const
BOX2I
ROUTER_PREVIEW_ITEM
::
ViewBBox
()
const
const
BOX2I
ROUTER_PREVIEW_ITEM
::
ViewBBox
()
const
{
{
BOX2I
bbox
;
BOX2I
bbox
;
switch
(
m_type
)
switch
(
m_type
)
{
{
case
PR_LINE
:
case
PR_LINE
:
bbox
=
m_line
.
BBox
();
bbox
=
m_line
.
BBox
();
bbox
.
Inflate
(
m_width
/
2
);
bbox
.
Inflate
(
m_width
/
2
);
return
bbox
;
return
bbox
;
case
PR_VIA
:
bbox
=
BOX2I
(
m_viaCenter
,
VECTOR2I
(
0
,
0
));
case
PR_VIA
:
bbox
.
Inflate
(
m_width
/
2
);
bbox
=
BOX2I
(
m_viaCenter
,
VECTOR2I
(
0
,
0
)
);
return
bbox
;
bbox
.
Inflate
(
m_width
/
2
);
default
:
return
bbox
;
break
;
}
default
:
return
bbox
;
break
;
}
return
bbox
;
}
}
void
ROUTER_PREVIEW_ITEM
::
ViewDraw
(
int
aLayer
,
KiGfx
::
GAL
*
aGal
)
const
void
ROUTER_PREVIEW_ITEM
::
ViewDraw
(
int
aLayer
,
KiGfx
::
GAL
*
aGal
)
const
{
{
switch
(
m_type
)
switch
(
m_type
)
{
{
case
PR_LINE
:
case
PR_LINE
:
aGal
->
SetLayerDepth
(
-
100.0
);
aGal
->
SetLayerDepth
(
-
100.0
);
aGal
->
SetLineWidth
(
m_width
);
aGal
->
SetLineWidth
(
m_width
);
aGal
->
SetStrokeColor
(
m_color
);
aGal
->
SetStrokeColor
(
m_color
);
aGal
->
SetIsStroke
(
true
);
aGal
->
SetIsStroke
(
true
);
aGal
->
SetIsFill
(
false
);
aGal
->
SetIsFill
(
false
);
for
(
int
s
=
0
;
s
<
m_line
.
SegmentCount
();
s
++
)
for
(
int
s
=
0
;
s
<
m_line
.
SegmentCount
();
s
++
)
aGal
->
DrawLine
(
m_line
.
CSegment
(
s
).
a
,
m_line
.
CSegment
(
s
).
b
);
aGal
->
DrawLine
(
m_line
.
CSegment
(
s
).
a
,
m_line
.
CSegment
(
s
).
b
);
if
(
m_line
.
IsClosed
())
aGal
->
DrawLine
(
m_line
.
CSegment
(
-
1
).
b
,
m_line
.
CSegment
(
0
).
a
);
if
(
m_line
.
IsClosed
()
)
break
;
aGal
->
DrawLine
(
m_line
.
CSegment
(
-
1
).
b
,
m_line
.
CSegment
(
0
).
a
);
case
PR_VIA
:
break
;
aGal
->
SetLayerDepth
(
-
101.0
);
case
PR_VIA
:
aGal
->
SetIsStroke
(
false
);
aGal
->
SetLayerDepth
(
-
101.0
);
aGal
->
SetIsFill
(
true
);
aGal
->
SetIsStroke
(
false
);
aGal
->
SetFillColor
(
m_color
);
aGal
->
SetIsFill
(
true
);
aGal
->
DrawCircle
(
m_viaCenter
,
m_width
/
2
);
aGal
->
SetFillColor
(
m_color
);
break
;
aGal
->
DrawCircle
(
m_viaCenter
,
m_width
/
2
);
default
:
break
;
break
;
}
default
:
break
;
}
}
}
void
ROUTER_PREVIEW_ITEM
::
DebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aWidth
,
int
aStyle
)
void
ROUTER_PREVIEW_ITEM
::
DebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aWidth
,
int
aStyle
)
{
{
#if 0
#if 0
m_line
= aLine;
m_line
= aLine;
m_width = aWidth;
m_width = aWidth;
m_color = assignColor(aStyle
);
m_color = assignColor( aStyle
);
m_type = PR_LINE;
m_type = PR_LINE;
ViewUpdate(GEOMETRY | APPEARANCE
);
ViewUpdate( GEOMETRY | APPEARANCE
);
#endif
#endif
}
}
void
ROUTER_PREVIEW_ITEM
::
DebugBox
(
const
BOX2I
&
aBox
,
int
aStyle
)
void
ROUTER_PREVIEW_ITEM
::
DebugBox
(
const
BOX2I
&
aBox
,
int
aStyle
)
{
{
#if 0
#if 0
assert(false
);
assert( false
);
m_line.Clear();
m_line.Clear();
m_line.Append( aBox.GetX(), aBox.GetY() );
m_line.Append( aBox.GetX(), aBox.GetY() );
m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight()
);
m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight()
);
m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight()
);
m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight()
);
m_line.Append( aBox.GetX(), aBox.GetY() + aBox.GetHeight()
);
m_line.Append( aBox.GetX(), aBox.GetY() + aBox.GetHeight()
);
m_line.SetClosed(true
);
m_line.SetClosed( true
);
m_width = 20000;
m_width = 20000;
m_color = assignColor(aStyle
);
m_color = assignColor( aStyle
);
m_type
= PR_LINE;
m_type
= PR_LINE;
ViewUpdate(GEOMETRY | APPEARANCE
);
ViewUpdate( GEOMETRY | APPEARANCE
);
#endif
#endif
}
}
const
COLOR4D
ROUTER_PREVIEW_ITEM
::
getLayerColor
(
int
layer
)
const
const
COLOR4D
ROUTER_PREVIEW_ITEM
::
getLayerColor
(
int
aLayer
)
const
{
{
//
assert (m_view != NULL);
//
assert (m_view != NULL);
PCB_RENDER_SETTINGS
*
settings
=
static_cast
<
PCB_RENDER_SETTINGS
*>
(
m_parent
->
GetView
()
->
GetPainter
()
->
GetSettings
());
PCB_RENDER_SETTINGS
*
settings
=
return
settings
->
GetLayerColor
(
layer
);
static_cast
<
PCB_RENDER_SETTINGS
*>
(
m_parent
->
GetView
()
->
GetPainter
()
->
GetSettings
()
);
return
settings
->
GetLayerColor
(
aLayer
);
}
}
const
COLOR4D
ROUTER_PREVIEW_ITEM
::
assignColor
(
int
s
tyle
)
const
const
COLOR4D
ROUTER_PREVIEW_ITEM
::
assignColor
(
int
aS
tyle
)
const
{
{
COLOR4D
color
;
COLOR4D
color
;
switch
(
style
)
{
switch
(
aStyle
)
case
0
:
color
=
COLOR4D
(
0
,
1
,
0
,
1
);
break
;
{
case
1
:
color
=
COLOR4D
(
1
,
0
,
0
,
0.3
);
break
;
case
0
:
case
2
:
color
=
COLOR4D
(
1
,
0.5
,
0.5
,
1
);
break
;
color
=
COLOR4D
(
0
,
1
,
0
,
1
);
break
;
case
3
:
color
=
COLOR4D
(
0
,
0
,
1
,
1
);
break
;
case
4
:
color
=
COLOR4D
(
1
,
1
,
1
,
1
);
break
;
case
1
:
case
5
:
color
=
COLOR4D
(
1
,
1
,
0
,
1
);
break
;
color
=
COLOR4D
(
1
,
0
,
0
,
0.3
);
break
;
case
6
:
color
=
COLOR4D
(
0
,
1
,
1
,
1
);
break
;
case
32
:
color
=
COLOR4D
(
0
,
0
,
1
,
0.5
);
break
;
case
2
:
default
:
break
;
color
=
COLOR4D
(
1
,
0.5
,
0.5
,
1
);
break
;
}
return
color
;
case
3
:
color
=
COLOR4D
(
0
,
0
,
1
,
1
);
break
;
case
4
:
color
=
COLOR4D
(
1
,
1
,
1
,
1
);
break
;
case
5
:
color
=
COLOR4D
(
1
,
1
,
0
,
1
);
break
;
case
6
:
color
=
COLOR4D
(
0
,
1
,
1
,
1
);
break
;
case
32
:
color
=
COLOR4D
(
0
,
0
,
1
,
0.5
);
break
;
default
:
break
;
}
return
color
;
}
}
pcbnew/router/router_preview_item.h
View file @
5598acb6
...
@@ -3,21 +3,21 @@
...
@@ -3,21 +3,21 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#ifndef __ROUTER_PREVIEW_ITEM_H
#ifndef __ROUTER_PREVIEW_ITEM_H
#define __ROUTER_PREVIEW_ITEM_H
#define __ROUTER_PREVIEW_ITEM_H
...
@@ -43,61 +43,61 @@ class PNS_ROUTER;
...
@@ -43,61 +43,61 @@ class PNS_ROUTER;
class
ROUTER_PREVIEW_ITEM
:
public
EDA_ITEM
class
ROUTER_PREVIEW_ITEM
:
public
EDA_ITEM
{
{
public
:
public
:
enum
ItemType
{
enum
ItemType
PR_VIA
,
{
PR_LINE
,
PR_VIA
,
PR_STUCK_MARKER
PR_LINE
,
};
PR_STUCK_MARKER
};
enum
ItemFlags
{
PR_SUGGESTION
=
1
};
ROUTER_PREVIEW_ITEM
(
const
PNS_ITEM
*
aItem
=
NULL
,
KiGfx
::
VIEW_GROUP
*
aParent
=
NULL
);
~
ROUTER_PREVIEW_ITEM
();
void
Update
(
const
PNS_ITEM
*
aItem
);
void
StuckMarker
(
VECTOR2I
&
aPosition
);
void
DebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aWidth
=
0
,
int
aStyle
=
0
);
void
DebugBox
(
const
BOX2I
&
aBox
,
int
aStyle
=
0
);
void
Show
(
int
a
,
std
::
ostream
&
b
)
const
{};
const
BOX2I
ViewBBox
()
const
;
virtual
void
ViewDraw
(
int
aLayer
,
KiGfx
::
GAL
*
aGal
)
const
;
virtual
void
ViewGetLayers
(
int
aLayers
[],
int
&
aCount
)
const
{
aLayers
[
0
]
=
GP_OVERLAY
;
aCount
=
1
;
}
void
MarkAsHead
(
);
private
:
const
KiGfx
::
COLOR4D
assignColor
(
int
style
)
const
;
const
KiGfx
::
COLOR4D
getLayerColor
(
int
layer
)
const
;
KiGfx
::
VIEW_GROUP
*
m_parent
;
PNS_ROUTER
*
m_router
;
SHAPE_LINE_CHAIN
m_line
;
ItemType
m_type
;
int
m_style
;
int
m_width
;
int
m_layer
;
KiGfx
::
COLOR4D
m_color
;
VECTOR2I
m_stuckPosition
;
VECTOR2I
m_viaCenter
;
};
enum
ItemFlags
{
PR_SUGGESTION
=
1
};
ROUTER_PREVIEW_ITEM
(
const
PNS_ITEM
*
aItem
=
NULL
,
KiGfx
::
VIEW_GROUP
*
aParent
=
NULL
);
~
ROUTER_PREVIEW_ITEM
();
void
Update
(
const
PNS_ITEM
*
aItem
);
void
StuckMarker
(
VECTOR2I
&
aPosition
);
void
DebugLine
(
const
SHAPE_LINE_CHAIN
&
aLine
,
int
aWidth
=
0
,
int
aStyle
=
0
);
void
DebugBox
(
const
BOX2I
&
aBox
,
int
aStyle
=
0
);
void
Show
(
int
a
,
std
::
ostream
&
b
)
const
{};
const
BOX2I
ViewBBox
()
const
;
virtual
void
ViewDraw
(
int
aLayer
,
KiGfx
::
GAL
*
aGal
)
const
;
virtual
void
ViewGetLayers
(
int
aLayers
[],
int
&
aCount
)
const
{
aLayers
[
0
]
=
GP_OVERLAY
;
aCount
=
1
;
}
void
MarkAsHead
();
private
:
const
KiGfx
::
COLOR4D
assignColor
(
int
aStyle
)
const
;
const
KiGfx
::
COLOR4D
getLayerColor
(
int
aLayer
)
const
;
KiGfx
::
VIEW_GROUP
*
m_parent
;
PNS_ROUTER
*
m_router
;
SHAPE_LINE_CHAIN
m_line
;
ItemType
m_type
;
int
m_style
;
int
m_width
;
int
m_layer
;
KiGfx
::
COLOR4D
m_color
;
VECTOR2I
m_stuckPosition
;
VECTOR2I
m_viaCenter
;
};
#endif
#endif
pcbnew/router/router_tool.cpp
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -42,70 +42,73 @@ using namespace KiGfx;
...
@@ -42,70 +42,73 @@ using namespace KiGfx;
using
namespace
std
;
using
namespace
std
;
using
boost
::
optional
;
using
boost
::
optional
;
static
TOOL_ACTION
ACT_AutoEndRoute
(
"AutoEndRoute"
,
AS_CONTEXT
,
'F'
);
static
TOOL_ACTION
ACT_AutoEndRoute
(
"AutoEndRoute"
,
AS_CONTEXT
,
'F'
);
static
TOOL_ACTION
ACT_PlaceVia
(
"PlaceVia"
,
AS_CONTEXT
,
'V'
);
static
TOOL_ACTION
ACT_PlaceVia
(
"PlaceVia"
,
AS_CONTEXT
,
'V'
);
static
TOOL_ACTION
ACT_OpenRouteOptions
(
"OpenRouterOptions"
,
AS_CONTEXT
,
'E'
);
static
TOOL_ACTION
ACT_OpenRouteOptions
(
"OpenRouterOptions"
,
AS_CONTEXT
,
'E'
);
static
TOOL_ACTION
ACT_SwitchPosture
(
"SwitchPosture"
,
AS_CONTEXT
,
'/'
);
static
TOOL_ACTION
ACT_SwitchPosture
(
"SwitchPosture"
,
AS_CONTEXT
,
'/'
);
static
TOOL_ACTION
ACT_EndTrack
(
"SwitchPosture"
,
AS_CONTEXT
,
WXK_END
);
static
TOOL_ACTION
ACT_EndTrack
(
"SwitchPosture"
,
AS_CONTEXT
,
WXK_END
);
ROUTER_TOOL
::
ROUTER_TOOL
()
:
ROUTER_TOOL
::
ROUTER_TOOL
()
:
TOOL_INTERACTIVE
(
"pcbnew.InteractiveRouter"
)
TOOL_INTERACTIVE
(
"pcbnew.InteractiveRouter"
)
{
{
m_router
=
NULL
;
m_router
=
NULL
;
m_menu
=
new
CONTEXT_MENU
;
m_menu
=
new
CONTEXT_MENU
;
m_menu
->
SetTitle
(
wxT
(
"Interactive router"
)
);
// fixme: not implemented yet. Sorry.
m_menu
->
SetTitle
(
wxT
(
"Interactive router"
)
);
// fixme: not implemented yet. Sorry.
m_menu
->
Add
(
wxT
(
"Cancel"
),
0
);
m_menu
->
Add
(
wxT
(
"Cancel"
),
0
);
m_menu
->
Add
(
wxT
(
"New track"
),
1
);
m_menu
->
Add
(
wxT
(
"New track"
),
1
);
m_menu
->
Add
(
wxT
(
"End track"
),
2
);
m_menu
->
Add
(
wxT
(
"End track"
),
2
);
m_menu
->
Add
(
wxT
(
"Auto-end track"
),
2
);
m_menu
->
Add
(
wxT
(
"Auto-end track"
),
2
);
m_menu
->
Add
(
wxT
(
"Place via"
),
3
);
m_menu
->
Add
(
wxT
(
"Place via"
),
3
);
m_menu
->
Add
(
wxT
(
"Switch posture"
),
4
);
m_menu
->
Add
(
wxT
(
"Switch posture"
),
4
);
m_menu
->
Add
(
wxT
(
"Routing options..."
),
5
);
m_menu
->
Add
(
wxT
(
"Routing options..."
),
5
);
}
}
ROUTER_TOOL
::~
ROUTER_TOOL
()
ROUTER_TOOL
::~
ROUTER_TOOL
()
{
{
delete
m_router
;
delete
m_router
;
}
}
void
ROUTER_TOOL
::
Reset
()
void
ROUTER_TOOL
::
Reset
()
{
{
if
(
m_router
)
if
(
m_router
)
delete
m_router
;
delete
m_router
;
m_router
=
new
PNS_ROUTER
;
m_router
=
new
PNS_ROUTER
;
TRACEn
(
0
,
"Reset"
);
TRACEn
(
0
,
"Reset"
);
m_router
->
ClearWorld
();
m_router
->
ClearWorld
();
m_router
->
SetBoard
(
getModel
<
BOARD
>
(
PCB_T
)
);
m_router
->
SetBoard
(
getModel
<
BOARD
>
(
PCB_T
)
);
m_router
->
SyncWorld
();
m_router
->
SyncWorld
();
if
(
getView
()
)
if
(
getView
()
)
m_router
->
SetView
(
getView
()
);
m_router
->
SetView
(
getView
()
);
Go
(
&
ROUTER_TOOL
::
Main
,
TOOL_EVENT
(
TC_Command
,
TA_Action
,
GetName
()
)
);
Go
(
&
ROUTER_TOOL
::
Main
,
TOOL_EVENT
(
TC_Command
,
TA_Action
,
GetName
()
)
);
}
}
int
ROUTER_TOOL
::
getDefaultWidth
(
int
aNetCode
)
int
ROUTER_TOOL
::
getDefaultWidth
(
int
aNetCode
)
{
{
int
w
,
d1
,
d2
;
int
w
,
d1
,
d2
;
getNetclassDimensions
(
aNetCode
,
w
,
d1
,
d2
);
getNetclassDimensions
(
aNetCode
,
w
,
d1
,
d2
);
return
w
;
return
w
;
}
}
void
ROUTER_TOOL
::
getNetclassDimensions
(
int
aNetCode
,
int
&
aWidth
,
int
&
aViaDiameter
,
int
&
aViaDrill
)
void
ROUTER_TOOL
::
getNetclassDimensions
(
int
aNetCode
,
int
&
aWidth
,
int
&
aViaDiameter
,
int
&
aViaDrill
)
{
{
BOARD
*
board
=
getModel
<
BOARD
>
(
PCB_T
);
BOARD
*
board
=
getModel
<
BOARD
>
(
PCB_T
);
NETCLASS
*
netClass
=
NULL
;
NETCLASS
*
netClass
=
NULL
;
NETINFO_ITEM
*
ni
=
board
->
FindNet
(
aNetCode
);
NETINFO_ITEM
*
ni
=
board
->
FindNet
(
aNetCode
);
if
(
ni
)
if
(
ni
)
{
{
wxString
netClassName
=
ni
->
GetClassName
();
wxString
netClassName
=
ni
->
GetClassName
();
netClass
=
board
->
m_NetClasses
.
Find
(
netClassName
);
netClass
=
board
->
m_NetClasses
.
Find
(
netClassName
);
...
@@ -113,26 +116,27 @@ void ROUTER_TOOL::getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDi
...
@@ -113,26 +116,27 @@ void ROUTER_TOOL::getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDi
if
(
!
netClass
)
if
(
!
netClass
)
netClass
=
board
->
m_NetClasses
.
GetDefault
();
netClass
=
board
->
m_NetClasses
.
GetDefault
();
aWidth
=
netClass
->
GetTrackWidth
();
aWidth
=
netClass
->
GetTrackWidth
();
aViaDiameter
=
netClass
->
GetViaDiameter
();
aViaDiameter
=
netClass
->
GetViaDiameter
();
aViaDrill
=
netClass
->
GetViaDrill
();
aViaDrill
=
netClass
->
GetViaDrill
();
}
}
PNS_ITEM
*
ROUTER_TOOL
::
pickSingleItem
(
const
VECTOR2I
&
aWhere
,
int
aNet
,
int
aLayer
)
PNS_ITEM
*
ROUTER_TOOL
::
pickSingleItem
(
const
VECTOR2I
&
aWhere
,
int
aNet
,
int
aLayer
)
{
{
int
tl
=
getView
()
->
GetTopLayer
();
int
tl
=
getView
()
->
GetTopLayer
();
if
(
aLayer
>
0
)
if
(
aLayer
>
0
)
tl
=
aLayer
;
tl
=
aLayer
;
PNS_ITEM
*
picked_seg
=
NULL
,
*
picked_via
=
NULL
;
PNS_ITEM
*
picked_seg
=
NULL
;
PNS_ITEMSET
candidates
=
m_router
->
QueryHoverItems
(
aWhere
);
PNS_ITEM
*
picked_via
=
NULL
;
PNS_ITEMSET
candidates
=
m_router
->
QueryHoverItems
(
aWhere
);
BOOST_FOREACH
(
PNS_ITEM
*
item
,
candidates
.
Items
()
)
BOOST_FOREACH
(
PNS_ITEM
*
item
,
candidates
.
Items
()
)
{
{
if
(
!
IsCopperLayer
(
item
->
GetLayers
().
Start
())
)
if
(
!
IsCopperLayer
(
item
->
GetLayers
().
Start
()
)
)
continue
;
continue
;
if
(
item
->
GetParent
()
&&
!
item
->
GetParent
()
->
ViewIsVisible
()
)
if
(
item
->
GetParent
()
&&
!
item
->
GetParent
()
->
ViewIsVisible
()
)
...
@@ -140,108 +144,116 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa
...
@@ -140,108 +144,116 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa
if
(
aNet
<
0
||
item
->
GetNet
()
==
aNet
)
if
(
aNet
<
0
||
item
->
GetNet
()
==
aNet
)
{
{
if
(
item
->
OfKind
(
PNS_ITEM
::
VIA
|
PNS_ITEM
::
SOLID
)
)
if
(
item
->
OfKind
(
PNS_ITEM
::
VIA
|
PNS_ITEM
::
SOLID
)
)
{
if
(
item
->
GetLayers
().
Overlaps
(
tl
)
||
!
picked_via
)
picked_via
=
item
;
}
else
{
{
if
(
item
->
GetLayers
().
Overlaps
(
tl
)
||
!
picked_via
)
if
(
item
->
GetLayers
().
Overlaps
(
tl
)
||
!
picked_seg
)
picked_via
=
item
;
picked_seg
=
item
;
}
else
{
if
(
item
->
GetLayers
().
Overlaps
(
tl
)
||
!
picked_seg
)
picked_seg
=
item
;
}
}
}
}
}
}
if
(
DisplayOpt
.
ContrastModeDisplay
)
if
(
DisplayOpt
.
ContrastModeDisplay
)
{
{
if
(
picked_seg
&&
!
picked_seg
->
GetLayers
().
Overlaps
(
tl
)
)
if
(
picked_seg
&&
!
picked_seg
->
GetLayers
().
Overlaps
(
tl
)
)
picked_seg
=
NULL
;
picked_seg
=
NULL
;
}
}
PNS_ITEM
*
rv
=
picked_via
?
picked_via
:
picked_seg
;
if
(
rv
&&
aLayer
>=
0
&&
!
rv
->
GetLayers
().
Overlaps
(
aLayer
)
)
PNS_ITEM
*
rv
=
picked_via
?
picked_via
:
picked_seg
;
if
(
rv
&&
aLayer
>=
0
&&
!
rv
->
GetLayers
().
Overlaps
(
aLayer
)
)
rv
=
NULL
;
rv
=
NULL
;
if
(
rv
)
if
(
rv
)
TRACE
(
0
,
"%s, layer : %d, tl: %d"
,
rv
->
GetKindStr
().
c_str
()
%
rv
->
GetLayers
().
Start
()
%
tl
);
TRACE
(
0
,
"%s, layer : %d, tl: %d"
,
rv
->
GetKindStr
().
c_str
()
%
rv
->
GetLayers
().
Start
()
%
tl
);
return
rv
;
return
rv
;
}
}
void
ROUTER_TOOL
::
setMsgPanel
(
bool
enabled
,
int
entry
,
const
wxString
&
aUpperMessage
,
const
wxString
&
aLowerMessage
)
void
ROUTER_TOOL
::
setMsgPanel
(
bool
aEnabled
,
int
aEntry
,
const
wxString
&
aUpperMessage
,
const
wxString
&
aLowerMessage
)
{
{
PCB_EDIT_FRAME
*
frame
=
getEditFrame
<
PCB_EDIT_FRAME
>
();
PCB_EDIT_FRAME
*
frame
=
getEditFrame
<
PCB_EDIT_FRAME
>
();
if
(
m_panelItems
.
size
()
<=
(
unsigned
int
)
entry
)
if
(
m_panelItems
.
size
()
<=
(
unsigned
int
)
aEntry
)
m_panelItems
.
resize
(
entry
+
1
);
m_panelItems
.
resize
(
aEntry
+
1
);
m_panelItems
[
e
ntry
]
=
MSG_PANEL_ITEM
(
aUpperMessage
,
aLowerMessage
,
BLACK
);
m_panelItems
[
aE
ntry
]
=
MSG_PANEL_ITEM
(
aUpperMessage
,
aLowerMessage
,
BLACK
);
frame
->
SetMsgPanel
(
m_panelItems
);
frame
->
SetMsgPanel
(
m_panelItems
);
}
}
void
ROUTER_TOOL
::
clearMsgPanel
()
void
ROUTER_TOOL
::
clearMsgPanel
()
{
{
PCB_EDIT_FRAME
*
frame
=
getEditFrame
<
PCB_EDIT_FRAME
>
();
PCB_EDIT_FRAME
*
frame
=
getEditFrame
<
PCB_EDIT_FRAME
>
();
frame
->
ClearMsgPanel
();
frame
->
ClearMsgPanel
();
}
}
void
ROUTER_TOOL
::
highlightNet
(
bool
enabled
,
int
netcode
)
void
ROUTER_TOOL
::
highlightNet
(
bool
aEnabled
,
int
aNetcode
)
{
{
RENDER_SETTINGS
*
rs
=
getView
()
->
GetPainter
()
->
GetSettings
();
RENDER_SETTINGS
*
rs
=
getView
()
->
GetPainter
()
->
GetSettings
();
if
(
netcode
>=
0
&&
enabled
)
if
(
aNetcode
>=
0
&&
aEnabled
)
rs
->
SetHighlight
(
true
,
netcode
);
rs
->
SetHighlight
(
true
,
aNetcode
);
else
else
rs
->
SetHighlight
(
false
);
rs
->
SetHighlight
(
false
);
getView
()
->
UpdateAllLayersColor
();
getView
()
->
UpdateAllLayersColor
();
}
}
void
ROUTER_TOOL
::
updateStartItem
(
TOOL_EVENT
&
aEvent
)
void
ROUTER_TOOL
::
updateStartItem
(
TOOL_EVENT
&
aEvent
)
{
{
VIEW_CONTROLS
*
ctls
=
getViewControls
();
VIEW_CONTROLS
*
ctls
=
getViewControls
();
int
tl
=
getView
()
->
GetTopLayer
();
int
tl
=
getView
()
->
GetTopLayer
();
PNS_ITEM
*
startItem
=
NULL
;
PNS_ITEM
*
startItem
=
NULL
;
if
(
aEvent
.
IsMotion
()
||
aEvent
.
IsClick
()
)
if
(
aEvent
.
IsMotion
()
||
aEvent
.
IsClick
()
)
{
{
VECTOR2I
p
=
aEvent
.
Position
();
VECTOR2I
p
=
aEvent
.
Position
();
startItem
=
pickSingleItem
(
p
);
startItem
=
pickSingleItem
(
p
);
if
(
startItem
&&
startItem
->
GetNet
()
>=
0
)
if
(
startItem
&&
startItem
->
GetNet
()
>=
0
)
{
{
bool
dummy
;
bool
dummy
;
VECTOR2I
cursorPos
=
m_router
->
SnapToItem
(
startItem
,
p
,
dummy
);
VECTOR2I
cursorPos
=
m_router
->
SnapToItem
(
startItem
,
p
,
dummy
);
ctls
->
ForceCursorPosition
(
true
,
cursorPos
);
ctls
->
ForceCursorPosition
(
true
,
cursorPos
);
m_startSnapPoint
=
cursorPos
;
m_startSnapPoint
=
cursorPos
;
if
(
startItem
->
GetLayers
().
IsMultilayer
())
if
(
startItem
->
GetLayers
().
IsMultilayer
()
)
m_startLayer
=
tl
;
m_startLayer
=
tl
;
else
else
m_startLayer
=
startItem
->
GetLayers
().
Start
();
m_startLayer
=
startItem
->
GetLayers
().
Start
();
m_startItem
=
startItem
;
m_startItem
=
startItem
;
}
else
{
}
else
{
m_startItem
=
NULL
;
m_startItem
=
NULL
;
m_startSnapPoint
=
p
;
m_startSnapPoint
=
p
;
m_startLayer
=
tl
;
m_startLayer
=
tl
;
ctls
->
ForceCursorPosition
(
false
);
ctls
->
ForceCursorPosition
(
false
);
}
}
}
}
}
}
void
ROUTER_TOOL
::
updateEndItem
(
TOOL_EVENT
&
aEvent
)
void
ROUTER_TOOL
::
updateEndItem
(
TOOL_EVENT
&
aEvent
)
{
{
VIEW_CONTROLS
*
ctls
=
getViewControls
();
VIEW_CONTROLS
*
ctls
=
getViewControls
();
VECTOR2I
p
=
aEvent
.
Position
();
VECTOR2I
p
=
aEvent
.
Position
();
int
layer
;
int
layer
;
if
(
m_router
->
GetCurrentNet
()
<
0
||
!
m_startItem
)
if
(
m_router
->
GetCurrentNet
()
<
0
||
!
m_startItem
)
{
{
m_endItem
=
NULL
;
m_endItem
=
NULL
;
m_endSnapPoint
=
p
;
m_endSnapPoint
=
p
;
...
@@ -250,48 +262,53 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent )
...
@@ -250,48 +262,53 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent )
bool
dummy
;
bool
dummy
;
if
(
m_router
->
IsPlacingVia
()
)
if
(
m_router
->
IsPlacingVia
()
)
layer
=
-
1
;
layer
=
-
1
;
else
else
layer
=
m_router
->
GetCurrentLayer
();
layer
=
m_router
->
GetCurrentLayer
();
PNS_ITEM
*
endItem
=
pickSingleItem
(
p
,
m_startItem
->
GetNet
(),
layer
);
if
(
endItem
)
PNS_ITEM
*
endItem
=
pickSingleItem
(
p
,
m_startItem
->
GetNet
(),
layer
);
if
(
endItem
)
{
{
VECTOR2I
cursorPos
=
m_router
->
SnapToItem
(
endItem
,
p
,
dummy
);
VECTOR2I
cursorPos
=
m_router
->
SnapToItem
(
endItem
,
p
,
dummy
);
ctls
->
ForceCursorPosition
(
true
,
cursorPos
);
ctls
->
ForceCursorPosition
(
true
,
cursorPos
);
m_endItem
=
endItem
;
m_endItem
=
endItem
;
m_endSnapPoint
=
cursorPos
;
m_endSnapPoint
=
cursorPos
;
}
else
{
}
else
{
m_endItem
=
NULL
;
m_endItem
=
NULL
;
m_endSnapPoint
=
p
;
m_endSnapPoint
=
p
;
ctls
->
ForceCursorPosition
(
false
);
ctls
->
ForceCursorPosition
(
false
);
}
}
if
(
m_endItem
)
if
(
m_endItem
)
TRACE
(
0
,
"%s, layer : %d"
,
m_endItem
->
GetKindStr
().
c_str
()
%
m_endItem
->
GetLayers
().
Start
()
);
TRACE
(
0
,
"%s, layer : %d"
,
m_endItem
->
GetKindStr
().
c_str
()
%
m_endItem
->
GetLayers
().
Start
()
);
}
}
void
ROUTER_TOOL
::
startRouting
(
)
void
ROUTER_TOOL
::
startRouting
()
{
{
VIEW_CONTROLS
*
ctls
=
getViewControls
();
VIEW_CONTROLS
*
ctls
=
getViewControls
();
int
width
=
getDefaultWidth
(
m_startItem
?
m_startItem
->
GetNet
()
:
-
1
);
int
width
=
getDefaultWidth
(
m_startItem
?
m_startItem
->
GetNet
()
:
-
1
);
if
(
m_startItem
&&
m_startItem
->
OfKind
(
PNS_ITEM
::
SEGMENT
))
width
=
static_cast
<
PNS_SEGMENT
*>
(
m_startItem
)
->
GetWidth
();
if
(
m_startItem
&&
m_startItem
->
OfKind
(
PNS_ITEM
::
SEGMENT
)
)
width
=
static_cast
<
PNS_SEGMENT
*>
(
m_startItem
)
->
GetWidth
();
m_router
->
SetCurrentWidth
(
width
);
m_router
->
SetCurrentWidth
(
width
);
m_router
->
SwitchLayer
(
m_startLayer
);
m_router
->
SwitchLayer
(
m_startLayer
);
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_startLayer
);
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_startLayer
);
if
(
m_startItem
&&
m_startItem
->
GetNet
()
>=
0
)
if
(
m_startItem
&&
m_startItem
->
GetNet
()
>=
0
)
highlightNet
(
true
,
m_startItem
->
GetNet
()
);
highlightNet
(
true
,
m_startItem
->
GetNet
()
);
ctls
->
ForceCursorPosition
(
false
);
ctls
->
SetAutoPan
(
true
);
ctls
->
ForceCursorPosition
(
false
);
ctls
->
SetAutoPan
(
true
);
m_router
->
StartRouting
(
m_startSnapPoint
,
m_startItem
);
m_router
->
StartRouting
(
m_startSnapPoint
,
m_startItem
);
m_endItem
=
NULL
;
m_endItem
=
NULL
;
...
@@ -299,93 +316,94 @@ void ROUTER_TOOL::startRouting ( )
...
@@ -299,93 +316,94 @@ void ROUTER_TOOL::startRouting ( )
while
(
OPT_TOOL_EVENT
evt
=
Wait
()
)
while
(
OPT_TOOL_EVENT
evt
=
Wait
()
)
{
{
if
(
evt
->
IsCancel
()
)
if
(
evt
->
IsCancel
()
)
break
;
break
;
else
if
(
evt
->
IsMotion
()
)
else
if
(
evt
->
IsMotion
()
)
{
{
updateEndItem
(
*
evt
);
updateEndItem
(
*
evt
);
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
}
}
else
if
(
evt
->
IsClick
(
MB_Left
)
)
else
if
(
evt
->
IsClick
(
MB_Left
)
)
{
{
updateEndItem
(
*
evt
);
updateEndItem
(
*
evt
);
if
(
m_router
->
FixRoute
(
m_endSnapPoint
,
m_endItem
))
if
(
m_router
->
FixRoute
(
m_endSnapPoint
,
m_endItem
)
)
break
;
break
;
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
}
else
if
(
evt
->
IsKeyUp
())
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
{
}
else
if
(
evt
->
IsKeyUp
()
)
{
switch
(
evt
->
KeyCode
()
)
switch
(
evt
->
KeyCode
()
)
{
{
case
'V'
:
case
'V'
:
{
{
int
w
,
diameter
,
drill
;
int
w
,
diameter
,
drill
;
getNetclassDimensions
(
m_router
->
GetCurrentNet
(),
w
,
diameter
,
drill
);
getNetclassDimensions
(
m_router
->
GetCurrentNet
(),
w
,
diameter
,
drill
);
m_router
->
SetCurrentViaDiameter
(
diameter
);
m_router
->
SetCurrentViaDiameter
(
diameter
);
m_router
->
SetCurrentViaDrill
(
drill
);
m_router
->
SetCurrentViaDrill
(
drill
);
m_router
->
ToggleViaPlacement
();
m_router
->
ToggleViaPlacement
();
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_router
->
GetCurrentLayer
());
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_router
->
GetCurrentLayer
()
);
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
break
;
break
;
}
case
'/'
:
m_router
->
FlipPosture
();
break
;
case
'+'
:
case
'='
:
m_router
->
SwitchLayer
(
m_router
->
NextCopperLayer
(
true
)
);
updateEndItem
(
*
evt
);
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_router
->
GetCurrentLayer
());
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
break
;
case
'-'
:
m_router
->
SwitchLayer
(
m_router
->
NextCopperLayer
(
false
)
);
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_router
->
GetCurrentLayer
());
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
break
;
}
}
}
case
'/'
:
m_router
->
FlipPosture
();
break
;
case
'+'
:
case
'='
:
m_router
->
SwitchLayer
(
m_router
->
NextCopperLayer
(
true
)
);
updateEndItem
(
*
evt
);
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_router
->
GetCurrentLayer
()
);
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
break
;
case
'-'
:
m_router
->
SwitchLayer
(
m_router
->
NextCopperLayer
(
false
)
);
getEditFrame
<
PCB_EDIT_FRAME
>
()
->
SetTopLayer
(
m_router
->
GetCurrentLayer
()
);
m_router
->
Move
(
m_endSnapPoint
,
m_endItem
);
break
;
}
}
}
}
if
(
m_router
->
RoutingInProgress
()
)
if
(
m_router
->
RoutingInProgress
()
)
m_router
->
StopRouting
();
m_router
->
StopRouting
();
ctls
->
SetAutoPan
(
false
);
ctls
->
SetAutoPan
(
false
);
ctls
->
ForceCursorPosition
(
false
);
ctls
->
ForceCursorPosition
(
false
);
highlightNet
(
false
);
highlightNet
(
false
);
}
}
int
ROUTER_TOOL
::
Main
(
TOOL_EVENT
&
aEvent
)
int
ROUTER_TOOL
::
Main
(
TOOL_EVENT
&
aEvent
)
{
{
VIEW_CONTROLS
*
ctls
=
getViewControls
();
VIEW_CONTROLS
*
ctls
=
getViewControls
();
//SetContextMenu ( m_menu );
//
SetContextMenu ( m_menu );
//setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing"));
//
setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing"));
ctls
->
SetSnapping
(
true
);
ctls
->
SetSnapping
(
true
);
ctls
->
ShowCursor
(
true
);
ctls
->
ShowCursor
(
true
);
// Main loop: keep receiving events
// Main loop: keep receiving events
while
(
OPT_TOOL_EVENT
evt
=
Wait
()
)
while
(
OPT_TOOL_EVENT
evt
=
Wait
()
)
{
{
if
(
evt
->
IsCancel
()
)
if
(
evt
->
IsCancel
()
)
break
;
// Finish
break
;
// Finish
else
if
(
evt
->
IsMotion
(
)
)
else
if
(
evt
->
IsMotion
()
)
updateStartItem
(
*
evt
);
updateStartItem
(
*
evt
);
else
if
(
evt
->
IsClick
(
MB_Left
)
)
else
if
(
evt
->
IsClick
(
MB_Left
)
)
{
{
updateStartItem
(
*
evt
);
updateStartItem
(
*
evt
);
startRouting
(
);
startRouting
();
}
}
}
}
// clearMsgPanel();
//clearMsgPanel();
// Restore the default settings
// Restore the default settings
ctls
->
SetAutoPan
(
false
);
ctls
->
SetAutoPan
(
false
);
...
@@ -394,4 +412,3 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent )
...
@@ -394,4 +412,3 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent )
return
0
;
return
0
;
}
}
pcbnew/router/router_tool.h
View file @
5598acb6
...
@@ -3,17 +3,17 @@
...
@@ -3,17 +3,17 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
...
@@ -45,35 +45,36 @@ public:
...
@@ -45,35 +45,36 @@ public:
int
Main
(
TOOL_EVENT
&
aEvent
);
int
Main
(
TOOL_EVENT
&
aEvent
);
private
:
private
:
PNS_ITEM
*
pickSingleItem
(
const
VECTOR2I
&
aWhere
,
int
aNet
=
-
1
,
int
aLayer
=
-
1
);
void
setMsgPanel
(
bool
enabled
,
int
entry
,
const
wxString
&
aUpperMessage
=
wxT
(
""
),
const
wxString
&
aLowerMessage
=
wxT
(
""
)
);
PNS_ITEM
*
pickSingleItem
(
const
VECTOR2I
&
aWhere
,
int
aNet
=
-
1
,
int
aLayer
=
-
1
);
void
clearMsgPanel
();
int
getDefaultWidth
(
int
aNetCode
);
void
setMsgPanel
(
bool
enabled
,
int
entry
,
const
wxString
&
aUpperMessage
=
wxT
(
""
),
void
startRouting
(
);
const
wxString
&
aLowerMessage
=
wxT
(
""
)
);
void
highlightNet
(
bool
enabled
,
int
netcode
=
-
1
);
void
clearMsgPanel
(
);
void
updateStartItem
(
TOOL_EVENT
&
aEvent
);
int
getDefaultWidth
(
int
aNetCode
);
void
updateEndItem
(
TOOL_EVENT
&
aEvent
);
void
startRouting
();
void
highlightNet
(
bool
enabled
,
int
netcode
=
-
1
);
void
getNetclassDimensions
(
int
aNetCode
,
int
&
aWidth
,
int
&
aViaDiameter
,
int
&
aViaDrill
);
void
updateStartItem
(
TOOL_EVENT
&
aEvent
);
void
updateEndItem
(
TOOL_EVENT
&
aEvent
);
MSG_PANEL_ITEMS
m_panelItems
;
void
getNetclassDimensions
(
int
aNetCode
,
int
&
aWidth
,
int
&
aViaDiameter
,
int
&
aViaDrill
)
;
PNS_ROUTER
*
m_router
;
MSG_PANEL_ITEMS
m_panelItems
;
PNS_ITEM
*
m_startItem
;
PNS_ROUTER
*
m_router
;
int
m_startLayer
;
VECTOR2I
m_startSnapPoint
;
PNS_ITEM
*
m_endItem
;
PNS_ITEM
*
m_startItem
;
VECTOR2I
m_endSnapPoint
;
int
m_startLayer
;
VECTOR2I
m_startSnapPoint
;
PNS_ITEM
*
m_endItem
;
VECTOR2I
m_endSnapPoint
;
/*boost::shared_ptr<CONTEXT_MENU> m_menu;*/
/*boost::shared_ptr<CONTEXT_MENU> m_menu;*/
CONTEXT_MENU
*
m_menu
;
CONTEXT_MENU
*
m_menu
;
};
};
#endif
#endif
pcbnew/router/trace.h
View file @
5598acb6
...
@@ -3,48 +3,45 @@
...
@@ -3,48 +3,45 @@
*
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
* This program is free software: you can redistribute it and/or modify it
* 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
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
*/
#ifndef __TRACE_H
#ifndef __TRACE_H
#define __TRACE_H
#define __TRACE_H
#ifdef DEBUG
#ifdef DEBUG
#include <string>
#include <string>
#include <iostream>
#include <iostream>
#include <boost/format.hpp>
#include <boost/format.hpp>
static
void
_trace_print
(
const
char
*
funcName
,
int
level
,
const
std
::
string
&
msg
)
static
void
_trace_print
(
const
char
*
funcName
,
int
level
,
const
std
::
string
&
msg
)
{
{
std
::
cerr
<<
"trace["
<<
level
<<
"]: "
<<
funcName
<<
": "
<<
msg
<<
std
::
endl
;
std
::
cerr
<<
"trace["
<<
level
<<
"]: "
<<
funcName
<<
": "
<<
msg
<<
std
::
endl
;
}
}
#define TRACE( level, fmt, ... ) \
_trace_print( __FUNCTION__, level, (boost::format( fmt ) % __VA_ARGS__).str() );
#define TRACEn( level, msg ) \
#define TRACE(level, fmt, ...) \
_trace_print( __FUNCTION__, level, std::string( msg ) );
_trace_print(__FUNCTION__, level, (boost::format(fmt) % __VA_ARGS__).str() );
#define TRACEn(level, msg) \
_trace_print(__FUNCTION__, level, std::string(msg));
#else
#else
#define TRACE(
level, fmt, ...
)
#define TRACE(
level, fmt, ...
)
#define TRACEn(
level, msg
)
#define TRACEn(
level, msg
)
#endif
#endif
...
...
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