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
e126042b
Commit
e126042b
authored
Dec 29, 2007
by
raburton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
set eol-style native on new files
parent
5eda8a52
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
4471 additions
and
4471 deletions
+4471
-4471
PolyLine.cpp
polygon/PolyLine.cpp
+1888
-1888
PolyLine.h
polygon/PolyLine.h
+177
-177
PolyLine2Kicad.h
polygon/PolyLine2Kicad.h
+94
-94
cdisplaylist_stuff.cpp
polygon/cdisplaylist_stuff.cpp
+85
-85
freepcbDisplayList.h
polygon/freepcbDisplayList.h
+269
-269
freepcb_ids.h
polygon/freepcb_ids.h
+118
-118
math_for_graphics.cpp
polygon/math_for_graphics.cpp
+1736
-1736
math_for_graphics.h
polygon/math_for_graphics.h
+104
-104
No files found.
polygon/PolyLine.cpp
View file @
e126042b
// PolyLine.cpp ... implementation of CPolyLine class
// from FreePCB.
// Adaptation for kicad
//
using
namespace
std
;
#include <math.h>
#include <vector>
#include "PolyLine.h"
#define to_int(x) (int)round((x))
/* Stuff to compile PolyLine.cpp, used in std::vector as CArray. does not work. must be redesigned, only for test */
#define SetSize reserve
#define pi 3.14159265359
#define DENOM 10 // to use mils for php clipping
//#define DENOM 1 // to use internal units for php clipping
// dl is a pointer to CDisplayList for drawing graphic elements
// if dl = NULL, doesn't draw anything but can still hold data
//
CPolyLine
::
CPolyLine
(
CDisplayList
*
dl
)
{
m_dlist
=
dl
;
m_HatchStyle
=
0
;
m_sel_box
=
0
;
m_gpc_poly
=
new
gpc_polygon
;
m_gpc_poly
->
num_contours
=
0
;
m_php_poly
=
new
polygon
;
}
CPolyLine
::
CPolyLine
()
{
m_dlist
=
NULL
;
m_HatchStyle
=
0
;
m_sel_box
=
0
;
m_gpc_poly
=
new
gpc_polygon
;
m_gpc_poly
->
num_contours
=
0
;
m_php_poly
=
new
polygon
;
}
// destructor, removes display elements
//
CPolyLine
::~
CPolyLine
()
{
Undraw
();
FreeGpcPoly
();
delete
m_gpc_poly
;
delete
m_php_poly
;
}
// Use the General Polygon Clipping Library to clip contours
// If this results in new polygons, return them as std::vector p
// If bRetainArcs == TRUE, try to retain arcs in polys
// Returns number of external contours, or -1 if error
//
int
CPolyLine
::
NormalizeWithGpc
(
std
::
vector
<
CPolyLine
*>
*
pa
,
BOOL
bRetainArcs
)
{
std
::
vector
<
CArc
>
arc_array
;
if
(
bRetainArcs
)
MakeGpcPoly
(
-
1
,
&
arc_array
);
else
MakeGpcPoly
(
-
1
,
NULL
);
Undraw
();
// now, recreate poly
// first, find outside contours and create new CPolyLines if necessary
int
n_ext_cont
=
0
;
for
(
int
ic
=
0
;
ic
<
m_gpc_poly
->
num_contours
;
ic
++
)
{
if
(
!
(
m_gpc_poly
->
hole
)[
ic
]
)
{
if
(
n_ext_cont
==
0
)
{
// first external contour, replace this poly
corner
.
clear
();
side_style
.
clear
();
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
if
(
i
==
0
)
Start
(
m_layer
,
m_Width
,
m_sel_box
,
x
,
y
,
m_HatchStyle
);
else
AppendCorner
(
x
,
y
,
STRAIGHT
,
FALSE
);
}
Close
();
n_ext_cont
++
;
}
else
if
(
pa
)
{
// next external contour, create new poly
CPolyLine
*
poly
=
new
CPolyLine
;
pa
->
SetSize
(
n_ext_cont
);
// put in array
(
*
pa
)[
n_ext_cont
-
1
]
=
poly
;
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
if
(
i
==
0
)
poly
->
Start
(
m_layer
,
m_Width
,
m_sel_box
,
x
,
y
,
m_HatchStyle
);
else
poly
->
AppendCorner
(
x
,
y
,
STRAIGHT
,
FALSE
);
}
poly
->
Close
(
STRAIGHT
,
FALSE
);
n_ext_cont
++
;
}
}
}
// now add cutouts to the CPolyLine(s)
for
(
int
ic
=
0
;
ic
<
m_gpc_poly
->
num_contours
;
ic
++
)
{
if
(
(
m_gpc_poly
->
hole
)[
ic
]
)
{
CPolyLine
*
ext_poly
=
NULL
;
if
(
n_ext_cont
==
1
)
{
ext_poly
=
this
;
}
else
{
// find the polygon that contains this hole
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
if
(
TestPointInside
(
x
,
y
)
)
ext_poly
=
this
;
else
{
for
(
int
ext_ic
=
0
;
ext_ic
<
n_ext_cont
-
1
;
ext_ic
++
)
{
if
(
(
*
pa
)[
ext_ic
]
->
TestPointInside
(
x
,
y
)
)
{
ext_poly
=
(
*
pa
)[
ext_ic
];
break
;
}
}
}
if
(
ext_poly
)
break
;
}
}
if
(
!
ext_poly
)
ASSERT
(
0
);
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
ext_poly
->
AppendCorner
(
x
,
y
,
STRAIGHT
,
FALSE
);
}
ext_poly
->
Close
(
STRAIGHT
,
FALSE
);
}
}
if
(
bRetainArcs
)
RestoreArcs
(
&
arc_array
,
pa
);
FreeGpcPoly
();
return
n_ext_cont
;
}
// make a php_polygon from first contour
int
CPolyLine
::
MakePhpPoly
()
{
FreePhpPoly
();
polygon
test_poly
;
int
nv
=
GetContourEnd
(
0
);
for
(
int
iv
=
0
;
iv
<=
nv
;
iv
++
)
{
int
x
=
GetX
(
iv
)
/
DENOM
;
int
y
=
GetY
(
iv
)
/
DENOM
;
m_php_poly
->
addv
(
x
,
y
);
}
return
0
;
}
void
CPolyLine
::
FreePhpPoly
()
{
// delete all vertices
while
(
m_php_poly
->
m_cnt
>
1
)
{
vertex
*
fv
=
m_php_poly
->
getFirst
();
m_php_poly
->
del
(
fv
->
m_nextV
);
}
delete
m_php_poly
->
m_first
;
m_php_poly
->
m_first
=
NULL
;
m_php_poly
->
m_cnt
=
0
;
}
// Use the php clipping lib to clip this poly against poly
//
void
CPolyLine
::
ClipPhpPolygon
(
int
php_op
,
CPolyLine
*
poly
)
{
Undraw
();
poly
->
MakePhpPoly
();
MakePhpPoly
();
polygon
*
p
=
m_php_poly
->
boolean
(
poly
->
m_php_poly
,
php_op
);
poly
->
FreePhpPoly
();
FreePhpPoly
();
if
(
p
)
{
// now screw with the PolyLine
corner
.
clear
();
side_style
.
clear
();
do
{
vertex
*
v
=
p
->
getFirst
();
Start
(
m_layer
,
m_Width
,
m_sel_box
,
to_int
(
v
->
X
()
*
DENOM
),
to_int
(
v
->
Y
()
*
DENOM
),
m_HatchStyle
);
do
{
vertex
*
n
=
v
->
Next
();
AppendCorner
(
to_int
(
v
->
X
()
*
DENOM
),
to_int
((
v
->
Y
()
*
DENOM
))
);
v
=
n
;
}
while
(
v
->
id
()
!=
p
->
getFirst
()
->
id
()
);
Close
();
// p = p->NextPoly();
delete
p
;
p
=
NULL
;
}
while
(
p
);
}
Draw
();
}
// make a gpc_polygon for a closed polyline contour
// approximates arcs with multiple straight-line segments
// if icontour = -1, make polygon with all contours,
// combining intersecting contours if possible
// returns data on arcs in arc_array
//
int
CPolyLine
::
MakeGpcPoly
(
int
icontour
,
std
::
vector
<
CArc
>
*
arc_array
)
{
if
(
m_gpc_poly
->
num_contours
)
FreeGpcPoly
();
if
(
!
GetClosed
()
&&
(
icontour
==
(
GetNumContours
()
-
1
)
||
icontour
==
-
1
))
return
1
;
// error
// initialize m_gpc_poly
m_gpc_poly
->
num_contours
=
0
;
m_gpc_poly
->
hole
=
NULL
;
m_gpc_poly
->
contour
=
NULL
;
int
n_arcs
=
0
;
int
first_contour
=
icontour
;
int
last_contour
=
icontour
;
if
(
icontour
==
-
1
)
{
first_contour
=
0
;
last_contour
=
GetNumContours
()
-
1
;
}
if
(
arc_array
)
arc_array
->
SetSize
(
0
);
int
iarc
=
0
;
for
(
int
icont
=
first_contour
;
icont
<=
last_contour
;
icont
++
)
{
// make gpc_polygon for this contour
gpc_polygon
*
gpc
=
new
gpc_polygon
;
gpc
->
num_contours
=
0
;
gpc
->
hole
=
NULL
;
gpc
->
contour
=
NULL
;
// first, calculate number of vertices in contour
int
n_vertices
=
0
;
int
ic_st
=
GetContourStart
(
icont
);
int
ic_end
=
GetContourEnd
(
icont
);
for
(
int
ic
=
ic_st
;
ic
<=
ic_end
;
ic
++
)
{
int
style
=
side_style
[
ic
];
int
x1
=
corner
[
ic
].
x
;
int
y1
=
corner
[
ic
].
y
;
int
x2
,
y2
;
if
(
ic
<
ic_end
)
{
x2
=
corner
[
ic
+
1
].
x
;
y2
=
corner
[
ic
+
1
].
y
;
}
else
{
x2
=
corner
[
ic_st
].
x
;
y2
=
corner
[
ic_st
].
y
;
}
if
(
style
==
STRAIGHT
)
n_vertices
++
;
else
{
// style is ARC_CW or ARC_CCW
int
n
;
// number of steps for arcs
n
=
(
abs
(
x2
-
x1
)
+
abs
(
y2
-
y1
))
/
(
CArc
::
MAX_STEP
);
n
=
max
(
n
,
CArc
::
MIN_STEPS
);
// or at most 5 degrees of arc
n_vertices
+=
n
;
n_arcs
++
;
}
}
// now create gcp_vertex_list for this contour
gpc_vertex_list
*
g_v_list
=
new
gpc_vertex_list
;
g_v_list
->
vertex
=
(
gpc_vertex
*
)
calloc
(
sizeof
(
gpc_vertex
),
n_vertices
);
g_v_list
->
num_vertices
=
n_vertices
;
int
ivtx
=
0
;
for
(
int
ic
=
ic_st
;
ic
<=
ic_end
;
ic
++
)
{
int
style
=
side_style
[
ic
];
int
x1
=
corner
[
ic
].
x
;
int
y1
=
corner
[
ic
].
y
;
int
x2
,
y2
;
if
(
ic
<
ic_end
)
{
x2
=
corner
[
ic
+
1
].
x
;
y2
=
corner
[
ic
+
1
].
y
;
}
else
{
x2
=
corner
[
ic_st
].
x
;
y2
=
corner
[
ic_st
].
y
;
}
if
(
style
==
STRAIGHT
)
{
g_v_list
->
vertex
[
ivtx
].
x
=
x1
;
g_v_list
->
vertex
[
ivtx
].
y
=
y1
;
ivtx
++
;
}
else
{
// style is arc_cw or arc_ccw
int
n
;
// number of steps for arcs
n
=
(
abs
(
x2
-
x1
)
+
abs
(
y2
-
y1
))
/
(
CArc
::
MAX_STEP
);
n
=
max
(
n
,
CArc
::
MIN_STEPS
);
// or at most 5 degrees of arc
double
xo
,
yo
,
theta1
,
theta2
,
a
,
b
;
a
=
fabs
(
(
double
)(
x1
-
x2
)
);
b
=
fabs
(
(
double
)(
y1
-
y2
)
);
if
(
style
==
CPolyLine
::
ARC_CW
)
{
// clockwise arc (ie.quadrant of ellipse)
if
(
x2
>
x1
&&
y2
>
y1
)
{
// first quadrant, draw second quadrant of ellipse
xo
=
x2
;
yo
=
y1
;
theta1
=
pi
;
theta2
=
pi
/
2.0
;
}
else
if
(
x2
<
x1
&&
y2
>
y1
)
{
// second quadrant, draw third quadrant of ellipse
xo
=
x1
;
yo
=
y2
;
theta1
=
3.0
*
pi
/
2.0
;
theta2
=
pi
;
}
else
if
(
x2
<
x1
&&
y2
<
y1
)
{
// third quadrant, draw fourth quadrant of ellipse
xo
=
x2
;
yo
=
y1
;
theta1
=
2.0
*
pi
;
theta2
=
3.0
*
pi
/
2.0
;
}
else
{
xo
=
x1
;
// fourth quadrant, draw first quadrant of ellipse
yo
=
y2
;
theta1
=
pi
/
2.0
;
theta2
=
0.0
;
}
}
else
{
// counter-clockwise arc
if
(
x2
>
x1
&&
y2
>
y1
)
{
xo
=
x1
;
// first quadrant, draw fourth quadrant of ellipse
yo
=
y2
;
theta1
=
3.0
*
pi
/
2.0
;
theta2
=
2.0
*
pi
;
}
else
if
(
x2
<
x1
&&
y2
>
y1
)
{
xo
=
x2
;
// second quadrant
yo
=
y1
;
theta1
=
0.0
;
theta2
=
pi
/
2.0
;
}
else
if
(
x2
<
x1
&&
y2
<
y1
)
{
xo
=
x1
;
// third quadrant
yo
=
y2
;
theta1
=
pi
/
2.0
;
theta2
=
pi
;
}
else
{
xo
=
x2
;
// fourth quadrant
yo
=
y1
;
theta1
=
pi
;
theta2
=
3.0
*
pi
/
2.0
;
}
}
// now write steps for arc
if
(
arc_array
)
{
arc_array
->
SetSize
(
iarc
+
1
);
(
*
arc_array
)[
iarc
].
style
=
style
;
(
*
arc_array
)[
iarc
].
n_steps
=
n
;
(
*
arc_array
)[
iarc
].
xi
=
x1
;
(
*
arc_array
)[
iarc
].
yi
=
y1
;
(
*
arc_array
)[
iarc
].
xf
=
x2
;
(
*
arc_array
)[
iarc
].
yf
=
y2
;
iarc
++
;
}
for
(
int
is
=
0
;
is
<
n
;
is
++
)
{
double
theta
=
theta1
+
((
theta2
-
theta1
)
*
(
double
)
is
)
/
n
;
double
x
=
xo
+
a
*
cos
(
theta
);
double
y
=
yo
+
b
*
sin
(
theta
);
if
(
is
==
0
)
{
x
=
x1
;
y
=
y1
;
}
g_v_list
->
vertex
[
ivtx
].
x
=
x
;
g_v_list
->
vertex
[
ivtx
].
y
=
y
;
ivtx
++
;
}
}
}
if
(
n_vertices
!=
ivtx
)
ASSERT
(
0
);
// add vertex_list to gpc
gpc_add_contour
(
gpc
,
g_v_list
,
0
);
// now clip m_gpc_poly with gpc, put new poly into result
gpc_polygon
*
result
=
new
gpc_polygon
;
if
(
icontour
==
-
1
&&
icont
!=
0
)
gpc_polygon_clip
(
GPC_DIFF
,
m_gpc_poly
,
gpc
,
result
);
// hole
else
gpc_polygon_clip
(
GPC_UNION
,
m_gpc_poly
,
gpc
,
result
);
// outside
// now copy result to m_gpc_poly
gpc_free_polygon
(
m_gpc_poly
);
delete
m_gpc_poly
;
m_gpc_poly
=
result
;
gpc_free_polygon
(
gpc
);
delete
gpc
;
free
(
g_v_list
->
vertex
);
free
(
g_v_list
);
}
return
0
;
}
int
CPolyLine
::
FreeGpcPoly
()
{
if
(
m_gpc_poly
->
num_contours
)
{
delete
m_gpc_poly
->
contour
->
vertex
;
delete
m_gpc_poly
->
contour
;
delete
m_gpc_poly
->
hole
;
}
m_gpc_poly
->
num_contours
=
0
;
return
0
;
}
// Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array
//
int
CPolyLine
::
RestoreArcs
(
std
::
vector
<
CArc
>
*
arc_array
,
std
::
vector
<
CPolyLine
*>
*
pa
)
{
// get poly info
int
n_polys
=
1
;
if
(
pa
)
n_polys
+=
pa
->
size
();
CPolyLine
*
poly
;
// undraw polys and clear utility flag for all corners
for
(
int
ip
=
0
;
ip
<
n_polys
;
ip
++
)
{
if
(
ip
==
0
)
poly
=
this
;
else
poly
=
(
*
pa
)[
ip
-
1
];
poly
->
Undraw
();
for
(
int
ic
=
0
;
ic
<
poly
->
GetNumCorners
();
ic
++
)
poly
->
SetUtility
(
ic
,
0
);
// clear utility flag
}
// find arcs and replace them
BOOL
bFound
;
int
arc_start
;
int
arc_end
;
for
(
unsigned
iarc
=
0
;
iarc
<
arc_array
->
size
();
iarc
++
)
{
int
arc_xi
=
(
*
arc_array
)[
iarc
].
xi
;
int
arc_yi
=
(
*
arc_array
)[
iarc
].
yi
;
int
arc_xf
=
(
*
arc_array
)[
iarc
].
xf
;
int
arc_yf
=
(
*
arc_array
)[
iarc
].
yf
;
int
n_steps
=
(
*
arc_array
)[
iarc
].
n_steps
;
int
style
=
(
*
arc_array
)[
iarc
].
style
;
bFound
=
FALSE
;
// loop through polys
for
(
int
ip
=
0
;
ip
<
n_polys
;
ip
++
)
{
if
(
ip
==
0
)
poly
=
this
;
else
poly
=
(
*
pa
)[
ip
-
1
];
for
(
int
icont
=
0
;
icont
<
poly
->
GetNumContours
();
icont
++
)
{
int
ic_start
=
poly
->
GetContourStart
(
icont
);
int
ic_end
=
poly
->
GetContourEnd
(
icont
);
if
(
(
ic_end
-
ic_start
)
>
n_steps
)
{
for
(
int
ic
=
ic_start
;
ic
<=
ic_end
;
ic
++
)
{
int
ic_next
=
ic
+
1
;
if
(
ic_next
>
ic_end
)
ic_next
=
ic_start
;
int
xi
=
poly
->
GetX
(
ic
);
int
yi
=
poly
->
GetY
(
ic
);
if
(
xi
==
arc_xi
&&
yi
==
arc_yi
)
{
// test for forward arc
int
ic2
=
ic
+
n_steps
;
if
(
ic2
>
ic_end
)
ic2
=
ic2
-
ic_end
+
ic_start
-
1
;
int
xf
=
poly
->
GetX
(
ic2
);
int
yf
=
poly
->
GetY
(
ic2
);
if
(
xf
==
arc_xf
&&
yf
==
arc_yf
)
{
// arc from ic to ic2
bFound
=
TRUE
;
arc_start
=
ic
;
arc_end
=
ic2
;
}
else
{
// try reverse arc
ic2
=
ic
-
n_steps
;
if
(
ic2
<
ic_start
)
ic2
=
ic2
-
ic_start
+
ic_end
+
1
;
xf
=
poly
->
GetX
(
ic2
);
yf
=
poly
->
GetY
(
ic2
);
if
(
xf
==
arc_xf
&&
yf
==
arc_yf
)
{
// arc from ic2 to ic
bFound
=
TRUE
;
arc_start
=
ic2
;
arc_end
=
ic
;
style
=
3
-
style
;
}
}
if
(
bFound
)
{
poly
->
side_style
[
arc_start
]
=
style
;
// mark corners for deletion from arc_start+1 to arc_end-1
for
(
int
i
=
arc_start
+
1
;
i
!=
arc_end
;
)
{
if
(
i
>
ic_end
)
i
=
ic_start
;
poly
->
SetUtility
(
i
,
1
);
if
(
i
==
ic_end
)
i
=
ic_start
;
else
i
++
;
}
break
;
}
}
if
(
bFound
)
break
;
}
}
if
(
bFound
)
break
;
}
}
if
(
bFound
)
(
*
arc_array
)[
iarc
].
bFound
=
TRUE
;
}
// now delete all marked corners
for
(
int
ip
=
0
;
ip
<
n_polys
;
ip
++
)
{
if
(
ip
==
0
)
poly
=
this
;
else
poly
=
(
*
pa
)[
ip
-
1
];
for
(
int
ic
=
poly
->
GetNumCorners
()
-
1
;
ic
>=
0
;
ic
--
)
{
if
(
poly
->
GetUtility
(
ic
)
)
poly
->
DeleteCorner
(
ic
,
FALSE
);
}
}
return
0
;
}
// initialize new polyline
// set layer, width, selection box size, starting point, id and pointer
//
// if sel_box = 0, don't create selection elements at all
//
// if polyline is board outline, enter with:
// id.type = ID_BOARD
// id.st = ID_BOARD_OUTLINE
// id.i = 0
// ptr = NULL
//
// if polyline is copper area, enter with:
// id.type = ID_NET;
// id.st = ID_AREA
// id.i = index to area
// ptr = pointer to net
//
void
CPolyLine
::
Start
(
int
layer
,
int
w
,
int
sel_box
,
int
x
,
int
y
,
int
hatch
)
{
m_layer
=
layer
;
m_Width
=
w
;
m_sel_box
=
sel_box
;
m_HatchStyle
=
hatch
;
CPolyPt
poly_pt
(
x
,
y
);
poly_pt
.
end_contour
=
FALSE
;
corner
.
push_back
(
poly_pt
);
side_style
.
push_back
(
0
);
}
// add a corner to unclosed polyline
//
void
CPolyLine
::
AppendCorner
(
int
x
,
int
y
,
int
style
,
BOOL
bDraw
)
{
Undraw
();
CPolyPt
poly_pt
(
x
,
y
);
poly_pt
.
end_contour
=
FALSE
;
// add entries for new corner and side
corner
.
push_back
(
poly_pt
);
side_style
.
push_back
(
style
);
if
(
corner
.
size
()
>
0
&&
!
corner
[
corner
.
size
()
-
1
].
end_contour
)
side_style
[
corner
.
size
()
-
1
]
=
style
;
int
dl_type
;
if
(
style
==
CPolyLine
::
STRAIGHT
)
dl_type
=
DL_LINE
;
else
if
(
style
==
CPolyLine
::
ARC_CW
)
dl_type
=
DL_ARC_CW
;
else
if
(
style
==
CPolyLine
::
ARC_CCW
)
dl_type
=
DL_ARC_CCW
;
else
ASSERT
(
0
);
if
(
bDraw
)
Draw
();
}
// close last polyline contour
//
void
CPolyLine
::
Close
(
int
style
,
BOOL
bDraw
)
{
if
(
GetClosed
()
)
ASSERT
(
0
);
Undraw
();
side_style
[
corner
.
size
()
-
1
]
=
style
;
corner
[
corner
.
size
()
-
1
].
end_contour
=
TRUE
;
if
(
bDraw
)
Draw
();
}
// move corner of polyline
//
void
CPolyLine
::
MoveCorner
(
int
ic
,
int
x
,
int
y
)
{
Undraw
();
corner
[
ic
].
x
=
x
;
corner
[
ic
].
y
=
y
;
Draw
();
}
// delete corner and adjust arrays
//
void
CPolyLine
::
DeleteCorner
(
int
ic
,
BOOL
bDraw
)
{
Undraw
();
int
icont
=
GetContour
(
ic
);
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
BOOL
bClosed
=
icont
<
GetNumContours
()
-
1
||
GetClosed
();
if
(
!
bClosed
)
{
// open contour, must be last contour
corner
.
erase
(
corner
.
begin
()
+
ic
);
if
(
ic
!=
istart
)
side_style
.
erase
(
side_style
.
begin
()
+
ic
-
1
);
}
else
{
// closed contour
corner
.
erase
(
corner
.
begin
()
+
ic
);
side_style
.
erase
(
side_style
.
begin
()
+
ic
);
if
(
ic
==
iend
)
corner
[
ic
-
1
].
end_contour
=
TRUE
;
}
if
(
bClosed
&&
GetContourSize
(
icont
)
<
3
)
{
// delete the entire contour
RemoveContour
(
icont
);
}
if
(
bDraw
)
Draw
();
}
void
CPolyLine
::
RemoveContour
(
int
icont
)
{
Undraw
();
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
if
(
icont
==
0
&&
GetNumContours
()
==
1
)
{
// remove the only contour
ASSERT
(
0
);
}
else
if
(
icont
==
GetNumContours
()
-
1
)
{
// remove last contour
corner
.
erase
(
corner
.
begin
()
+
icont
,
corner
.
end
()
);
side_style
.
erase
(
side_style
.
begin
()
+
icont
,
side_style
.
end
()
);
}
else
{
// remove closed contour
for
(
int
ic
=
iend
;
ic
>=
istart
;
ic
--
)
{
corner
.
erase
(
corner
.
begin
()
+
ic
);
side_style
.
erase
(
side_style
.
begin
()
+
ic
);
}
}
Draw
();
}
/** Function InsertCorner
* insert a new corner between two existing corners
* @param ic = index for the insertion point: the corner is inserted AFTER ic
* @param x, y = coordinates corner to insert
*/
void
CPolyLine
::
InsertCorner
(
int
ic
,
int
x
,
int
y
)
{
Undraw
();
if
(
(
unsigned
)(
ic
)
>=
corner
.
size
()
)
{
corner
.
push_back
(
CPolyPt
(
x
,
y
)
);
side_style
.
push_back
(
STRAIGHT
);
}
else
{
corner
.
insert
(
corner
.
begin
()
+
ic
+
1
,
CPolyPt
(
x
,
y
)
);
side_style
.
insert
(
side_style
.
begin
()
+
ic
+
1
,
STRAIGHT
);
}
if
(
(
unsigned
)(
ic
+
1
)
<
corner
.
size
()
)
{
if
(
corner
[
ic
].
end_contour
)
{
corner
[
ic
+
1
].
end_contour
=
TRUE
;
corner
[
ic
].
end_contour
=
FALSE
;
}
}
Draw
();
}
// undraw polyline by removing all graphic elements from display list
//
void
CPolyLine
::
Undraw
()
{
if
(
m_dlist
&&
bDrawn
)
{
// remove display elements, if present
for
(
unsigned
i
=
0
;
i
<
dl_side
.
size
();
i
++
)
m_dlist
->
Remove
(
dl_side
[
i
]
);
for
(
unsigned
i
=
0
;
i
<
dl_side_sel
.
size
();
i
++
)
m_dlist
->
Remove
(
dl_side_sel
[
i
]
);
for
(
unsigned
i
=
0
;
i
<
dl_corner_sel
.
size
();
i
++
)
m_dlist
->
Remove
(
dl_corner_sel
[
i
]
);
// remove pointers
dl_side
.
clear
();
dl_side_sel
.
clear
();
dl_corner_sel
.
clear
();
}
m_HatchLines
.
clear
();
bDrawn
=
FALSE
;
}
// draw polyline by adding all graphics to display list
// if side style is ARC_CW or ARC_CCW but endpoints are not angled,
// convert to STRAIGHT
//
void
CPolyLine
::
Draw
(
CDisplayList
*
dl
)
{
// first, undraw if necessary
if
(
bDrawn
)
Undraw
();
// use new display list if provided
if
(
dl
)
m_dlist
=
dl
;
#if 0
int i_start_contour = 0;
if( m_dlist )
{
// set up std::vectors
dl_side.SetSize( corner.size() );
if( m_sel_box )
{
dl_side_sel.SetSize( corner.size() );
dl_corner_sel.SetSize( corner.size() );
}
else
{
dl_side_sel.clear();
dl_corner_sel.clear();
}
// now draw elements
for( int ic=0; ic<corner.size(); ic++ )
{
m_id.ii = ic;
int xi = corner[ic].x;
int yi = corner[ic].y;
int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size()-1 )
{
xf = corner[ic+1].x;
yf = corner[ic+1].y;
}
else
{
xf = corner[i_start_contour].x;
yf = corner[i_start_contour].y;
i_start_contour = ic+1;
}
// draw
if( m_sel_box )
{
m_id.sst = ID_SEL_CORNER;
dl_corner_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, DL_HOLLOW_RECT,
1, 0, 0, xi-m_sel_box, yi-m_sel_box,
xi+m_sel_box, yi+m_sel_box, 0, 0 );
}
if( ic<(corner.size()-1) || corner[ic].end_contour )
{
// draw side
if( xi == xf || yi == yf )
{
// if endpoints not angled, make side STRAIGHT
side_style[ic] = STRAIGHT;
}
int g_type = DL_LINE;
if( side_style[ic] == STRAIGHT )
g_type = DL_LINE;
else if( side_style[ic] == ARC_CW )
g_type = DL_ARC_CW;
else if( side_style[ic] == ARC_CCW )
g_type = DL_ARC_CCW;
m_id.sst = ID_SIDE;
dl_side[ic] = m_dlist->Add( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 );
if( m_sel_box )
{
m_id.sst = ID_SEL_SIDE;
dl_side_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 );
}
}
}
// if( m_HatchStyle )
// Hatch();
}
#endif
Hatch
();
bDrawn
=
TRUE
;
}
// start dragging new corner to be inserted into side, make side and hatching invisible
//
void
CPolyLine
::
StartDraggingToInsertCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
int
icont
=
GetContour
(
ic
);
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
int
post_c
;
if
(
ic
==
iend
)
post_c
=
istart
;
else
post_c
=
ic
+
1
;
int
xi
=
corner
[
ic
].
x
;
int
yi
=
corner
[
ic
].
y
;
int
xf
=
corner
[
post_c
].
x
;
int
yf
=
corner
[
post_c
].
y
;
m_dlist
->
StartDraggingLineVertex
(
pDC
,
x
,
y
,
xi
,
yi
,
xf
,
yf
,
LAY_SELECTION
,
LAY_SELECTION
,
1
,
1
,
DSS_STRAIGHT
,
DSS_STRAIGHT
,
0
,
0
,
0
,
0
,
1
);
m_dlist
->
CancelHighLight
();
m_dlist
->
Set_visible
(
dl_side
[
ic
],
0
);
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
// cancel dragging inserted corner, make side and hatching visible again
//
void
CPolyLine
::
CancelDraggingToInsertCorner
(
int
ic
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
int
post_c
;
if
(
ic
==
(
int
)(
corner
.
size
()
-
1
)
)
post_c
=
0
;
else
post_c
=
ic
+
1
;
m_dlist
->
StopDragging
();
/* m_dlist->Set_visible( dl_side[ic], 1 );
for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 1 );
*/
}
// start dragging corner to new position, make adjacent sides and hatching invisible
//
void
CPolyLine
::
StartDraggingToMoveCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
// see if corner is the first or last corner of an open contour
int
icont
=
GetContour
(
ic
);
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
if
(
!
GetClosed
()
&&
icont
==
GetNumContours
()
-
1
&&
(
ic
==
istart
||
ic
==
iend
)
)
{
// yes
int
style
,
xi
,
yi
,
iside
;
if
(
ic
==
istart
)
{
// first corner
iside
=
ic
;
xi
=
GetX
(
ic
+
1
);
yi
=
GetY
(
ic
+
1
);
style
=
GetSideStyle
(
iside
);
// reverse arc since we are drawing from corner 1 to 0
if
(
style
==
CPolyLine
::
ARC_CW
)
style
=
CPolyLine
::
ARC_CCW
;
else
if
(
style
==
CPolyLine
::
ARC_CCW
)
style
=
CPolyLine
::
ARC_CW
;
}
else
{
// last corner
iside
=
ic
-
1
;
xi
=
GetX
(
ic
-
1
);
yi
=
GetY
(
ic
-
1
);
style
=
GetSideStyle
(
iside
);
}
m_dlist
->
StartDraggingArc
(
pDC
,
style
,
GetX
(
ic
),
GetY
(
ic
),
xi
,
yi
,
LAY_SELECTION
,
1
,
1
);
m_dlist
->
CancelHighLight
();
m_dlist
->
Set_visible
(
dl_side
[
iside
],
0
);
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
else
{
// no
// get indexes for preceding and following corners
int
pre_c
,
post_c
;
int
poly_side_style1
,
poly_side_style2
;
int
style1
,
style2
;
if
(
ic
==
istart
)
{
pre_c
=
iend
;
post_c
=
istart
+
1
;
poly_side_style1
=
side_style
[
iend
];
poly_side_style2
=
side_style
[
istart
];
}
else
if
(
ic
==
iend
)
{
// last side
pre_c
=
ic
-
1
;
post_c
=
istart
;
poly_side_style1
=
side_style
[
ic
-
1
];
poly_side_style2
=
side_style
[
ic
];
}
else
{
pre_c
=
ic
-
1
;
post_c
=
ic
+
1
;
poly_side_style1
=
side_style
[
ic
-
1
];
poly_side_style2
=
side_style
[
ic
];
}
if
(
poly_side_style1
==
STRAIGHT
)
style1
=
DSS_STRAIGHT
;
else
if
(
poly_side_style1
==
ARC_CW
)
style1
=
DSS_ARC_CW
;
else
if
(
poly_side_style1
==
ARC_CCW
)
style1
=
DSS_ARC_CCW
;
if
(
poly_side_style2
==
STRAIGHT
)
style2
=
DSS_STRAIGHT
;
else
if
(
poly_side_style2
==
ARC_CW
)
style2
=
DSS_ARC_CW
;
else
if
(
poly_side_style2
==
ARC_CCW
)
style2
=
DSS_ARC_CCW
;
int
xi
=
corner
[
pre_c
].
x
;
int
yi
=
corner
[
pre_c
].
y
;
int
xf
=
corner
[
post_c
].
x
;
int
yf
=
corner
[
post_c
].
y
;
m_dlist
->
StartDraggingLineVertex
(
pDC
,
x
,
y
,
xi
,
yi
,
xf
,
yf
,
LAY_SELECTION
,
LAY_SELECTION
,
1
,
1
,
style1
,
style2
,
0
,
0
,
0
,
0
,
1
);
m_dlist
->
CancelHighLight
();
m_dlist
->
Set_visible
(
dl_side
[
pre_c
],
0
);
m_dlist
->
Set_visible
(
dl_side
[
ic
],
0
);
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
}
// cancel dragging corner to new position, make sides and hatching visible again
//
// highlight side by drawing line over it
//
void
CPolyLine
::
HighlightSide
(
int
is
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
if
(
GetClosed
()
&&
is
>=
(
int
)
corner
.
size
()
)
return
;
if
(
!
GetClosed
()
&&
is
>=
(
int
)(
corner
.
size
()
-
1
)
)
return
;
int
style
;
if
(
side_style
[
is
]
==
CPolyLine
::
STRAIGHT
)
style
=
DL_LINE
;
else
if
(
side_style
[
is
]
==
CPolyLine
::
ARC_CW
)
style
=
DL_ARC_CW
;
else
if
(
side_style
[
is
]
==
CPolyLine
::
ARC_CCW
)
style
=
DL_ARC_CCW
;
m_dlist
->
HighLight
(
style
,
m_dlist
->
Get_x
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_y
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_xf
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_yf
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_w
(
dl_side_sel
[
is
])
);
}
int
CPolyLine
::
GetX
(
int
ic
)
{
return
corner
[
ic
].
x
;
}
int
CPolyLine
::
GetY
(
int
ic
)
{
return
corner
[
ic
].
y
;
}
int
CPolyLine
::
GetEndContour
(
int
ic
)
{
return
corner
[
ic
].
end_contour
;
}
CRect
CPolyLine
::
GetBounds
()
{
CRect
r
=
GetCornerBounds
();
r
.
left
-=
m_Width
/
2
;
r
.
right
+=
m_Width
/
2
;
r
.
bottom
-=
m_Width
/
2
;
r
.
top
+=
m_Width
/
2
;
return
r
;
}
CRect
CPolyLine
::
GetCornerBounds
()
{
CRect
r
;
r
.
left
=
r
.
bottom
=
INT_MAX
;
r
.
right
=
r
.
top
=
INT_MIN
;
for
(
unsigned
i
=
0
;
i
<
corner
.
size
();
i
++
)
{
r
.
left
=
min
(
r
.
left
,
corner
[
i
].
x
);
r
.
right
=
max
(
r
.
right
,
corner
[
i
].
x
);
r
.
bottom
=
min
(
r
.
bottom
,
corner
[
i
].
y
);
r
.
top
=
max
(
r
.
top
,
corner
[
i
].
y
);
}
return
r
;
}
CRect
CPolyLine
::
GetCornerBounds
(
int
icont
)
{
CRect
r
;
r
.
left
=
r
.
bottom
=
INT_MAX
;
r
.
right
=
r
.
top
=
INT_MIN
;
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
for
(
int
i
=
istart
;
i
<=
iend
;
i
++
)
{
r
.
left
=
min
(
r
.
left
,
corner
[
i
].
x
);
r
.
right
=
max
(
r
.
right
,
corner
[
i
].
x
);
r
.
bottom
=
min
(
r
.
bottom
,
corner
[
i
].
y
);
r
.
top
=
max
(
r
.
top
,
corner
[
i
].
y
);
}
return
r
;
}
int
CPolyLine
::
GetNumCorners
()
{
return
corner
.
size
();
}
int
CPolyLine
::
GetNumSides
()
{
if
(
GetClosed
()
)
return
corner
.
size
();
else
return
corner
.
size
()
-
1
;
}
int
CPolyLine
::
GetW
()
{
return
m_Width
;
}
int
CPolyLine
::
GetSelBoxSize
()
{
return
m_sel_box
;
}
int
CPolyLine
::
GetNumContours
()
{
int
ncont
=
0
;
if
(
!
corner
.
size
()
)
return
0
;
for
(
unsigned
ic
=
0
;
ic
<
corner
.
size
();
ic
++
)
if
(
corner
[
ic
].
end_contour
)
ncont
++
;
if
(
!
corner
[
corner
.
size
()
-
1
].
end_contour
)
ncont
++
;
return
ncont
;
}
int
CPolyLine
::
GetContour
(
int
ic
)
{
int
ncont
=
0
;
for
(
int
i
=
0
;
i
<
ic
;
i
++
)
{
if
(
corner
[
i
].
end_contour
)
ncont
++
;
}
return
ncont
;
}
int
CPolyLine
::
GetContourStart
(
int
icont
)
{
if
(
icont
==
0
)
return
0
;
int
ncont
=
0
;
for
(
unsigned
i
=
0
;
i
<
corner
.
size
();
i
++
)
{
if
(
corner
[
i
].
end_contour
)
{
ncont
++
;
if
(
ncont
==
icont
)
return
i
+
1
;
}
}
ASSERT
(
0
);
return
0
;
}
int
CPolyLine
::
GetContourEnd
(
int
icont
)
{
if
(
icont
<
0
)
return
0
;
if
(
icont
==
GetNumContours
()
-
1
)
return
corner
.
size
()
-
1
;
int
ncont
=
0
;
for
(
unsigned
i
=
0
;
i
<
corner
.
size
();
i
++
)
{
if
(
corner
[
i
].
end_contour
)
{
if
(
ncont
==
icont
)
return
i
;
ncont
++
;
}
}
ASSERT
(
0
);
return
0
;
}
int
CPolyLine
::
GetContourSize
(
int
icont
)
{
return
GetContourEnd
(
icont
)
-
GetContourStart
(
icont
)
+
1
;
}
void
CPolyLine
::
SetSideStyle
(
int
is
,
int
style
)
{
Undraw
();
CPoint
p1
,
p2
;
if
(
is
==
(
int
)(
corner
.
size
()
-
1
)
)
{
p1
.
x
=
corner
[
corner
.
size
()
-
1
].
x
;
p1
.
y
=
corner
[
corner
.
size
()
-
1
].
y
;
p2
.
x
=
corner
[
0
].
x
;
p2
.
y
=
corner
[
0
].
y
;
}
else
{
p1
.
x
=
corner
[
is
].
x
;
p1
.
y
=
corner
[
is
].
y
;
p2
.
x
=
corner
[
is
+
1
].
x
;
p2
.
y
=
corner
[
is
+
1
].
y
;
}
if
(
p1
.
x
==
p2
.
x
||
p1
.
y
==
p2
.
y
)
side_style
[
is
]
=
STRAIGHT
;
else
side_style
[
is
]
=
style
;
Draw
();
}
int
CPolyLine
::
GetSideStyle
(
int
is
)
{
return
side_style
[
is
];
}
int
CPolyLine
::
GetClosed
()
{
if
(
corner
.
size
()
==
0
)
return
0
;
else
return
corner
[
corner
.
size
()
-
1
].
end_contour
;
}
// draw hatch lines
//
void
CPolyLine
::
Hatch
()
{
m_HatchLines
.
clear
();
if
(
m_HatchStyle
==
NO_HATCH
)
{
return
;
}
int
layer
=
m_layer
;
// if( /*m_dlist && */GetClosed() )
{
enum
{
MAXPTS
=
100
,
MAXLINES
=
1000
};
int
xx
[
MAXPTS
],
yy
[
MAXPTS
];
// define range for hatch lines
int
min_x
=
corner
[
0
].
x
;
int
max_x
=
corner
[
0
].
x
;
int
min_y
=
corner
[
0
].
y
;
int
max_y
=
corner
[
0
].
y
;
for
(
unsigned
ic
=
1
;
ic
<
corner
.
size
();
ic
++
)
{
if
(
corner
[
ic
].
x
<
min_x
)
min_x
=
corner
[
ic
].
x
;
if
(
corner
[
ic
].
x
>
max_x
)
max_x
=
corner
[
ic
].
x
;
if
(
corner
[
ic
].
y
<
min_y
)
min_y
=
corner
[
ic
].
y
;
if
(
corner
[
ic
].
y
>
max_y
)
max_y
=
corner
[
ic
].
y
;
}
int
slope_flag
=
(
layer
&
1
)
?
1
:
-
1
;
// 1 or -1
double
slope
=
0.707106
*
slope_flag
;
int
spacing
;
if
(
m_HatchStyle
==
DIAGONAL_EDGE
)
spacing
=
10
*
PCBU_PER_MIL
;
else
spacing
=
50
*
PCBU_PER_MIL
;
int
max_a
,
min_a
;
if
(
slope_flag
==
1
)
{
max_a
=
(
int
)(
max_y
-
slope
*
min_x
);
min_a
=
(
int
)(
min_y
-
slope
*
max_x
);
}
else
{
max_a
=
(
int
)(
max_y
-
slope
*
max_x
);
min_a
=
(
int
)(
min_y
-
slope
*
min_x
);
}
min_a
=
(
min_a
/
spacing
)
*
spacing
;
int
offset
;
if
(
layer
<
(
LAY_TOP_COPPER
+
2
)
)
offset
=
0
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
4
)
)
offset
=
spacing
/
2
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
6
)
)
offset
=
spacing
/
4
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
8
)
)
offset
=
3
*
spacing
/
4
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
10
)
)
offset
=
1
*
spacing
/
8
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
12
)
)
offset
=
3
*
spacing
/
8
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
14
)
)
offset
=
5
*
spacing
/
8
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
16
)
)
offset
=
7
*
spacing
/
8
;
else
ASSERT
(
0
);
min_a
+=
offset
;
// now calculate and draw hatch lines
int
nc
=
corner
.
size
();
// loop through hatch lines
for
(
int
a
=
min_a
;
a
<
max_a
;
a
+=
spacing
)
{
// get intersection points for this hatch line
int
nloops
=
0
;
int
npts
;
// make this a loop in case my homebrew hatching algorithm screws up
do
{
npts
=
0
;
int
i_start_contour
=
0
;
for
(
int
ic
=
0
;
ic
<
nc
;
ic
++
)
{
double
x
,
y
,
x2
,
y2
;
int
ok
;
if
(
corner
[
ic
].
end_contour
)
{
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
corner
[
i_start_contour
].
x
,
corner
[
i_start_contour
].
y
,
side_style
[
ic
],
&
x
,
&
y
,
&
x2
,
&
y2
);
i_start_contour
=
ic
+
1
;
}
else
{
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
corner
[
ic
+
1
].
x
,
corner
[
ic
+
1
].
y
,
side_style
[
ic
],
&
x
,
&
y
,
&
x2
,
&
y2
);
}
if
(
ok
)
{
xx
[
npts
]
=
(
int
)
x
;
yy
[
npts
]
=
(
int
)
y
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
if
(
ok
==
2
)
{
xx
[
npts
]
=
(
int
)
x2
;
yy
[
npts
]
=
(
int
)
y2
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
}
nloops
++
;
a
+=
PCBU_PER_MIL
/
100
;
}
while
(
npts
%
2
!=
0
&&
nloops
<
3
);
ASSERT
(
npts
%
2
==
0
);
// odd number of intersection points, error
// sort points in order of descending x (if more than 2)
if
(
npts
>
2
)
{
for
(
int
istart
=
0
;
istart
<
(
npts
-
1
);
istart
++
)
{
int
max_x
=
INT_MIN
;
int
imax
;
for
(
int
i
=
istart
;
i
<
npts
;
i
++
)
{
if
(
xx
[
i
]
>
max_x
)
{
max_x
=
xx
[
i
];
imax
=
i
;
}
}
int
temp
=
xx
[
istart
];
xx
[
istart
]
=
xx
[
imax
];
xx
[
imax
]
=
temp
;
temp
=
yy
[
istart
];
yy
[
istart
]
=
yy
[
imax
];
yy
[
imax
]
=
temp
;
}
}
// draw lines
for
(
int
ip
=
0
;
ip
<
npts
;
ip
+=
2
)
{
double
dx
=
xx
[
ip
+
1
]
-
xx
[
ip
];
if
(
m_HatchStyle
==
DIAGONAL_FULL
||
fabs
(
dx
)
<
40
*
NM_PER_MIL
)
{
m_HatchLines
.
push_back
(
CSegment
(
xx
[
ip
],
yy
[
ip
],
xx
[
ip
+
1
],
yy
[
ip
+
1
])
);
}
else
{
double
dy
=
yy
[
ip
+
1
]
-
yy
[
ip
];
double
slope
=
dy
/
dx
;
if
(
dx
>
0
)
dx
=
20
*
NM_PER_MIL
;
else
dx
=
-
20
*
NM_PER_MIL
;
double
x1
=
xx
[
ip
]
+
dx
;
double
x2
=
xx
[
ip
+
1
]
-
dx
;
double
y1
=
yy
[
ip
]
+
dx
*
slope
;
double
y2
=
yy
[
ip
+
1
]
-
dx
*
slope
;
m_HatchLines
.
push_back
(
CSegment
(
xx
[
ip
],
yy
[
ip
],
to_int
(
x1
),
to_int
(
y1
))
);
m_HatchLines
.
push_back
(
CSegment
(
xx
[
ip
+
1
],
yy
[
ip
+
1
],
to_int
(
x2
),
to_int
(
y2
))
);
}
}
}
// end for
}
}
// test to see if a point is inside polyline
//
BOOL
CPolyLine
::
TestPointInside
(
int
x
,
int
y
)
{
enum
{
MAXPTS
=
100
};
if
(
!
GetClosed
()
)
ASSERT
(
0
);
// define line passing through (x,y), with slope = 2/3;
// get intersection points
double
xx
[
MAXPTS
],
yy
[
MAXPTS
];
double
slope
=
(
double
)
2.0
/
3.0
;
double
a
=
y
-
slope
*
x
;
int
nloops
=
0
;
int
npts
;
// make this a loop so if my homebrew algorithm screws up, we try it again
do
{
// now find all intersection points of line with polyline sides
npts
=
0
;
for
(
int
icont
=
0
;
icont
<
GetNumContours
();
icont
++
)
{
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
for
(
int
ic
=
istart
;
ic
<=
iend
;
ic
++
)
{
double
x
,
y
,
x2
,
y2
;
int
ok
;
if
(
ic
==
istart
)
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
iend
].
x
,
corner
[
iend
].
y
,
corner
[
istart
].
x
,
corner
[
istart
].
y
,
side_style
[
corner
.
size
()
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
else
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
-
1
].
x
,
corner
[
ic
-
1
].
y
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
side_style
[
ic
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
if
(
ok
)
{
xx
[
npts
]
=
(
int
)
x
;
yy
[
npts
]
=
(
int
)
y
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
if
(
ok
==
2
)
{
xx
[
npts
]
=
(
int
)
x2
;
yy
[
npts
]
=
(
int
)
y2
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
}
}
nloops
++
;
a
+=
PCBU_PER_MIL
/
100
;
}
while
(
npts
%
2
!=
0
&&
nloops
<
3
);
ASSERT
(
npts
%
2
==
0
);
// odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline
int
ncount
=
0
;
for
(
int
ip
=
0
;
ip
<
npts
;
ip
++
)
{
if
(
xx
[
ip
]
==
x
&&
yy
[
ip
]
==
y
)
return
FALSE
;
// (x,y) is on a side, call it outside
else
if
(
xx
[
ip
]
>
x
)
ncount
++
;
}
if
(
ncount
%
2
)
return
TRUE
;
else
return
FALSE
;
}
// test to see if a point is inside polyline contour
//
BOOL
CPolyLine
::
TestPointInsideContour
(
int
icont
,
int
x
,
int
y
)
{
if
(
icont
>=
GetNumContours
()
)
return
FALSE
;
enum
{
MAXPTS
=
100
};
if
(
!
GetClosed
()
)
ASSERT
(
0
);
// define line passing through (x,y), with slope = 2/3;
// get intersection points
double
xx
[
MAXPTS
],
yy
[
MAXPTS
];
double
slope
=
(
double
)
2.0
/
3.0
;
double
a
=
y
-
slope
*
x
;
int
nloops
=
0
;
int
npts
;
// make this a loop so if my homebrew algorithm screws up, we try it again
do
{
// now find all intersection points of line with polyline sides
npts
=
0
;
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
for
(
int
ic
=
istart
;
ic
<=
iend
;
ic
++
)
{
double
x
,
y
,
x2
,
y2
;
int
ok
;
if
(
ic
==
istart
)
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
iend
].
x
,
corner
[
iend
].
y
,
corner
[
istart
].
x
,
corner
[
istart
].
y
,
side_style
[
corner
.
size
()
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
else
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
-
1
].
x
,
corner
[
ic
-
1
].
y
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
side_style
[
ic
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
if
(
ok
)
{
xx
[
npts
]
=
(
int
)
x
;
yy
[
npts
]
=
(
int
)
y
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
if
(
ok
==
2
)
{
xx
[
npts
]
=
(
int
)
x2
;
yy
[
npts
]
=
(
int
)
y2
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
}
nloops
++
;
a
+=
PCBU_PER_MIL
/
100
;
}
while
(
npts
%
2
!=
0
&&
nloops
<
3
);
ASSERT
(
npts
%
2
==
0
);
// odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline
int
ncount
=
0
;
for
(
int
ip
=
0
;
ip
<
npts
;
ip
++
)
{
if
(
xx
[
ip
]
==
x
&&
yy
[
ip
]
==
y
)
return
FALSE
;
// (x,y) is on a side, call it outside
else
if
(
xx
[
ip
]
>
x
)
ncount
++
;
}
if
(
ncount
%
2
)
return
TRUE
;
else
return
FALSE
;
}
// Test for intersection of sides
//
int
CPolyLine
::
TestIntersection
(
CPolyLine
*
poly
)
{
if
(
!
GetClosed
()
)
ASSERT
(
0
);
if
(
!
poly
->
GetClosed
()
)
ASSERT
(
0
);
for
(
int
ic
=
0
;
ic
<
GetNumContours
();
ic
++
)
{
int
istart
=
GetContourStart
(
ic
);
int
iend
=
GetContourEnd
(
ic
);
for
(
int
is
=
istart
;
is
<=
iend
;
is
++
)
{
int
xf
,
yf
;
if
(
is
<
GetContourEnd
(
ic
)
)
{
xf
=
GetX
(
is
+
1
);
yf
=
GetY
(
is
+
1
);
}
else
{
xf
=
GetX
(
istart
);
yf
=
GetY
(
istart
);
}
for
(
int
ic2
=
0
;
ic2
<
poly
->
GetNumContours
();
ic2
++
)
{
int
istart2
=
poly
->
GetContourStart
(
ic2
);
int
iend2
=
poly
->
GetContourEnd
(
ic2
);
for
(
int
is2
=
istart2
;
is2
<=
iend2
;
is2
++
)
{
int
xf2
,
yf2
;
if
(
is2
<
poly
->
GetContourEnd
(
ic2
)
)
{
xf2
=
poly
->
GetX
(
is2
+
1
);
yf2
=
poly
->
GetY
(
is2
+
1
);
}
else
{
xf2
=
poly
->
GetX
(
istart2
);
yf2
=
poly
->
GetY
(
istart2
);
}
// test for intersection between side and side2
}
}
}
}
return
0
;
}
// set selection box size
//
void
CPolyLine
::
SetSelBoxSize
(
int
sel_box
)
{
// Undraw();
m_sel_box
=
sel_box
;
// Draw();
}
// set pointer to display list, and draw into display list
//
void
CPolyLine
::
SetDisplayList
(
CDisplayList
*
dl
)
{
if
(
m_dlist
)
Undraw
();
m_dlist
=
dl
;
if
(
m_dlist
)
Draw
();
}
// copy data from another poly, but don't draw it
//
void
CPolyLine
::
Copy
(
CPolyLine
*
src
)
{
Undraw
();
m_dlist
=
src
->
m_dlist
;
m_sel_box
=
src
->
m_sel_box
;
// copy corners
for
(
unsigned
i
=
0
;
i
<
src
->
corner
.
size
();
i
++
)
corner
.
push_back
(
src
->
corner
[
i
]);
// copy side styles
int
nsides
=
src
->
GetNumSides
();
side_style
.
SetSize
(
nsides
);
for
(
int
i
=
0
;
i
<
nsides
;
i
++
)
side_style
[
i
]
=
src
->
side_style
[
i
];
// don't copy the Gpc_poly, just clear the old one
FreeGpcPoly
();
}
void
CPolyLine
::
MoveOrigin
(
int
x_off
,
int
y_off
)
{
Undraw
();
for
(
int
ic
=
0
;
ic
<
GetNumCorners
();
ic
++
)
{
SetX
(
ic
,
GetX
(
ic
)
+
x_off
);
SetY
(
ic
,
GetY
(
ic
)
+
y_off
);
}
Draw
();
}
// Set various parameters:
// the calling function should Undraw() before calling them,
// and Draw() after
//
void
CPolyLine
::
SetX
(
int
ic
,
int
x
)
{
corner
[
ic
].
x
=
x
;
}
void
CPolyLine
::
SetY
(
int
ic
,
int
y
)
{
corner
[
ic
].
y
=
y
;
}
void
CPolyLine
::
SetEndContour
(
int
ic
,
BOOL
end_contour
)
{
corner
[
ic
].
end_contour
=
end_contour
;
}
// Create CPolyLine for a pad
//
CPolyLine
*
CPolyLine
::
MakePolylineForPad
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
)
{
CPolyLine
*
poly
=
new
CPolyLine
;
int
dx
=
l
/
2
;
int
dy
=
w
/
2
;
if
(
angle
%
180
==
90
)
{
dx
=
w
/
2
;
dy
=
l
/
2
;
}
if
(
type
==
PAD_ROUND
)
{
poly
->
Start
(
0
,
0
,
0
,
x
-
dx
,
y
,
0
);
poly
->
AppendCorner
(
x
,
y
+
dy
,
ARC_CW
,
0
);
poly
->
AppendCorner
(
x
+
dx
,
y
,
ARC_CW
,
0
);
poly
->
AppendCorner
(
x
,
y
-
dy
,
ARC_CW
,
0
);
poly
->
Close
(
ARC_CW
);
}
return
poly
;
}
// Add cutout for a pad
// Convert arcs to multiple straight lines
// Do NOT draw or undraw
//
void
CPolyLine
::
AddContourForPadClearance
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
,
int
fill_clearance
,
int
hole_w
,
int
hole_clearance
,
BOOL
bThermal
,
int
spoke_w
)
{
int
dx
=
l
/
2
;
int
dy
=
w
/
2
;
if
(
angle
%
180
==
90
)
{
dx
=
w
/
2
;
dy
=
l
/
2
;
}
int
x_clearance
=
max
(
fill_clearance
,
hole_clearance
+
hole_w
/
2
-
dx
);
int
y_clearance
=
max
(
fill_clearance
,
hole_clearance
+
hole_w
/
2
-
dy
);
dx
+=
x_clearance
;
dy
+=
y_clearance
;
if
(
!
bThermal
)
{
// normal clearance
if
(
type
==
PAD_ROUND
||
(
type
==
PAD_NONE
&&
hole_w
>
0
)
)
{
AppendCorner
(
x
-
dx
,
y
,
ARC_CW
,
0
);
AppendCorner
(
x
,
y
+
dy
,
ARC_CW
,
0
);
AppendCorner
(
x
+
dx
,
y
,
ARC_CW
,
0
);
AppendCorner
(
x
,
y
-
dy
,
ARC_CW
,
0
);
Close
(
ARC_CW
);
}
else
if
(
type
==
PAD_SQUARE
||
type
==
PAD_RECT
||
type
==
PAD_RRECT
||
type
==
PAD_OVAL
)
{
AppendCorner
(
x
-
dx
,
y
-
dy
,
STRAIGHT
,
0
);
AppendCorner
(
x
+
dx
,
y
-
dy
,
STRAIGHT
,
0
);
AppendCorner
(
x
+
dx
,
y
+
dy
,
STRAIGHT
,
0
);
AppendCorner
(
x
-
dx
,
y
+
dy
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
}
}
else
{
// thermal relief
if
(
type
==
PAD_ROUND
||
(
type
==
PAD_NONE
&&
hole_w
>
0
)
)
{
// draw 4 "wedges"
double
r
=
max
(
w
/
2
+
fill_clearance
,
hole_w
/
2
+
hole_clearance
);
double
start_angle
=
asin
(
spoke_w
/
(
2.0
*
r
)
);
double
th1
,
th2
,
corner_x
,
corner_y
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
if
(
i
==
0
)
{
corner_x
=
spoke_w
/
2
;
corner_y
=
spoke_w
/
2
;
th1
=
start_angle
;
th2
=
pi
/
2.0
-
start_angle
;
}
else
if
(
i
==
1
)
{
corner_x
=
-
spoke_w
/
2
;
corner_y
=
spoke_w
/
2
;
th1
=
pi
/
2.0
+
start_angle
;
th2
=
pi
-
start_angle
;
}
else
if
(
i
==
2
)
{
corner_x
=
-
spoke_w
/
2
;
corner_y
=
-
spoke_w
/
2
;
th1
=
-
pi
+
start_angle
;
th2
=
-
pi
/
2.0
-
start_angle
;
}
else
if
(
i
==
3
)
{
corner_x
=
spoke_w
/
2
;
corner_y
=
-
spoke_w
/
2
;
th1
=
-
pi
/
2.0
+
start_angle
;
th2
=
-
start_angle
;
}
AppendCorner
(
to_int
(
x
+
corner_x
),
to_int
(
y
+
corner_y
),
STRAIGHT
,
0
);
AppendCorner
(
to_int
(
x
+
r
*
cos
(
th1
)),
to_int
(
y
+
r
*
sin
(
th1
)),
STRAIGHT
,
0
);
AppendCorner
(
to_int
(
x
+
r
*
cos
(
th2
)),
to_int
(
y
+
r
*
sin
(
th2
)),
ARC_CCW
,
0
);
Close
(
STRAIGHT
);
}
}
else
if
(
type
==
PAD_SQUARE
||
type
==
PAD_RECT
||
type
==
PAD_RRECT
||
type
==
PAD_OVAL
)
{
// draw 4 rectangles
int
xL
=
x
-
dx
;
int
xR
=
x
-
spoke_w
/
2
;
int
yB
=
y
-
dy
;
int
yT
=
y
-
spoke_w
/
2
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
xL
=
x
+
spoke_w
/
2
;
xR
=
x
+
dx
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
xL
=
x
-
dx
;
xR
=
x
-
spoke_w
/
2
;
yB
=
y
+
spoke_w
/
2
;
yT
=
y
+
dy
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
xL
=
x
+
spoke_w
/
2
;
xR
=
x
+
dx
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
}
}
return
;
}
void
CPolyLine
::
AppendArc
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
xc
,
int
yc
,
int
num
)
{
// get radius
double
r
=
sqrt
(
(
double
)(
xi
-
xc
)
*
(
xi
-
xc
)
+
(
double
)(
yi
-
yc
)
*
(
yi
-
yc
)
);
// get angles of start and finish
double
th_i
=
atan2
(
(
double
)
yi
-
yc
,
(
double
)
xi
-
xc
);
double
th_f
=
atan2
(
(
double
)
yf
-
yc
,
(
double
)
xf
-
xc
);
double
th_d
=
(
th_f
-
th_i
)
/
(
num
-
1
);
double
theta
=
th_i
;
// generate arc
for
(
int
ic
=
0
;
ic
<
num
;
ic
++
)
{
int
x
=
to_int
(
xc
+
r
*
cos
(
theta
));
int
y
=
to_int
(
yc
+
r
*
sin
(
theta
));
AppendCorner
(
x
,
y
,
STRAIGHT
,
0
);
theta
+=
th_d
;
}
Close
(
STRAIGHT
);
}
void
CPolyLine
::
ClipGpcPolygon
(
gpc_op
op
,
CPolyLine
*
clip_poly
)
{
gpc_polygon
*
result
=
new
gpc_polygon
;
gpc_polygon_clip
(
op
,
m_gpc_poly
,
clip_poly
->
GetGpcPoly
(),
result
);
gpc_free_polygon
(
m_gpc_poly
);
delete
m_gpc_poly
;
m_gpc_poly
=
result
;
}
// PolyLine.cpp ... implementation of CPolyLine class
// from FreePCB.
// Adaptation for kicad
//
using
namespace
std
;
#include <math.h>
#include <vector>
#include "PolyLine.h"
#define to_int(x) (int)round((x))
/* Stuff to compile PolyLine.cpp, used in std::vector as CArray. does not work. must be redesigned, only for test */
#define SetSize reserve
#define pi 3.14159265359
#define DENOM 10 // to use mils for php clipping
//#define DENOM 1 // to use internal units for php clipping
// dl is a pointer to CDisplayList for drawing graphic elements
// if dl = NULL, doesn't draw anything but can still hold data
//
CPolyLine
::
CPolyLine
(
CDisplayList
*
dl
)
{
m_dlist
=
dl
;
m_HatchStyle
=
0
;
m_sel_box
=
0
;
m_gpc_poly
=
new
gpc_polygon
;
m_gpc_poly
->
num_contours
=
0
;
m_php_poly
=
new
polygon
;
}
CPolyLine
::
CPolyLine
()
{
m_dlist
=
NULL
;
m_HatchStyle
=
0
;
m_sel_box
=
0
;
m_gpc_poly
=
new
gpc_polygon
;
m_gpc_poly
->
num_contours
=
0
;
m_php_poly
=
new
polygon
;
}
// destructor, removes display elements
//
CPolyLine
::~
CPolyLine
()
{
Undraw
();
FreeGpcPoly
();
delete
m_gpc_poly
;
delete
m_php_poly
;
}
// Use the General Polygon Clipping Library to clip contours
// If this results in new polygons, return them as std::vector p
// If bRetainArcs == TRUE, try to retain arcs in polys
// Returns number of external contours, or -1 if error
//
int
CPolyLine
::
NormalizeWithGpc
(
std
::
vector
<
CPolyLine
*>
*
pa
,
BOOL
bRetainArcs
)
{
std
::
vector
<
CArc
>
arc_array
;
if
(
bRetainArcs
)
MakeGpcPoly
(
-
1
,
&
arc_array
);
else
MakeGpcPoly
(
-
1
,
NULL
);
Undraw
();
// now, recreate poly
// first, find outside contours and create new CPolyLines if necessary
int
n_ext_cont
=
0
;
for
(
int
ic
=
0
;
ic
<
m_gpc_poly
->
num_contours
;
ic
++
)
{
if
(
!
(
m_gpc_poly
->
hole
)[
ic
]
)
{
if
(
n_ext_cont
==
0
)
{
// first external contour, replace this poly
corner
.
clear
();
side_style
.
clear
();
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
if
(
i
==
0
)
Start
(
m_layer
,
m_Width
,
m_sel_box
,
x
,
y
,
m_HatchStyle
);
else
AppendCorner
(
x
,
y
,
STRAIGHT
,
FALSE
);
}
Close
();
n_ext_cont
++
;
}
else
if
(
pa
)
{
// next external contour, create new poly
CPolyLine
*
poly
=
new
CPolyLine
;
pa
->
SetSize
(
n_ext_cont
);
// put in array
(
*
pa
)[
n_ext_cont
-
1
]
=
poly
;
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
if
(
i
==
0
)
poly
->
Start
(
m_layer
,
m_Width
,
m_sel_box
,
x
,
y
,
m_HatchStyle
);
else
poly
->
AppendCorner
(
x
,
y
,
STRAIGHT
,
FALSE
);
}
poly
->
Close
(
STRAIGHT
,
FALSE
);
n_ext_cont
++
;
}
}
}
// now add cutouts to the CPolyLine(s)
for
(
int
ic
=
0
;
ic
<
m_gpc_poly
->
num_contours
;
ic
++
)
{
if
(
(
m_gpc_poly
->
hole
)[
ic
]
)
{
CPolyLine
*
ext_poly
=
NULL
;
if
(
n_ext_cont
==
1
)
{
ext_poly
=
this
;
}
else
{
// find the polygon that contains this hole
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
if
(
TestPointInside
(
x
,
y
)
)
ext_poly
=
this
;
else
{
for
(
int
ext_ic
=
0
;
ext_ic
<
n_ext_cont
-
1
;
ext_ic
++
)
{
if
(
(
*
pa
)[
ext_ic
]
->
TestPointInside
(
x
,
y
)
)
{
ext_poly
=
(
*
pa
)[
ext_ic
];
break
;
}
}
}
if
(
ext_poly
)
break
;
}
}
if
(
!
ext_poly
)
ASSERT
(
0
);
for
(
int
i
=
0
;
i
<
m_gpc_poly
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
x
);
int
y
=
to_int
(((
m_gpc_poly
->
contour
)[
ic
].
vertex
)[
i
].
y
);
ext_poly
->
AppendCorner
(
x
,
y
,
STRAIGHT
,
FALSE
);
}
ext_poly
->
Close
(
STRAIGHT
,
FALSE
);
}
}
if
(
bRetainArcs
)
RestoreArcs
(
&
arc_array
,
pa
);
FreeGpcPoly
();
return
n_ext_cont
;
}
// make a php_polygon from first contour
int
CPolyLine
::
MakePhpPoly
()
{
FreePhpPoly
();
polygon
test_poly
;
int
nv
=
GetContourEnd
(
0
);
for
(
int
iv
=
0
;
iv
<=
nv
;
iv
++
)
{
int
x
=
GetX
(
iv
)
/
DENOM
;
int
y
=
GetY
(
iv
)
/
DENOM
;
m_php_poly
->
addv
(
x
,
y
);
}
return
0
;
}
void
CPolyLine
::
FreePhpPoly
()
{
// delete all vertices
while
(
m_php_poly
->
m_cnt
>
1
)
{
vertex
*
fv
=
m_php_poly
->
getFirst
();
m_php_poly
->
del
(
fv
->
m_nextV
);
}
delete
m_php_poly
->
m_first
;
m_php_poly
->
m_first
=
NULL
;
m_php_poly
->
m_cnt
=
0
;
}
// Use the php clipping lib to clip this poly against poly
//
void
CPolyLine
::
ClipPhpPolygon
(
int
php_op
,
CPolyLine
*
poly
)
{
Undraw
();
poly
->
MakePhpPoly
();
MakePhpPoly
();
polygon
*
p
=
m_php_poly
->
boolean
(
poly
->
m_php_poly
,
php_op
);
poly
->
FreePhpPoly
();
FreePhpPoly
();
if
(
p
)
{
// now screw with the PolyLine
corner
.
clear
();
side_style
.
clear
();
do
{
vertex
*
v
=
p
->
getFirst
();
Start
(
m_layer
,
m_Width
,
m_sel_box
,
to_int
(
v
->
X
()
*
DENOM
),
to_int
(
v
->
Y
()
*
DENOM
),
m_HatchStyle
);
do
{
vertex
*
n
=
v
->
Next
();
AppendCorner
(
to_int
(
v
->
X
()
*
DENOM
),
to_int
((
v
->
Y
()
*
DENOM
))
);
v
=
n
;
}
while
(
v
->
id
()
!=
p
->
getFirst
()
->
id
()
);
Close
();
// p = p->NextPoly();
delete
p
;
p
=
NULL
;
}
while
(
p
);
}
Draw
();
}
// make a gpc_polygon for a closed polyline contour
// approximates arcs with multiple straight-line segments
// if icontour = -1, make polygon with all contours,
// combining intersecting contours if possible
// returns data on arcs in arc_array
//
int
CPolyLine
::
MakeGpcPoly
(
int
icontour
,
std
::
vector
<
CArc
>
*
arc_array
)
{
if
(
m_gpc_poly
->
num_contours
)
FreeGpcPoly
();
if
(
!
GetClosed
()
&&
(
icontour
==
(
GetNumContours
()
-
1
)
||
icontour
==
-
1
))
return
1
;
// error
// initialize m_gpc_poly
m_gpc_poly
->
num_contours
=
0
;
m_gpc_poly
->
hole
=
NULL
;
m_gpc_poly
->
contour
=
NULL
;
int
n_arcs
=
0
;
int
first_contour
=
icontour
;
int
last_contour
=
icontour
;
if
(
icontour
==
-
1
)
{
first_contour
=
0
;
last_contour
=
GetNumContours
()
-
1
;
}
if
(
arc_array
)
arc_array
->
SetSize
(
0
);
int
iarc
=
0
;
for
(
int
icont
=
first_contour
;
icont
<=
last_contour
;
icont
++
)
{
// make gpc_polygon for this contour
gpc_polygon
*
gpc
=
new
gpc_polygon
;
gpc
->
num_contours
=
0
;
gpc
->
hole
=
NULL
;
gpc
->
contour
=
NULL
;
// first, calculate number of vertices in contour
int
n_vertices
=
0
;
int
ic_st
=
GetContourStart
(
icont
);
int
ic_end
=
GetContourEnd
(
icont
);
for
(
int
ic
=
ic_st
;
ic
<=
ic_end
;
ic
++
)
{
int
style
=
side_style
[
ic
];
int
x1
=
corner
[
ic
].
x
;
int
y1
=
corner
[
ic
].
y
;
int
x2
,
y2
;
if
(
ic
<
ic_end
)
{
x2
=
corner
[
ic
+
1
].
x
;
y2
=
corner
[
ic
+
1
].
y
;
}
else
{
x2
=
corner
[
ic_st
].
x
;
y2
=
corner
[
ic_st
].
y
;
}
if
(
style
==
STRAIGHT
)
n_vertices
++
;
else
{
// style is ARC_CW or ARC_CCW
int
n
;
// number of steps for arcs
n
=
(
abs
(
x2
-
x1
)
+
abs
(
y2
-
y1
))
/
(
CArc
::
MAX_STEP
);
n
=
max
(
n
,
CArc
::
MIN_STEPS
);
// or at most 5 degrees of arc
n_vertices
+=
n
;
n_arcs
++
;
}
}
// now create gcp_vertex_list for this contour
gpc_vertex_list
*
g_v_list
=
new
gpc_vertex_list
;
g_v_list
->
vertex
=
(
gpc_vertex
*
)
calloc
(
sizeof
(
gpc_vertex
),
n_vertices
);
g_v_list
->
num_vertices
=
n_vertices
;
int
ivtx
=
0
;
for
(
int
ic
=
ic_st
;
ic
<=
ic_end
;
ic
++
)
{
int
style
=
side_style
[
ic
];
int
x1
=
corner
[
ic
].
x
;
int
y1
=
corner
[
ic
].
y
;
int
x2
,
y2
;
if
(
ic
<
ic_end
)
{
x2
=
corner
[
ic
+
1
].
x
;
y2
=
corner
[
ic
+
1
].
y
;
}
else
{
x2
=
corner
[
ic_st
].
x
;
y2
=
corner
[
ic_st
].
y
;
}
if
(
style
==
STRAIGHT
)
{
g_v_list
->
vertex
[
ivtx
].
x
=
x1
;
g_v_list
->
vertex
[
ivtx
].
y
=
y1
;
ivtx
++
;
}
else
{
// style is arc_cw or arc_ccw
int
n
;
// number of steps for arcs
n
=
(
abs
(
x2
-
x1
)
+
abs
(
y2
-
y1
))
/
(
CArc
::
MAX_STEP
);
n
=
max
(
n
,
CArc
::
MIN_STEPS
);
// or at most 5 degrees of arc
double
xo
,
yo
,
theta1
,
theta2
,
a
,
b
;
a
=
fabs
(
(
double
)(
x1
-
x2
)
);
b
=
fabs
(
(
double
)(
y1
-
y2
)
);
if
(
style
==
CPolyLine
::
ARC_CW
)
{
// clockwise arc (ie.quadrant of ellipse)
if
(
x2
>
x1
&&
y2
>
y1
)
{
// first quadrant, draw second quadrant of ellipse
xo
=
x2
;
yo
=
y1
;
theta1
=
pi
;
theta2
=
pi
/
2.0
;
}
else
if
(
x2
<
x1
&&
y2
>
y1
)
{
// second quadrant, draw third quadrant of ellipse
xo
=
x1
;
yo
=
y2
;
theta1
=
3.0
*
pi
/
2.0
;
theta2
=
pi
;
}
else
if
(
x2
<
x1
&&
y2
<
y1
)
{
// third quadrant, draw fourth quadrant of ellipse
xo
=
x2
;
yo
=
y1
;
theta1
=
2.0
*
pi
;
theta2
=
3.0
*
pi
/
2.0
;
}
else
{
xo
=
x1
;
// fourth quadrant, draw first quadrant of ellipse
yo
=
y2
;
theta1
=
pi
/
2.0
;
theta2
=
0.0
;
}
}
else
{
// counter-clockwise arc
if
(
x2
>
x1
&&
y2
>
y1
)
{
xo
=
x1
;
// first quadrant, draw fourth quadrant of ellipse
yo
=
y2
;
theta1
=
3.0
*
pi
/
2.0
;
theta2
=
2.0
*
pi
;
}
else
if
(
x2
<
x1
&&
y2
>
y1
)
{
xo
=
x2
;
// second quadrant
yo
=
y1
;
theta1
=
0.0
;
theta2
=
pi
/
2.0
;
}
else
if
(
x2
<
x1
&&
y2
<
y1
)
{
xo
=
x1
;
// third quadrant
yo
=
y2
;
theta1
=
pi
/
2.0
;
theta2
=
pi
;
}
else
{
xo
=
x2
;
// fourth quadrant
yo
=
y1
;
theta1
=
pi
;
theta2
=
3.0
*
pi
/
2.0
;
}
}
// now write steps for arc
if
(
arc_array
)
{
arc_array
->
SetSize
(
iarc
+
1
);
(
*
arc_array
)[
iarc
].
style
=
style
;
(
*
arc_array
)[
iarc
].
n_steps
=
n
;
(
*
arc_array
)[
iarc
].
xi
=
x1
;
(
*
arc_array
)[
iarc
].
yi
=
y1
;
(
*
arc_array
)[
iarc
].
xf
=
x2
;
(
*
arc_array
)[
iarc
].
yf
=
y2
;
iarc
++
;
}
for
(
int
is
=
0
;
is
<
n
;
is
++
)
{
double
theta
=
theta1
+
((
theta2
-
theta1
)
*
(
double
)
is
)
/
n
;
double
x
=
xo
+
a
*
cos
(
theta
);
double
y
=
yo
+
b
*
sin
(
theta
);
if
(
is
==
0
)
{
x
=
x1
;
y
=
y1
;
}
g_v_list
->
vertex
[
ivtx
].
x
=
x
;
g_v_list
->
vertex
[
ivtx
].
y
=
y
;
ivtx
++
;
}
}
}
if
(
n_vertices
!=
ivtx
)
ASSERT
(
0
);
// add vertex_list to gpc
gpc_add_contour
(
gpc
,
g_v_list
,
0
);
// now clip m_gpc_poly with gpc, put new poly into result
gpc_polygon
*
result
=
new
gpc_polygon
;
if
(
icontour
==
-
1
&&
icont
!=
0
)
gpc_polygon_clip
(
GPC_DIFF
,
m_gpc_poly
,
gpc
,
result
);
// hole
else
gpc_polygon_clip
(
GPC_UNION
,
m_gpc_poly
,
gpc
,
result
);
// outside
// now copy result to m_gpc_poly
gpc_free_polygon
(
m_gpc_poly
);
delete
m_gpc_poly
;
m_gpc_poly
=
result
;
gpc_free_polygon
(
gpc
);
delete
gpc
;
free
(
g_v_list
->
vertex
);
free
(
g_v_list
);
}
return
0
;
}
int
CPolyLine
::
FreeGpcPoly
()
{
if
(
m_gpc_poly
->
num_contours
)
{
delete
m_gpc_poly
->
contour
->
vertex
;
delete
m_gpc_poly
->
contour
;
delete
m_gpc_poly
->
hole
;
}
m_gpc_poly
->
num_contours
=
0
;
return
0
;
}
// Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array
//
int
CPolyLine
::
RestoreArcs
(
std
::
vector
<
CArc
>
*
arc_array
,
std
::
vector
<
CPolyLine
*>
*
pa
)
{
// get poly info
int
n_polys
=
1
;
if
(
pa
)
n_polys
+=
pa
->
size
();
CPolyLine
*
poly
;
// undraw polys and clear utility flag for all corners
for
(
int
ip
=
0
;
ip
<
n_polys
;
ip
++
)
{
if
(
ip
==
0
)
poly
=
this
;
else
poly
=
(
*
pa
)[
ip
-
1
];
poly
->
Undraw
();
for
(
int
ic
=
0
;
ic
<
poly
->
GetNumCorners
();
ic
++
)
poly
->
SetUtility
(
ic
,
0
);
// clear utility flag
}
// find arcs and replace them
BOOL
bFound
;
int
arc_start
;
int
arc_end
;
for
(
unsigned
iarc
=
0
;
iarc
<
arc_array
->
size
();
iarc
++
)
{
int
arc_xi
=
(
*
arc_array
)[
iarc
].
xi
;
int
arc_yi
=
(
*
arc_array
)[
iarc
].
yi
;
int
arc_xf
=
(
*
arc_array
)[
iarc
].
xf
;
int
arc_yf
=
(
*
arc_array
)[
iarc
].
yf
;
int
n_steps
=
(
*
arc_array
)[
iarc
].
n_steps
;
int
style
=
(
*
arc_array
)[
iarc
].
style
;
bFound
=
FALSE
;
// loop through polys
for
(
int
ip
=
0
;
ip
<
n_polys
;
ip
++
)
{
if
(
ip
==
0
)
poly
=
this
;
else
poly
=
(
*
pa
)[
ip
-
1
];
for
(
int
icont
=
0
;
icont
<
poly
->
GetNumContours
();
icont
++
)
{
int
ic_start
=
poly
->
GetContourStart
(
icont
);
int
ic_end
=
poly
->
GetContourEnd
(
icont
);
if
(
(
ic_end
-
ic_start
)
>
n_steps
)
{
for
(
int
ic
=
ic_start
;
ic
<=
ic_end
;
ic
++
)
{
int
ic_next
=
ic
+
1
;
if
(
ic_next
>
ic_end
)
ic_next
=
ic_start
;
int
xi
=
poly
->
GetX
(
ic
);
int
yi
=
poly
->
GetY
(
ic
);
if
(
xi
==
arc_xi
&&
yi
==
arc_yi
)
{
// test for forward arc
int
ic2
=
ic
+
n_steps
;
if
(
ic2
>
ic_end
)
ic2
=
ic2
-
ic_end
+
ic_start
-
1
;
int
xf
=
poly
->
GetX
(
ic2
);
int
yf
=
poly
->
GetY
(
ic2
);
if
(
xf
==
arc_xf
&&
yf
==
arc_yf
)
{
// arc from ic to ic2
bFound
=
TRUE
;
arc_start
=
ic
;
arc_end
=
ic2
;
}
else
{
// try reverse arc
ic2
=
ic
-
n_steps
;
if
(
ic2
<
ic_start
)
ic2
=
ic2
-
ic_start
+
ic_end
+
1
;
xf
=
poly
->
GetX
(
ic2
);
yf
=
poly
->
GetY
(
ic2
);
if
(
xf
==
arc_xf
&&
yf
==
arc_yf
)
{
// arc from ic2 to ic
bFound
=
TRUE
;
arc_start
=
ic2
;
arc_end
=
ic
;
style
=
3
-
style
;
}
}
if
(
bFound
)
{
poly
->
side_style
[
arc_start
]
=
style
;
// mark corners for deletion from arc_start+1 to arc_end-1
for
(
int
i
=
arc_start
+
1
;
i
!=
arc_end
;
)
{
if
(
i
>
ic_end
)
i
=
ic_start
;
poly
->
SetUtility
(
i
,
1
);
if
(
i
==
ic_end
)
i
=
ic_start
;
else
i
++
;
}
break
;
}
}
if
(
bFound
)
break
;
}
}
if
(
bFound
)
break
;
}
}
if
(
bFound
)
(
*
arc_array
)[
iarc
].
bFound
=
TRUE
;
}
// now delete all marked corners
for
(
int
ip
=
0
;
ip
<
n_polys
;
ip
++
)
{
if
(
ip
==
0
)
poly
=
this
;
else
poly
=
(
*
pa
)[
ip
-
1
];
for
(
int
ic
=
poly
->
GetNumCorners
()
-
1
;
ic
>=
0
;
ic
--
)
{
if
(
poly
->
GetUtility
(
ic
)
)
poly
->
DeleteCorner
(
ic
,
FALSE
);
}
}
return
0
;
}
// initialize new polyline
// set layer, width, selection box size, starting point, id and pointer
//
// if sel_box = 0, don't create selection elements at all
//
// if polyline is board outline, enter with:
// id.type = ID_BOARD
// id.st = ID_BOARD_OUTLINE
// id.i = 0
// ptr = NULL
//
// if polyline is copper area, enter with:
// id.type = ID_NET;
// id.st = ID_AREA
// id.i = index to area
// ptr = pointer to net
//
void
CPolyLine
::
Start
(
int
layer
,
int
w
,
int
sel_box
,
int
x
,
int
y
,
int
hatch
)
{
m_layer
=
layer
;
m_Width
=
w
;
m_sel_box
=
sel_box
;
m_HatchStyle
=
hatch
;
CPolyPt
poly_pt
(
x
,
y
);
poly_pt
.
end_contour
=
FALSE
;
corner
.
push_back
(
poly_pt
);
side_style
.
push_back
(
0
);
}
// add a corner to unclosed polyline
//
void
CPolyLine
::
AppendCorner
(
int
x
,
int
y
,
int
style
,
BOOL
bDraw
)
{
Undraw
();
CPolyPt
poly_pt
(
x
,
y
);
poly_pt
.
end_contour
=
FALSE
;
// add entries for new corner and side
corner
.
push_back
(
poly_pt
);
side_style
.
push_back
(
style
);
if
(
corner
.
size
()
>
0
&&
!
corner
[
corner
.
size
()
-
1
].
end_contour
)
side_style
[
corner
.
size
()
-
1
]
=
style
;
int
dl_type
;
if
(
style
==
CPolyLine
::
STRAIGHT
)
dl_type
=
DL_LINE
;
else
if
(
style
==
CPolyLine
::
ARC_CW
)
dl_type
=
DL_ARC_CW
;
else
if
(
style
==
CPolyLine
::
ARC_CCW
)
dl_type
=
DL_ARC_CCW
;
else
ASSERT
(
0
);
if
(
bDraw
)
Draw
();
}
// close last polyline contour
//
void
CPolyLine
::
Close
(
int
style
,
BOOL
bDraw
)
{
if
(
GetClosed
()
)
ASSERT
(
0
);
Undraw
();
side_style
[
corner
.
size
()
-
1
]
=
style
;
corner
[
corner
.
size
()
-
1
].
end_contour
=
TRUE
;
if
(
bDraw
)
Draw
();
}
// move corner of polyline
//
void
CPolyLine
::
MoveCorner
(
int
ic
,
int
x
,
int
y
)
{
Undraw
();
corner
[
ic
].
x
=
x
;
corner
[
ic
].
y
=
y
;
Draw
();
}
// delete corner and adjust arrays
//
void
CPolyLine
::
DeleteCorner
(
int
ic
,
BOOL
bDraw
)
{
Undraw
();
int
icont
=
GetContour
(
ic
);
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
BOOL
bClosed
=
icont
<
GetNumContours
()
-
1
||
GetClosed
();
if
(
!
bClosed
)
{
// open contour, must be last contour
corner
.
erase
(
corner
.
begin
()
+
ic
);
if
(
ic
!=
istart
)
side_style
.
erase
(
side_style
.
begin
()
+
ic
-
1
);
}
else
{
// closed contour
corner
.
erase
(
corner
.
begin
()
+
ic
);
side_style
.
erase
(
side_style
.
begin
()
+
ic
);
if
(
ic
==
iend
)
corner
[
ic
-
1
].
end_contour
=
TRUE
;
}
if
(
bClosed
&&
GetContourSize
(
icont
)
<
3
)
{
// delete the entire contour
RemoveContour
(
icont
);
}
if
(
bDraw
)
Draw
();
}
void
CPolyLine
::
RemoveContour
(
int
icont
)
{
Undraw
();
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
if
(
icont
==
0
&&
GetNumContours
()
==
1
)
{
// remove the only contour
ASSERT
(
0
);
}
else
if
(
icont
==
GetNumContours
()
-
1
)
{
// remove last contour
corner
.
erase
(
corner
.
begin
()
+
icont
,
corner
.
end
()
);
side_style
.
erase
(
side_style
.
begin
()
+
icont
,
side_style
.
end
()
);
}
else
{
// remove closed contour
for
(
int
ic
=
iend
;
ic
>=
istart
;
ic
--
)
{
corner
.
erase
(
corner
.
begin
()
+
ic
);
side_style
.
erase
(
side_style
.
begin
()
+
ic
);
}
}
Draw
();
}
/** Function InsertCorner
* insert a new corner between two existing corners
* @param ic = index for the insertion point: the corner is inserted AFTER ic
* @param x, y = coordinates corner to insert
*/
void
CPolyLine
::
InsertCorner
(
int
ic
,
int
x
,
int
y
)
{
Undraw
();
if
(
(
unsigned
)(
ic
)
>=
corner
.
size
()
)
{
corner
.
push_back
(
CPolyPt
(
x
,
y
)
);
side_style
.
push_back
(
STRAIGHT
);
}
else
{
corner
.
insert
(
corner
.
begin
()
+
ic
+
1
,
CPolyPt
(
x
,
y
)
);
side_style
.
insert
(
side_style
.
begin
()
+
ic
+
1
,
STRAIGHT
);
}
if
(
(
unsigned
)(
ic
+
1
)
<
corner
.
size
()
)
{
if
(
corner
[
ic
].
end_contour
)
{
corner
[
ic
+
1
].
end_contour
=
TRUE
;
corner
[
ic
].
end_contour
=
FALSE
;
}
}
Draw
();
}
// undraw polyline by removing all graphic elements from display list
//
void
CPolyLine
::
Undraw
()
{
if
(
m_dlist
&&
bDrawn
)
{
// remove display elements, if present
for
(
unsigned
i
=
0
;
i
<
dl_side
.
size
();
i
++
)
m_dlist
->
Remove
(
dl_side
[
i
]
);
for
(
unsigned
i
=
0
;
i
<
dl_side_sel
.
size
();
i
++
)
m_dlist
->
Remove
(
dl_side_sel
[
i
]
);
for
(
unsigned
i
=
0
;
i
<
dl_corner_sel
.
size
();
i
++
)
m_dlist
->
Remove
(
dl_corner_sel
[
i
]
);
// remove pointers
dl_side
.
clear
();
dl_side_sel
.
clear
();
dl_corner_sel
.
clear
();
}
m_HatchLines
.
clear
();
bDrawn
=
FALSE
;
}
// draw polyline by adding all graphics to display list
// if side style is ARC_CW or ARC_CCW but endpoints are not angled,
// convert to STRAIGHT
//
void
CPolyLine
::
Draw
(
CDisplayList
*
dl
)
{
// first, undraw if necessary
if
(
bDrawn
)
Undraw
();
// use new display list if provided
if
(
dl
)
m_dlist
=
dl
;
#if 0
int i_start_contour = 0;
if( m_dlist )
{
// set up std::vectors
dl_side.SetSize( corner.size() );
if( m_sel_box )
{
dl_side_sel.SetSize( corner.size() );
dl_corner_sel.SetSize( corner.size() );
}
else
{
dl_side_sel.clear();
dl_corner_sel.clear();
}
// now draw elements
for( int ic=0; ic<corner.size(); ic++ )
{
m_id.ii = ic;
int xi = corner[ic].x;
int yi = corner[ic].y;
int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size()-1 )
{
xf = corner[ic+1].x;
yf = corner[ic+1].y;
}
else
{
xf = corner[i_start_contour].x;
yf = corner[i_start_contour].y;
i_start_contour = ic+1;
}
// draw
if( m_sel_box )
{
m_id.sst = ID_SEL_CORNER;
dl_corner_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, DL_HOLLOW_RECT,
1, 0, 0, xi-m_sel_box, yi-m_sel_box,
xi+m_sel_box, yi+m_sel_box, 0, 0 );
}
if( ic<(corner.size()-1) || corner[ic].end_contour )
{
// draw side
if( xi == xf || yi == yf )
{
// if endpoints not angled, make side STRAIGHT
side_style[ic] = STRAIGHT;
}
int g_type = DL_LINE;
if( side_style[ic] == STRAIGHT )
g_type = DL_LINE;
else if( side_style[ic] == ARC_CW )
g_type = DL_ARC_CW;
else if( side_style[ic] == ARC_CCW )
g_type = DL_ARC_CCW;
m_id.sst = ID_SIDE;
dl_side[ic] = m_dlist->Add( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 );
if( m_sel_box )
{
m_id.sst = ID_SEL_SIDE;
dl_side_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 );
}
}
}
// if( m_HatchStyle )
// Hatch();
}
#endif
Hatch
();
bDrawn
=
TRUE
;
}
// start dragging new corner to be inserted into side, make side and hatching invisible
//
void
CPolyLine
::
StartDraggingToInsertCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
int
icont
=
GetContour
(
ic
);
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
int
post_c
;
if
(
ic
==
iend
)
post_c
=
istart
;
else
post_c
=
ic
+
1
;
int
xi
=
corner
[
ic
].
x
;
int
yi
=
corner
[
ic
].
y
;
int
xf
=
corner
[
post_c
].
x
;
int
yf
=
corner
[
post_c
].
y
;
m_dlist
->
StartDraggingLineVertex
(
pDC
,
x
,
y
,
xi
,
yi
,
xf
,
yf
,
LAY_SELECTION
,
LAY_SELECTION
,
1
,
1
,
DSS_STRAIGHT
,
DSS_STRAIGHT
,
0
,
0
,
0
,
0
,
1
);
m_dlist
->
CancelHighLight
();
m_dlist
->
Set_visible
(
dl_side
[
ic
],
0
);
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
// cancel dragging inserted corner, make side and hatching visible again
//
void
CPolyLine
::
CancelDraggingToInsertCorner
(
int
ic
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
int
post_c
;
if
(
ic
==
(
int
)(
corner
.
size
()
-
1
)
)
post_c
=
0
;
else
post_c
=
ic
+
1
;
m_dlist
->
StopDragging
();
/* m_dlist->Set_visible( dl_side[ic], 1 );
for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 1 );
*/
}
// start dragging corner to new position, make adjacent sides and hatching invisible
//
void
CPolyLine
::
StartDraggingToMoveCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
// see if corner is the first or last corner of an open contour
int
icont
=
GetContour
(
ic
);
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
if
(
!
GetClosed
()
&&
icont
==
GetNumContours
()
-
1
&&
(
ic
==
istart
||
ic
==
iend
)
)
{
// yes
int
style
,
xi
,
yi
,
iside
;
if
(
ic
==
istart
)
{
// first corner
iside
=
ic
;
xi
=
GetX
(
ic
+
1
);
yi
=
GetY
(
ic
+
1
);
style
=
GetSideStyle
(
iside
);
// reverse arc since we are drawing from corner 1 to 0
if
(
style
==
CPolyLine
::
ARC_CW
)
style
=
CPolyLine
::
ARC_CCW
;
else
if
(
style
==
CPolyLine
::
ARC_CCW
)
style
=
CPolyLine
::
ARC_CW
;
}
else
{
// last corner
iside
=
ic
-
1
;
xi
=
GetX
(
ic
-
1
);
yi
=
GetY
(
ic
-
1
);
style
=
GetSideStyle
(
iside
);
}
m_dlist
->
StartDraggingArc
(
pDC
,
style
,
GetX
(
ic
),
GetY
(
ic
),
xi
,
yi
,
LAY_SELECTION
,
1
,
1
);
m_dlist
->
CancelHighLight
();
m_dlist
->
Set_visible
(
dl_side
[
iside
],
0
);
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
else
{
// no
// get indexes for preceding and following corners
int
pre_c
,
post_c
;
int
poly_side_style1
,
poly_side_style2
;
int
style1
,
style2
;
if
(
ic
==
istart
)
{
pre_c
=
iend
;
post_c
=
istart
+
1
;
poly_side_style1
=
side_style
[
iend
];
poly_side_style2
=
side_style
[
istart
];
}
else
if
(
ic
==
iend
)
{
// last side
pre_c
=
ic
-
1
;
post_c
=
istart
;
poly_side_style1
=
side_style
[
ic
-
1
];
poly_side_style2
=
side_style
[
ic
];
}
else
{
pre_c
=
ic
-
1
;
post_c
=
ic
+
1
;
poly_side_style1
=
side_style
[
ic
-
1
];
poly_side_style2
=
side_style
[
ic
];
}
if
(
poly_side_style1
==
STRAIGHT
)
style1
=
DSS_STRAIGHT
;
else
if
(
poly_side_style1
==
ARC_CW
)
style1
=
DSS_ARC_CW
;
else
if
(
poly_side_style1
==
ARC_CCW
)
style1
=
DSS_ARC_CCW
;
if
(
poly_side_style2
==
STRAIGHT
)
style2
=
DSS_STRAIGHT
;
else
if
(
poly_side_style2
==
ARC_CW
)
style2
=
DSS_ARC_CW
;
else
if
(
poly_side_style2
==
ARC_CCW
)
style2
=
DSS_ARC_CCW
;
int
xi
=
corner
[
pre_c
].
x
;
int
yi
=
corner
[
pre_c
].
y
;
int
xf
=
corner
[
post_c
].
x
;
int
yf
=
corner
[
post_c
].
y
;
m_dlist
->
StartDraggingLineVertex
(
pDC
,
x
,
y
,
xi
,
yi
,
xf
,
yf
,
LAY_SELECTION
,
LAY_SELECTION
,
1
,
1
,
style1
,
style2
,
0
,
0
,
0
,
0
,
1
);
m_dlist
->
CancelHighLight
();
m_dlist
->
Set_visible
(
dl_side
[
pre_c
],
0
);
m_dlist
->
Set_visible
(
dl_side
[
ic
],
0
);
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
}
// cancel dragging corner to new position, make sides and hatching visible again
//
// highlight side by drawing line over it
//
void
CPolyLine
::
HighlightSide
(
int
is
)
{
if
(
!
m_dlist
)
ASSERT
(
0
);
if
(
GetClosed
()
&&
is
>=
(
int
)
corner
.
size
()
)
return
;
if
(
!
GetClosed
()
&&
is
>=
(
int
)(
corner
.
size
()
-
1
)
)
return
;
int
style
;
if
(
side_style
[
is
]
==
CPolyLine
::
STRAIGHT
)
style
=
DL_LINE
;
else
if
(
side_style
[
is
]
==
CPolyLine
::
ARC_CW
)
style
=
DL_ARC_CW
;
else
if
(
side_style
[
is
]
==
CPolyLine
::
ARC_CCW
)
style
=
DL_ARC_CCW
;
m_dlist
->
HighLight
(
style
,
m_dlist
->
Get_x
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_y
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_xf
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_yf
(
dl_side_sel
[
is
]
),
m_dlist
->
Get_w
(
dl_side_sel
[
is
])
);
}
int
CPolyLine
::
GetX
(
int
ic
)
{
return
corner
[
ic
].
x
;
}
int
CPolyLine
::
GetY
(
int
ic
)
{
return
corner
[
ic
].
y
;
}
int
CPolyLine
::
GetEndContour
(
int
ic
)
{
return
corner
[
ic
].
end_contour
;
}
CRect
CPolyLine
::
GetBounds
()
{
CRect
r
=
GetCornerBounds
();
r
.
left
-=
m_Width
/
2
;
r
.
right
+=
m_Width
/
2
;
r
.
bottom
-=
m_Width
/
2
;
r
.
top
+=
m_Width
/
2
;
return
r
;
}
CRect
CPolyLine
::
GetCornerBounds
()
{
CRect
r
;
r
.
left
=
r
.
bottom
=
INT_MAX
;
r
.
right
=
r
.
top
=
INT_MIN
;
for
(
unsigned
i
=
0
;
i
<
corner
.
size
();
i
++
)
{
r
.
left
=
min
(
r
.
left
,
corner
[
i
].
x
);
r
.
right
=
max
(
r
.
right
,
corner
[
i
].
x
);
r
.
bottom
=
min
(
r
.
bottom
,
corner
[
i
].
y
);
r
.
top
=
max
(
r
.
top
,
corner
[
i
].
y
);
}
return
r
;
}
CRect
CPolyLine
::
GetCornerBounds
(
int
icont
)
{
CRect
r
;
r
.
left
=
r
.
bottom
=
INT_MAX
;
r
.
right
=
r
.
top
=
INT_MIN
;
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
for
(
int
i
=
istart
;
i
<=
iend
;
i
++
)
{
r
.
left
=
min
(
r
.
left
,
corner
[
i
].
x
);
r
.
right
=
max
(
r
.
right
,
corner
[
i
].
x
);
r
.
bottom
=
min
(
r
.
bottom
,
corner
[
i
].
y
);
r
.
top
=
max
(
r
.
top
,
corner
[
i
].
y
);
}
return
r
;
}
int
CPolyLine
::
GetNumCorners
()
{
return
corner
.
size
();
}
int
CPolyLine
::
GetNumSides
()
{
if
(
GetClosed
()
)
return
corner
.
size
();
else
return
corner
.
size
()
-
1
;
}
int
CPolyLine
::
GetW
()
{
return
m_Width
;
}
int
CPolyLine
::
GetSelBoxSize
()
{
return
m_sel_box
;
}
int
CPolyLine
::
GetNumContours
()
{
int
ncont
=
0
;
if
(
!
corner
.
size
()
)
return
0
;
for
(
unsigned
ic
=
0
;
ic
<
corner
.
size
();
ic
++
)
if
(
corner
[
ic
].
end_contour
)
ncont
++
;
if
(
!
corner
[
corner
.
size
()
-
1
].
end_contour
)
ncont
++
;
return
ncont
;
}
int
CPolyLine
::
GetContour
(
int
ic
)
{
int
ncont
=
0
;
for
(
int
i
=
0
;
i
<
ic
;
i
++
)
{
if
(
corner
[
i
].
end_contour
)
ncont
++
;
}
return
ncont
;
}
int
CPolyLine
::
GetContourStart
(
int
icont
)
{
if
(
icont
==
0
)
return
0
;
int
ncont
=
0
;
for
(
unsigned
i
=
0
;
i
<
corner
.
size
();
i
++
)
{
if
(
corner
[
i
].
end_contour
)
{
ncont
++
;
if
(
ncont
==
icont
)
return
i
+
1
;
}
}
ASSERT
(
0
);
return
0
;
}
int
CPolyLine
::
GetContourEnd
(
int
icont
)
{
if
(
icont
<
0
)
return
0
;
if
(
icont
==
GetNumContours
()
-
1
)
return
corner
.
size
()
-
1
;
int
ncont
=
0
;
for
(
unsigned
i
=
0
;
i
<
corner
.
size
();
i
++
)
{
if
(
corner
[
i
].
end_contour
)
{
if
(
ncont
==
icont
)
return
i
;
ncont
++
;
}
}
ASSERT
(
0
);
return
0
;
}
int
CPolyLine
::
GetContourSize
(
int
icont
)
{
return
GetContourEnd
(
icont
)
-
GetContourStart
(
icont
)
+
1
;
}
void
CPolyLine
::
SetSideStyle
(
int
is
,
int
style
)
{
Undraw
();
CPoint
p1
,
p2
;
if
(
is
==
(
int
)(
corner
.
size
()
-
1
)
)
{
p1
.
x
=
corner
[
corner
.
size
()
-
1
].
x
;
p1
.
y
=
corner
[
corner
.
size
()
-
1
].
y
;
p2
.
x
=
corner
[
0
].
x
;
p2
.
y
=
corner
[
0
].
y
;
}
else
{
p1
.
x
=
corner
[
is
].
x
;
p1
.
y
=
corner
[
is
].
y
;
p2
.
x
=
corner
[
is
+
1
].
x
;
p2
.
y
=
corner
[
is
+
1
].
y
;
}
if
(
p1
.
x
==
p2
.
x
||
p1
.
y
==
p2
.
y
)
side_style
[
is
]
=
STRAIGHT
;
else
side_style
[
is
]
=
style
;
Draw
();
}
int
CPolyLine
::
GetSideStyle
(
int
is
)
{
return
side_style
[
is
];
}
int
CPolyLine
::
GetClosed
()
{
if
(
corner
.
size
()
==
0
)
return
0
;
else
return
corner
[
corner
.
size
()
-
1
].
end_contour
;
}
// draw hatch lines
//
void
CPolyLine
::
Hatch
()
{
m_HatchLines
.
clear
();
if
(
m_HatchStyle
==
NO_HATCH
)
{
return
;
}
int
layer
=
m_layer
;
// if( /*m_dlist && */GetClosed() )
{
enum
{
MAXPTS
=
100
,
MAXLINES
=
1000
};
int
xx
[
MAXPTS
],
yy
[
MAXPTS
];
// define range for hatch lines
int
min_x
=
corner
[
0
].
x
;
int
max_x
=
corner
[
0
].
x
;
int
min_y
=
corner
[
0
].
y
;
int
max_y
=
corner
[
0
].
y
;
for
(
unsigned
ic
=
1
;
ic
<
corner
.
size
();
ic
++
)
{
if
(
corner
[
ic
].
x
<
min_x
)
min_x
=
corner
[
ic
].
x
;
if
(
corner
[
ic
].
x
>
max_x
)
max_x
=
corner
[
ic
].
x
;
if
(
corner
[
ic
].
y
<
min_y
)
min_y
=
corner
[
ic
].
y
;
if
(
corner
[
ic
].
y
>
max_y
)
max_y
=
corner
[
ic
].
y
;
}
int
slope_flag
=
(
layer
&
1
)
?
1
:
-
1
;
// 1 or -1
double
slope
=
0.707106
*
slope_flag
;
int
spacing
;
if
(
m_HatchStyle
==
DIAGONAL_EDGE
)
spacing
=
10
*
PCBU_PER_MIL
;
else
spacing
=
50
*
PCBU_PER_MIL
;
int
max_a
,
min_a
;
if
(
slope_flag
==
1
)
{
max_a
=
(
int
)(
max_y
-
slope
*
min_x
);
min_a
=
(
int
)(
min_y
-
slope
*
max_x
);
}
else
{
max_a
=
(
int
)(
max_y
-
slope
*
max_x
);
min_a
=
(
int
)(
min_y
-
slope
*
min_x
);
}
min_a
=
(
min_a
/
spacing
)
*
spacing
;
int
offset
;
if
(
layer
<
(
LAY_TOP_COPPER
+
2
)
)
offset
=
0
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
4
)
)
offset
=
spacing
/
2
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
6
)
)
offset
=
spacing
/
4
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
8
)
)
offset
=
3
*
spacing
/
4
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
10
)
)
offset
=
1
*
spacing
/
8
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
12
)
)
offset
=
3
*
spacing
/
8
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
14
)
)
offset
=
5
*
spacing
/
8
;
else
if
(
layer
<
(
LAY_TOP_COPPER
+
16
)
)
offset
=
7
*
spacing
/
8
;
else
ASSERT
(
0
);
min_a
+=
offset
;
// now calculate and draw hatch lines
int
nc
=
corner
.
size
();
// loop through hatch lines
for
(
int
a
=
min_a
;
a
<
max_a
;
a
+=
spacing
)
{
// get intersection points for this hatch line
int
nloops
=
0
;
int
npts
;
// make this a loop in case my homebrew hatching algorithm screws up
do
{
npts
=
0
;
int
i_start_contour
=
0
;
for
(
int
ic
=
0
;
ic
<
nc
;
ic
++
)
{
double
x
,
y
,
x2
,
y2
;
int
ok
;
if
(
corner
[
ic
].
end_contour
)
{
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
corner
[
i_start_contour
].
x
,
corner
[
i_start_contour
].
y
,
side_style
[
ic
],
&
x
,
&
y
,
&
x2
,
&
y2
);
i_start_contour
=
ic
+
1
;
}
else
{
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
corner
[
ic
+
1
].
x
,
corner
[
ic
+
1
].
y
,
side_style
[
ic
],
&
x
,
&
y
,
&
x2
,
&
y2
);
}
if
(
ok
)
{
xx
[
npts
]
=
(
int
)
x
;
yy
[
npts
]
=
(
int
)
y
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
if
(
ok
==
2
)
{
xx
[
npts
]
=
(
int
)
x2
;
yy
[
npts
]
=
(
int
)
y2
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
}
nloops
++
;
a
+=
PCBU_PER_MIL
/
100
;
}
while
(
npts
%
2
!=
0
&&
nloops
<
3
);
ASSERT
(
npts
%
2
==
0
);
// odd number of intersection points, error
// sort points in order of descending x (if more than 2)
if
(
npts
>
2
)
{
for
(
int
istart
=
0
;
istart
<
(
npts
-
1
);
istart
++
)
{
int
max_x
=
INT_MIN
;
int
imax
;
for
(
int
i
=
istart
;
i
<
npts
;
i
++
)
{
if
(
xx
[
i
]
>
max_x
)
{
max_x
=
xx
[
i
];
imax
=
i
;
}
}
int
temp
=
xx
[
istart
];
xx
[
istart
]
=
xx
[
imax
];
xx
[
imax
]
=
temp
;
temp
=
yy
[
istart
];
yy
[
istart
]
=
yy
[
imax
];
yy
[
imax
]
=
temp
;
}
}
// draw lines
for
(
int
ip
=
0
;
ip
<
npts
;
ip
+=
2
)
{
double
dx
=
xx
[
ip
+
1
]
-
xx
[
ip
];
if
(
m_HatchStyle
==
DIAGONAL_FULL
||
fabs
(
dx
)
<
40
*
NM_PER_MIL
)
{
m_HatchLines
.
push_back
(
CSegment
(
xx
[
ip
],
yy
[
ip
],
xx
[
ip
+
1
],
yy
[
ip
+
1
])
);
}
else
{
double
dy
=
yy
[
ip
+
1
]
-
yy
[
ip
];
double
slope
=
dy
/
dx
;
if
(
dx
>
0
)
dx
=
20
*
NM_PER_MIL
;
else
dx
=
-
20
*
NM_PER_MIL
;
double
x1
=
xx
[
ip
]
+
dx
;
double
x2
=
xx
[
ip
+
1
]
-
dx
;
double
y1
=
yy
[
ip
]
+
dx
*
slope
;
double
y2
=
yy
[
ip
+
1
]
-
dx
*
slope
;
m_HatchLines
.
push_back
(
CSegment
(
xx
[
ip
],
yy
[
ip
],
to_int
(
x1
),
to_int
(
y1
))
);
m_HatchLines
.
push_back
(
CSegment
(
xx
[
ip
+
1
],
yy
[
ip
+
1
],
to_int
(
x2
),
to_int
(
y2
))
);
}
}
}
// end for
}
}
// test to see if a point is inside polyline
//
BOOL
CPolyLine
::
TestPointInside
(
int
x
,
int
y
)
{
enum
{
MAXPTS
=
100
};
if
(
!
GetClosed
()
)
ASSERT
(
0
);
// define line passing through (x,y), with slope = 2/3;
// get intersection points
double
xx
[
MAXPTS
],
yy
[
MAXPTS
];
double
slope
=
(
double
)
2.0
/
3.0
;
double
a
=
y
-
slope
*
x
;
int
nloops
=
0
;
int
npts
;
// make this a loop so if my homebrew algorithm screws up, we try it again
do
{
// now find all intersection points of line with polyline sides
npts
=
0
;
for
(
int
icont
=
0
;
icont
<
GetNumContours
();
icont
++
)
{
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
for
(
int
ic
=
istart
;
ic
<=
iend
;
ic
++
)
{
double
x
,
y
,
x2
,
y2
;
int
ok
;
if
(
ic
==
istart
)
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
iend
].
x
,
corner
[
iend
].
y
,
corner
[
istart
].
x
,
corner
[
istart
].
y
,
side_style
[
corner
.
size
()
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
else
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
-
1
].
x
,
corner
[
ic
-
1
].
y
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
side_style
[
ic
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
if
(
ok
)
{
xx
[
npts
]
=
(
int
)
x
;
yy
[
npts
]
=
(
int
)
y
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
if
(
ok
==
2
)
{
xx
[
npts
]
=
(
int
)
x2
;
yy
[
npts
]
=
(
int
)
y2
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
}
}
nloops
++
;
a
+=
PCBU_PER_MIL
/
100
;
}
while
(
npts
%
2
!=
0
&&
nloops
<
3
);
ASSERT
(
npts
%
2
==
0
);
// odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline
int
ncount
=
0
;
for
(
int
ip
=
0
;
ip
<
npts
;
ip
++
)
{
if
(
xx
[
ip
]
==
x
&&
yy
[
ip
]
==
y
)
return
FALSE
;
// (x,y) is on a side, call it outside
else
if
(
xx
[
ip
]
>
x
)
ncount
++
;
}
if
(
ncount
%
2
)
return
TRUE
;
else
return
FALSE
;
}
// test to see if a point is inside polyline contour
//
BOOL
CPolyLine
::
TestPointInsideContour
(
int
icont
,
int
x
,
int
y
)
{
if
(
icont
>=
GetNumContours
()
)
return
FALSE
;
enum
{
MAXPTS
=
100
};
if
(
!
GetClosed
()
)
ASSERT
(
0
);
// define line passing through (x,y), with slope = 2/3;
// get intersection points
double
xx
[
MAXPTS
],
yy
[
MAXPTS
];
double
slope
=
(
double
)
2.0
/
3.0
;
double
a
=
y
-
slope
*
x
;
int
nloops
=
0
;
int
npts
;
// make this a loop so if my homebrew algorithm screws up, we try it again
do
{
// now find all intersection points of line with polyline sides
npts
=
0
;
int
istart
=
GetContourStart
(
icont
);
int
iend
=
GetContourEnd
(
icont
);
for
(
int
ic
=
istart
;
ic
<=
iend
;
ic
++
)
{
double
x
,
y
,
x2
,
y2
;
int
ok
;
if
(
ic
==
istart
)
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
iend
].
x
,
corner
[
iend
].
y
,
corner
[
istart
].
x
,
corner
[
istart
].
y
,
side_style
[
corner
.
size
()
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
else
ok
=
FindLineSegmentIntersection
(
a
,
slope
,
corner
[
ic
-
1
].
x
,
corner
[
ic
-
1
].
y
,
corner
[
ic
].
x
,
corner
[
ic
].
y
,
side_style
[
ic
-
1
],
&
x
,
&
y
,
&
x2
,
&
y2
);
if
(
ok
)
{
xx
[
npts
]
=
(
int
)
x
;
yy
[
npts
]
=
(
int
)
y
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
if
(
ok
==
2
)
{
xx
[
npts
]
=
(
int
)
x2
;
yy
[
npts
]
=
(
int
)
y2
;
npts
++
;
ASSERT
(
npts
<
MAXPTS
);
// overflow
}
}
nloops
++
;
a
+=
PCBU_PER_MIL
/
100
;
}
while
(
npts
%
2
!=
0
&&
nloops
<
3
);
ASSERT
(
npts
%
2
==
0
);
// odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline
int
ncount
=
0
;
for
(
int
ip
=
0
;
ip
<
npts
;
ip
++
)
{
if
(
xx
[
ip
]
==
x
&&
yy
[
ip
]
==
y
)
return
FALSE
;
// (x,y) is on a side, call it outside
else
if
(
xx
[
ip
]
>
x
)
ncount
++
;
}
if
(
ncount
%
2
)
return
TRUE
;
else
return
FALSE
;
}
// Test for intersection of sides
//
int
CPolyLine
::
TestIntersection
(
CPolyLine
*
poly
)
{
if
(
!
GetClosed
()
)
ASSERT
(
0
);
if
(
!
poly
->
GetClosed
()
)
ASSERT
(
0
);
for
(
int
ic
=
0
;
ic
<
GetNumContours
();
ic
++
)
{
int
istart
=
GetContourStart
(
ic
);
int
iend
=
GetContourEnd
(
ic
);
for
(
int
is
=
istart
;
is
<=
iend
;
is
++
)
{
int
xf
,
yf
;
if
(
is
<
GetContourEnd
(
ic
)
)
{
xf
=
GetX
(
is
+
1
);
yf
=
GetY
(
is
+
1
);
}
else
{
xf
=
GetX
(
istart
);
yf
=
GetY
(
istart
);
}
for
(
int
ic2
=
0
;
ic2
<
poly
->
GetNumContours
();
ic2
++
)
{
int
istart2
=
poly
->
GetContourStart
(
ic2
);
int
iend2
=
poly
->
GetContourEnd
(
ic2
);
for
(
int
is2
=
istart2
;
is2
<=
iend2
;
is2
++
)
{
int
xf2
,
yf2
;
if
(
is2
<
poly
->
GetContourEnd
(
ic2
)
)
{
xf2
=
poly
->
GetX
(
is2
+
1
);
yf2
=
poly
->
GetY
(
is2
+
1
);
}
else
{
xf2
=
poly
->
GetX
(
istart2
);
yf2
=
poly
->
GetY
(
istart2
);
}
// test for intersection between side and side2
}
}
}
}
return
0
;
}
// set selection box size
//
void
CPolyLine
::
SetSelBoxSize
(
int
sel_box
)
{
// Undraw();
m_sel_box
=
sel_box
;
// Draw();
}
// set pointer to display list, and draw into display list
//
void
CPolyLine
::
SetDisplayList
(
CDisplayList
*
dl
)
{
if
(
m_dlist
)
Undraw
();
m_dlist
=
dl
;
if
(
m_dlist
)
Draw
();
}
// copy data from another poly, but don't draw it
//
void
CPolyLine
::
Copy
(
CPolyLine
*
src
)
{
Undraw
();
m_dlist
=
src
->
m_dlist
;
m_sel_box
=
src
->
m_sel_box
;
// copy corners
for
(
unsigned
i
=
0
;
i
<
src
->
corner
.
size
();
i
++
)
corner
.
push_back
(
src
->
corner
[
i
]);
// copy side styles
int
nsides
=
src
->
GetNumSides
();
side_style
.
SetSize
(
nsides
);
for
(
int
i
=
0
;
i
<
nsides
;
i
++
)
side_style
[
i
]
=
src
->
side_style
[
i
];
// don't copy the Gpc_poly, just clear the old one
FreeGpcPoly
();
}
void
CPolyLine
::
MoveOrigin
(
int
x_off
,
int
y_off
)
{
Undraw
();
for
(
int
ic
=
0
;
ic
<
GetNumCorners
();
ic
++
)
{
SetX
(
ic
,
GetX
(
ic
)
+
x_off
);
SetY
(
ic
,
GetY
(
ic
)
+
y_off
);
}
Draw
();
}
// Set various parameters:
// the calling function should Undraw() before calling them,
// and Draw() after
//
void
CPolyLine
::
SetX
(
int
ic
,
int
x
)
{
corner
[
ic
].
x
=
x
;
}
void
CPolyLine
::
SetY
(
int
ic
,
int
y
)
{
corner
[
ic
].
y
=
y
;
}
void
CPolyLine
::
SetEndContour
(
int
ic
,
BOOL
end_contour
)
{
corner
[
ic
].
end_contour
=
end_contour
;
}
// Create CPolyLine for a pad
//
CPolyLine
*
CPolyLine
::
MakePolylineForPad
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
)
{
CPolyLine
*
poly
=
new
CPolyLine
;
int
dx
=
l
/
2
;
int
dy
=
w
/
2
;
if
(
angle
%
180
==
90
)
{
dx
=
w
/
2
;
dy
=
l
/
2
;
}
if
(
type
==
PAD_ROUND
)
{
poly
->
Start
(
0
,
0
,
0
,
x
-
dx
,
y
,
0
);
poly
->
AppendCorner
(
x
,
y
+
dy
,
ARC_CW
,
0
);
poly
->
AppendCorner
(
x
+
dx
,
y
,
ARC_CW
,
0
);
poly
->
AppendCorner
(
x
,
y
-
dy
,
ARC_CW
,
0
);
poly
->
Close
(
ARC_CW
);
}
return
poly
;
}
// Add cutout for a pad
// Convert arcs to multiple straight lines
// Do NOT draw or undraw
//
void
CPolyLine
::
AddContourForPadClearance
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
,
int
fill_clearance
,
int
hole_w
,
int
hole_clearance
,
BOOL
bThermal
,
int
spoke_w
)
{
int
dx
=
l
/
2
;
int
dy
=
w
/
2
;
if
(
angle
%
180
==
90
)
{
dx
=
w
/
2
;
dy
=
l
/
2
;
}
int
x_clearance
=
max
(
fill_clearance
,
hole_clearance
+
hole_w
/
2
-
dx
);
int
y_clearance
=
max
(
fill_clearance
,
hole_clearance
+
hole_w
/
2
-
dy
);
dx
+=
x_clearance
;
dy
+=
y_clearance
;
if
(
!
bThermal
)
{
// normal clearance
if
(
type
==
PAD_ROUND
||
(
type
==
PAD_NONE
&&
hole_w
>
0
)
)
{
AppendCorner
(
x
-
dx
,
y
,
ARC_CW
,
0
);
AppendCorner
(
x
,
y
+
dy
,
ARC_CW
,
0
);
AppendCorner
(
x
+
dx
,
y
,
ARC_CW
,
0
);
AppendCorner
(
x
,
y
-
dy
,
ARC_CW
,
0
);
Close
(
ARC_CW
);
}
else
if
(
type
==
PAD_SQUARE
||
type
==
PAD_RECT
||
type
==
PAD_RRECT
||
type
==
PAD_OVAL
)
{
AppendCorner
(
x
-
dx
,
y
-
dy
,
STRAIGHT
,
0
);
AppendCorner
(
x
+
dx
,
y
-
dy
,
STRAIGHT
,
0
);
AppendCorner
(
x
+
dx
,
y
+
dy
,
STRAIGHT
,
0
);
AppendCorner
(
x
-
dx
,
y
+
dy
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
}
}
else
{
// thermal relief
if
(
type
==
PAD_ROUND
||
(
type
==
PAD_NONE
&&
hole_w
>
0
)
)
{
// draw 4 "wedges"
double
r
=
max
(
w
/
2
+
fill_clearance
,
hole_w
/
2
+
hole_clearance
);
double
start_angle
=
asin
(
spoke_w
/
(
2.0
*
r
)
);
double
th1
,
th2
,
corner_x
,
corner_y
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
if
(
i
==
0
)
{
corner_x
=
spoke_w
/
2
;
corner_y
=
spoke_w
/
2
;
th1
=
start_angle
;
th2
=
pi
/
2.0
-
start_angle
;
}
else
if
(
i
==
1
)
{
corner_x
=
-
spoke_w
/
2
;
corner_y
=
spoke_w
/
2
;
th1
=
pi
/
2.0
+
start_angle
;
th2
=
pi
-
start_angle
;
}
else
if
(
i
==
2
)
{
corner_x
=
-
spoke_w
/
2
;
corner_y
=
-
spoke_w
/
2
;
th1
=
-
pi
+
start_angle
;
th2
=
-
pi
/
2.0
-
start_angle
;
}
else
if
(
i
==
3
)
{
corner_x
=
spoke_w
/
2
;
corner_y
=
-
spoke_w
/
2
;
th1
=
-
pi
/
2.0
+
start_angle
;
th2
=
-
start_angle
;
}
AppendCorner
(
to_int
(
x
+
corner_x
),
to_int
(
y
+
corner_y
),
STRAIGHT
,
0
);
AppendCorner
(
to_int
(
x
+
r
*
cos
(
th1
)),
to_int
(
y
+
r
*
sin
(
th1
)),
STRAIGHT
,
0
);
AppendCorner
(
to_int
(
x
+
r
*
cos
(
th2
)),
to_int
(
y
+
r
*
sin
(
th2
)),
ARC_CCW
,
0
);
Close
(
STRAIGHT
);
}
}
else
if
(
type
==
PAD_SQUARE
||
type
==
PAD_RECT
||
type
==
PAD_RRECT
||
type
==
PAD_OVAL
)
{
// draw 4 rectangles
int
xL
=
x
-
dx
;
int
xR
=
x
-
spoke_w
/
2
;
int
yB
=
y
-
dy
;
int
yT
=
y
-
spoke_w
/
2
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
xL
=
x
+
spoke_w
/
2
;
xR
=
x
+
dx
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
xL
=
x
-
dx
;
xR
=
x
-
spoke_w
/
2
;
yB
=
y
+
spoke_w
/
2
;
yT
=
y
+
dy
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
xL
=
x
+
spoke_w
/
2
;
xR
=
x
+
dx
;
AppendCorner
(
xL
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yB
,
STRAIGHT
,
0
);
AppendCorner
(
xR
,
yT
,
STRAIGHT
,
0
);
AppendCorner
(
xL
,
yT
,
STRAIGHT
,
0
);
Close
(
STRAIGHT
);
}
}
return
;
}
void
CPolyLine
::
AppendArc
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
xc
,
int
yc
,
int
num
)
{
// get radius
double
r
=
sqrt
(
(
double
)(
xi
-
xc
)
*
(
xi
-
xc
)
+
(
double
)(
yi
-
yc
)
*
(
yi
-
yc
)
);
// get angles of start and finish
double
th_i
=
atan2
(
(
double
)
yi
-
yc
,
(
double
)
xi
-
xc
);
double
th_f
=
atan2
(
(
double
)
yf
-
yc
,
(
double
)
xf
-
xc
);
double
th_d
=
(
th_f
-
th_i
)
/
(
num
-
1
);
double
theta
=
th_i
;
// generate arc
for
(
int
ic
=
0
;
ic
<
num
;
ic
++
)
{
int
x
=
to_int
(
xc
+
r
*
cos
(
theta
));
int
y
=
to_int
(
yc
+
r
*
sin
(
theta
));
AppendCorner
(
x
,
y
,
STRAIGHT
,
0
);
theta
+=
th_d
;
}
Close
(
STRAIGHT
);
}
void
CPolyLine
::
ClipGpcPolygon
(
gpc_op
op
,
CPolyLine
*
clip_poly
)
{
gpc_polygon
*
result
=
new
gpc_polygon
;
gpc_polygon_clip
(
op
,
m_gpc_poly
,
clip_poly
->
GetGpcPoly
(),
result
);
gpc_free_polygon
(
m_gpc_poly
);
delete
m_gpc_poly
;
m_gpc_poly
=
result
;
}
polygon/PolyLine.h
View file @
e126042b
// PolyLine.h ... definition of CPolyLine class
//
// A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles
// There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of
// each contour.
//
// When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper.
//
// If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE_H
#define POLYLINE_H
#include <vector>
#include "defs-macros.h"
#include "GenericPolygonClipperLibrary.h"
#include "php_polygon.h"
#include "php_polygon_vertex.h"
#include "PolyLine2Kicad.h"
#include "freepcb_ids.h"
#include "freepcbDisplayList.h"
#include "math_for_graphics.h"
class
CSegment
{
public
:
int
xi
,
yi
,
xf
,
yf
;
CSegment
()
{};
CSegment
(
int
x0
,
int
y0
,
int
x1
,
int
y1
)
{
xi
=
x0
;
yi
=
y0
;
xf
=
x1
;
yf
=
y1
;
}
};
class
CArc
{
public
:
enum
{
MAX_STEP
=
50
*
25400
};
// max step is 20 mils
enum
{
MIN_STEPS
=
18
};
// min step is 5 degrees
int
style
;
int
xi
,
yi
,
xf
,
yf
;
int
n_steps
;
// number of straight-line segments in gpc_poly
BOOL
bFound
;
};
class
CPolyPt
{
public
:
CPolyPt
(
int
qx
=
0
,
int
qy
=
0
,
BOOL
qf
=
FALSE
)
{
x
=
qx
;
y
=
qy
;
end_contour
=
qf
;
utility
=
0
;
};
int
x
;
int
y
;
BOOL
end_contour
;
int
utility
;
};
class
CPolyLine
{
public
:
enum
{
STRAIGHT
,
ARC_CW
,
ARC_CCW
};
// side styles
enum
{
NO_HATCH
,
DIAGONAL_FULL
,
DIAGONAL_EDGE
};
// hatch styles
enum
{
DEF_SIZE
=
50
,
DEF_ADD
=
50
};
// number of array elements to add at a time
// constructors/destructor
CPolyLine
(
CDisplayList
*
dl
);
CPolyLine
();
~
CPolyLine
();
// functions for modifying polyline
void
Start
(
int
layer
,
int
w
,
int
sel_box
,
int
x
,
int
y
,
int
hatch
);
void
AppendCorner
(
int
x
,
int
y
,
int
style
=
STRAIGHT
,
BOOL
bDraw
=
TRUE
);
void
InsertCorner
(
int
ic
,
int
x
,
int
y
);
void
DeleteCorner
(
int
ic
,
BOOL
bDraw
=
TRUE
);
void
MoveCorner
(
int
ic
,
int
x
,
int
y
);
void
Close
(
int
style
=
STRAIGHT
,
BOOL
bDraw
=
TRUE
);
void
RemoveContour
(
int
icont
);
// drawing functions
void
HighlightSide
(
int
is
);
void
HighlightCorner
(
int
ic
);
void
StartDraggingToInsertCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
);
void
StartDraggingToMoveCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
);
void
CancelDraggingToInsertCorner
(
int
ic
);
void
CancelDraggingToMoveCorner
(
int
ic
);
void
Undraw
();
void
Draw
(
CDisplayList
*
dl
=
NULL
);
void
Hatch
();
void
MakeVisible
(
BOOL
visible
=
TRUE
);
void
MoveOrigin
(
int
x_off
,
int
y_off
);
// misc. functions
CRect
GetBounds
();
CRect
GetCornerBounds
();
CRect
GetCornerBounds
(
int
icont
);
void
Copy
(
CPolyLine
*
src
);
BOOL
TestPointInside
(
int
x
,
int
y
);
BOOL
TestPointInsideContour
(
int
icont
,
int
x
,
int
y
);
int
TestIntersection
(
CPolyLine
*
poly
);
void
AppendArc
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
xc
,
int
yc
,
int
num
);
// access functions
int
GetNumCorners
();
int
GetNumSides
();
int
GetClosed
();
int
GetNumContours
();
int
GetContour
(
int
ic
);
int
GetContourStart
(
int
icont
);
int
GetContourEnd
(
int
icont
);
int
GetContourSize
(
int
icont
);
int
GetX
(
int
ic
);
int
GetY
(
int
ic
);
int
GetEndContour
(
int
ic
);
int
GetUtility
(
int
ic
){
return
corner
[
ic
].
utility
;
};
void
SetUtility
(
int
ic
,
int
utility
){
corner
[
ic
].
utility
=
utility
;
};
int
GetW
();
int
GetSideStyle
(
int
is
);
id
GetId
();
int
GetSelBoxSize
();
CDisplayList
*
GetDisplayList
(){
return
m_dlist
;
};
int
GetHatch
(){
return
m_HatchStyle
;
}
void
SetHatch
(
int
hatch
){
Undraw
();
m_HatchStyle
=
hatch
;
Draw
();
};
void
SetX
(
int
ic
,
int
x
);
void
SetY
(
int
ic
,
int
y
);
void
SetEndContour
(
int
ic
,
BOOL
end_contour
);
// void SetLayer( int layer );
void
SetW
(
int
w
);
void
SetSideStyle
(
int
is
,
int
style
);
void
SetSelBoxSize
(
int
sel_box
);
void
SetDisplayList
(
CDisplayList
*
dl
);
// GPC functions
int
MakeGpcPoly
(
int
icontour
=
0
,
std
::
vector
<
CArc
>
*
arc_array
=
NULL
);
int
FreeGpcPoly
();
gpc_polygon
*
GetGpcPoly
(){
return
m_gpc_poly
;
};
int
NormalizeWithGpc
(
std
::
vector
<
CPolyLine
*>
*
pa
=
NULL
,
BOOL
bRetainArcs
=
FALSE
);
int
RestoreArcs
(
std
::
vector
<
CArc
>
*
arc_array
,
std
::
vector
<
CPolyLine
*>
*
pa
=
NULL
);
CPolyLine
*
MakePolylineForPad
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
);
void
AddContourForPadClearance
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
,
int
fill_clearance
,
int
hole_w
,
int
hole_clearance
,
BOOL
bThermal
=
FALSE
,
int
spoke_w
=
0
);
void
ClipGpcPolygon
(
gpc_op
op
,
CPolyLine
*
poly
);
// PHP functions
int
MakePhpPoly
();
void
FreePhpPoly
();
void
ClipPhpPolygon
(
int
php_op
,
CPolyLine
*
poly
);
private
:
CDisplayList
*
m_dlist
;
// display list
int
m_layer
;
// layer to draw on
int
m_Width
;
// line width
int
m_sel_box
;
// corner selection box width/2
public
:
std
::
vector
<
CPolyPt
>
corner
;
// array of points for corners
std
::
vector
<
int
>
side_style
;
// array of styles for sides
private
:
std
::
vector
<
dl_element
*>
dl_side
;
// graphic elements
std
::
vector
<
dl_element
*>
dl_side_sel
;
std
::
vector
<
dl_element
*>
dl_corner_sel
;
public
:
int
m_HatchStyle
;
// hatch style, see enum above
std
::
vector
<
CSegment
>
m_HatchLines
;
// hatch lines
private
:
gpc_polygon
*
m_gpc_poly
;
// polygon in gpc format
polygon
*
m_php_poly
;
BOOL
bDrawn
;
};
#endif // #ifndef POLYLINE_H
// PolyLine.h ... definition of CPolyLine class
//
// A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles
// There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of
// each contour.
//
// When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper.
//
// If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE_H
#define POLYLINE_H
#include <vector>
#include "defs-macros.h"
#include "GenericPolygonClipperLibrary.h"
#include "php_polygon.h"
#include "php_polygon_vertex.h"
#include "PolyLine2Kicad.h"
#include "freepcb_ids.h"
#include "freepcbDisplayList.h"
#include "math_for_graphics.h"
class
CSegment
{
public
:
int
xi
,
yi
,
xf
,
yf
;
CSegment
()
{};
CSegment
(
int
x0
,
int
y0
,
int
x1
,
int
y1
)
{
xi
=
x0
;
yi
=
y0
;
xf
=
x1
;
yf
=
y1
;
}
};
class
CArc
{
public
:
enum
{
MAX_STEP
=
50
*
25400
};
// max step is 20 mils
enum
{
MIN_STEPS
=
18
};
// min step is 5 degrees
int
style
;
int
xi
,
yi
,
xf
,
yf
;
int
n_steps
;
// number of straight-line segments in gpc_poly
BOOL
bFound
;
};
class
CPolyPt
{
public
:
CPolyPt
(
int
qx
=
0
,
int
qy
=
0
,
BOOL
qf
=
FALSE
)
{
x
=
qx
;
y
=
qy
;
end_contour
=
qf
;
utility
=
0
;
};
int
x
;
int
y
;
BOOL
end_contour
;
int
utility
;
};
class
CPolyLine
{
public
:
enum
{
STRAIGHT
,
ARC_CW
,
ARC_CCW
};
// side styles
enum
{
NO_HATCH
,
DIAGONAL_FULL
,
DIAGONAL_EDGE
};
// hatch styles
enum
{
DEF_SIZE
=
50
,
DEF_ADD
=
50
};
// number of array elements to add at a time
// constructors/destructor
CPolyLine
(
CDisplayList
*
dl
);
CPolyLine
();
~
CPolyLine
();
// functions for modifying polyline
void
Start
(
int
layer
,
int
w
,
int
sel_box
,
int
x
,
int
y
,
int
hatch
);
void
AppendCorner
(
int
x
,
int
y
,
int
style
=
STRAIGHT
,
BOOL
bDraw
=
TRUE
);
void
InsertCorner
(
int
ic
,
int
x
,
int
y
);
void
DeleteCorner
(
int
ic
,
BOOL
bDraw
=
TRUE
);
void
MoveCorner
(
int
ic
,
int
x
,
int
y
);
void
Close
(
int
style
=
STRAIGHT
,
BOOL
bDraw
=
TRUE
);
void
RemoveContour
(
int
icont
);
// drawing functions
void
HighlightSide
(
int
is
);
void
HighlightCorner
(
int
ic
);
void
StartDraggingToInsertCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
);
void
StartDraggingToMoveCorner
(
CDC
*
pDC
,
int
ic
,
int
x
,
int
y
);
void
CancelDraggingToInsertCorner
(
int
ic
);
void
CancelDraggingToMoveCorner
(
int
ic
);
void
Undraw
();
void
Draw
(
CDisplayList
*
dl
=
NULL
);
void
Hatch
();
void
MakeVisible
(
BOOL
visible
=
TRUE
);
void
MoveOrigin
(
int
x_off
,
int
y_off
);
// misc. functions
CRect
GetBounds
();
CRect
GetCornerBounds
();
CRect
GetCornerBounds
(
int
icont
);
void
Copy
(
CPolyLine
*
src
);
BOOL
TestPointInside
(
int
x
,
int
y
);
BOOL
TestPointInsideContour
(
int
icont
,
int
x
,
int
y
);
int
TestIntersection
(
CPolyLine
*
poly
);
void
AppendArc
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
xc
,
int
yc
,
int
num
);
// access functions
int
GetNumCorners
();
int
GetNumSides
();
int
GetClosed
();
int
GetNumContours
();
int
GetContour
(
int
ic
);
int
GetContourStart
(
int
icont
);
int
GetContourEnd
(
int
icont
);
int
GetContourSize
(
int
icont
);
int
GetX
(
int
ic
);
int
GetY
(
int
ic
);
int
GetEndContour
(
int
ic
);
int
GetUtility
(
int
ic
){
return
corner
[
ic
].
utility
;
};
void
SetUtility
(
int
ic
,
int
utility
){
corner
[
ic
].
utility
=
utility
;
};
int
GetW
();
int
GetSideStyle
(
int
is
);
id
GetId
();
int
GetSelBoxSize
();
CDisplayList
*
GetDisplayList
(){
return
m_dlist
;
};
int
GetHatch
(){
return
m_HatchStyle
;
}
void
SetHatch
(
int
hatch
){
Undraw
();
m_HatchStyle
=
hatch
;
Draw
();
};
void
SetX
(
int
ic
,
int
x
);
void
SetY
(
int
ic
,
int
y
);
void
SetEndContour
(
int
ic
,
BOOL
end_contour
);
// void SetLayer( int layer );
void
SetW
(
int
w
);
void
SetSideStyle
(
int
is
,
int
style
);
void
SetSelBoxSize
(
int
sel_box
);
void
SetDisplayList
(
CDisplayList
*
dl
);
// GPC functions
int
MakeGpcPoly
(
int
icontour
=
0
,
std
::
vector
<
CArc
>
*
arc_array
=
NULL
);
int
FreeGpcPoly
();
gpc_polygon
*
GetGpcPoly
(){
return
m_gpc_poly
;
};
int
NormalizeWithGpc
(
std
::
vector
<
CPolyLine
*>
*
pa
=
NULL
,
BOOL
bRetainArcs
=
FALSE
);
int
RestoreArcs
(
std
::
vector
<
CArc
>
*
arc_array
,
std
::
vector
<
CPolyLine
*>
*
pa
=
NULL
);
CPolyLine
*
MakePolylineForPad
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
);
void
AddContourForPadClearance
(
int
type
,
int
x
,
int
y
,
int
w
,
int
l
,
int
r
,
int
angle
,
int
fill_clearance
,
int
hole_w
,
int
hole_clearance
,
BOOL
bThermal
=
FALSE
,
int
spoke_w
=
0
);
void
ClipGpcPolygon
(
gpc_op
op
,
CPolyLine
*
poly
);
// PHP functions
int
MakePhpPoly
();
void
FreePhpPoly
();
void
ClipPhpPolygon
(
int
php_op
,
CPolyLine
*
poly
);
private
:
CDisplayList
*
m_dlist
;
// display list
int
m_layer
;
// layer to draw on
int
m_Width
;
// line width
int
m_sel_box
;
// corner selection box width/2
public
:
std
::
vector
<
CPolyPt
>
corner
;
// array of points for corners
std
::
vector
<
int
>
side_style
;
// array of styles for sides
private
:
std
::
vector
<
dl_element
*>
dl_side
;
// graphic elements
std
::
vector
<
dl_element
*>
dl_side_sel
;
std
::
vector
<
dl_element
*>
dl_corner_sel
;
public
:
int
m_HatchStyle
;
// hatch style, see enum above
std
::
vector
<
CSegment
>
m_HatchLines
;
// hatch lines
private
:
gpc_polygon
*
m_gpc_poly
;
// polygon in gpc format
polygon
*
m_php_poly
;
BOOL
bDrawn
;
};
#endif // #ifndef POLYLINE_H
polygon/PolyLine2Kicad.h
View file @
e126042b
// PolyLine.h ... definition of CPolyLine class
//
// A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles
// There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of
// each contour.
//
// When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper.
//
// If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE2KICAD_H
#define POLYLINE2KICAD_H
#define PCBU_PER_MIL 10
#define MAX_LAYERS 32
#define NM_PER_MIL 10 // 25400
// pad shapes
enum
{
PAD_NONE
=
0
,
PAD_ROUND
,
PAD_SQUARE
,
PAD_RECT
,
PAD_RRECT
,
PAD_OVAL
,
PAD_OCTAGON
};
/*
enum
{
// visible layers
LAY_SELECTION = 0,
LAY_BACKGND,
LAY_VISIBLE_GRID,
LAY_HILITE,
LAY_DRC_ERROR,
LAY_BOARD_OUTLINE,
LAY_RAT_LINE,
LAY_SILK_TOP,
LAY_SILK_BOTTOM,
LAY_SM_TOP,
LAY_SM_BOTTOM,
LAY_PAD_THRU,
LAY_TOP_COPPER,
LAY_BOTTOM_COPPER,
// invisible layers
LAY_MASK_TOP = -100,
LAY_MASK_BOTTOM = -101,
LAY_PASTE_TOP = -102,
LAY_PASTE_BOTTOM = -103
};
*/
#define LAY_SELECTION 0
#define LAY_TOP_COPPER 0
#define CDC wxDC
class
wxDC
;
#if 0
class dl_element;
class CDisplayList {
public:
void Set_visible(void*, int) {};
int Get_x(void) { return 0;};
int Get_y(void) { return 0;};
void StopDragging(void) {};
void CancelHighLight(void) {};
void StartDraggingLineVertex(...) {};
void Add() {};
};
#endif
class
CRect
{
public
:
int
left
,
right
,
top
,
bottom
;
};
class
CPoint
{
public
:
int
x
,
y
;
public
:
CPoint
(
void
)
{
x
=
y
=
0
;};
CPoint
(
int
i
,
int
j
)
{
x
=
i
;
y
=
j
;};
};
#endif // #ifndef POLYLINE2KICAD_H
// PolyLine.h ... definition of CPolyLine class
//
// A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles
// There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of
// each contour.
//
// When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper.
//
// If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE2KICAD_H
#define POLYLINE2KICAD_H
#define PCBU_PER_MIL 10
#define MAX_LAYERS 32
#define NM_PER_MIL 10 // 25400
// pad shapes
enum
{
PAD_NONE
=
0
,
PAD_ROUND
,
PAD_SQUARE
,
PAD_RECT
,
PAD_RRECT
,
PAD_OVAL
,
PAD_OCTAGON
};
/*
enum
{
// visible layers
LAY_SELECTION = 0,
LAY_BACKGND,
LAY_VISIBLE_GRID,
LAY_HILITE,
LAY_DRC_ERROR,
LAY_BOARD_OUTLINE,
LAY_RAT_LINE,
LAY_SILK_TOP,
LAY_SILK_BOTTOM,
LAY_SM_TOP,
LAY_SM_BOTTOM,
LAY_PAD_THRU,
LAY_TOP_COPPER,
LAY_BOTTOM_COPPER,
// invisible layers
LAY_MASK_TOP = -100,
LAY_MASK_BOTTOM = -101,
LAY_PASTE_TOP = -102,
LAY_PASTE_BOTTOM = -103
};
*/
#define LAY_SELECTION 0
#define LAY_TOP_COPPER 0
#define CDC wxDC
class
wxDC
;
#if 0
class dl_element;
class CDisplayList {
public:
void Set_visible(void*, int) {};
int Get_x(void) { return 0;};
int Get_y(void) { return 0;};
void StopDragging(void) {};
void CancelHighLight(void) {};
void StartDraggingLineVertex(...) {};
void Add() {};
};
#endif
class
CRect
{
public
:
int
left
,
right
,
top
,
bottom
;
};
class
CPoint
{
public
:
int
x
,
y
;
public
:
CPoint
(
void
)
{
x
=
y
=
0
;};
CPoint
(
int
i
,
int
j
)
{
x
=
i
;
y
=
j
;};
};
#endif // #ifndef POLYLINE2KICAD_H
polygon/cdisplaylist_stuff.cpp
View file @
e126042b
/* stuff for class CDisplayList */
#include "PolyLine.h"
dl_element
*
CDisplayList
::
Add
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
,
int
orig_layer
)
{
return
NULL
;
}
dl_element
*
CDisplayList
::
AddSelector
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
)
{
return
NULL
;
}
void
CDisplayList
::
Set_visible
(
dl_element
*
el
,
int
visible
)
{
}
int
CDisplayList
::
StopDragging
()
{
return
0
;
}
int
CDisplayList
::
CancelHighLight
()
{
return
0
;
}
void
CDisplayList
::
Set_id
(
dl_element
*
el
,
id
*
id
)
{
}
id
CDisplayList
::
Remove
(
dl_element
*
element
)
{
return
0
;
}
int
CDisplayList
::
Get_w
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_x
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_y
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_xf
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_yf
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
HighLight
(
int
gtype
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
w
,
int
orig_layer
)
{
return
0
;
}
int
CDisplayList
::
StartDraggingLineVertex
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
layer1
,
int
layer2
,
int
w1
,
int
w2
,
int
style1
,
int
style2
,
int
layer_no_via
,
int
via_w
,
int
via_holew
,
int
dir
,
int
crosshair
)
{
return
0
;
}
int
CDisplayList
::
StartDraggingArc
(
CDC
*
pDC
,
int
style
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
layer
,
int
w
,
int
crosshair
)
{
return
0
;
}
/* stuff for class CDisplayList */
#include "PolyLine.h"
dl_element
*
CDisplayList
::
Add
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
,
int
orig_layer
)
{
return
NULL
;
}
dl_element
*
CDisplayList
::
AddSelector
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
)
{
return
NULL
;
}
void
CDisplayList
::
Set_visible
(
dl_element
*
el
,
int
visible
)
{
}
int
CDisplayList
::
StopDragging
()
{
return
0
;
}
int
CDisplayList
::
CancelHighLight
()
{
return
0
;
}
void
CDisplayList
::
Set_id
(
dl_element
*
el
,
id
*
id
)
{
}
id
CDisplayList
::
Remove
(
dl_element
*
element
)
{
return
0
;
}
int
CDisplayList
::
Get_w
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_x
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_y
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_xf
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
Get_yf
(
dl_element
*
el
)
{
return
0
;
}
int
CDisplayList
::
HighLight
(
int
gtype
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
w
,
int
orig_layer
)
{
return
0
;
}
int
CDisplayList
::
StartDraggingLineVertex
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
layer1
,
int
layer2
,
int
w1
,
int
w2
,
int
style1
,
int
style2
,
int
layer_no_via
,
int
via_w
,
int
via_holew
,
int
dir
,
int
crosshair
)
{
return
0
;
}
int
CDisplayList
::
StartDraggingArc
(
CDC
*
pDC
,
int
style
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
layer
,
int
w
,
int
crosshair
)
{
return
0
;
}
polygon/freepcbDisplayList.h
View file @
e126042b
// DisplayList.h : header file for CDisplayList class
//
#ifndef FP_DISPLAY_LIST_H
#define FP_DISPLAY_LIST_H
//#define DL_MAX_LAYERS 32
#define DL_MAGIC 2674
#define PCBU_PER_WU 25400 // conversion from PCB units to world units
// graphics element types
enum
{
DL_NONE
=
0
,
DL_LINE
,
// line segment with round end-caps
DL_CIRC
,
// filled circle
DL_HOLLOW_CIRC
,
// circle outline
DL_DONUT
,
// annulus
DL_SQUARE
,
// filled square
DL_RECT
,
// filled rectangle
DL_RRECT
,
// filled rounded rectangle
DL_OVAL
,
// filled oval
DL_OCTAGON
,
// filled octagon
DL_HOLE
,
// hole, shown as circle
DL_HOLLOW_RECT
,
// rectangle outline
DL_RECT_X
,
// rectangle outline with X
DL_POINT
,
// shape to highlight a point
DL_ARC_CW
,
// arc with clockwise curve
DL_ARC_CCW
,
// arc with counter-clockwise curve
DL_X
// X
};
// dragging line shapes
enum
{
DS_NONE
=
0
,
DS_LINE_VERTEX
,
// vertex between two lines
DS_LINE
,
// line
DS_ARC_STRAIGHT
,
// straight line (used when drawing polylines)
DS_ARC_CW
,
// clockwise arc (used when drawing polylines)
DS_ARC_CCW
// counterclockwise arc (used when drawing polylines)
};
// styles of line segment when dragging line or line vertex
enum
{
DSS_STRAIGHT
=
100
,
// straight line
DSS_ARC_CW
,
// clockwise arc
DSS_ARC_CCW
// counterclockwise arc
};
// inflection modes for DS_LINE and DS_LINE_VERTEX
enum
{
IM_NONE
=
0
,
IM_90_45
,
IM_45_90
,
IM_90
};
class
CDisplayList
;
// this structure contains an element of the display list
class
dl_element
{
friend
class
CDisplayList
;
public
:
CDisplayList
*
dlist
;
int
magic
;
dl_element
*
prev
;
dl_element
*
next
;
id
m_id
;
// identifier (see ids.h)
void
*
ptr
;
// pointer to object drawing this element
int
gtype
;
// type of primitive
int
visible
;
// 0 to hide
//private:
int
sel_vert
;
// for selection rectangles, 1 if part is vertical
int
w
;
// width (for round or square shapes)
int
holew
;
// hole width (for round holes)
int
x_org
,
y_org
;
// x origin (for rotation, reflection, etc.)
int
x
,
y
;
// starting or center position of element
int
xf
,
yf
;
// opposite corner (for rectangle or line)
int
radius
;
// radius of corners for DL_RRECT
int
layer
;
// layer to draw on
int
orig_layer
;
// for elements on highlight layer,
// the original layer, the highlight will
// only be drawn if this layer is visible
};
class
CDisplayList
{
private
:
// display-list parameters for each layer
dl_element
m_start
[
MAX_LAYERS
],
m_end
[
MAX_LAYERS
];
int
m_rgb
[
MAX_LAYERS
][
3
];
// layer colors
BOOL
m_vis
[
MAX_LAYERS
];
// layer visibility flags
int
m_layer_in_order
[
MAX_LAYERS
];
// array of layers in draw order
int
m_order_for_layer
[
MAX_LAYERS
];
// draw order for each layer
// window parameters
int
m_pcbu_per_wu
;
// i.e. nm per world unit
CRect
m_client_r
;
// client rect (pixels)
CRect
m_screen_r
;
// client rect (screen coords)
int
m_pane_org_x
;
// left border of drawing pane (pixels)
int
m_pane_org_y
;
// bottom border of drawing pane (pixels)
int
m_bottom_pane_h
;
// height of bottom pane
CDC
*
memDC
;
// pointer to memory DC
double
m_scale
;
// world units per pixel
int
m_org_x
;
// world x-coord of left side of screen (world units)
int
m_org_y
;
// world y-coord of bottom of screen (world units)
int
m_max_x
;
// world x_coord of right side of screen (world units)
int
m_max_y
;
// world y_coord of top of screen (world units)
int
w_ext_x
,
w_ext_y
;
// window extents (world units)
int
v_ext_x
,
v_ext_y
;
// viewport extents (pixels)
double
m_wu_per_pixel_x
;
// ratio w_ext_x/v_ext_x (world units per pixel)
double
m_wu_per_pixel_y
;
// ratio w_ext_y/v_ext_y (world units per pixel)
double
m_pcbu_per_pixel_x
;
double
m_pcbu_per_pixel_y
;
// general dragging parameters
int
m_drag_angle
;
// angle of rotation of selection rectangle (starts at 0)
int
m_drag_side
;
// 0 = no change, 1 = switch to opposite
int
m_drag_vert
;
// 1 if item being dragged is a vertical part
// parameters for dragging polyline sides and trace segments
// that can be modified while dragging
int
m_drag_flag
;
// 1 if dragging something
int
m_drag_shape
;
// shape
int
m_last_drag_shape
;
// last shape drawn
int
m_drag_x
;
// last cursor position for dragged shape
int
m_drag_y
;
int
m_drag_xi
;
// start of rubberband drag line
int
m_drag_yi
;
int
m_drag_xf
;
// end of rubberband drag line
int
m_drag_yf
;
int
m_drag_layer_1
;
// line layer
int
m_drag_w1
;
// line width
int
m_drag_style1
;
// line style
int
m_inflection_mode
;
// inflection mode
int
m_last_inflection_mode
;
// last mode drawn
// extra parameters when dragging vertex between 2 line segments
int
m_drag_style2
;
int
m_drag_layer_2
;
int
m_drag_w2
;
// parameters used to draw leading via if necessary
int
m_drag_layer_no_via
;
int
m_drag_via_w
;
int
m_drag_via_holew
;
int
m_drag_via_drawn
;
// arrays of lines and ratlines being dragged
// these can be rotated and flipped while being dragged
int
m_drag_layer
;
// layer
int
m_drag_max_lines
;
// max size of array for line segments
int
m_drag_num_lines
;
// number of line segments to drag
CPoint
*
m_drag_line_pt
;
// array of relative coords for line endpoints
int
m_drag_max_ratlines
;
// max size of ratline array
int
m_drag_num_ratlines
;
// number of ratlines to drag
CPoint
*
m_drag_ratline_start_pt
;
// absolute coords for ratline start points
CPoint
*
m_drag_ratline_end_pt
;
// relative coords for ratline endpoints
int
m_drag_ratline_width
;
// cursor parameters
int
m_cross_hairs
;
// 0 = none, 1 = cross-hairs, 2 = diagonals
CPoint
m_cross_left
,
m_cross_right
,
m_cross_top
,
m_cross_bottom
;
// end-points
CPoint
m_cross_topleft
,
m_cross_topright
,
m_cross_botleft
,
m_cross_botright
;
// grid
int
m_visual_grid_on
;
double
m_visual_grid_spacing
;
// in world units
public
:
CDisplayList
(
int
pcbu_per_wu
);
~
CDisplayList
();
void
SetVisibleGrid
(
BOOL
on
,
double
grid
);
void
SetMapping
(
CRect
*
client_r
,
CRect
*
screen_r
,
int
pane_org_x
,
int
pane_bottom_h
,
double
scale
,
int
org_x
,
int
org_y
);
void
SetDCToWorldCoords
(
CDC
*
pDC
,
CDC
*
mDC
,
int
pcbu_org_x
,
int
pcbu_org_y
);
void
SetLayerRGB
(
int
layer
,
int
r
,
int
g
,
int
b
);
void
SetLayerVisible
(
int
layer
,
BOOL
vis
);
void
SetLayerDrawOrder
(
int
layer
,
int
order
)
{
m_layer_in_order
[
order
]
=
layer
;
m_order_for_layer
[
layer
]
=
order
;
};
dl_element
*
Add
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
=
0
,
int
orig_layer
=
LAY_SELECTION
);
dl_element
*
AddSelector
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
=
0
);
void
RemoveAll
();
void
RemoveAllFromLayer
(
int
layer
);
id
Remove
(
dl_element
*
element
);
void
Draw
(
CDC
*
pDC
);
int
HighLight
(
int
gtype
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
w
,
int
orig_layer
=
LAY_SELECTION
);
int
CancelHighLight
();
void
*
TestSelect
(
int
x
,
int
y
,
id
*
sel_id
,
int
*
layer
,
id
*
exclude_id
=
NULL
,
void
*
exclude_ptr
=
NULL
,
id
*
include_id
=
NULL
,
int
n_include_ids
=
1
);
int
StartDraggingArray
(
CDC
*
pDC
,
int
x
,
int
y
,
int
vert
,
int
layer
,
int
crosshair
=
1
);
int
StartDraggingRatLine
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
layer
,
int
w
,
int
crosshair
=
1
);
int
StartDraggingRectangle
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
vert
,
int
layer
);
int
StartDraggingLineVertex
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
layer1
,
int
layer2
,
int
w1
,
int
w2
,
int
style1
,
int
style2
,
int
layer_no_via
,
int
via_w
,
int
via_holew
,
int
dir
,
int
crosshair
);
int
StartDraggingLine
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
layer1
,
int
w
,
int
layer_no_via
,
int
via_w
,
int
via_holew
,
int
crosshair
,
int
style
,
int
inflection_mode
);
int
StartDraggingArc
(
CDC
*
pDC
,
int
style
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
layer
,
int
w
,
int
crosshair
);
void
SetDragArcStyle
(
int
style
);
void
Drag
(
CDC
*
pDC
,
int
x
,
int
y
);
int
StopDragging
();
void
ChangeRoutingLayer
(
CDC
*
pDC
,
int
layer1
,
int
layer2
,
int
w
);
void
IncrementDragAngle
(
CDC
*
pDC
);
int
MakeDragLineArray
(
int
num_lines
);
int
MakeDragRatlineArray
(
int
num_ratlines
,
int
width
);
int
AddDragLine
(
CPoint
pi
,
CPoint
pf
);
int
AddDragRatline
(
CPoint
pi
,
CPoint
pf
);
int
GetDragAngle
();
void
FlipDragSide
(
CDC
*
pDC
);
int
GetDragSide
();
void
SetUpCrosshairs
(
int
type
,
int
x
,
int
y
);
void
SetInflectionMode
(
int
mode
){
m_inflection_mode
=
mode
;
};
CPoint
ScreenToPCB
(
CPoint
point
);
CPoint
PCBToScreen
(
CPoint
point
);
CPoint
WindowToPCB
(
CPoint
point
);
// set element parameters
void
Set_gtype
(
dl_element
*
el
,
int
gtype
);
void
Set_visible
(
dl_element
*
el
,
int
visible
);
void
Set_sel_vert
(
dl_element
*
el
,
int
sel_vert
);
void
Set_w
(
dl_element
*
el
,
int
w
);
void
Set_holew
(
dl_element
*
el
,
int
holew
);
void
Set_x_org
(
dl_element
*
el
,
int
x_org
);
void
Set_y_org
(
dl_element
*
el
,
int
y_org
);
void
Set_x
(
dl_element
*
el
,
int
x
);
void
Set_y
(
dl_element
*
el
,
int
y
);
void
Set_xf
(
dl_element
*
el
,
int
xf
);
void
Set_yf
(
dl_element
*
el
,
int
yf
);
void
Set_id
(
dl_element
*
el
,
id
*
id
);
void
Set_layer
(
dl_element
*
el
,
int
layer
);
void
Set_radius
(
dl_element
*
el
,
int
radius
);
void
Move
(
dl_element
*
el
,
int
dx
,
int
dy
);
// get element parameters
void
*
Get_ptr
(
dl_element
*
el
);
int
Get_gtype
(
dl_element
*
el
);
int
Get_visible
(
dl_element
*
el
);
int
Get_sel_vert
(
dl_element
*
el
);
int
Get_w
(
dl_element
*
el
);
int
Get_holew
(
dl_element
*
el
);
int
Get_x_org
(
dl_element
*
el
);
int
Get_y_org
(
dl_element
*
el
);
int
Get_x
(
dl_element
*
el
);
int
Get_y
(
dl_element
*
el
);
int
Get_xf
(
dl_element
*
el
);
int
Get_yf
(
dl_element
*
el
);
int
Get_radius
(
dl_element
*
el
);
int
Get_layer
(
dl_element
*
el
);
id
Get_id
(
dl_element
*
el
);
};
#endif // #ifndef FP_DISPLAY_LIST_H
// DisplayList.h : header file for CDisplayList class
//
#ifndef FP_DISPLAY_LIST_H
#define FP_DISPLAY_LIST_H
//#define DL_MAX_LAYERS 32
#define DL_MAGIC 2674
#define PCBU_PER_WU 25400 // conversion from PCB units to world units
// graphics element types
enum
{
DL_NONE
=
0
,
DL_LINE
,
// line segment with round end-caps
DL_CIRC
,
// filled circle
DL_HOLLOW_CIRC
,
// circle outline
DL_DONUT
,
// annulus
DL_SQUARE
,
// filled square
DL_RECT
,
// filled rectangle
DL_RRECT
,
// filled rounded rectangle
DL_OVAL
,
// filled oval
DL_OCTAGON
,
// filled octagon
DL_HOLE
,
// hole, shown as circle
DL_HOLLOW_RECT
,
// rectangle outline
DL_RECT_X
,
// rectangle outline with X
DL_POINT
,
// shape to highlight a point
DL_ARC_CW
,
// arc with clockwise curve
DL_ARC_CCW
,
// arc with counter-clockwise curve
DL_X
// X
};
// dragging line shapes
enum
{
DS_NONE
=
0
,
DS_LINE_VERTEX
,
// vertex between two lines
DS_LINE
,
// line
DS_ARC_STRAIGHT
,
// straight line (used when drawing polylines)
DS_ARC_CW
,
// clockwise arc (used when drawing polylines)
DS_ARC_CCW
// counterclockwise arc (used when drawing polylines)
};
// styles of line segment when dragging line or line vertex
enum
{
DSS_STRAIGHT
=
100
,
// straight line
DSS_ARC_CW
,
// clockwise arc
DSS_ARC_CCW
// counterclockwise arc
};
// inflection modes for DS_LINE and DS_LINE_VERTEX
enum
{
IM_NONE
=
0
,
IM_90_45
,
IM_45_90
,
IM_90
};
class
CDisplayList
;
// this structure contains an element of the display list
class
dl_element
{
friend
class
CDisplayList
;
public
:
CDisplayList
*
dlist
;
int
magic
;
dl_element
*
prev
;
dl_element
*
next
;
id
m_id
;
// identifier (see ids.h)
void
*
ptr
;
// pointer to object drawing this element
int
gtype
;
// type of primitive
int
visible
;
// 0 to hide
//private:
int
sel_vert
;
// for selection rectangles, 1 if part is vertical
int
w
;
// width (for round or square shapes)
int
holew
;
// hole width (for round holes)
int
x_org
,
y_org
;
// x origin (for rotation, reflection, etc.)
int
x
,
y
;
// starting or center position of element
int
xf
,
yf
;
// opposite corner (for rectangle or line)
int
radius
;
// radius of corners for DL_RRECT
int
layer
;
// layer to draw on
int
orig_layer
;
// for elements on highlight layer,
// the original layer, the highlight will
// only be drawn if this layer is visible
};
class
CDisplayList
{
private
:
// display-list parameters for each layer
dl_element
m_start
[
MAX_LAYERS
],
m_end
[
MAX_LAYERS
];
int
m_rgb
[
MAX_LAYERS
][
3
];
// layer colors
BOOL
m_vis
[
MAX_LAYERS
];
// layer visibility flags
int
m_layer_in_order
[
MAX_LAYERS
];
// array of layers in draw order
int
m_order_for_layer
[
MAX_LAYERS
];
// draw order for each layer
// window parameters
int
m_pcbu_per_wu
;
// i.e. nm per world unit
CRect
m_client_r
;
// client rect (pixels)
CRect
m_screen_r
;
// client rect (screen coords)
int
m_pane_org_x
;
// left border of drawing pane (pixels)
int
m_pane_org_y
;
// bottom border of drawing pane (pixels)
int
m_bottom_pane_h
;
// height of bottom pane
CDC
*
memDC
;
// pointer to memory DC
double
m_scale
;
// world units per pixel
int
m_org_x
;
// world x-coord of left side of screen (world units)
int
m_org_y
;
// world y-coord of bottom of screen (world units)
int
m_max_x
;
// world x_coord of right side of screen (world units)
int
m_max_y
;
// world y_coord of top of screen (world units)
int
w_ext_x
,
w_ext_y
;
// window extents (world units)
int
v_ext_x
,
v_ext_y
;
// viewport extents (pixels)
double
m_wu_per_pixel_x
;
// ratio w_ext_x/v_ext_x (world units per pixel)
double
m_wu_per_pixel_y
;
// ratio w_ext_y/v_ext_y (world units per pixel)
double
m_pcbu_per_pixel_x
;
double
m_pcbu_per_pixel_y
;
// general dragging parameters
int
m_drag_angle
;
// angle of rotation of selection rectangle (starts at 0)
int
m_drag_side
;
// 0 = no change, 1 = switch to opposite
int
m_drag_vert
;
// 1 if item being dragged is a vertical part
// parameters for dragging polyline sides and trace segments
// that can be modified while dragging
int
m_drag_flag
;
// 1 if dragging something
int
m_drag_shape
;
// shape
int
m_last_drag_shape
;
// last shape drawn
int
m_drag_x
;
// last cursor position for dragged shape
int
m_drag_y
;
int
m_drag_xi
;
// start of rubberband drag line
int
m_drag_yi
;
int
m_drag_xf
;
// end of rubberband drag line
int
m_drag_yf
;
int
m_drag_layer_1
;
// line layer
int
m_drag_w1
;
// line width
int
m_drag_style1
;
// line style
int
m_inflection_mode
;
// inflection mode
int
m_last_inflection_mode
;
// last mode drawn
// extra parameters when dragging vertex between 2 line segments
int
m_drag_style2
;
int
m_drag_layer_2
;
int
m_drag_w2
;
// parameters used to draw leading via if necessary
int
m_drag_layer_no_via
;
int
m_drag_via_w
;
int
m_drag_via_holew
;
int
m_drag_via_drawn
;
// arrays of lines and ratlines being dragged
// these can be rotated and flipped while being dragged
int
m_drag_layer
;
// layer
int
m_drag_max_lines
;
// max size of array for line segments
int
m_drag_num_lines
;
// number of line segments to drag
CPoint
*
m_drag_line_pt
;
// array of relative coords for line endpoints
int
m_drag_max_ratlines
;
// max size of ratline array
int
m_drag_num_ratlines
;
// number of ratlines to drag
CPoint
*
m_drag_ratline_start_pt
;
// absolute coords for ratline start points
CPoint
*
m_drag_ratline_end_pt
;
// relative coords for ratline endpoints
int
m_drag_ratline_width
;
// cursor parameters
int
m_cross_hairs
;
// 0 = none, 1 = cross-hairs, 2 = diagonals
CPoint
m_cross_left
,
m_cross_right
,
m_cross_top
,
m_cross_bottom
;
// end-points
CPoint
m_cross_topleft
,
m_cross_topright
,
m_cross_botleft
,
m_cross_botright
;
// grid
int
m_visual_grid_on
;
double
m_visual_grid_spacing
;
// in world units
public
:
CDisplayList
(
int
pcbu_per_wu
);
~
CDisplayList
();
void
SetVisibleGrid
(
BOOL
on
,
double
grid
);
void
SetMapping
(
CRect
*
client_r
,
CRect
*
screen_r
,
int
pane_org_x
,
int
pane_bottom_h
,
double
scale
,
int
org_x
,
int
org_y
);
void
SetDCToWorldCoords
(
CDC
*
pDC
,
CDC
*
mDC
,
int
pcbu_org_x
,
int
pcbu_org_y
);
void
SetLayerRGB
(
int
layer
,
int
r
,
int
g
,
int
b
);
void
SetLayerVisible
(
int
layer
,
BOOL
vis
);
void
SetLayerDrawOrder
(
int
layer
,
int
order
)
{
m_layer_in_order
[
order
]
=
layer
;
m_order_for_layer
[
layer
]
=
order
;
};
dl_element
*
Add
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
=
0
,
int
orig_layer
=
LAY_SELECTION
);
dl_element
*
AddSelector
(
id
id
,
void
*
ptr
,
int
glayer
,
int
gtype
,
int
visible
,
int
w
,
int
holew
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
xo
,
int
yo
,
int
radius
=
0
);
void
RemoveAll
();
void
RemoveAllFromLayer
(
int
layer
);
id
Remove
(
dl_element
*
element
);
void
Draw
(
CDC
*
pDC
);
int
HighLight
(
int
gtype
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
w
,
int
orig_layer
=
LAY_SELECTION
);
int
CancelHighLight
();
void
*
TestSelect
(
int
x
,
int
y
,
id
*
sel_id
,
int
*
layer
,
id
*
exclude_id
=
NULL
,
void
*
exclude_ptr
=
NULL
,
id
*
include_id
=
NULL
,
int
n_include_ids
=
1
);
int
StartDraggingArray
(
CDC
*
pDC
,
int
x
,
int
y
,
int
vert
,
int
layer
,
int
crosshair
=
1
);
int
StartDraggingRatLine
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xf
,
int
yf
,
int
layer
,
int
w
,
int
crosshair
=
1
);
int
StartDraggingRectangle
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
vert
,
int
layer
);
int
StartDraggingLineVertex
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
layer1
,
int
layer2
,
int
w1
,
int
w2
,
int
style1
,
int
style2
,
int
layer_no_via
,
int
via_w
,
int
via_holew
,
int
dir
,
int
crosshair
);
int
StartDraggingLine
(
CDC
*
pDC
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
layer1
,
int
w
,
int
layer_no_via
,
int
via_w
,
int
via_holew
,
int
crosshair
,
int
style
,
int
inflection_mode
);
int
StartDraggingArc
(
CDC
*
pDC
,
int
style
,
int
x
,
int
y
,
int
xi
,
int
yi
,
int
layer
,
int
w
,
int
crosshair
);
void
SetDragArcStyle
(
int
style
);
void
Drag
(
CDC
*
pDC
,
int
x
,
int
y
);
int
StopDragging
();
void
ChangeRoutingLayer
(
CDC
*
pDC
,
int
layer1
,
int
layer2
,
int
w
);
void
IncrementDragAngle
(
CDC
*
pDC
);
int
MakeDragLineArray
(
int
num_lines
);
int
MakeDragRatlineArray
(
int
num_ratlines
,
int
width
);
int
AddDragLine
(
CPoint
pi
,
CPoint
pf
);
int
AddDragRatline
(
CPoint
pi
,
CPoint
pf
);
int
GetDragAngle
();
void
FlipDragSide
(
CDC
*
pDC
);
int
GetDragSide
();
void
SetUpCrosshairs
(
int
type
,
int
x
,
int
y
);
void
SetInflectionMode
(
int
mode
){
m_inflection_mode
=
mode
;
};
CPoint
ScreenToPCB
(
CPoint
point
);
CPoint
PCBToScreen
(
CPoint
point
);
CPoint
WindowToPCB
(
CPoint
point
);
// set element parameters
void
Set_gtype
(
dl_element
*
el
,
int
gtype
);
void
Set_visible
(
dl_element
*
el
,
int
visible
);
void
Set_sel_vert
(
dl_element
*
el
,
int
sel_vert
);
void
Set_w
(
dl_element
*
el
,
int
w
);
void
Set_holew
(
dl_element
*
el
,
int
holew
);
void
Set_x_org
(
dl_element
*
el
,
int
x_org
);
void
Set_y_org
(
dl_element
*
el
,
int
y_org
);
void
Set_x
(
dl_element
*
el
,
int
x
);
void
Set_y
(
dl_element
*
el
,
int
y
);
void
Set_xf
(
dl_element
*
el
,
int
xf
);
void
Set_yf
(
dl_element
*
el
,
int
yf
);
void
Set_id
(
dl_element
*
el
,
id
*
id
);
void
Set_layer
(
dl_element
*
el
,
int
layer
);
void
Set_radius
(
dl_element
*
el
,
int
radius
);
void
Move
(
dl_element
*
el
,
int
dx
,
int
dy
);
// get element parameters
void
*
Get_ptr
(
dl_element
*
el
);
int
Get_gtype
(
dl_element
*
el
);
int
Get_visible
(
dl_element
*
el
);
int
Get_sel_vert
(
dl_element
*
el
);
int
Get_w
(
dl_element
*
el
);
int
Get_holew
(
dl_element
*
el
);
int
Get_x_org
(
dl_element
*
el
);
int
Get_y_org
(
dl_element
*
el
);
int
Get_x
(
dl_element
*
el
);
int
Get_y
(
dl_element
*
el
);
int
Get_xf
(
dl_element
*
el
);
int
Get_yf
(
dl_element
*
el
);
int
Get_radius
(
dl_element
*
el
);
int
Get_layer
(
dl_element
*
el
);
id
Get_id
(
dl_element
*
el
);
};
#endif // #ifndef FP_DISPLAY_LIST_H
polygon/freepcb_ids.h
View file @
e126042b
// definition of ID structure used by FreePCB
//
#pragma once
// struct id : this structure is used to identify PCB design elements
// such as instances of parts or nets, and their subelements
// Each element will have its own id.
// An id is attached to each item of the Display List so that it can
// be linked back to the PCB design element which drew it.
// These are mainly used to identify items selected by clicking the mouse
//
// In general:
// id.type = type of PCB element (e.g. part, net, text)
// id.st = subelement type (e.g. part pad, net connection)
// id.i = subelement index (zero-based)
// id.sst = subelement of subelement (e.g. net connection segment)
// id.ii = subsubelement index (zero-based)
//
// For example, the id for segment 0 of connection 4 of net 12 would be
// id = { ID_NET, 12, ID_CONNECT, 4, ID_SEG, 0 };
//
//
class
id
{
public
:
// constructor
id
(
int
qt
=
0
,
int
qst
=
0
,
int
qis
=
0
,
int
qsst
=
0
,
int
qiis
=
0
)
{
type
=
qt
;
st
=
qst
;
i
=
qis
;
sst
=
qsst
;
ii
=
qiis
;
}
// operators
friend
int
operator
==
(
id
id1
,
id
id2
)
{
return
(
id1
.
type
==
id2
.
type
&&
id1
.
st
==
id2
.
st
&&
id1
.
sst
==
id2
.
sst
&&
id1
.
i
==
id2
.
i
&&
id1
.
ii
==
id2
.
ii
);
}
// member functions
void
Clear
()
{
type
=
0
;
st
=
0
;
i
=
0
;
sst
=
0
;
ii
=
0
;
}
void
Set
(
int
qt
,
int
qst
=
0
,
int
qis
=
0
,
int
qsst
=
0
,
int
qiis
=
0
)
{
type
=
qt
;
st
=
qst
;
i
=
qis
;
sst
=
qsst
;
ii
=
qiis
;
}
// member variables
unsigned
int
type
;
// type of element
unsigned
int
st
;
// type of subelement
unsigned
int
i
;
// index of subelement
unsigned
int
sst
;
// type of subsubelement
unsigned
int
ii
;
// index of subsubelement
};
// these are constants used in ids
// root types
enum
{
ID_NONE
=
0
,
// an undefined type or st (or an error)
ID_BOARD
,
// board outline
ID_PART
,
// part
ID_NET
,
// net
ID_TEXT
,
// free-standing text
ID_DRC
,
// DRC error
ID_SM_CUTOUT
,
// cutout for solder mask
ID_MULTI
// if multiple selections
};
// subtypes of ID_PART
enum
{
ID_PAD
=
1
,
// pad_stack in a part
ID_SEL_PAD
,
// selection rectangle for pad_stack in a part
ID_OUTLINE
,
// part outline
ID_REF_TXT
,
// text showing ref num for part
ID_ORIG
,
// part origin
ID_SEL_RECT
,
// selection rectangle for part
ID_SEL_REF_TXT
// selection rectangle for ref text
};
// subtypes of ID_TEXT
enum
{
ID_SEL_TXT
=
1
,
// selection rectangle
ID_STROKE
// stroke for text
};
// subtypes of ID_NET
enum
{
ID_ENTIRE_NET
=
0
,
ID_CONNECT
,
// connection
ID_AREA
// copper area
};
// subtypes of ID_BOARD
enum
{
ID_BOARD_OUTLINE
=
1
,
};
// subsubtypes of ID_NET.ID_CONNECT
enum
{
ID_ENTIRE_CONNECT
=
0
,
ID_SEG
,
ID_SEL_SEG
,
ID_VERTEX
,
ID_SEL_VERTEX
,
ID_VIA
};
// subsubtypes of ID_NET.ID_AREA, ID_BOARD.ID_BOARD_OUTLINE, ID_SM_CUTOUT
enum
{
ID_SIDE
=
1
,
ID_SEL_SIDE
,
ID_SEL_CORNER
,
ID_HATCH
,
ID_PIN_X
,
// only used by ID_AREA
ID_STUB_X
// only used by ID_AREA
};
// subtypes of ID_DRC
// for subsubtypes, use types in DesignRules.h
enum
{
ID_DRE
=
1
,
ID_SEL_DRE
};
// definition of ID structure used by FreePCB
//
#pragma once
// struct id : this structure is used to identify PCB design elements
// such as instances of parts or nets, and their subelements
// Each element will have its own id.
// An id is attached to each item of the Display List so that it can
// be linked back to the PCB design element which drew it.
// These are mainly used to identify items selected by clicking the mouse
//
// In general:
// id.type = type of PCB element (e.g. part, net, text)
// id.st = subelement type (e.g. part pad, net connection)
// id.i = subelement index (zero-based)
// id.sst = subelement of subelement (e.g. net connection segment)
// id.ii = subsubelement index (zero-based)
//
// For example, the id for segment 0 of connection 4 of net 12 would be
// id = { ID_NET, 12, ID_CONNECT, 4, ID_SEG, 0 };
//
//
class
id
{
public
:
// constructor
id
(
int
qt
=
0
,
int
qst
=
0
,
int
qis
=
0
,
int
qsst
=
0
,
int
qiis
=
0
)
{
type
=
qt
;
st
=
qst
;
i
=
qis
;
sst
=
qsst
;
ii
=
qiis
;
}
// operators
friend
int
operator
==
(
id
id1
,
id
id2
)
{
return
(
id1
.
type
==
id2
.
type
&&
id1
.
st
==
id2
.
st
&&
id1
.
sst
==
id2
.
sst
&&
id1
.
i
==
id2
.
i
&&
id1
.
ii
==
id2
.
ii
);
}
// member functions
void
Clear
()
{
type
=
0
;
st
=
0
;
i
=
0
;
sst
=
0
;
ii
=
0
;
}
void
Set
(
int
qt
,
int
qst
=
0
,
int
qis
=
0
,
int
qsst
=
0
,
int
qiis
=
0
)
{
type
=
qt
;
st
=
qst
;
i
=
qis
;
sst
=
qsst
;
ii
=
qiis
;
}
// member variables
unsigned
int
type
;
// type of element
unsigned
int
st
;
// type of subelement
unsigned
int
i
;
// index of subelement
unsigned
int
sst
;
// type of subsubelement
unsigned
int
ii
;
// index of subsubelement
};
// these are constants used in ids
// root types
enum
{
ID_NONE
=
0
,
// an undefined type or st (or an error)
ID_BOARD
,
// board outline
ID_PART
,
// part
ID_NET
,
// net
ID_TEXT
,
// free-standing text
ID_DRC
,
// DRC error
ID_SM_CUTOUT
,
// cutout for solder mask
ID_MULTI
// if multiple selections
};
// subtypes of ID_PART
enum
{
ID_PAD
=
1
,
// pad_stack in a part
ID_SEL_PAD
,
// selection rectangle for pad_stack in a part
ID_OUTLINE
,
// part outline
ID_REF_TXT
,
// text showing ref num for part
ID_ORIG
,
// part origin
ID_SEL_RECT
,
// selection rectangle for part
ID_SEL_REF_TXT
// selection rectangle for ref text
};
// subtypes of ID_TEXT
enum
{
ID_SEL_TXT
=
1
,
// selection rectangle
ID_STROKE
// stroke for text
};
// subtypes of ID_NET
enum
{
ID_ENTIRE_NET
=
0
,
ID_CONNECT
,
// connection
ID_AREA
// copper area
};
// subtypes of ID_BOARD
enum
{
ID_BOARD_OUTLINE
=
1
,
};
// subsubtypes of ID_NET.ID_CONNECT
enum
{
ID_ENTIRE_CONNECT
=
0
,
ID_SEG
,
ID_SEL_SEG
,
ID_VERTEX
,
ID_SEL_VERTEX
,
ID_VIA
};
// subsubtypes of ID_NET.ID_AREA, ID_BOARD.ID_BOARD_OUTLINE, ID_SM_CUTOUT
enum
{
ID_SIDE
=
1
,
ID_SEL_SIDE
,
ID_SEL_CORNER
,
ID_HATCH
,
ID_PIN_X
,
// only used by ID_AREA
ID_STUB_X
// only used by ID_AREA
};
// subtypes of ID_DRC
// for subsubtypes, use types in DesignRules.h
enum
{
ID_DRE
=
1
,
ID_SEL_DRE
};
polygon/math_for_graphics.cpp
View file @
e126042b
// math for graphics utility routines, from FreePCB
using
namespace
std
;
#include <vector>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "defs-macros.h"
#include "PolyLine2Kicad.h"
#include "freepcb_ids.h"
#include "PolyLine.h"
// function to find inflection-pont to create a "dogleg" of two straight-line segments
// where one segment is vertical or horizontal and the other is at 45 degrees or 90 degrees
// enter with:
// pi = start point
// pf = end point
// mode = IM_90_45 or IM_45_90 or IM_90
//
CPoint
GetInflectionPoint
(
CPoint
pi
,
CPoint
pf
,
int
mode
)
{
CPoint
p
=
pi
;
if
(
mode
==
IM_NONE
)
return
p
;
int
dx
=
pf
.
x
-
pi
.
x
;
int
dy
=
pf
.
y
-
pi
.
y
;
if
(
dx
==
0
||
dy
==
0
||
abs
(
dx
)
==
abs
(
dy
)
)
{
// only one segment needed
}
else
{
if
(
abs
(
dy
)
>
abs
(
dx
)
)
{
// vertical > horizontal
if
(
mode
==
IM_90
)
{
p
.
x
=
pi
.
x
;
p
.
y
=
pf
.
y
;
}
else
if
(
mode
==
IM_45_90
||
mode
==
IM_90_45
)
{
int
vert
;
// length of vertical line needed
if
(
dy
>
0
)
vert
=
dy
-
abs
(
dx
);
// positive
else
vert
=
dy
+
abs
(
dx
);
// negative
if
(
mode
==
IM_90_45
)
p
.
y
=
pi
.
y
+
vert
;
else
if
(
mode
==
IM_45_90
)
{
p
.
y
=
pf
.
y
-
vert
;
p
.
x
=
pf
.
x
;
}
}
else
ASSERT
(
0
);
}
else
{
// horizontal > vertical
if
(
mode
==
IM_90
)
{
p
.
x
=
pf
.
x
;
p
.
y
=
pi
.
y
;
}
else
if
(
mode
==
IM_45_90
||
mode
==
IM_90_45
)
{
int
hor
;
// length of horizontal line needed
if
(
dx
>
0
)
hor
=
dx
-
abs
(
dy
);
// positive
else
hor
=
dx
+
abs
(
dy
);
// negative
if
(
mode
==
IM_90_45
)
p
.
x
=
pi
.
x
+
hor
;
else
if
(
mode
==
IM_45_90
)
{
p
.
x
=
pf
.
x
-
hor
;
p
.
y
=
pf
.
y
;
}
}
else
ASSERT
(
0
);
}
}
return
p
;
}
//
// function to rotate a point clockwise about another point
// currently, angle must be 0, 90, 180 or 270
//
void
RotatePoint
(
CPoint
*
p
,
int
angle
,
CPoint
org
)
{
if
(
angle
==
90
)
{
int
tempy
=
org
.
y
+
(
org
.
x
-
p
->
x
);
p
->
x
=
org
.
x
+
(
p
->
y
-
org
.
y
);
p
->
y
=
tempy
;
}
else
if
(
angle
>
90
)
{
for
(
int
i
=
0
;
i
<
(
angle
/
90
);
i
++
)
RotatePoint
(
p
,
90
,
org
);
}
}
// function to rotate a rectangle clockwise about a point
// angle must be 0, 90, 180 or 270
// on exit, r->top > r.bottom, r.right > r.left
//
void
RotateRect
(
CRect
*
r
,
int
angle
,
CPoint
org
)
{
CRect
tr
;
if
(
angle
==
90
)
{
tr
.
left
=
org
.
x
+
(
r
->
bottom
-
org
.
y
);
tr
.
right
=
org
.
x
+
(
r
->
top
-
org
.
y
);
tr
.
top
=
org
.
y
+
(
org
.
x
-
r
->
right
);
tr
.
bottom
=
org
.
y
+
(
org
.
x
-
r
->
left
);
if
(
tr
.
left
>
tr
.
right
)
{
int
temp
=
tr
.
right
;
tr
.
left
=
tr
.
right
;
tr
.
left
=
temp
;
}
if
(
tr
.
left
>
tr
.
right
)
{
int
temp
=
tr
.
right
;
tr
.
left
=
tr
.
right
;
tr
.
left
=
temp
;
}
if
(
tr
.
bottom
>
tr
.
top
)
{
int
temp
=
tr
.
bottom
;
tr
.
bottom
=
tr
.
top
;
tr
.
top
=
temp
;
}
}
else
if
(
angle
>
90
)
{
tr
=
*
r
;
for
(
int
i
=
0
;
i
<
(
angle
/
90
);
i
++
)
RotateRect
(
&
tr
,
90
,
org
);
}
*
r
=
tr
;
}
// test for hit on line segment
// i.e. cursor within a given distance from segment
// enter with: x,y = cursor coords
// (xi,yi) and (xf,yf) are the end-points of the line segment
// dist = maximum distance for hit
//
int
TestLineHit
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
x
,
int
y
,
double
dist
)
{
double
dd
;
// test for vertical or horizontal segment
if
(
xf
==
xi
)
{
// vertical segment
dd
=
fabs
(
(
double
)(
x
-
xi
)
);
if
(
dd
<
dist
&&
(
(
yf
>
yi
&&
y
<
yf
&&
y
>
yi
)
||
(
yf
<
yi
&&
y
>
yf
&&
y
<
yi
)
)
)
return
1
;
}
else
if
(
yf
==
yi
)
{
// horizontal segment
dd
=
fabs
(
(
double
)(
y
-
yi
)
);
if
(
dd
<
dist
&&
(
(
xf
>
xi
&&
x
<
xf
&&
x
>
xi
)
||
(
xf
<
xi
&&
x
>
xf
&&
x
<
xi
)
)
)
return
1
;
}
else
{
// oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double
b
=
(
double
)(
yf
-
yi
)
/
(
xf
-
xi
);
double
a
=
(
double
)
yi
-
b
*
xi
;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double
d
=
-
1.0
/
b
;
double
c
=
(
double
)
y
-
d
*
x
;
// find nearest point to (x,y) on line segment (xi,yi) to (xf,yf)
double
xp
=
(
a
-
c
)
/
(
d
-
b
);
double
yp
=
a
+
b
*
xp
;
// find distance
dd
=
sqrt
((
x
-
xp
)
*
(
x
-
xp
)
+
(
y
-
yp
)
*
(
y
-
yp
));
if
(
fabs
(
b
)
>
0.7
)
{
// line segment more vertical than horizontal
if
(
dd
<
dist
&&
(
(
yf
>
yi
&&
yp
<
yf
&&
yp
>
yi
)
||
(
yf
<
yi
&&
yp
>
yf
&&
yp
<
yi
)
)
)
return
1
;
}
else
{
// line segment more horizontal than vertical
if
(
dd
<
dist
&&
(
(
xf
>
xi
&&
xp
<
xf
&&
xp
>
xi
)
||
(
xf
<
xi
&&
xp
>
xf
&&
xp
<
xi
)
)
)
return
1
;
}
}
return
0
;
// no hit
}
// find intersection between y = a + bx and y = c + dx;
//
int
FindLineIntersection
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x
,
double
*
y
)
{
*
x
=
(
c
-
a
)
/
(
b
-
d
);
*
y
=
a
+
b
*
(
*
x
);
return
0
;
}
// set EllipseKH struct to describe the ellipse for an arc
//
int
MakeEllipseFromArc
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
EllipseKH
*
el
)
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int
xxi
,
xxf
,
yyi
,
yyf
;
if
(
style
==
CPolyLine
::
ARC_CCW
)
{
xxi
=
xf
;
xxf
=
xi
;
yyi
=
yf
;
yyf
=
yi
;
}
else
{
xxi
=
xi
;
xxf
=
xf
;
yyi
=
yi
;
yyf
=
yf
;
}
// find center and radii of ellipse
double
xo
,
yo
;
if
(
xxf
>
xxi
&&
yyf
>
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
el
->
theta1
=
M_PI
;
el
->
theta2
=
M_PI
/
2.0
;
}
else
if
(
xxf
<
xxi
&&
yyf
>
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
el
->
theta1
=
-
M_PI
/
2.0
;
el
->
theta2
=
-
M_PI
;
}
else
if
(
xxf
<
xxi
&&
yyf
<
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
el
->
theta1
=
0.0
;
el
->
theta2
=
-
M_PI
/
2.0
;
}
else
if
(
xxf
>
xxi
&&
yyf
<
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
el
->
theta1
=
M_PI
/
2.0
;
el
->
theta2
=
0.0
;
}
el
->
Center
.
X
=
xo
;
el
->
Center
.
Y
=
yo
;
el
->
xrad
=
abs
(
xf
-
xi
);
el
->
yrad
=
abs
(
yf
-
yi
);
#if 0
el->Phi = 0.0;
el->MaxRad = el->xrad;
el->MinRad = el->yrad;
if( el->MaxRad < el->MinRad )
{
el->MaxRad = el->yrad;
el->MinRad = el->xrad;
el->Phi = M_PI/2.0;
}
#endif
return
0
;
}
// find intersections between line segment (xi,yi) to (xf,yf)
// and line segment (xi2,yi2) to (xf2,yf2)
// the line segments may be arcs (i.e. quadrant of an ellipse) or straight
// returns number of intersections found (max of 2)
// returns coords of intersections in arrays x[2], y[2]
//
int
FindSegmentIntersections
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
int
xi2
,
int
yi2
,
int
xf2
,
int
yf2
,
int
style2
,
double
x
[],
double
y
[]
)
{
double
xr
[
12
],
yr
[
12
];
int
iret
=
0
;
if
(
max
(
xi
,
xf
)
<
min
(
xi2
,
xf2
)
||
min
(
xi
,
xf
)
>
max
(
xi2
,
xf2
)
||
max
(
yi
,
yf
)
<
min
(
yi2
,
yf2
)
||
min
(
yi
,
yf
)
>
max
(
yi2
,
yf2
)
)
return
0
;
if
(
style
!=
CPolyLine
::
STRAIGHT
&&
style2
!=
CPolyLine
::
STRAIGHT
)
{
// two identical arcs intersect
if
(
style
==
style2
&&
xi
==
xi2
&&
yi
==
yi2
&&
xf
==
xf2
&&
yf
==
yf2
)
{
if
(
x
&&
y
)
{
x
[
0
]
=
xi
;
y
[
0
]
=
yi
;
}
return
1
;
}
else
if
(
style
!=
style2
&&
xi
==
xf2
&&
yi
==
yf2
&&
xf
==
xi2
&&
yf
==
yi2
)
{
if
(
x
&&
y
)
{
x
[
0
]
=
xi
;
y
[
0
]
=
yi
;
}
return
1
;
}
}
if
(
style
==
CPolyLine
::
STRAIGHT
&&
style2
==
CPolyLine
::
STRAIGHT
)
{
// both straight-line segments
int
x
,
y
;
bool
bYes
=
TestForIntersectionOfStraightLineSegments
(
xi
,
yi
,
xf
,
yf
,
xi2
,
yi2
,
xf2
,
yf2
,
&
x
,
&
y
);
if
(
!
bYes
)
return
0
;
xr
[
0
]
=
x
;
yr
[
0
]
=
y
;
iret
=
1
;
}
else
if
(
style
==
CPolyLine
::
STRAIGHT
)
{
// first segment is straight, second segment is an arc
int
ret
;
double
x1r
,
y1r
,
x2r
,
y2r
;
if
(
xf
==
xi
)
{
// vertical first segment
double
a
=
xi
;
double
b
=
DBL_MAX
/
2.0
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
else
{
double
b
=
(
double
)(
yf
-
yi
)
/
(
double
)(
xf
-
xi
);
double
a
=
yf
-
b
*
xf
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
if
(
ret
==
0
)
return
0
;
if
(
InRange
(
x1r
,
xi
,
xf
)
&&
InRange
(
y1r
,
yi
,
yf
)
)
{
xr
[
iret
]
=
x1r
;
yr
[
iret
]
=
y1r
;
iret
++
;
}
if
(
ret
==
2
)
{
if
(
InRange
(
x2r
,
xi
,
xf
)
&&
InRange
(
y2r
,
yi
,
yf
)
)
{
xr
[
iret
]
=
x2r
;
yr
[
iret
]
=
y2r
;
iret
++
;
}
}
}
else
if
(
style2
==
CPolyLine
::
STRAIGHT
)
{
// first segment is an arc, second segment is straight
int
ret
;
double
x1r
,
y1r
,
x2r
,
y2r
;
if
(
xf2
==
xi2
)
{
// vertical second segment
double
a
=
xi2
;
double
b
=
DBL_MAX
/
2.0
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi
,
yi
,
xf
,
yf
,
style
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
else
{
double
b
=
(
double
)(
yf2
-
yi2
)
/
(
double
)(
xf2
-
xi2
);
double
a
=
yf2
-
b
*
xf2
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi
,
yi
,
xf
,
yf
,
style
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
if
(
ret
==
0
)
return
0
;
if
(
InRange
(
x1r
,
xi2
,
xf2
)
&&
InRange
(
y1r
,
yi2
,
yf2
)
)
{
xr
[
iret
]
=
x1r
;
yr
[
iret
]
=
y1r
;
iret
++
;
}
if
(
ret
==
2
)
{
if
(
InRange
(
x2r
,
xi2
,
xf2
)
&&
InRange
(
y2r
,
yi2
,
yf2
)
)
{
xr
[
iret
]
=
x2r
;
yr
[
iret
]
=
y2r
;
iret
++
;
}
}
}
else
{
// both segments are arcs
EllipseKH
el1
;
EllipseKH
el2
;
MakeEllipseFromArc
(
xi
,
yi
,
xf
,
yf
,
style
,
&
el1
);
MakeEllipseFromArc
(
xi2
,
yi2
,
xf2
,
yf2
,
style2
,
&
el2
);
int
n
;
if
(
el1
.
xrad
+
el1
.
yrad
>
el2
.
xrad
+
el2
.
yrad
)
n
=
GetArcIntersections
(
&
el1
,
&
el2
);
else
n
=
GetArcIntersections
(
&
el2
,
&
el1
);
iret
=
n
;
}
if
(
x
&&
y
)
{
for
(
int
i
=
0
;
i
<
iret
;
i
++
)
{
x
[
i
]
=
xr
[
i
];
y
[
i
]
=
yr
[
i
];
}
}
return
iret
;
}
// find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
// if b > DBL_MAX/10, assume vertical line at x = a
// the line segment may be an arc (i.e. quadrant of an ellipse)
// return 0 if no intersection
// returns 1 or 2 if intersections found
// sets coords of intersections in *x1, *y1, *x2, *y2
// if no intersection, returns min distance in dist
//
int
FindLineSegmentIntersection
(
double
a
,
double
b
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
,
double
*
dist
)
{
double
xx
,
yy
;
bool
bVert
=
false
;
if
(
b
>
DBL_MAX
/
10.0
)
bVert
=
true
;
if
(
xf
!=
xi
)
{
// non-vertical segment, get intersection
if
(
style
==
CPolyLine
::
STRAIGHT
||
yf
==
yi
)
{
// horizontal or oblique straight segment
// put into form y = c + dx;
double
d
=
(
double
)(
yf
-
yi
)
/
(
double
)(
xf
-
xi
);
double
c
=
yf
-
d
*
xf
;
if
(
bVert
)
{
// if vertical line, easy
if
(
InRange
(
a
,
xi
,
xf
)
)
{
*
x1
=
a
;
*
y1
=
c
+
d
*
a
;
return
1
;
}
else
{
if
(
dist
)
*
dist
=
min
(
abs
(
a
-
xi
),
abs
(
a
-
xf
)
);
return
0
;
}
}
if
(
fabs
(
b
-
d
)
<
1E-12
)
{
// parallel lines
if
(
dist
)
{
*
dist
=
GetPointToLineDistance
(
a
,
b
,
xi
,
xf
);
}
return
0
;
// lines parallel
}
// calculate intersection
xx
=
(
c
-
a
)
/
(
b
-
d
);
yy
=
a
+
b
*
(
xx
);
// see if intersection is within the line segment
if
(
yf
==
yi
)
{
// horizontal line
if
(
(
xx
>=
xi
&&
xx
>
xf
)
||
(
xx
<=
xi
&&
xx
<
xf
)
)
return
0
;
}
else
{
// oblique line
if
(
(
xx
>=
xi
&&
xx
>
xf
)
||
(
xx
<=
xi
&&
xx
<
xf
)
||
(
yy
>
yi
&&
yy
>
yf
)
||
(
yy
<
yi
&&
yy
<
yf
)
)
return
0
;
}
}
else
if
(
style
==
CPolyLine
::
ARC_CW
||
style
==
CPolyLine
::
ARC_CCW
)
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int
xxi
,
xxf
,
yyi
,
yyf
;
if
(
style
==
CPolyLine
::
ARC_CCW
)
{
xxi
=
xf
;
xxf
=
xi
;
yyi
=
yf
;
yyf
=
yi
;
}
else
{
xxi
=
xi
;
xxf
=
xf
;
yyi
=
yi
;
yyf
=
yf
;
}
// find center and radii of ellipse
double
xo
,
yo
,
rx
,
ry
;
if
(
xxf
>
xxi
&&
yyf
>
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
}
else
if
(
xxf
<
xxi
&&
yyf
>
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
}
else
if
(
xxf
<
xxi
&&
yyf
<
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
}
else
if
(
xxf
>
xxi
&&
yyf
<
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
}
rx
=
fabs
(
(
double
)(
xxi
-
xxf
)
);
ry
=
fabs
(
(
double
)(
yyi
-
yyf
)
);
bool
test
;
double
xx1
,
xx2
,
yy1
,
yy2
,
aa
;
if
(
bVert
)
{
// shift vertical line to coordinate system of ellipse
aa
=
a
-
xo
;
test
=
FindVerticalLineEllipseIntersections
(
rx
,
ry
,
aa
,
&
yy1
,
&
yy2
);
if
(
!
test
)
return
0
;
// shift back to PCB coordinates
yy1
+=
yo
;
yy2
+=
yo
;
xx1
=
a
;
xx2
=
a
;
}
else
{
// shift line to coordinate system of ellipse
aa
=
a
+
b
*
xo
-
yo
;
test
=
FindLineEllipseIntersections
(
rx
,
ry
,
aa
,
b
,
&
xx1
,
&
xx2
);
if
(
!
test
)
return
0
;
// shift back to PCB coordinates
yy1
=
aa
+
b
*
xx1
;
xx1
+=
xo
;
yy1
+=
yo
;
yy2
=
aa
+
b
*
xx2
;
xx2
+=
xo
;
yy2
+=
yo
;
}
int
npts
=
0
;
if
(
(
xxf
>
xxi
&&
xx1
<
xxf
&&
xx1
>
xxi
)
||
(
xxf
<
xxi
&&
xx1
<
xxi
&&
xx1
>
xxf
)
)
{
if
(
(
yyf
>
yyi
&&
yy1
<
yyf
&&
yy1
>
yyi
)
||
(
yyf
<
yyi
&&
yy1
<
yyi
&&
yy1
>
yyf
)
)
{
*
x1
=
xx1
;
*
y1
=
yy1
;
npts
=
1
;
}
}
if
(
(
xxf
>
xxi
&&
xx2
<
xxf
&&
xx2
>
xxi
)
||
(
xxf
<
xxi
&&
xx2
<
xxi
&&
xx2
>
xxf
)
)
{
if
(
(
yyf
>
yyi
&&
yy2
<
yyf
&&
yy2
>
yyi
)
||
(
yyf
<
yyi
&&
yy2
<
yyi
&&
yy2
>
yyf
)
)
{
if
(
npts
==
0
)
{
*
x1
=
xx2
;
*
y1
=
yy2
;
npts
=
1
;
}
else
{
*
x2
=
xx2
;
*
y2
=
yy2
;
npts
=
2
;
}
}
}
return
npts
;
}
else
ASSERT
(
0
);
}
else
{
// vertical line segment
if
(
bVert
)
return
0
;
xx
=
xi
;
yy
=
a
+
b
*
xx
;
if
(
(
yy
>=
yi
&&
yy
>
yf
)
||
(
yy
<=
yi
&&
yy
<
yf
)
)
return
0
;
}
*
x1
=
xx
;
*
y1
=
yy
;
return
1
;
}
// Test for intersection of line segments
// If lines are parallel, returns false
// If true, returns intersection coords in x, y
// if false, returns min. distance in dist (may be 0.0 if parallel)
// and coords on nearest point in one of the segments in (x,y)
//
bool
TestForIntersectionOfStraightLineSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
*
x
,
int
*
y
,
double
*
d
)
{
double
a
,
b
,
dist
;
// first, test for intersection
if
(
x1i
==
x1f
&&
x2i
==
x2f
)
{
// both segments are vertical, can't intersect
}
else
if
(
y1i
==
y1f
&&
y2i
==
y2f
)
{
// both segments are horizontal, can't intersect
}
else
if
(
x1i
==
x1f
&&
y2i
==
y2f
)
{
// first seg. vertical, second horizontal, see if they cross
if
(
InRange
(
x1i
,
x2i
,
x2f
)
&&
InRange
(
y2i
,
y1i
,
y1f
)
)
{
if
(
x
)
*
x
=
x1i
;
if
(
y
)
*
y
=
y2i
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
else
if
(
y1i
==
y1f
&&
x2i
==
x2f
)
{
// first seg. horizontal, second vertical, see if they cross
if
(
InRange
(
y1i
,
y2i
,
y2f
)
&&
InRange
(
x2i
,
x1i
,
x1f
)
)
{
if
(
x
)
*
x
=
x2i
;
if
(
y
)
*
y
=
y1i
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
else
if
(
x1i
==
x1f
)
{
// first segment vertical, second oblique
// get a and b for second line segment, so that y = a + bx;
b
=
(
double
)(
y2f
-
y2i
)
/
(
x2f
-
x2i
);
a
=
(
double
)
y2i
-
b
*
x2i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x1i
,
y1i
,
x1f
,
y1f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
y1
,
y1i
,
y1f
)
&&
InRange
(
x1
,
x2i
,
x2f
)
&&
InRange
(
y1
,
y2i
,
y2f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
if
(
y1i
==
y1f
)
{
// first segment horizontal, second oblique
// get a and b for second line segment, so that y = a + bx;
b
=
(
double
)(
y2f
-
y2i
)
/
(
x2f
-
x2i
);
a
=
(
double
)
y2i
-
b
*
x2i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x1i
,
y1i
,
x1f
,
y1f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
x1
,
x2i
,
x2f
)
&&
InRange
(
y1
,
y2i
,
y2f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
if
(
x2i
==
x2f
)
{
// second segment vertical, first oblique
// get a and b for first line segment, so that y = a + bx;
b
=
(
double
)(
y1f
-
y1i
)
/
(
x1f
-
x1i
);
a
=
(
double
)
y1i
-
b
*
x1i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x2i
,
y2i
,
x2f
,
y2f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
y1
,
y1i
,
y1f
)
&&
InRange
(
y1
,
y2i
,
y2f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
if
(
y2i
==
y2f
)
{
// second segment horizontal, first oblique
// get a and b for second line segment, so that y = a + bx;
b
=
(
double
)(
y1f
-
y1i
)
/
(
x1f
-
x1i
);
a
=
(
double
)
y1i
-
b
*
x1i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x2i
,
y2i
,
x2f
,
y2f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
y1
,
y1i
,
y1f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
{
// both segments oblique
if
(
(
long
)(
y1f
-
y1i
)
*
(
x2f
-
x2i
)
!=
(
long
)(
y2f
-
y2i
)
*
(
x1f
-
x1i
)
)
{
// not parallel, get a and b for first line segment, so that y = a + bx;
b
=
(
double
)(
y1f
-
y1i
)
/
(
x1f
-
x1i
);
a
=
(
double
)
y1i
-
b
*
x1i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x2i
,
y2i
,
x2f
,
y2f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
// both segments oblique
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
y1
,
y1i
,
y1f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
}
// don't intersect, get shortest distance between each endpoint and the other line segment
dist
=
GetPointToLineSegmentDistance
(
x1i
,
y1i
,
x2i
,
y2i
,
x2f
,
y2f
);
double
xx
=
x1i
;
double
yy
=
y1i
;
double
dd
=
GetPointToLineSegmentDistance
(
x1f
,
y1f
,
x2i
,
y2i
,
x2f
,
y2f
);
if
(
dd
<
dist
)
{
dist
=
dd
;
xx
=
x1f
;
yy
=
y1f
;
}
dd
=
GetPointToLineSegmentDistance
(
x2i
,
y2i
,
x1i
,
y1i
,
x1f
,
y1f
);
if
(
dd
<
dist
)
{
dist
=
dd
;
xx
=
x2i
;
yy
=
y2i
;
}
dd
=
GetPointToLineSegmentDistance
(
x2f
,
y2f
,
x1i
,
y1i
,
x1f
,
y1f
);
if
(
dd
<
dist
)
{
dist
=
dd
;
xx
=
x2f
;
yy
=
y2f
;
}
if
(
x
)
*
x
=
xx
;
if
(
y
)
*
y
=
yy
;
if
(
d
)
*
d
=
dist
;
return
false
;
}
// quicksort algorithm
// sorts array numbers[], also moves elements of another array index[]
//
#define Q3WAY
void
quickSort
(
int
numbers
[],
int
index
[],
int
array_size
)
{
#ifdef Q3WAY
q_sort_3way
(
numbers
,
index
,
0
,
array_size
-
1
);
#else
q_sort
(
numbers
,
index
,
0
,
array_size
-
1
);
#endif
}
// standard quicksort
//
void
q_sort
(
int
numbers
[],
int
index
[],
int
left
,
int
right
)
{
int
pivot
,
pivot_index
,
l_hold
,
r_hold
;
l_hold
=
left
;
r_hold
=
right
;
pivot
=
numbers
[
left
];
pivot_index
=
index
[
left
];
while
(
left
<
right
)
{
while
((
numbers
[
right
]
>=
pivot
)
&&
(
left
<
right
))
right
--
;
if
(
left
!=
right
)
{
numbers
[
left
]
=
numbers
[
right
];
index
[
left
]
=
index
[
right
];
left
++
;
}
while
((
numbers
[
left
]
<=
pivot
)
&&
(
left
<
right
))
left
++
;
if
(
left
!=
right
)
{
numbers
[
right
]
=
numbers
[
left
];
index
[
right
]
=
index
[
left
];
right
--
;
}
}
numbers
[
left
]
=
pivot
;
index
[
left
]
=
pivot_index
;
pivot
=
left
;
left
=
l_hold
;
right
=
r_hold
;
if
(
left
<
pivot
)
q_sort
(
numbers
,
index
,
left
,
pivot
-
1
);
if
(
right
>
pivot
)
q_sort
(
numbers
,
index
,
pivot
+
1
,
right
);
}
// 3-way quicksort...useful where there are duplicate values
//
void
q_sort_3way
(
int
a
[],
int
b
[],
int
l
,
int
r
)
{
#define EXCH(i,j) {int temp=a[i]; a[i]=a[j]; a[j]=temp; temp=b[i]; b[i]=b[j]; b[j]=temp;}
int
i
=
l
-
1
;
int
j
=
r
;
int
p
=
l
-
1
;
int
q
=
r
;
int
v
=
a
[
r
];
if
(
r
<=
l
)
return
;
for
(;;)
{
while
(
a
[
++
i
]
<
v
);
while
(
v
<
a
[
--
j
]
)
if
(
j
==
1
)
break
;
if
(
i
>=
j
)
break
;
EXCH
(
i
,
j
);
if
(
a
[
i
]
==
v
)
{
p
++
;
EXCH
(
p
,
i
);
}
if
(
v
==
a
[
j
]
)
{
q
--
;
EXCH
(
j
,
q
);
}
}
EXCH
(
i
,
r
);
j
=
i
-
1
;
i
=
i
+
1
;
for
(
int
k
=
l
;
k
<
p
;
k
++
,
j
--
)
EXCH
(
k
,
j
);
for
(
int
k
=
r
-
1
;
k
>
q
;
k
--
,
i
++
)
EXCH
(
i
,
k
);
q_sort_3way
(
a
,
b
,
l
,
j
);
q_sort_3way
(
a
,
b
,
i
,
r
);
}
// solves quadratic equation
// i.e. ax**2 + bx + c = 0
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool
Quadratic
(
double
a
,
double
b
,
double
c
,
double
*
x1
,
double
*
x2
)
{
double
root
=
b
*
b
-
4.0
*
a
*
c
;
if
(
root
<
0.0
)
return
false
;
root
=
sqrt
(
root
);
*
x1
=
(
-
b
+
root
)
/
(
2.0
*
a
);
*
x2
=
(
-
b
-
root
)
/
(
2.0
*
a
);
return
true
;
}
// finds intersections of vertical line at x
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in y1 and y2
// else returns false
//
bool
FindVerticalLineEllipseIntersections
(
double
a
,
double
b
,
double
x
,
double
*
y1
,
double
*
y2
)
{
double
y_sqr
=
(
1.0
-
(
x
*
x
)
/
(
a
*
a
))
*
b
*
b
;
if
(
y_sqr
<
0.0
)
return
false
;
*
y1
=
sqrt
(
y_sqr
);
*
y2
=
-*
y1
;
return
true
;
}
// finds intersections of straight line y = c + dx
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool
FindLineEllipseIntersections
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x1
,
double
*
x2
)
{
// quadratic terms
double
A
=
d
*
d
+
b
*
b
/
(
a
*
a
);
double
B
=
2.0
*
c
*
d
;
double
C
=
c
*
c
-
b
*
b
;
return
Quadratic
(
A
,
B
,
C
,
x1
,
x2
);
}
#if 0
// draw a straight line or an arc between xi,yi and xf,yf
//
void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, bool bMeta )
{
int xi, yi, xf, yf;
if( shape == DL_LINE || xxi == xxf || yyi == yyf )
{
// draw straight line
pDC->MoveTo( xxi, yyi );
pDC->LineTo( xxf, yyf );
}
else if( shape == DL_ARC_CCW || shape == DL_ARC_CW )
{
// set endpoints so we can always draw counter-clockwise arc
if( shape == DL_ARC_CW )
{
xi = xxf;
yi = yyf;
xf = xxi;
yf = yyi;
}
else
{
xi = xxi;
yi = yyi;
xf = xxf;
yf = yyf;
}
pDC->MoveTo( xi, yi );
if( xf > xi && yf > yi )
{
// quadrant 1
int w = (xf-xi)*2;
int h = (yf-yi)*2;
if( !bMeta )
pDC->Arc( xf-w, yi+h, xf, yi,
xi, yi, xf, yf );
else
pDC->Arc( xf-w, yi, xf, yi+h,
xf, yf, xi, yi );
}
else if( xf < xi && yf > yi )
{
// quadrant 2
int w = -(xf-xi)*2;
int h = (yf-yi)*2;
if( !bMeta )
pDC->Arc( xi-w, yf, xi, yf-h,
xi, yi, xf, yf );
else
pDC->Arc( xi-w, yf-h, xi, yf,
xf, yf, xi, yi );
}
else if( xf < xi && yf < yi )
{
// quadrant 3
int w = -(xf-xi)*2;
int h = -(yf-yi)*2;
if( !bMeta )
pDC->Arc( xf, yi, xf+w, yi-h,
xi, yi, xf, yf );
else
pDC->Arc( xf, yi-h, xf+w, yi,
xf, yf, xi, yi );
}
else if( xf > xi && yf < yi )
{
// quadrant 4
int w = (xf-xi)*2;
int h = -(yf-yi)*2;
if( !bMeta )
pDC->Arc( xi, yf+h, xi+w, yf,
xi, yi, xf, yf );
else
pDC->Arc( xi, yf, xi+w, yf+h,
xf, yf, xi, yi );
}
pDC->MoveTo( xxf, yyf );
}
else
ASSERT(0); // oops
}
#endif
// Get arrays of circles, rects and line segments to represent pad
// for purposes of drawing pad or calculating clearances
// margins of circles and line segments represent pad outline
// circles and rects are used to find points inside pad
//
void
GetPadElements
(
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
,
int
*
nr
,
my_rect
r
[],
int
*
nc
,
my_circle
c
[],
int
*
ns
,
my_seg
s
[]
)
{
*
nc
=
0
;
*
nr
=
0
;
*
ns
=
0
;
if
(
type
==
PAD_ROUND
)
{
*
nc
=
1
;
c
[
0
]
=
my_circle
(
x
,
y
,
wid
/
2
);
return
;
}
if
(
type
==
PAD_SQUARE
)
{
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
wid
/
2
,
y
-
wid
/
2
,
x
+
wid
/
2
,
y
+
wid
/
2
);
*
ns
=
4
;
s
[
0
]
=
my_seg
(
x
-
wid
/
2
,
y
+
wid
/
2
,
x
+
wid
/
2
,
y
+
wid
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
wid
/
2
,
y
-
wid
/
2
,
x
+
wid
/
2
,
y
-
wid
/
2
);
// bottom
s
[
2
]
=
my_seg
(
x
-
wid
/
2
,
y
-
wid
/
2
,
x
-
wid
/
2
,
y
+
wid
/
2
);
// left
s
[
3
]
=
my_seg
(
x
+
wid
/
2
,
y
-
wid
/
2
,
x
+
wid
/
2
,
y
+
wid
/
2
);
// right
return
;
}
if
(
type
==
PAD_OCTAGON
)
{
const
double
pi
=
3.14159265359
;
*
nc
=
1
;
// circle represents inside of polygon
c
[
0
]
=
my_circle
(
x
,
y
,
wid
/
2
);
*
ns
=
8
;
// now create sides of polygon
double
theta
=
pi
/
8.0
;
double
radius
=
0.5
*
(
double
)
wid
/
cos
(
theta
);
double
last_x
=
x
+
radius
*
cos
(
theta
);
double
last_y
=
y
+
radius
*
sin
(
theta
);
for
(
int
is
=
0
;
is
<
8
;
is
++
)
{
theta
+=
pi
/
4.0
;
double
dx
=
x
+
radius
*
cos
(
theta
);
double
dy
=
y
+
radius
*
sin
(
theta
);
s
[
is
]
=
my_seg
(
last_x
,
last_y
,
x
,
y
);
last_x
=
dx
;
last_y
=
dy
;
}
return
;
}
//
int
h
;
int
v
;
if
(
angle
==
90
||
angle
==
270
)
{
h
=
wid
;
v
=
len
;
}
else
{
v
=
wid
;
h
=
len
;
}
if
(
type
==
PAD_RECT
)
{
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
h
/
2
,
y
-
v
/
2
,
x
+
h
/
2
,
y
+
v
/
2
);
*
ns
=
4
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
,
y
+
v
/
2
,
x
+
h
/
2
,
y
+
v
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
,
x
+
h
/
2
,
y
-
v
/
2
);
// bottom
s
[
2
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
,
x
-
h
/
2
,
y
+
v
/
2
);
// left
s
[
3
]
=
my_seg
(
x
+
h
/
2
,
y
-
v
/
2
,
x
+
h
/
2
,
y
+
v
/
2
);
// right
return
;
}
if
(
type
==
PAD_RRECT
)
{
*
nc
=
4
;
c
[
0
]
=
my_circle
(
x
-
h
/
2
+
radius
,
y
-
v
/
2
+
radius
,
radius
);
// bottom left circle
c
[
1
]
=
my_circle
(
x
+
h
/
2
-
radius
,
y
-
v
/
2
+
radius
,
radius
);
// bottom right circle
c
[
2
]
=
my_circle
(
x
-
h
/
2
+
radius
,
y
+
v
/
2
-
radius
,
radius
);
// top left circle
c
[
3
]
=
my_circle
(
x
+
h
/
2
-
radius
,
y
+
v
/
2
-
radius
,
radius
);
// top right circle
*
ns
=
4
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
+
radius
,
y
+
v
/
2
,
x
+
h
/
2
-
radius
,
y
+
v
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
h
/
2
+
radius
,
y
-
v
/
2
,
x
+
h
/
2
-
radius
,
y
+
v
/
2
);
// bottom
s
[
2
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
+
radius
,
x
-
h
/
2
,
y
+
v
/
2
-
radius
);
// left
s
[
3
]
=
my_seg
(
x
+
h
/
2
,
y
-
v
/
2
+
radius
,
x
+
h
/
2
,
y
+
v
/
2
-
radius
);
// right
return
;
}
if
(
type
==
PAD_OVAL
)
{
if
(
h
>
v
)
{
// horizontal
*
nc
=
2
;
c
[
0
]
=
my_circle
(
x
-
h
/
2
+
v
/
2
,
y
,
v
/
2
);
// left circle
c
[
1
]
=
my_circle
(
x
+
h
/
2
-
v
/
2
,
y
,
v
/
2
);
// right circle
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
h
/
2
+
v
/
2
,
y
-
v
/
2
,
x
+
h
/
2
-
v
/
2
,
y
+
v
/
2
);
*
ns
=
2
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
+
v
/
2
,
y
+
v
/
2
,
x
+
h
/
2
-
v
/
2
,
y
+
v
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
h
/
2
+
v
/
2
,
y
-
v
/
2
,
x
+
h
/
2
-
v
/
2
,
y
-
v
/
2
);
// bottom
}
else
{
// vertical
*
nc
=
2
;
c
[
0
]
=
my_circle
(
x
,
y
+
v
/
2
-
h
/
2
,
h
/
2
);
// top circle
c
[
1
]
=
my_circle
(
x
,
y
-
v
/
2
+
h
/
2
,
h
/
2
);
// bottom circle
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
h
/
2
,
y
-
v
/
2
+
h
/
2
,
x
+
h
/
2
,
y
+
v
/
2
-
h
/
2
);
*
ns
=
2
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
+
h
/
2
,
x
-
h
/
2
,
y
+
v
/
2
-
h
/
2
);
// left
s
[
1
]
=
my_seg
(
x
+
h
/
2
,
y
-
v
/
2
+
h
/
2
,
x
+
h
/
2
,
y
+
v
/
2
-
h
/
2
);
// left
}
return
;
}
ASSERT
(
0
);
}
// Find distance from a staright line segment to a pad
//
int
GetClearanceBetweenSegmentAndPad
(
int
x1
,
int
y1
,
int
x2
,
int
y2
,
int
w
,
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
)
{
if
(
type
==
PAD_NONE
)
return
INT_MAX
;
else
{
int
nc
,
nr
,
ns
;
my_circle
c
[
4
];
my_rect
r
[
2
];
my_seg
s
[
8
];
GetPadElements
(
type
,
x
,
y
,
wid
,
len
,
radius
,
angle
,
&
nr
,
r
,
&
nc
,
c
,
&
ns
,
s
);
// first test for endpoints of line segment in rectangle
for
(
int
ir
=
0
;
ir
<
nr
;
ir
++
)
{
if
(
x1
>=
r
[
ir
].
xlo
&&
x1
<=
r
[
ir
].
xhi
&&
y1
>=
r
[
ir
].
ylo
&&
y1
<=
r
[
ir
].
yhi
)
return
0
;
if
(
x2
>=
r
[
ir
].
xlo
&&
x2
<=
r
[
ir
].
xhi
&&
y2
>=
r
[
ir
].
ylo
&&
y2
<=
r
[
ir
].
yhi
)
return
0
;
}
// now get distance from elements of pad outline
int
dist
=
INT_MAX
;
for
(
int
ic
=
0
;
ic
<
nc
;
ic
++
)
{
int
d
=
GetPointToLineSegmentDistance
(
c
[
ic
].
x
,
c
[
ic
].
y
,
x1
,
y1
,
x2
,
y2
)
-
c
[
ic
].
r
-
w
/
2
;
dist
=
min
(
dist
,
d
);
}
for
(
int
is
=
0
;
is
<
ns
;
is
++
)
{
double
d
;
TestForIntersectionOfStraightLineSegments
(
s
[
is
].
xi
,
s
[
is
].
yi
,
s
[
is
].
xf
,
s
[
is
].
yf
,
x1
,
y1
,
x2
,
y2
,
NULL
,
NULL
,
&
d
);
d
-=
w
/
2
;
dist
=
min
(
dist
,
d
);
}
return
max
(
0
,
dist
);
}
}
// Get clearance between 2 segments
// Returns point in segment closest to other segment in x, y
// in clearance > max_cl, just returns max_cl and doesn't return x,y
//
int
GetClearanceBetweenSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
style1
,
int
w1
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
style2
,
int
w2
,
int
max_cl
,
int
*
x
,
int
*
y
)
{
// check clearance between bounding rectangles
int
test
=
max_cl
+
w1
/
2
+
w2
/
2
;
if
(
min
(
x1i
,
x1f
)
-
max
(
x2i
,
x2f
)
>
test
)
return
max_cl
;
if
(
min
(
x2i
,
x2f
)
-
max
(
x1i
,
x1f
)
>
test
)
return
max_cl
;
if
(
min
(
y1i
,
y1f
)
-
max
(
y2i
,
y2f
)
>
test
)
return
max_cl
;
if
(
min
(
y2i
,
y2f
)
-
max
(
y1i
,
y1f
)
>
test
)
return
max_cl
;
if
(
style1
==
CPolyLine
::
STRAIGHT
&&
style1
==
CPolyLine
::
STRAIGHT
)
{
// both segments are straight lines
int
xx
,
yy
;
double
dd
;
TestForIntersectionOfStraightLineSegments
(
x1i
,
y1i
,
x1f
,
y1f
,
x2i
,
y2i
,
x2f
,
y2f
,
&
xx
,
&
yy
,
&
dd
);
int
d
=
max
(
0
,
dd
-
w1
/
2
-
w2
/
2
);
if
(
x
)
*
x
=
xx
;
if
(
y
)
*
y
=
yy
;
return
d
;
}
// not both straight-line segments
// see if segments intersect
double
xr
[
2
];
double
yr
[
2
];
test
=
FindSegmentIntersections
(
x1i
,
y1i
,
x1f
,
y1f
,
style1
,
x2i
,
y2i
,
x2f
,
y2f
,
style2
,
xr
,
yr
);
if
(
test
)
{
if
(
x
)
*
x
=
xr
[
0
];
if
(
y
)
*
y
=
yr
[
0
];
return
0.0
;
}
// at least one segment is an arc
EllipseKH
el1
;
EllipseKH
el2
;
bool
bArcs
;
int
xi
,
yi
,
xf
,
yf
;
if
(
style2
==
CPolyLine
::
STRAIGHT
)
{
// style1 = arc, style2 = straight
MakeEllipseFromArc
(
x1i
,
y1i
,
x1f
,
y1f
,
style1
,
&
el1
);
xi
=
x2i
;
yi
=
y2i
;
xf
=
x2f
;
yf
=
y2f
;
bArcs
=
false
;
}
else
if
(
style1
==
CPolyLine
::
STRAIGHT
)
{
// style2 = arc, style1 = straight
xi
=
x1i
;
yi
=
y1i
;
xf
=
x1f
;
yf
=
y1f
;
MakeEllipseFromArc
(
x2i
,
y2i
,
x2f
,
y2f
,
style2
,
&
el1
);
bArcs
=
false
;
}
else
{
// style1 = arc, style2 = arc
MakeEllipseFromArc
(
x1i
,
y1i
,
x1f
,
y1f
,
style1
,
&
el1
);
MakeEllipseFromArc
(
x2i
,
y2i
,
x2f
,
y2f
,
style2
,
&
el2
);
bArcs
=
true
;
}
const
int
NSTEPS
=
32
;
if
(
el1
.
theta2
>
el1
.
theta1
)
ASSERT
(
0
);
if
(
bArcs
&&
el2
.
theta2
>
el2
.
theta1
)
ASSERT
(
0
);
// test multiple points in both segments
double
th1
;
double
th2
;
double
len2
;
if
(
bArcs
)
{
th1
=
el2
.
theta1
;
th2
=
el2
.
theta2
;
len2
=
max
(
el2
.
xrad
,
el2
.
yrad
);
}
else
{
th1
=
1.0
;
th2
=
0.0
;
len2
=
abs
(
xf
-
xi
)
+
abs
(
yf
-
yi
);
}
double
s_start
=
el1
.
theta1
;
double
s_end
=
el1
.
theta2
;
double
s_start2
=
th1
;
double
s_end2
=
th2
;
double
dmin
=
DBL_MAX
;
double
xmin
,
ymin
,
smin
,
smin2
;
int
nsteps
=
NSTEPS
;
int
nsteps2
=
NSTEPS
;
double
step
=
(
s_start
-
s_end
)
/
(
nsteps
-
1
);
double
step2
=
(
s_start2
-
s_end2
)
/
(
nsteps2
-
1
);
while
(
(
step
*
max
(
el1
.
xrad
,
el1
.
yrad
))
>
0.1
*
NM_PER_MIL
&&
(
step2
*
len2
)
>
0.1
*
NM_PER_MIL
)
{
step
=
(
s_start
-
s_end
)
/
(
nsteps
-
1
);
for
(
int
i
=
0
;
i
<
nsteps
;
i
++
)
{
double
s
;
if
(
i
<
nsteps
-
1
)
s
=
s_start
-
i
*
step
;
else
s
=
s_end
;
double
x
=
el1
.
Center
.
X
+
el1
.
xrad
*
cos
(
s
);
double
y
=
el1
.
Center
.
Y
+
el1
.
yrad
*
sin
(
s
);
// if not an arc, use s2 as fractional distance along line
step2
=
(
s_start2
-
s_end2
)
/
(
nsteps2
-
1
);
for
(
int
i2
=
0
;
i2
<
nsteps2
;
i2
++
)
{
double
s2
;
if
(
i2
<
nsteps2
-
1
)
s2
=
s_start2
-
i2
*
step2
;
else
s2
=
s_end2
;
double
x2
,
y2
;
if
(
!
bArcs
)
{
x2
=
xi
+
(
xf
-
xi
)
*
s2
;
y2
=
yi
+
(
yf
-
yi
)
*
s2
;
}
else
{
x2
=
el2
.
Center
.
X
+
el2
.
xrad
*
cos
(
s2
);
y2
=
el2
.
Center
.
Y
+
el2
.
yrad
*
sin
(
s2
);
}
double
d
=
Distance
(
x
,
y
,
x2
,
y2
);
if
(
d
<
dmin
)
{
dmin
=
d
;
xmin
=
x
;
ymin
=
y
;
smin
=
s
;
smin2
=
s2
;
}
}
}
if
(
step
>
step2
)
{
s_start
=
min
(
el1
.
theta1
,
smin
+
step
);
s_end
=
max
(
el1
.
theta2
,
smin
-
step
);
step
=
(
s_start
-
s_end
)
/
nsteps
;
}
else
{
s_start2
=
min
(
th1
,
smin2
+
step2
);
s_end2
=
max
(
th2
,
smin2
-
step2
);
step2
=
(
s_start2
-
s_end2
)
/
nsteps2
;
}
}
if
(
x
)
*
x
=
xmin
;
if
(
y
)
*
y
=
ymin
;
return
max
(
0
,
dmin
-
w1
/
2
-
w2
/
2
);
// allow for widths
}
// Find clearance between pads
// For each pad:
// type = PAD_ROUND, PAD_SQUARE, etc.
// x, y = center position
// w, l = width and length
// r = corner radius
// angle = 0 or 90 (if 0, pad length is along x-axis)
//
int
GetClearanceBetweenPads
(
int
type1
,
int
x1
,
int
y1
,
int
w1
,
int
l1
,
int
r1
,
int
angle1
,
int
type2
,
int
x2
,
int
y2
,
int
w2
,
int
l2
,
int
r2
,
int
angle2
)
{
if
(
type1
==
PAD_NONE
)
return
INT_MAX
;
if
(
type2
==
PAD_NONE
)
return
INT_MAX
;
int
dist
=
INT_MAX
;
int
nr
,
nc
,
ns
,
nrr
,
ncc
,
nss
;
my_rect
r
[
2
],
rr
[
2
];
my_circle
c
[
4
],
cc
[
4
];
my_seg
s
[
8
],
ss
[
8
];
GetPadElements
(
type1
,
x1
,
y1
,
w1
,
l1
,
r1
,
angle1
,
&
nr
,
r
,
&
nc
,
c
,
&
ns
,
s
);
GetPadElements
(
type2
,
x2
,
y2
,
w2
,
l2
,
r2
,
angle2
,
&
nrr
,
rr
,
&
ncc
,
cc
,
&
nss
,
ss
);
// now find distance from every element of pad1 to every element of pad2
for
(
int
ic
=
0
;
ic
<
nc
;
ic
++
)
{
for
(
int
icc
=
0
;
icc
<
ncc
;
icc
++
)
{
int
d
=
Distance
(
c
[
ic
].
x
,
c
[
ic
].
y
,
cc
[
icc
].
x
,
cc
[
icc
].
y
)
-
c
[
ic
].
r
-
cc
[
icc
].
r
;
dist
=
min
(
dist
,
d
);
}
for
(
int
iss
=
0
;
iss
<
nss
;
iss
++
)
{
int
d
=
GetPointToLineSegmentDistance
(
c
[
ic
].
x
,
c
[
ic
].
y
,
ss
[
iss
].
xi
,
ss
[
iss
].
yi
,
ss
[
iss
].
xf
,
ss
[
iss
].
yf
)
-
c
[
ic
].
r
;
dist
=
min
(
dist
,
d
);
}
}
for
(
int
is
=
0
;
is
<
ns
;
is
++
)
{
for
(
int
icc
=
0
;
icc
<
ncc
;
icc
++
)
{
int
d
=
GetPointToLineSegmentDistance
(
cc
[
icc
].
x
,
cc
[
icc
].
y
,
s
[
is
].
xi
,
s
[
is
].
yi
,
s
[
is
].
xf
,
s
[
is
].
yf
)
-
cc
[
icc
].
r
;
dist
=
min
(
dist
,
d
);
}
for
(
int
iss
=
0
;
iss
<
nss
;
iss
++
)
{
double
d
;
TestForIntersectionOfStraightLineSegments
(
s
[
is
].
xi
,
s
[
is
].
yi
,
s
[
is
].
xf
,
s
[
is
].
yf
,
ss
[
iss
].
xi
,
ss
[
iss
].
yi
,
ss
[
iss
].
xf
,
ss
[
iss
].
yf
,
NULL
,
NULL
,
&
d
);
dist
=
min
(
dist
,
d
);
}
}
return
max
(
dist
,
0
);
}
// Get min. distance from (x,y) to line y = a + bx
// if b > DBL_MAX/10, assume vertical line at x = a
// returns closest point on line in xp, yp
//
double
GetPointToLineDistance
(
double
a
,
double
b
,
int
x
,
int
y
,
double
*
xpp
,
double
*
ypp
)
{
if
(
b
>
DBL_MAX
/
10
)
{
// vertical line
if
(
xpp
&&
ypp
)
{
*
xpp
=
a
;
*
ypp
=
y
;
}
return
abs
(
a
-
x
);
}
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double
d
=
-
1.0
/
b
;
double
c
=
(
double
)
y
-
d
*
x
;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double
xp
=
(
a
-
c
)
/
(
d
-
b
);
double
yp
=
a
+
b
*
xp
;
if
(
xpp
&&
ypp
)
{
*
xpp
=
xp
;
*
ypp
=
yp
;
}
// find distance
return
Distance
(
x
,
y
,
xp
,
yp
);
}
/***********************************************************************************/
double
GetPointToLineSegmentDistance
(
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
)
/***********************************************************************************/
/** Function GetPointToLineSegmentDistance
* Get distance between line segment and point
* @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance
*/
{
// test for vertical or horizontal segment
if
(
xf
==
xi
)
{
// vertical line segment
if
(
InRange
(
y
,
yi
,
yf
)
)
return
abs
(
x
-
xi
);
else
return
min
(
Distance
(
x
,
y
,
xi
,
yi
),
Distance
(
x
,
y
,
xf
,
yf
)
);
}
else
if
(
yf
==
yi
)
{
// horizontal line segment
if
(
InRange
(
x
,
xi
,
xf
)
)
return
abs
(
y
-
yi
);
else
return
min
(
Distance
(
x
,
y
,
xi
,
yi
),
Distance
(
x
,
y
,
xf
,
yf
)
);
}
else
{
// oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double
b
=
(
double
)(
yf
-
yi
)
/
(
xf
-
xi
);
double
a
=
(
double
)
yi
-
b
*
xi
;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double
d
=
-
1.0
/
b
;
double
c
=
(
double
)
y
-
d
*
x
;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double
xp
=
(
a
-
c
)
/
(
d
-
b
);
double
yp
=
a
+
b
*
xp
;
// find distance
if
(
InRange
(
xp
,
xi
,
xf
)
&&
InRange
(
yp
,
yi
,
yf
)
)
return
Distance
(
x
,
y
,
xp
,
yp
);
else
return
min
(
Distance
(
x
,
y
,
xi
,
yi
),
Distance
(
x
,
y
,
xf
,
yf
)
);
}
}
// test for value within range
//
bool
InRange
(
double
x
,
double
xi
,
double
xf
)
{
if
(
xf
>
xi
)
{
if
(
x
>=
xi
&&
x
<=
xf
)
return
true
;
}
else
{
if
(
x
>=
xf
&&
x
<=
xi
)
return
true
;
}
return
false
;
}
// Get distance between 2 points
//
double
Distance
(
int
x1
,
int
y1
,
int
x2
,
int
y2
)
{
double
d
;
d
=
sqrt
(
(
double
)(
x1
-
x2
)
*
(
x1
-
x2
)
+
(
double
)(
y1
-
y2
)
*
(
y1
-
y2
)
);
if
(
d
>
INT_MAX
||
d
<
INT_MIN
)
ASSERT
(
0
);
return
(
int
)
d
;
}
// this finds approximate solutions
// note: this works best if el2 is smaller than el1
//
int
GetArcIntersections
(
EllipseKH
*
el1
,
EllipseKH
*
el2
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
)
{
if
(
el1
->
theta2
>
el1
->
theta1
)
ASSERT
(
0
);
if
(
el2
->
theta2
>
el2
->
theta1
)
ASSERT
(
0
);
const
int
NSTEPS
=
32
;
double
xret
[
2
],
yret
[
2
];
double
xscale
=
1.0
/
el1
->
xrad
;
double
yscale
=
1.0
/
el1
->
yrad
;
// now transform params of second ellipse into reference frame
// with origin at center if first ellipse,
// scaled so the first ellipse is a circle of radius = 1.0
double
xo
=
(
el2
->
Center
.
X
-
el1
->
Center
.
X
)
*
xscale
;
double
yo
=
(
el2
->
Center
.
Y
-
el1
->
Center
.
Y
)
*
yscale
;
double
xr
=
el2
->
xrad
*
xscale
;
double
yr
=
el2
->
yrad
*
yscale
;
// now test NSTEPS positions in arc, moving clockwise (ie. decreasing theta)
double
step
=
M_PI
/
((
NSTEPS
-
1
)
*
2.0
);
double
d_prev
,
th_prev
;
double
th_interp
;
double
th1
;
int
n
=
0
;
for
(
int
i
=
0
;
i
<
NSTEPS
;
i
++
)
{
double
theta
;
if
(
i
<
NSTEPS
-
1
)
theta
=
el2
->
theta1
-
i
*
step
;
else
theta
=
el2
->
theta2
;
double
x
=
xo
+
xr
*
cos
(
theta
);
double
y
=
yo
+
yr
*
sin
(
theta
);
double
d
=
1.0
-
sqrt
(
x
*
x
+
y
*
y
);
if
(
i
>
0
)
{
bool
bInt
=
false
;
if
(
d
>=
0.0
&&
d_prev
<=
0.0
)
{
th_interp
=
theta
+
(
step
*
(
-
d_prev
))
/
(
d
-
d_prev
);
bInt
=
true
;
}
else
if
(
d
<=
0.0
&&
d_prev
>=
0.0
)
{
th_interp
=
theta
+
(
step
*
d_prev
)
/
(
d_prev
-
d
);
bInt
=
true
;
}
if
(
bInt
)
{
x
=
xo
+
xr
*
cos
(
th_interp
);
y
=
yo
+
yr
*
sin
(
th_interp
);
th1
=
atan2
(
y
,
x
);
if
(
th1
<=
el1
->
theta1
&&
th1
>=
el1
->
theta2
)
{
xret
[
n
]
=
x
*
el1
->
xrad
+
el1
->
Center
.
X
;
yret
[
n
]
=
y
*
el1
->
yrad
+
el1
->
Center
.
Y
;
n
++
;
if
(
n
>
2
)
ASSERT
(
0
);
}
}
}
d_prev
=
d
;
th_prev
=
theta
;
}
if
(
x1
)
*
x1
=
xret
[
0
];
if
(
y1
)
*
y1
=
yret
[
0
];
if
(
x2
)
*
x2
=
xret
[
1
];
if
(
y2
)
*
y2
=
yret
[
1
];
return
n
;
}
// this finds approximate solution
//
//double GetSegmentClearance( EllipseKH * el1, EllipseKH * el2,
double
GetArcClearance
(
EllipseKH
*
el1
,
EllipseKH
*
el2
,
double
*
x1
,
double
*
y1
)
{
const
int
NSTEPS
=
32
;
if
(
el1
->
theta2
>
el1
->
theta1
)
ASSERT
(
0
);
if
(
el2
->
theta2
>
el2
->
theta1
)
ASSERT
(
0
);
// test multiple positions in both arcs, moving clockwise (ie. decreasing theta)
double
th_start
=
el1
->
theta1
;
double
th_end
=
el1
->
theta2
;
double
th_start2
=
el2
->
theta1
;
double
th_end2
=
el2
->
theta2
;
double
dmin
=
DBL_MAX
;
double
xmin
,
ymin
,
thmin
,
thmin2
;
int
nsteps
=
NSTEPS
;
int
nsteps2
=
NSTEPS
;
double
step
=
(
th_start
-
th_end
)
/
(
nsteps
-
1
);
double
step2
=
(
th_start2
-
th_end2
)
/
(
nsteps2
-
1
);
while
(
(
step
*
max
(
el1
->
xrad
,
el1
->
yrad
))
>
1.0
*
NM_PER_MIL
&&
(
step2
*
max
(
el2
->
xrad
,
el2
->
yrad
))
>
1.0
*
NM_PER_MIL
)
{
step
=
(
th_start
-
th_end
)
/
(
nsteps
-
1
);
for
(
int
i
=
0
;
i
<
nsteps
;
i
++
)
{
double
theta
;
if
(
i
<
nsteps
-
1
)
theta
=
th_start
-
i
*
step
;
else
theta
=
th_end
;
double
x
=
el1
->
Center
.
X
+
el1
->
xrad
*
cos
(
theta
);
double
y
=
el1
->
Center
.
Y
+
el1
->
yrad
*
sin
(
theta
);
step2
=
(
th_start2
-
th_end2
)
/
(
nsteps2
-
1
);
for
(
int
i2
=
0
;
i2
<
nsteps2
;
i2
++
)
{
double
theta2
;
if
(
i2
<
nsteps2
-
1
)
theta2
=
th_start2
-
i2
*
step2
;
else
theta2
=
th_end2
;
double
x2
=
el2
->
Center
.
X
+
el2
->
xrad
*
cos
(
theta2
);
double
y2
=
el2
->
Center
.
Y
+
el2
->
yrad
*
sin
(
theta2
);
double
d
=
Distance
(
x
,
y
,
x2
,
y2
);
if
(
d
<
dmin
)
{
dmin
=
d
;
xmin
=
x
;
ymin
=
y
;
thmin
=
theta
;
thmin2
=
theta2
;
}
}
}
if
(
step
>
step2
)
{
th_start
=
min
(
el1
->
theta1
,
thmin
+
step
);
th_end
=
max
(
el1
->
theta2
,
thmin
-
step
);
step
=
(
th_start
-
th_end
)
/
nsteps
;
}
else
{
th_start2
=
min
(
el2
->
theta1
,
thmin2
+
step2
);
th_end2
=
max
(
el2
->
theta2
,
thmin2
-
step2
);
step2
=
(
th_start2
-
th_end2
)
/
nsteps2
;
}
}
if
(
x1
)
*
x1
=
xmin
;
if
(
y1
)
*
y1
=
ymin
;
return
dmin
;
}
// math for graphics utility routines, from FreePCB
using
namespace
std
;
#include <vector>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "defs-macros.h"
#include "PolyLine2Kicad.h"
#include "freepcb_ids.h"
#include "PolyLine.h"
// function to find inflection-pont to create a "dogleg" of two straight-line segments
// where one segment is vertical or horizontal and the other is at 45 degrees or 90 degrees
// enter with:
// pi = start point
// pf = end point
// mode = IM_90_45 or IM_45_90 or IM_90
//
CPoint
GetInflectionPoint
(
CPoint
pi
,
CPoint
pf
,
int
mode
)
{
CPoint
p
=
pi
;
if
(
mode
==
IM_NONE
)
return
p
;
int
dx
=
pf
.
x
-
pi
.
x
;
int
dy
=
pf
.
y
-
pi
.
y
;
if
(
dx
==
0
||
dy
==
0
||
abs
(
dx
)
==
abs
(
dy
)
)
{
// only one segment needed
}
else
{
if
(
abs
(
dy
)
>
abs
(
dx
)
)
{
// vertical > horizontal
if
(
mode
==
IM_90
)
{
p
.
x
=
pi
.
x
;
p
.
y
=
pf
.
y
;
}
else
if
(
mode
==
IM_45_90
||
mode
==
IM_90_45
)
{
int
vert
;
// length of vertical line needed
if
(
dy
>
0
)
vert
=
dy
-
abs
(
dx
);
// positive
else
vert
=
dy
+
abs
(
dx
);
// negative
if
(
mode
==
IM_90_45
)
p
.
y
=
pi
.
y
+
vert
;
else
if
(
mode
==
IM_45_90
)
{
p
.
y
=
pf
.
y
-
vert
;
p
.
x
=
pf
.
x
;
}
}
else
ASSERT
(
0
);
}
else
{
// horizontal > vertical
if
(
mode
==
IM_90
)
{
p
.
x
=
pf
.
x
;
p
.
y
=
pi
.
y
;
}
else
if
(
mode
==
IM_45_90
||
mode
==
IM_90_45
)
{
int
hor
;
// length of horizontal line needed
if
(
dx
>
0
)
hor
=
dx
-
abs
(
dy
);
// positive
else
hor
=
dx
+
abs
(
dy
);
// negative
if
(
mode
==
IM_90_45
)
p
.
x
=
pi
.
x
+
hor
;
else
if
(
mode
==
IM_45_90
)
{
p
.
x
=
pf
.
x
-
hor
;
p
.
y
=
pf
.
y
;
}
}
else
ASSERT
(
0
);
}
}
return
p
;
}
//
// function to rotate a point clockwise about another point
// currently, angle must be 0, 90, 180 or 270
//
void
RotatePoint
(
CPoint
*
p
,
int
angle
,
CPoint
org
)
{
if
(
angle
==
90
)
{
int
tempy
=
org
.
y
+
(
org
.
x
-
p
->
x
);
p
->
x
=
org
.
x
+
(
p
->
y
-
org
.
y
);
p
->
y
=
tempy
;
}
else
if
(
angle
>
90
)
{
for
(
int
i
=
0
;
i
<
(
angle
/
90
);
i
++
)
RotatePoint
(
p
,
90
,
org
);
}
}
// function to rotate a rectangle clockwise about a point
// angle must be 0, 90, 180 or 270
// on exit, r->top > r.bottom, r.right > r.left
//
void
RotateRect
(
CRect
*
r
,
int
angle
,
CPoint
org
)
{
CRect
tr
;
if
(
angle
==
90
)
{
tr
.
left
=
org
.
x
+
(
r
->
bottom
-
org
.
y
);
tr
.
right
=
org
.
x
+
(
r
->
top
-
org
.
y
);
tr
.
top
=
org
.
y
+
(
org
.
x
-
r
->
right
);
tr
.
bottom
=
org
.
y
+
(
org
.
x
-
r
->
left
);
if
(
tr
.
left
>
tr
.
right
)
{
int
temp
=
tr
.
right
;
tr
.
left
=
tr
.
right
;
tr
.
left
=
temp
;
}
if
(
tr
.
left
>
tr
.
right
)
{
int
temp
=
tr
.
right
;
tr
.
left
=
tr
.
right
;
tr
.
left
=
temp
;
}
if
(
tr
.
bottom
>
tr
.
top
)
{
int
temp
=
tr
.
bottom
;
tr
.
bottom
=
tr
.
top
;
tr
.
top
=
temp
;
}
}
else
if
(
angle
>
90
)
{
tr
=
*
r
;
for
(
int
i
=
0
;
i
<
(
angle
/
90
);
i
++
)
RotateRect
(
&
tr
,
90
,
org
);
}
*
r
=
tr
;
}
// test for hit on line segment
// i.e. cursor within a given distance from segment
// enter with: x,y = cursor coords
// (xi,yi) and (xf,yf) are the end-points of the line segment
// dist = maximum distance for hit
//
int
TestLineHit
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
x
,
int
y
,
double
dist
)
{
double
dd
;
// test for vertical or horizontal segment
if
(
xf
==
xi
)
{
// vertical segment
dd
=
fabs
(
(
double
)(
x
-
xi
)
);
if
(
dd
<
dist
&&
(
(
yf
>
yi
&&
y
<
yf
&&
y
>
yi
)
||
(
yf
<
yi
&&
y
>
yf
&&
y
<
yi
)
)
)
return
1
;
}
else
if
(
yf
==
yi
)
{
// horizontal segment
dd
=
fabs
(
(
double
)(
y
-
yi
)
);
if
(
dd
<
dist
&&
(
(
xf
>
xi
&&
x
<
xf
&&
x
>
xi
)
||
(
xf
<
xi
&&
x
>
xf
&&
x
<
xi
)
)
)
return
1
;
}
else
{
// oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double
b
=
(
double
)(
yf
-
yi
)
/
(
xf
-
xi
);
double
a
=
(
double
)
yi
-
b
*
xi
;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double
d
=
-
1.0
/
b
;
double
c
=
(
double
)
y
-
d
*
x
;
// find nearest point to (x,y) on line segment (xi,yi) to (xf,yf)
double
xp
=
(
a
-
c
)
/
(
d
-
b
);
double
yp
=
a
+
b
*
xp
;
// find distance
dd
=
sqrt
((
x
-
xp
)
*
(
x
-
xp
)
+
(
y
-
yp
)
*
(
y
-
yp
));
if
(
fabs
(
b
)
>
0.7
)
{
// line segment more vertical than horizontal
if
(
dd
<
dist
&&
(
(
yf
>
yi
&&
yp
<
yf
&&
yp
>
yi
)
||
(
yf
<
yi
&&
yp
>
yf
&&
yp
<
yi
)
)
)
return
1
;
}
else
{
// line segment more horizontal than vertical
if
(
dd
<
dist
&&
(
(
xf
>
xi
&&
xp
<
xf
&&
xp
>
xi
)
||
(
xf
<
xi
&&
xp
>
xf
&&
xp
<
xi
)
)
)
return
1
;
}
}
return
0
;
// no hit
}
// find intersection between y = a + bx and y = c + dx;
//
int
FindLineIntersection
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x
,
double
*
y
)
{
*
x
=
(
c
-
a
)
/
(
b
-
d
);
*
y
=
a
+
b
*
(
*
x
);
return
0
;
}
// set EllipseKH struct to describe the ellipse for an arc
//
int
MakeEllipseFromArc
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
EllipseKH
*
el
)
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int
xxi
,
xxf
,
yyi
,
yyf
;
if
(
style
==
CPolyLine
::
ARC_CCW
)
{
xxi
=
xf
;
xxf
=
xi
;
yyi
=
yf
;
yyf
=
yi
;
}
else
{
xxi
=
xi
;
xxf
=
xf
;
yyi
=
yi
;
yyf
=
yf
;
}
// find center and radii of ellipse
double
xo
,
yo
;
if
(
xxf
>
xxi
&&
yyf
>
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
el
->
theta1
=
M_PI
;
el
->
theta2
=
M_PI
/
2.0
;
}
else
if
(
xxf
<
xxi
&&
yyf
>
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
el
->
theta1
=
-
M_PI
/
2.0
;
el
->
theta2
=
-
M_PI
;
}
else
if
(
xxf
<
xxi
&&
yyf
<
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
el
->
theta1
=
0.0
;
el
->
theta2
=
-
M_PI
/
2.0
;
}
else
if
(
xxf
>
xxi
&&
yyf
<
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
el
->
theta1
=
M_PI
/
2.0
;
el
->
theta2
=
0.0
;
}
el
->
Center
.
X
=
xo
;
el
->
Center
.
Y
=
yo
;
el
->
xrad
=
abs
(
xf
-
xi
);
el
->
yrad
=
abs
(
yf
-
yi
);
#if 0
el->Phi = 0.0;
el->MaxRad = el->xrad;
el->MinRad = el->yrad;
if( el->MaxRad < el->MinRad )
{
el->MaxRad = el->yrad;
el->MinRad = el->xrad;
el->Phi = M_PI/2.0;
}
#endif
return
0
;
}
// find intersections between line segment (xi,yi) to (xf,yf)
// and line segment (xi2,yi2) to (xf2,yf2)
// the line segments may be arcs (i.e. quadrant of an ellipse) or straight
// returns number of intersections found (max of 2)
// returns coords of intersections in arrays x[2], y[2]
//
int
FindSegmentIntersections
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
int
xi2
,
int
yi2
,
int
xf2
,
int
yf2
,
int
style2
,
double
x
[],
double
y
[]
)
{
double
xr
[
12
],
yr
[
12
];
int
iret
=
0
;
if
(
max
(
xi
,
xf
)
<
min
(
xi2
,
xf2
)
||
min
(
xi
,
xf
)
>
max
(
xi2
,
xf2
)
||
max
(
yi
,
yf
)
<
min
(
yi2
,
yf2
)
||
min
(
yi
,
yf
)
>
max
(
yi2
,
yf2
)
)
return
0
;
if
(
style
!=
CPolyLine
::
STRAIGHT
&&
style2
!=
CPolyLine
::
STRAIGHT
)
{
// two identical arcs intersect
if
(
style
==
style2
&&
xi
==
xi2
&&
yi
==
yi2
&&
xf
==
xf2
&&
yf
==
yf2
)
{
if
(
x
&&
y
)
{
x
[
0
]
=
xi
;
y
[
0
]
=
yi
;
}
return
1
;
}
else
if
(
style
!=
style2
&&
xi
==
xf2
&&
yi
==
yf2
&&
xf
==
xi2
&&
yf
==
yi2
)
{
if
(
x
&&
y
)
{
x
[
0
]
=
xi
;
y
[
0
]
=
yi
;
}
return
1
;
}
}
if
(
style
==
CPolyLine
::
STRAIGHT
&&
style2
==
CPolyLine
::
STRAIGHT
)
{
// both straight-line segments
int
x
,
y
;
bool
bYes
=
TestForIntersectionOfStraightLineSegments
(
xi
,
yi
,
xf
,
yf
,
xi2
,
yi2
,
xf2
,
yf2
,
&
x
,
&
y
);
if
(
!
bYes
)
return
0
;
xr
[
0
]
=
x
;
yr
[
0
]
=
y
;
iret
=
1
;
}
else
if
(
style
==
CPolyLine
::
STRAIGHT
)
{
// first segment is straight, second segment is an arc
int
ret
;
double
x1r
,
y1r
,
x2r
,
y2r
;
if
(
xf
==
xi
)
{
// vertical first segment
double
a
=
xi
;
double
b
=
DBL_MAX
/
2.0
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
else
{
double
b
=
(
double
)(
yf
-
yi
)
/
(
double
)(
xf
-
xi
);
double
a
=
yf
-
b
*
xf
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
if
(
ret
==
0
)
return
0
;
if
(
InRange
(
x1r
,
xi
,
xf
)
&&
InRange
(
y1r
,
yi
,
yf
)
)
{
xr
[
iret
]
=
x1r
;
yr
[
iret
]
=
y1r
;
iret
++
;
}
if
(
ret
==
2
)
{
if
(
InRange
(
x2r
,
xi
,
xf
)
&&
InRange
(
y2r
,
yi
,
yf
)
)
{
xr
[
iret
]
=
x2r
;
yr
[
iret
]
=
y2r
;
iret
++
;
}
}
}
else
if
(
style2
==
CPolyLine
::
STRAIGHT
)
{
// first segment is an arc, second segment is straight
int
ret
;
double
x1r
,
y1r
,
x2r
,
y2r
;
if
(
xf2
==
xi2
)
{
// vertical second segment
double
a
=
xi2
;
double
b
=
DBL_MAX
/
2.0
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi
,
yi
,
xf
,
yf
,
style
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
else
{
double
b
=
(
double
)(
yf2
-
yi2
)
/
(
double
)(
xf2
-
xi2
);
double
a
=
yf2
-
b
*
xf2
;
ret
=
FindLineSegmentIntersection
(
a
,
b
,
xi
,
yi
,
xf
,
yf
,
style
,
&
x1r
,
&
y1r
,
&
x2r
,
&
y2r
);
}
if
(
ret
==
0
)
return
0
;
if
(
InRange
(
x1r
,
xi2
,
xf2
)
&&
InRange
(
y1r
,
yi2
,
yf2
)
)
{
xr
[
iret
]
=
x1r
;
yr
[
iret
]
=
y1r
;
iret
++
;
}
if
(
ret
==
2
)
{
if
(
InRange
(
x2r
,
xi2
,
xf2
)
&&
InRange
(
y2r
,
yi2
,
yf2
)
)
{
xr
[
iret
]
=
x2r
;
yr
[
iret
]
=
y2r
;
iret
++
;
}
}
}
else
{
// both segments are arcs
EllipseKH
el1
;
EllipseKH
el2
;
MakeEllipseFromArc
(
xi
,
yi
,
xf
,
yf
,
style
,
&
el1
);
MakeEllipseFromArc
(
xi2
,
yi2
,
xf2
,
yf2
,
style2
,
&
el2
);
int
n
;
if
(
el1
.
xrad
+
el1
.
yrad
>
el2
.
xrad
+
el2
.
yrad
)
n
=
GetArcIntersections
(
&
el1
,
&
el2
);
else
n
=
GetArcIntersections
(
&
el2
,
&
el1
);
iret
=
n
;
}
if
(
x
&&
y
)
{
for
(
int
i
=
0
;
i
<
iret
;
i
++
)
{
x
[
i
]
=
xr
[
i
];
y
[
i
]
=
yr
[
i
];
}
}
return
iret
;
}
// find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
// if b > DBL_MAX/10, assume vertical line at x = a
// the line segment may be an arc (i.e. quadrant of an ellipse)
// return 0 if no intersection
// returns 1 or 2 if intersections found
// sets coords of intersections in *x1, *y1, *x2, *y2
// if no intersection, returns min distance in dist
//
int
FindLineSegmentIntersection
(
double
a
,
double
b
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
,
double
*
dist
)
{
double
xx
,
yy
;
bool
bVert
=
false
;
if
(
b
>
DBL_MAX
/
10.0
)
bVert
=
true
;
if
(
xf
!=
xi
)
{
// non-vertical segment, get intersection
if
(
style
==
CPolyLine
::
STRAIGHT
||
yf
==
yi
)
{
// horizontal or oblique straight segment
// put into form y = c + dx;
double
d
=
(
double
)(
yf
-
yi
)
/
(
double
)(
xf
-
xi
);
double
c
=
yf
-
d
*
xf
;
if
(
bVert
)
{
// if vertical line, easy
if
(
InRange
(
a
,
xi
,
xf
)
)
{
*
x1
=
a
;
*
y1
=
c
+
d
*
a
;
return
1
;
}
else
{
if
(
dist
)
*
dist
=
min
(
abs
(
a
-
xi
),
abs
(
a
-
xf
)
);
return
0
;
}
}
if
(
fabs
(
b
-
d
)
<
1E-12
)
{
// parallel lines
if
(
dist
)
{
*
dist
=
GetPointToLineDistance
(
a
,
b
,
xi
,
xf
);
}
return
0
;
// lines parallel
}
// calculate intersection
xx
=
(
c
-
a
)
/
(
b
-
d
);
yy
=
a
+
b
*
(
xx
);
// see if intersection is within the line segment
if
(
yf
==
yi
)
{
// horizontal line
if
(
(
xx
>=
xi
&&
xx
>
xf
)
||
(
xx
<=
xi
&&
xx
<
xf
)
)
return
0
;
}
else
{
// oblique line
if
(
(
xx
>=
xi
&&
xx
>
xf
)
||
(
xx
<=
xi
&&
xx
<
xf
)
||
(
yy
>
yi
&&
yy
>
yf
)
||
(
yy
<
yi
&&
yy
<
yf
)
)
return
0
;
}
}
else
if
(
style
==
CPolyLine
::
ARC_CW
||
style
==
CPolyLine
::
ARC_CCW
)
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int
xxi
,
xxf
,
yyi
,
yyf
;
if
(
style
==
CPolyLine
::
ARC_CCW
)
{
xxi
=
xf
;
xxf
=
xi
;
yyi
=
yf
;
yyf
=
yi
;
}
else
{
xxi
=
xi
;
xxf
=
xf
;
yyi
=
yi
;
yyf
=
yf
;
}
// find center and radii of ellipse
double
xo
,
yo
,
rx
,
ry
;
if
(
xxf
>
xxi
&&
yyf
>
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
}
else
if
(
xxf
<
xxi
&&
yyf
>
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
}
else
if
(
xxf
<
xxi
&&
yyf
<
yyi
)
{
xo
=
xxf
;
yo
=
yyi
;
}
else
if
(
xxf
>
xxi
&&
yyf
<
yyi
)
{
xo
=
xxi
;
yo
=
yyf
;
}
rx
=
fabs
(
(
double
)(
xxi
-
xxf
)
);
ry
=
fabs
(
(
double
)(
yyi
-
yyf
)
);
bool
test
;
double
xx1
,
xx2
,
yy1
,
yy2
,
aa
;
if
(
bVert
)
{
// shift vertical line to coordinate system of ellipse
aa
=
a
-
xo
;
test
=
FindVerticalLineEllipseIntersections
(
rx
,
ry
,
aa
,
&
yy1
,
&
yy2
);
if
(
!
test
)
return
0
;
// shift back to PCB coordinates
yy1
+=
yo
;
yy2
+=
yo
;
xx1
=
a
;
xx2
=
a
;
}
else
{
// shift line to coordinate system of ellipse
aa
=
a
+
b
*
xo
-
yo
;
test
=
FindLineEllipseIntersections
(
rx
,
ry
,
aa
,
b
,
&
xx1
,
&
xx2
);
if
(
!
test
)
return
0
;
// shift back to PCB coordinates
yy1
=
aa
+
b
*
xx1
;
xx1
+=
xo
;
yy1
+=
yo
;
yy2
=
aa
+
b
*
xx2
;
xx2
+=
xo
;
yy2
+=
yo
;
}
int
npts
=
0
;
if
(
(
xxf
>
xxi
&&
xx1
<
xxf
&&
xx1
>
xxi
)
||
(
xxf
<
xxi
&&
xx1
<
xxi
&&
xx1
>
xxf
)
)
{
if
(
(
yyf
>
yyi
&&
yy1
<
yyf
&&
yy1
>
yyi
)
||
(
yyf
<
yyi
&&
yy1
<
yyi
&&
yy1
>
yyf
)
)
{
*
x1
=
xx1
;
*
y1
=
yy1
;
npts
=
1
;
}
}
if
(
(
xxf
>
xxi
&&
xx2
<
xxf
&&
xx2
>
xxi
)
||
(
xxf
<
xxi
&&
xx2
<
xxi
&&
xx2
>
xxf
)
)
{
if
(
(
yyf
>
yyi
&&
yy2
<
yyf
&&
yy2
>
yyi
)
||
(
yyf
<
yyi
&&
yy2
<
yyi
&&
yy2
>
yyf
)
)
{
if
(
npts
==
0
)
{
*
x1
=
xx2
;
*
y1
=
yy2
;
npts
=
1
;
}
else
{
*
x2
=
xx2
;
*
y2
=
yy2
;
npts
=
2
;
}
}
}
return
npts
;
}
else
ASSERT
(
0
);
}
else
{
// vertical line segment
if
(
bVert
)
return
0
;
xx
=
xi
;
yy
=
a
+
b
*
xx
;
if
(
(
yy
>=
yi
&&
yy
>
yf
)
||
(
yy
<=
yi
&&
yy
<
yf
)
)
return
0
;
}
*
x1
=
xx
;
*
y1
=
yy
;
return
1
;
}
// Test for intersection of line segments
// If lines are parallel, returns false
// If true, returns intersection coords in x, y
// if false, returns min. distance in dist (may be 0.0 if parallel)
// and coords on nearest point in one of the segments in (x,y)
//
bool
TestForIntersectionOfStraightLineSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
*
x
,
int
*
y
,
double
*
d
)
{
double
a
,
b
,
dist
;
// first, test for intersection
if
(
x1i
==
x1f
&&
x2i
==
x2f
)
{
// both segments are vertical, can't intersect
}
else
if
(
y1i
==
y1f
&&
y2i
==
y2f
)
{
// both segments are horizontal, can't intersect
}
else
if
(
x1i
==
x1f
&&
y2i
==
y2f
)
{
// first seg. vertical, second horizontal, see if they cross
if
(
InRange
(
x1i
,
x2i
,
x2f
)
&&
InRange
(
y2i
,
y1i
,
y1f
)
)
{
if
(
x
)
*
x
=
x1i
;
if
(
y
)
*
y
=
y2i
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
else
if
(
y1i
==
y1f
&&
x2i
==
x2f
)
{
// first seg. horizontal, second vertical, see if they cross
if
(
InRange
(
y1i
,
y2i
,
y2f
)
&&
InRange
(
x2i
,
x1i
,
x1f
)
)
{
if
(
x
)
*
x
=
x2i
;
if
(
y
)
*
y
=
y1i
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
else
if
(
x1i
==
x1f
)
{
// first segment vertical, second oblique
// get a and b for second line segment, so that y = a + bx;
b
=
(
double
)(
y2f
-
y2i
)
/
(
x2f
-
x2i
);
a
=
(
double
)
y2i
-
b
*
x2i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x1i
,
y1i
,
x1f
,
y1f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
y1
,
y1i
,
y1f
)
&&
InRange
(
x1
,
x2i
,
x2f
)
&&
InRange
(
y1
,
y2i
,
y2f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
if
(
y1i
==
y1f
)
{
// first segment horizontal, second oblique
// get a and b for second line segment, so that y = a + bx;
b
=
(
double
)(
y2f
-
y2i
)
/
(
x2f
-
x2i
);
a
=
(
double
)
y2i
-
b
*
x2i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x1i
,
y1i
,
x1f
,
y1f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
x1
,
x2i
,
x2f
)
&&
InRange
(
y1
,
y2i
,
y2f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
if
(
x2i
==
x2f
)
{
// second segment vertical, first oblique
// get a and b for first line segment, so that y = a + bx;
b
=
(
double
)(
y1f
-
y1i
)
/
(
x1f
-
x1i
);
a
=
(
double
)
y1i
-
b
*
x1i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x2i
,
y2i
,
x2f
,
y2f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
y1
,
y1i
,
y1f
)
&&
InRange
(
y1
,
y2i
,
y2f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
if
(
y2i
==
y2f
)
{
// second segment horizontal, first oblique
// get a and b for second line segment, so that y = a + bx;
b
=
(
double
)(
y1f
-
y1i
)
/
(
x1f
-
x1i
);
a
=
(
double
)
y1i
-
b
*
x1i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x2i
,
y2i
,
x2f
,
y2f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
y1
,
y1i
,
y1f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
else
{
// both segments oblique
if
(
(
long
)(
y1f
-
y1i
)
*
(
x2f
-
x2i
)
!=
(
long
)(
y2f
-
y2i
)
*
(
x1f
-
x1i
)
)
{
// not parallel, get a and b for first line segment, so that y = a + bx;
b
=
(
double
)(
y1f
-
y1i
)
/
(
x1f
-
x1i
);
a
=
(
double
)
y1i
-
b
*
x1i
;
double
x1
,
y1
,
x2
,
y2
;
int
test
=
FindLineSegmentIntersection
(
a
,
b
,
x2i
,
y2i
,
x2f
,
y2f
,
CPolyLine
::
STRAIGHT
,
&
x1
,
&
y1
,
&
x2
,
&
y2
);
// both segments oblique
if
(
test
)
{
if
(
InRange
(
x1
,
x1i
,
x1f
)
&&
InRange
(
y1
,
y1i
,
y1f
)
)
{
if
(
x
)
*
x
=
x1
;
if
(
y
)
*
y
=
y1
;
if
(
d
)
*
d
=
0.0
;
return
true
;
}
}
}
}
// don't intersect, get shortest distance between each endpoint and the other line segment
dist
=
GetPointToLineSegmentDistance
(
x1i
,
y1i
,
x2i
,
y2i
,
x2f
,
y2f
);
double
xx
=
x1i
;
double
yy
=
y1i
;
double
dd
=
GetPointToLineSegmentDistance
(
x1f
,
y1f
,
x2i
,
y2i
,
x2f
,
y2f
);
if
(
dd
<
dist
)
{
dist
=
dd
;
xx
=
x1f
;
yy
=
y1f
;
}
dd
=
GetPointToLineSegmentDistance
(
x2i
,
y2i
,
x1i
,
y1i
,
x1f
,
y1f
);
if
(
dd
<
dist
)
{
dist
=
dd
;
xx
=
x2i
;
yy
=
y2i
;
}
dd
=
GetPointToLineSegmentDistance
(
x2f
,
y2f
,
x1i
,
y1i
,
x1f
,
y1f
);
if
(
dd
<
dist
)
{
dist
=
dd
;
xx
=
x2f
;
yy
=
y2f
;
}
if
(
x
)
*
x
=
xx
;
if
(
y
)
*
y
=
yy
;
if
(
d
)
*
d
=
dist
;
return
false
;
}
// quicksort algorithm
// sorts array numbers[], also moves elements of another array index[]
//
#define Q3WAY
void
quickSort
(
int
numbers
[],
int
index
[],
int
array_size
)
{
#ifdef Q3WAY
q_sort_3way
(
numbers
,
index
,
0
,
array_size
-
1
);
#else
q_sort
(
numbers
,
index
,
0
,
array_size
-
1
);
#endif
}
// standard quicksort
//
void
q_sort
(
int
numbers
[],
int
index
[],
int
left
,
int
right
)
{
int
pivot
,
pivot_index
,
l_hold
,
r_hold
;
l_hold
=
left
;
r_hold
=
right
;
pivot
=
numbers
[
left
];
pivot_index
=
index
[
left
];
while
(
left
<
right
)
{
while
((
numbers
[
right
]
>=
pivot
)
&&
(
left
<
right
))
right
--
;
if
(
left
!=
right
)
{
numbers
[
left
]
=
numbers
[
right
];
index
[
left
]
=
index
[
right
];
left
++
;
}
while
((
numbers
[
left
]
<=
pivot
)
&&
(
left
<
right
))
left
++
;
if
(
left
!=
right
)
{
numbers
[
right
]
=
numbers
[
left
];
index
[
right
]
=
index
[
left
];
right
--
;
}
}
numbers
[
left
]
=
pivot
;
index
[
left
]
=
pivot_index
;
pivot
=
left
;
left
=
l_hold
;
right
=
r_hold
;
if
(
left
<
pivot
)
q_sort
(
numbers
,
index
,
left
,
pivot
-
1
);
if
(
right
>
pivot
)
q_sort
(
numbers
,
index
,
pivot
+
1
,
right
);
}
// 3-way quicksort...useful where there are duplicate values
//
void
q_sort_3way
(
int
a
[],
int
b
[],
int
l
,
int
r
)
{
#define EXCH(i,j) {int temp=a[i]; a[i]=a[j]; a[j]=temp; temp=b[i]; b[i]=b[j]; b[j]=temp;}
int
i
=
l
-
1
;
int
j
=
r
;
int
p
=
l
-
1
;
int
q
=
r
;
int
v
=
a
[
r
];
if
(
r
<=
l
)
return
;
for
(;;)
{
while
(
a
[
++
i
]
<
v
);
while
(
v
<
a
[
--
j
]
)
if
(
j
==
1
)
break
;
if
(
i
>=
j
)
break
;
EXCH
(
i
,
j
);
if
(
a
[
i
]
==
v
)
{
p
++
;
EXCH
(
p
,
i
);
}
if
(
v
==
a
[
j
]
)
{
q
--
;
EXCH
(
j
,
q
);
}
}
EXCH
(
i
,
r
);
j
=
i
-
1
;
i
=
i
+
1
;
for
(
int
k
=
l
;
k
<
p
;
k
++
,
j
--
)
EXCH
(
k
,
j
);
for
(
int
k
=
r
-
1
;
k
>
q
;
k
--
,
i
++
)
EXCH
(
i
,
k
);
q_sort_3way
(
a
,
b
,
l
,
j
);
q_sort_3way
(
a
,
b
,
i
,
r
);
}
// solves quadratic equation
// i.e. ax**2 + bx + c = 0
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool
Quadratic
(
double
a
,
double
b
,
double
c
,
double
*
x1
,
double
*
x2
)
{
double
root
=
b
*
b
-
4.0
*
a
*
c
;
if
(
root
<
0.0
)
return
false
;
root
=
sqrt
(
root
);
*
x1
=
(
-
b
+
root
)
/
(
2.0
*
a
);
*
x2
=
(
-
b
-
root
)
/
(
2.0
*
a
);
return
true
;
}
// finds intersections of vertical line at x
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in y1 and y2
// else returns false
//
bool
FindVerticalLineEllipseIntersections
(
double
a
,
double
b
,
double
x
,
double
*
y1
,
double
*
y2
)
{
double
y_sqr
=
(
1.0
-
(
x
*
x
)
/
(
a
*
a
))
*
b
*
b
;
if
(
y_sqr
<
0.0
)
return
false
;
*
y1
=
sqrt
(
y_sqr
);
*
y2
=
-*
y1
;
return
true
;
}
// finds intersections of straight line y = c + dx
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool
FindLineEllipseIntersections
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x1
,
double
*
x2
)
{
// quadratic terms
double
A
=
d
*
d
+
b
*
b
/
(
a
*
a
);
double
B
=
2.0
*
c
*
d
;
double
C
=
c
*
c
-
b
*
b
;
return
Quadratic
(
A
,
B
,
C
,
x1
,
x2
);
}
#if 0
// draw a straight line or an arc between xi,yi and xf,yf
//
void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, bool bMeta )
{
int xi, yi, xf, yf;
if( shape == DL_LINE || xxi == xxf || yyi == yyf )
{
// draw straight line
pDC->MoveTo( xxi, yyi );
pDC->LineTo( xxf, yyf );
}
else if( shape == DL_ARC_CCW || shape == DL_ARC_CW )
{
// set endpoints so we can always draw counter-clockwise arc
if( shape == DL_ARC_CW )
{
xi = xxf;
yi = yyf;
xf = xxi;
yf = yyi;
}
else
{
xi = xxi;
yi = yyi;
xf = xxf;
yf = yyf;
}
pDC->MoveTo( xi, yi );
if( xf > xi && yf > yi )
{
// quadrant 1
int w = (xf-xi)*2;
int h = (yf-yi)*2;
if( !bMeta )
pDC->Arc( xf-w, yi+h, xf, yi,
xi, yi, xf, yf );
else
pDC->Arc( xf-w, yi, xf, yi+h,
xf, yf, xi, yi );
}
else if( xf < xi && yf > yi )
{
// quadrant 2
int w = -(xf-xi)*2;
int h = (yf-yi)*2;
if( !bMeta )
pDC->Arc( xi-w, yf, xi, yf-h,
xi, yi, xf, yf );
else
pDC->Arc( xi-w, yf-h, xi, yf,
xf, yf, xi, yi );
}
else if( xf < xi && yf < yi )
{
// quadrant 3
int w = -(xf-xi)*2;
int h = -(yf-yi)*2;
if( !bMeta )
pDC->Arc( xf, yi, xf+w, yi-h,
xi, yi, xf, yf );
else
pDC->Arc( xf, yi-h, xf+w, yi,
xf, yf, xi, yi );
}
else if( xf > xi && yf < yi )
{
// quadrant 4
int w = (xf-xi)*2;
int h = -(yf-yi)*2;
if( !bMeta )
pDC->Arc( xi, yf+h, xi+w, yf,
xi, yi, xf, yf );
else
pDC->Arc( xi, yf, xi+w, yf+h,
xf, yf, xi, yi );
}
pDC->MoveTo( xxf, yyf );
}
else
ASSERT(0); // oops
}
#endif
// Get arrays of circles, rects and line segments to represent pad
// for purposes of drawing pad or calculating clearances
// margins of circles and line segments represent pad outline
// circles and rects are used to find points inside pad
//
void
GetPadElements
(
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
,
int
*
nr
,
my_rect
r
[],
int
*
nc
,
my_circle
c
[],
int
*
ns
,
my_seg
s
[]
)
{
*
nc
=
0
;
*
nr
=
0
;
*
ns
=
0
;
if
(
type
==
PAD_ROUND
)
{
*
nc
=
1
;
c
[
0
]
=
my_circle
(
x
,
y
,
wid
/
2
);
return
;
}
if
(
type
==
PAD_SQUARE
)
{
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
wid
/
2
,
y
-
wid
/
2
,
x
+
wid
/
2
,
y
+
wid
/
2
);
*
ns
=
4
;
s
[
0
]
=
my_seg
(
x
-
wid
/
2
,
y
+
wid
/
2
,
x
+
wid
/
2
,
y
+
wid
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
wid
/
2
,
y
-
wid
/
2
,
x
+
wid
/
2
,
y
-
wid
/
2
);
// bottom
s
[
2
]
=
my_seg
(
x
-
wid
/
2
,
y
-
wid
/
2
,
x
-
wid
/
2
,
y
+
wid
/
2
);
// left
s
[
3
]
=
my_seg
(
x
+
wid
/
2
,
y
-
wid
/
2
,
x
+
wid
/
2
,
y
+
wid
/
2
);
// right
return
;
}
if
(
type
==
PAD_OCTAGON
)
{
const
double
pi
=
3.14159265359
;
*
nc
=
1
;
// circle represents inside of polygon
c
[
0
]
=
my_circle
(
x
,
y
,
wid
/
2
);
*
ns
=
8
;
// now create sides of polygon
double
theta
=
pi
/
8.0
;
double
radius
=
0.5
*
(
double
)
wid
/
cos
(
theta
);
double
last_x
=
x
+
radius
*
cos
(
theta
);
double
last_y
=
y
+
radius
*
sin
(
theta
);
for
(
int
is
=
0
;
is
<
8
;
is
++
)
{
theta
+=
pi
/
4.0
;
double
dx
=
x
+
radius
*
cos
(
theta
);
double
dy
=
y
+
radius
*
sin
(
theta
);
s
[
is
]
=
my_seg
(
last_x
,
last_y
,
x
,
y
);
last_x
=
dx
;
last_y
=
dy
;
}
return
;
}
//
int
h
;
int
v
;
if
(
angle
==
90
||
angle
==
270
)
{
h
=
wid
;
v
=
len
;
}
else
{
v
=
wid
;
h
=
len
;
}
if
(
type
==
PAD_RECT
)
{
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
h
/
2
,
y
-
v
/
2
,
x
+
h
/
2
,
y
+
v
/
2
);
*
ns
=
4
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
,
y
+
v
/
2
,
x
+
h
/
2
,
y
+
v
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
,
x
+
h
/
2
,
y
-
v
/
2
);
// bottom
s
[
2
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
,
x
-
h
/
2
,
y
+
v
/
2
);
// left
s
[
3
]
=
my_seg
(
x
+
h
/
2
,
y
-
v
/
2
,
x
+
h
/
2
,
y
+
v
/
2
);
// right
return
;
}
if
(
type
==
PAD_RRECT
)
{
*
nc
=
4
;
c
[
0
]
=
my_circle
(
x
-
h
/
2
+
radius
,
y
-
v
/
2
+
radius
,
radius
);
// bottom left circle
c
[
1
]
=
my_circle
(
x
+
h
/
2
-
radius
,
y
-
v
/
2
+
radius
,
radius
);
// bottom right circle
c
[
2
]
=
my_circle
(
x
-
h
/
2
+
radius
,
y
+
v
/
2
-
radius
,
radius
);
// top left circle
c
[
3
]
=
my_circle
(
x
+
h
/
2
-
radius
,
y
+
v
/
2
-
radius
,
radius
);
// top right circle
*
ns
=
4
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
+
radius
,
y
+
v
/
2
,
x
+
h
/
2
-
radius
,
y
+
v
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
h
/
2
+
radius
,
y
-
v
/
2
,
x
+
h
/
2
-
radius
,
y
+
v
/
2
);
// bottom
s
[
2
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
+
radius
,
x
-
h
/
2
,
y
+
v
/
2
-
radius
);
// left
s
[
3
]
=
my_seg
(
x
+
h
/
2
,
y
-
v
/
2
+
radius
,
x
+
h
/
2
,
y
+
v
/
2
-
radius
);
// right
return
;
}
if
(
type
==
PAD_OVAL
)
{
if
(
h
>
v
)
{
// horizontal
*
nc
=
2
;
c
[
0
]
=
my_circle
(
x
-
h
/
2
+
v
/
2
,
y
,
v
/
2
);
// left circle
c
[
1
]
=
my_circle
(
x
+
h
/
2
-
v
/
2
,
y
,
v
/
2
);
// right circle
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
h
/
2
+
v
/
2
,
y
-
v
/
2
,
x
+
h
/
2
-
v
/
2
,
y
+
v
/
2
);
*
ns
=
2
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
+
v
/
2
,
y
+
v
/
2
,
x
+
h
/
2
-
v
/
2
,
y
+
v
/
2
);
// top
s
[
1
]
=
my_seg
(
x
-
h
/
2
+
v
/
2
,
y
-
v
/
2
,
x
+
h
/
2
-
v
/
2
,
y
-
v
/
2
);
// bottom
}
else
{
// vertical
*
nc
=
2
;
c
[
0
]
=
my_circle
(
x
,
y
+
v
/
2
-
h
/
2
,
h
/
2
);
// top circle
c
[
1
]
=
my_circle
(
x
,
y
-
v
/
2
+
h
/
2
,
h
/
2
);
// bottom circle
*
nr
=
1
;
r
[
0
]
=
my_rect
(
x
-
h
/
2
,
y
-
v
/
2
+
h
/
2
,
x
+
h
/
2
,
y
+
v
/
2
-
h
/
2
);
*
ns
=
2
;
s
[
0
]
=
my_seg
(
x
-
h
/
2
,
y
-
v
/
2
+
h
/
2
,
x
-
h
/
2
,
y
+
v
/
2
-
h
/
2
);
// left
s
[
1
]
=
my_seg
(
x
+
h
/
2
,
y
-
v
/
2
+
h
/
2
,
x
+
h
/
2
,
y
+
v
/
2
-
h
/
2
);
// left
}
return
;
}
ASSERT
(
0
);
}
// Find distance from a staright line segment to a pad
//
int
GetClearanceBetweenSegmentAndPad
(
int
x1
,
int
y1
,
int
x2
,
int
y2
,
int
w
,
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
)
{
if
(
type
==
PAD_NONE
)
return
INT_MAX
;
else
{
int
nc
,
nr
,
ns
;
my_circle
c
[
4
];
my_rect
r
[
2
];
my_seg
s
[
8
];
GetPadElements
(
type
,
x
,
y
,
wid
,
len
,
radius
,
angle
,
&
nr
,
r
,
&
nc
,
c
,
&
ns
,
s
);
// first test for endpoints of line segment in rectangle
for
(
int
ir
=
0
;
ir
<
nr
;
ir
++
)
{
if
(
x1
>=
r
[
ir
].
xlo
&&
x1
<=
r
[
ir
].
xhi
&&
y1
>=
r
[
ir
].
ylo
&&
y1
<=
r
[
ir
].
yhi
)
return
0
;
if
(
x2
>=
r
[
ir
].
xlo
&&
x2
<=
r
[
ir
].
xhi
&&
y2
>=
r
[
ir
].
ylo
&&
y2
<=
r
[
ir
].
yhi
)
return
0
;
}
// now get distance from elements of pad outline
int
dist
=
INT_MAX
;
for
(
int
ic
=
0
;
ic
<
nc
;
ic
++
)
{
int
d
=
GetPointToLineSegmentDistance
(
c
[
ic
].
x
,
c
[
ic
].
y
,
x1
,
y1
,
x2
,
y2
)
-
c
[
ic
].
r
-
w
/
2
;
dist
=
min
(
dist
,
d
);
}
for
(
int
is
=
0
;
is
<
ns
;
is
++
)
{
double
d
;
TestForIntersectionOfStraightLineSegments
(
s
[
is
].
xi
,
s
[
is
].
yi
,
s
[
is
].
xf
,
s
[
is
].
yf
,
x1
,
y1
,
x2
,
y2
,
NULL
,
NULL
,
&
d
);
d
-=
w
/
2
;
dist
=
min
(
dist
,
d
);
}
return
max
(
0
,
dist
);
}
}
// Get clearance between 2 segments
// Returns point in segment closest to other segment in x, y
// in clearance > max_cl, just returns max_cl and doesn't return x,y
//
int
GetClearanceBetweenSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
style1
,
int
w1
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
style2
,
int
w2
,
int
max_cl
,
int
*
x
,
int
*
y
)
{
// check clearance between bounding rectangles
int
test
=
max_cl
+
w1
/
2
+
w2
/
2
;
if
(
min
(
x1i
,
x1f
)
-
max
(
x2i
,
x2f
)
>
test
)
return
max_cl
;
if
(
min
(
x2i
,
x2f
)
-
max
(
x1i
,
x1f
)
>
test
)
return
max_cl
;
if
(
min
(
y1i
,
y1f
)
-
max
(
y2i
,
y2f
)
>
test
)
return
max_cl
;
if
(
min
(
y2i
,
y2f
)
-
max
(
y1i
,
y1f
)
>
test
)
return
max_cl
;
if
(
style1
==
CPolyLine
::
STRAIGHT
&&
style1
==
CPolyLine
::
STRAIGHT
)
{
// both segments are straight lines
int
xx
,
yy
;
double
dd
;
TestForIntersectionOfStraightLineSegments
(
x1i
,
y1i
,
x1f
,
y1f
,
x2i
,
y2i
,
x2f
,
y2f
,
&
xx
,
&
yy
,
&
dd
);
int
d
=
max
(
0
,
dd
-
w1
/
2
-
w2
/
2
);
if
(
x
)
*
x
=
xx
;
if
(
y
)
*
y
=
yy
;
return
d
;
}
// not both straight-line segments
// see if segments intersect
double
xr
[
2
];
double
yr
[
2
];
test
=
FindSegmentIntersections
(
x1i
,
y1i
,
x1f
,
y1f
,
style1
,
x2i
,
y2i
,
x2f
,
y2f
,
style2
,
xr
,
yr
);
if
(
test
)
{
if
(
x
)
*
x
=
xr
[
0
];
if
(
y
)
*
y
=
yr
[
0
];
return
0.0
;
}
// at least one segment is an arc
EllipseKH
el1
;
EllipseKH
el2
;
bool
bArcs
;
int
xi
,
yi
,
xf
,
yf
;
if
(
style2
==
CPolyLine
::
STRAIGHT
)
{
// style1 = arc, style2 = straight
MakeEllipseFromArc
(
x1i
,
y1i
,
x1f
,
y1f
,
style1
,
&
el1
);
xi
=
x2i
;
yi
=
y2i
;
xf
=
x2f
;
yf
=
y2f
;
bArcs
=
false
;
}
else
if
(
style1
==
CPolyLine
::
STRAIGHT
)
{
// style2 = arc, style1 = straight
xi
=
x1i
;
yi
=
y1i
;
xf
=
x1f
;
yf
=
y1f
;
MakeEllipseFromArc
(
x2i
,
y2i
,
x2f
,
y2f
,
style2
,
&
el1
);
bArcs
=
false
;
}
else
{
// style1 = arc, style2 = arc
MakeEllipseFromArc
(
x1i
,
y1i
,
x1f
,
y1f
,
style1
,
&
el1
);
MakeEllipseFromArc
(
x2i
,
y2i
,
x2f
,
y2f
,
style2
,
&
el2
);
bArcs
=
true
;
}
const
int
NSTEPS
=
32
;
if
(
el1
.
theta2
>
el1
.
theta1
)
ASSERT
(
0
);
if
(
bArcs
&&
el2
.
theta2
>
el2
.
theta1
)
ASSERT
(
0
);
// test multiple points in both segments
double
th1
;
double
th2
;
double
len2
;
if
(
bArcs
)
{
th1
=
el2
.
theta1
;
th2
=
el2
.
theta2
;
len2
=
max
(
el2
.
xrad
,
el2
.
yrad
);
}
else
{
th1
=
1.0
;
th2
=
0.0
;
len2
=
abs
(
xf
-
xi
)
+
abs
(
yf
-
yi
);
}
double
s_start
=
el1
.
theta1
;
double
s_end
=
el1
.
theta2
;
double
s_start2
=
th1
;
double
s_end2
=
th2
;
double
dmin
=
DBL_MAX
;
double
xmin
,
ymin
,
smin
,
smin2
;
int
nsteps
=
NSTEPS
;
int
nsteps2
=
NSTEPS
;
double
step
=
(
s_start
-
s_end
)
/
(
nsteps
-
1
);
double
step2
=
(
s_start2
-
s_end2
)
/
(
nsteps2
-
1
);
while
(
(
step
*
max
(
el1
.
xrad
,
el1
.
yrad
))
>
0.1
*
NM_PER_MIL
&&
(
step2
*
len2
)
>
0.1
*
NM_PER_MIL
)
{
step
=
(
s_start
-
s_end
)
/
(
nsteps
-
1
);
for
(
int
i
=
0
;
i
<
nsteps
;
i
++
)
{
double
s
;
if
(
i
<
nsteps
-
1
)
s
=
s_start
-
i
*
step
;
else
s
=
s_end
;
double
x
=
el1
.
Center
.
X
+
el1
.
xrad
*
cos
(
s
);
double
y
=
el1
.
Center
.
Y
+
el1
.
yrad
*
sin
(
s
);
// if not an arc, use s2 as fractional distance along line
step2
=
(
s_start2
-
s_end2
)
/
(
nsteps2
-
1
);
for
(
int
i2
=
0
;
i2
<
nsteps2
;
i2
++
)
{
double
s2
;
if
(
i2
<
nsteps2
-
1
)
s2
=
s_start2
-
i2
*
step2
;
else
s2
=
s_end2
;
double
x2
,
y2
;
if
(
!
bArcs
)
{
x2
=
xi
+
(
xf
-
xi
)
*
s2
;
y2
=
yi
+
(
yf
-
yi
)
*
s2
;
}
else
{
x2
=
el2
.
Center
.
X
+
el2
.
xrad
*
cos
(
s2
);
y2
=
el2
.
Center
.
Y
+
el2
.
yrad
*
sin
(
s2
);
}
double
d
=
Distance
(
x
,
y
,
x2
,
y2
);
if
(
d
<
dmin
)
{
dmin
=
d
;
xmin
=
x
;
ymin
=
y
;
smin
=
s
;
smin2
=
s2
;
}
}
}
if
(
step
>
step2
)
{
s_start
=
min
(
el1
.
theta1
,
smin
+
step
);
s_end
=
max
(
el1
.
theta2
,
smin
-
step
);
step
=
(
s_start
-
s_end
)
/
nsteps
;
}
else
{
s_start2
=
min
(
th1
,
smin2
+
step2
);
s_end2
=
max
(
th2
,
smin2
-
step2
);
step2
=
(
s_start2
-
s_end2
)
/
nsteps2
;
}
}
if
(
x
)
*
x
=
xmin
;
if
(
y
)
*
y
=
ymin
;
return
max
(
0
,
dmin
-
w1
/
2
-
w2
/
2
);
// allow for widths
}
// Find clearance between pads
// For each pad:
// type = PAD_ROUND, PAD_SQUARE, etc.
// x, y = center position
// w, l = width and length
// r = corner radius
// angle = 0 or 90 (if 0, pad length is along x-axis)
//
int
GetClearanceBetweenPads
(
int
type1
,
int
x1
,
int
y1
,
int
w1
,
int
l1
,
int
r1
,
int
angle1
,
int
type2
,
int
x2
,
int
y2
,
int
w2
,
int
l2
,
int
r2
,
int
angle2
)
{
if
(
type1
==
PAD_NONE
)
return
INT_MAX
;
if
(
type2
==
PAD_NONE
)
return
INT_MAX
;
int
dist
=
INT_MAX
;
int
nr
,
nc
,
ns
,
nrr
,
ncc
,
nss
;
my_rect
r
[
2
],
rr
[
2
];
my_circle
c
[
4
],
cc
[
4
];
my_seg
s
[
8
],
ss
[
8
];
GetPadElements
(
type1
,
x1
,
y1
,
w1
,
l1
,
r1
,
angle1
,
&
nr
,
r
,
&
nc
,
c
,
&
ns
,
s
);
GetPadElements
(
type2
,
x2
,
y2
,
w2
,
l2
,
r2
,
angle2
,
&
nrr
,
rr
,
&
ncc
,
cc
,
&
nss
,
ss
);
// now find distance from every element of pad1 to every element of pad2
for
(
int
ic
=
0
;
ic
<
nc
;
ic
++
)
{
for
(
int
icc
=
0
;
icc
<
ncc
;
icc
++
)
{
int
d
=
Distance
(
c
[
ic
].
x
,
c
[
ic
].
y
,
cc
[
icc
].
x
,
cc
[
icc
].
y
)
-
c
[
ic
].
r
-
cc
[
icc
].
r
;
dist
=
min
(
dist
,
d
);
}
for
(
int
iss
=
0
;
iss
<
nss
;
iss
++
)
{
int
d
=
GetPointToLineSegmentDistance
(
c
[
ic
].
x
,
c
[
ic
].
y
,
ss
[
iss
].
xi
,
ss
[
iss
].
yi
,
ss
[
iss
].
xf
,
ss
[
iss
].
yf
)
-
c
[
ic
].
r
;
dist
=
min
(
dist
,
d
);
}
}
for
(
int
is
=
0
;
is
<
ns
;
is
++
)
{
for
(
int
icc
=
0
;
icc
<
ncc
;
icc
++
)
{
int
d
=
GetPointToLineSegmentDistance
(
cc
[
icc
].
x
,
cc
[
icc
].
y
,
s
[
is
].
xi
,
s
[
is
].
yi
,
s
[
is
].
xf
,
s
[
is
].
yf
)
-
cc
[
icc
].
r
;
dist
=
min
(
dist
,
d
);
}
for
(
int
iss
=
0
;
iss
<
nss
;
iss
++
)
{
double
d
;
TestForIntersectionOfStraightLineSegments
(
s
[
is
].
xi
,
s
[
is
].
yi
,
s
[
is
].
xf
,
s
[
is
].
yf
,
ss
[
iss
].
xi
,
ss
[
iss
].
yi
,
ss
[
iss
].
xf
,
ss
[
iss
].
yf
,
NULL
,
NULL
,
&
d
);
dist
=
min
(
dist
,
d
);
}
}
return
max
(
dist
,
0
);
}
// Get min. distance from (x,y) to line y = a + bx
// if b > DBL_MAX/10, assume vertical line at x = a
// returns closest point on line in xp, yp
//
double
GetPointToLineDistance
(
double
a
,
double
b
,
int
x
,
int
y
,
double
*
xpp
,
double
*
ypp
)
{
if
(
b
>
DBL_MAX
/
10
)
{
// vertical line
if
(
xpp
&&
ypp
)
{
*
xpp
=
a
;
*
ypp
=
y
;
}
return
abs
(
a
-
x
);
}
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double
d
=
-
1.0
/
b
;
double
c
=
(
double
)
y
-
d
*
x
;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double
xp
=
(
a
-
c
)
/
(
d
-
b
);
double
yp
=
a
+
b
*
xp
;
if
(
xpp
&&
ypp
)
{
*
xpp
=
xp
;
*
ypp
=
yp
;
}
// find distance
return
Distance
(
x
,
y
,
xp
,
yp
);
}
/***********************************************************************************/
double
GetPointToLineSegmentDistance
(
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
)
/***********************************************************************************/
/** Function GetPointToLineSegmentDistance
* Get distance between line segment and point
* @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance
*/
{
// test for vertical or horizontal segment
if
(
xf
==
xi
)
{
// vertical line segment
if
(
InRange
(
y
,
yi
,
yf
)
)
return
abs
(
x
-
xi
);
else
return
min
(
Distance
(
x
,
y
,
xi
,
yi
),
Distance
(
x
,
y
,
xf
,
yf
)
);
}
else
if
(
yf
==
yi
)
{
// horizontal line segment
if
(
InRange
(
x
,
xi
,
xf
)
)
return
abs
(
y
-
yi
);
else
return
min
(
Distance
(
x
,
y
,
xi
,
yi
),
Distance
(
x
,
y
,
xf
,
yf
)
);
}
else
{
// oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double
b
=
(
double
)(
yf
-
yi
)
/
(
xf
-
xi
);
double
a
=
(
double
)
yi
-
b
*
xi
;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double
d
=
-
1.0
/
b
;
double
c
=
(
double
)
y
-
d
*
x
;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double
xp
=
(
a
-
c
)
/
(
d
-
b
);
double
yp
=
a
+
b
*
xp
;
// find distance
if
(
InRange
(
xp
,
xi
,
xf
)
&&
InRange
(
yp
,
yi
,
yf
)
)
return
Distance
(
x
,
y
,
xp
,
yp
);
else
return
min
(
Distance
(
x
,
y
,
xi
,
yi
),
Distance
(
x
,
y
,
xf
,
yf
)
);
}
}
// test for value within range
//
bool
InRange
(
double
x
,
double
xi
,
double
xf
)
{
if
(
xf
>
xi
)
{
if
(
x
>=
xi
&&
x
<=
xf
)
return
true
;
}
else
{
if
(
x
>=
xf
&&
x
<=
xi
)
return
true
;
}
return
false
;
}
// Get distance between 2 points
//
double
Distance
(
int
x1
,
int
y1
,
int
x2
,
int
y2
)
{
double
d
;
d
=
sqrt
(
(
double
)(
x1
-
x2
)
*
(
x1
-
x2
)
+
(
double
)(
y1
-
y2
)
*
(
y1
-
y2
)
);
if
(
d
>
INT_MAX
||
d
<
INT_MIN
)
ASSERT
(
0
);
return
(
int
)
d
;
}
// this finds approximate solutions
// note: this works best if el2 is smaller than el1
//
int
GetArcIntersections
(
EllipseKH
*
el1
,
EllipseKH
*
el2
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
)
{
if
(
el1
->
theta2
>
el1
->
theta1
)
ASSERT
(
0
);
if
(
el2
->
theta2
>
el2
->
theta1
)
ASSERT
(
0
);
const
int
NSTEPS
=
32
;
double
xret
[
2
],
yret
[
2
];
double
xscale
=
1.0
/
el1
->
xrad
;
double
yscale
=
1.0
/
el1
->
yrad
;
// now transform params of second ellipse into reference frame
// with origin at center if first ellipse,
// scaled so the first ellipse is a circle of radius = 1.0
double
xo
=
(
el2
->
Center
.
X
-
el1
->
Center
.
X
)
*
xscale
;
double
yo
=
(
el2
->
Center
.
Y
-
el1
->
Center
.
Y
)
*
yscale
;
double
xr
=
el2
->
xrad
*
xscale
;
double
yr
=
el2
->
yrad
*
yscale
;
// now test NSTEPS positions in arc, moving clockwise (ie. decreasing theta)
double
step
=
M_PI
/
((
NSTEPS
-
1
)
*
2.0
);
double
d_prev
,
th_prev
;
double
th_interp
;
double
th1
;
int
n
=
0
;
for
(
int
i
=
0
;
i
<
NSTEPS
;
i
++
)
{
double
theta
;
if
(
i
<
NSTEPS
-
1
)
theta
=
el2
->
theta1
-
i
*
step
;
else
theta
=
el2
->
theta2
;
double
x
=
xo
+
xr
*
cos
(
theta
);
double
y
=
yo
+
yr
*
sin
(
theta
);
double
d
=
1.0
-
sqrt
(
x
*
x
+
y
*
y
);
if
(
i
>
0
)
{
bool
bInt
=
false
;
if
(
d
>=
0.0
&&
d_prev
<=
0.0
)
{
th_interp
=
theta
+
(
step
*
(
-
d_prev
))
/
(
d
-
d_prev
);
bInt
=
true
;
}
else
if
(
d
<=
0.0
&&
d_prev
>=
0.0
)
{
th_interp
=
theta
+
(
step
*
d_prev
)
/
(
d_prev
-
d
);
bInt
=
true
;
}
if
(
bInt
)
{
x
=
xo
+
xr
*
cos
(
th_interp
);
y
=
yo
+
yr
*
sin
(
th_interp
);
th1
=
atan2
(
y
,
x
);
if
(
th1
<=
el1
->
theta1
&&
th1
>=
el1
->
theta2
)
{
xret
[
n
]
=
x
*
el1
->
xrad
+
el1
->
Center
.
X
;
yret
[
n
]
=
y
*
el1
->
yrad
+
el1
->
Center
.
Y
;
n
++
;
if
(
n
>
2
)
ASSERT
(
0
);
}
}
}
d_prev
=
d
;
th_prev
=
theta
;
}
if
(
x1
)
*
x1
=
xret
[
0
];
if
(
y1
)
*
y1
=
yret
[
0
];
if
(
x2
)
*
x2
=
xret
[
1
];
if
(
y2
)
*
y2
=
yret
[
1
];
return
n
;
}
// this finds approximate solution
//
//double GetSegmentClearance( EllipseKH * el1, EllipseKH * el2,
double
GetArcClearance
(
EllipseKH
*
el1
,
EllipseKH
*
el2
,
double
*
x1
,
double
*
y1
)
{
const
int
NSTEPS
=
32
;
if
(
el1
->
theta2
>
el1
->
theta1
)
ASSERT
(
0
);
if
(
el2
->
theta2
>
el2
->
theta1
)
ASSERT
(
0
);
// test multiple positions in both arcs, moving clockwise (ie. decreasing theta)
double
th_start
=
el1
->
theta1
;
double
th_end
=
el1
->
theta2
;
double
th_start2
=
el2
->
theta1
;
double
th_end2
=
el2
->
theta2
;
double
dmin
=
DBL_MAX
;
double
xmin
,
ymin
,
thmin
,
thmin2
;
int
nsteps
=
NSTEPS
;
int
nsteps2
=
NSTEPS
;
double
step
=
(
th_start
-
th_end
)
/
(
nsteps
-
1
);
double
step2
=
(
th_start2
-
th_end2
)
/
(
nsteps2
-
1
);
while
(
(
step
*
max
(
el1
->
xrad
,
el1
->
yrad
))
>
1.0
*
NM_PER_MIL
&&
(
step2
*
max
(
el2
->
xrad
,
el2
->
yrad
))
>
1.0
*
NM_PER_MIL
)
{
step
=
(
th_start
-
th_end
)
/
(
nsteps
-
1
);
for
(
int
i
=
0
;
i
<
nsteps
;
i
++
)
{
double
theta
;
if
(
i
<
nsteps
-
1
)
theta
=
th_start
-
i
*
step
;
else
theta
=
th_end
;
double
x
=
el1
->
Center
.
X
+
el1
->
xrad
*
cos
(
theta
);
double
y
=
el1
->
Center
.
Y
+
el1
->
yrad
*
sin
(
theta
);
step2
=
(
th_start2
-
th_end2
)
/
(
nsteps2
-
1
);
for
(
int
i2
=
0
;
i2
<
nsteps2
;
i2
++
)
{
double
theta2
;
if
(
i2
<
nsteps2
-
1
)
theta2
=
th_start2
-
i2
*
step2
;
else
theta2
=
th_end2
;
double
x2
=
el2
->
Center
.
X
+
el2
->
xrad
*
cos
(
theta2
);
double
y2
=
el2
->
Center
.
Y
+
el2
->
yrad
*
sin
(
theta2
);
double
d
=
Distance
(
x
,
y
,
x2
,
y2
);
if
(
d
<
dmin
)
{
dmin
=
d
;
xmin
=
x
;
ymin
=
y
;
thmin
=
theta
;
thmin2
=
theta2
;
}
}
}
if
(
step
>
step2
)
{
th_start
=
min
(
el1
->
theta1
,
thmin
+
step
);
th_end
=
max
(
el1
->
theta2
,
thmin
-
step
);
step
=
(
th_start
-
th_end
)
/
nsteps
;
}
else
{
th_start2
=
min
(
el2
->
theta1
,
thmin2
+
step2
);
th_end2
=
max
(
el2
->
theta2
,
thmin2
-
step2
);
step2
=
(
th_start2
-
th_end2
)
/
nsteps2
;
}
}
if
(
x1
)
*
x1
=
xmin
;
if
(
y1
)
*
y1
=
ymin
;
return
dmin
;
}
polygon/math_for_graphics.h
View file @
e126042b
// math stuff for graphics, from FreePCB
typedef
struct
PointTag
{
double
X
,
Y
;
}
Point
;
typedef
struct
EllipseTag
{
Point
Center
;
/* ellipse center */
// double MaxRad,MinRad; /* major and minor axis */
// double Phi; /* major axis rotation */
double
xrad
,
yrad
;
// radii on x and y
double
theta1
,
theta2
;
// start and end angle for arc
}
EllipseKH
;
const
CPoint
zero
(
0
,
0
);
class
my_circle
{
public
:
my_circle
(){};
my_circle
(
int
xx
,
int
yy
,
int
rr
)
{
x
=
xx
;
y
=
yy
;
r
=
rr
;
};
int
x
,
y
,
r
;
};
class
my_rect
{
public
:
my_rect
(){};
my_rect
(
int
xi
,
int
yi
,
int
xf
,
int
yf
)
{
xlo
=
min
(
xi
,
xf
);
xhi
=
max
(
xi
,
xf
);
ylo
=
min
(
yi
,
yf
);
yhi
=
max
(
yi
,
yf
);
};
int
xlo
,
ylo
,
xhi
,
yhi
;
};
class
my_seg
{
public
:
my_seg
(){};
my_seg
(
int
xxi
,
int
yyi
,
int
xxf
,
int
yyf
)
{
xi
=
xxi
;
yi
=
yyi
;
xf
=
xxf
;
yf
=
yyf
;
};
int
xi
,
yi
,
xf
,
yf
;
};
// math stuff for graphics
BOOL
Quadratic
(
double
a
,
double
b
,
double
c
,
double
*
x1
,
double
*
x2
);
void
DrawArc
(
CDC
*
pDC
,
int
shape
,
int
xxi
,
int
yyi
,
int
xxf
,
int
yyf
,
BOOL
bMeta
=
FALSE
);
void
RotatePoint
(
CPoint
*
p
,
int
angle
,
CPoint
org
);
void
RotateRect
(
CRect
*
r
,
int
angle
,
CPoint
org
);
int
TestLineHit
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
x
,
int
y
,
double
dist
);
int
FindLineIntersection
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x
,
double
*
y
);
int
FindLineSegmentIntersection
(
double
a
,
double
b
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
,
double
*
dist
=
NULL
);
int
FindSegmentIntersections
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
int
xi2
,
int
yi2
,
int
xf2
,
int
yf2
,
int
style2
,
double
x
[]
=
NULL
,
double
y
[]
=
NULL
);
BOOL
FindLineEllipseIntersections
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x1
,
double
*
x2
);
BOOL
FindVerticalLineEllipseIntersections
(
double
a
,
double
b
,
double
x
,
double
*
y1
,
double
*
y2
);
BOOL
TestForIntersectionOfStraightLineSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
*
x
=
NULL
,
int
*
y
=
NULL
,
double
*
dist
=
NULL
);
void
GetPadElements
(
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
,
int
*
nr
,
my_rect
r
[],
int
*
nc
,
my_circle
c
[],
int
*
ns
,
my_seg
s
[]
);
int
GetClearanceBetweenPads
(
int
type1
,
int
x1
,
int
y1
,
int
w1
,
int
l1
,
int
r1
,
int
angle1
,
int
type2
,
int
x2
,
int
y2
,
int
w2
,
int
l2
,
int
r2
,
int
angle2
);
int
GetClearanceBetweenSegmentAndPad
(
int
x1
,
int
y1
,
int
x2
,
int
y2
,
int
w
,
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
);
int
GetClearanceBetweenSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
style1
,
int
w1
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
style2
,
int
w2
,
int
max_cl
,
int
*
x
,
int
*
y
);
/** Function GetPointToLineSegmentDistance
* Get distance between line segment and point
* @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance
*/
double
GetPointToLineSegmentDistance
(
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
);
double
GetPointToLineDistance
(
double
a
,
double
b
,
int
x
,
int
y
,
double
*
xp
=
NULL
,
double
*
yp
=
NULL
);
BOOL
InRange
(
double
x
,
double
xi
,
double
xf
);
double
Distance
(
int
x1
,
int
y1
,
int
x2
,
int
y2
);
int
GetArcIntersections
(
EllipseKH
*
el1
,
EllipseKH
*
el2
,
double
*
x1
=
NULL
,
double
*
y1
=
NULL
,
double
*
x2
=
NULL
,
double
*
y2
=
NULL
);
CPoint
GetInflectionPoint
(
CPoint
pi
,
CPoint
pf
,
int
mode
);
// quicksort (2-way or 3-way)
void
quickSort
(
int
numbers
[],
int
index
[],
int
array_size
);
void
q_sort
(
int
numbers
[],
int
index
[],
int
left
,
int
right
);
void
q_sort_3way
(
int
a
[],
int
b
[],
int
left
,
int
right
);
// math stuff for graphics, from FreePCB
typedef
struct
PointTag
{
double
X
,
Y
;
}
Point
;
typedef
struct
EllipseTag
{
Point
Center
;
/* ellipse center */
// double MaxRad,MinRad; /* major and minor axis */
// double Phi; /* major axis rotation */
double
xrad
,
yrad
;
// radii on x and y
double
theta1
,
theta2
;
// start and end angle for arc
}
EllipseKH
;
const
CPoint
zero
(
0
,
0
);
class
my_circle
{
public
:
my_circle
(){};
my_circle
(
int
xx
,
int
yy
,
int
rr
)
{
x
=
xx
;
y
=
yy
;
r
=
rr
;
};
int
x
,
y
,
r
;
};
class
my_rect
{
public
:
my_rect
(){};
my_rect
(
int
xi
,
int
yi
,
int
xf
,
int
yf
)
{
xlo
=
min
(
xi
,
xf
);
xhi
=
max
(
xi
,
xf
);
ylo
=
min
(
yi
,
yf
);
yhi
=
max
(
yi
,
yf
);
};
int
xlo
,
ylo
,
xhi
,
yhi
;
};
class
my_seg
{
public
:
my_seg
(){};
my_seg
(
int
xxi
,
int
yyi
,
int
xxf
,
int
yyf
)
{
xi
=
xxi
;
yi
=
yyi
;
xf
=
xxf
;
yf
=
yyf
;
};
int
xi
,
yi
,
xf
,
yf
;
};
// math stuff for graphics
BOOL
Quadratic
(
double
a
,
double
b
,
double
c
,
double
*
x1
,
double
*
x2
);
void
DrawArc
(
CDC
*
pDC
,
int
shape
,
int
xxi
,
int
yyi
,
int
xxf
,
int
yyf
,
BOOL
bMeta
=
FALSE
);
void
RotatePoint
(
CPoint
*
p
,
int
angle
,
CPoint
org
);
void
RotateRect
(
CRect
*
r
,
int
angle
,
CPoint
org
);
int
TestLineHit
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
x
,
int
y
,
double
dist
);
int
FindLineIntersection
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x
,
double
*
y
);
int
FindLineSegmentIntersection
(
double
a
,
double
b
,
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
double
*
x1
,
double
*
y1
,
double
*
x2
,
double
*
y2
,
double
*
dist
=
NULL
);
int
FindSegmentIntersections
(
int
xi
,
int
yi
,
int
xf
,
int
yf
,
int
style
,
int
xi2
,
int
yi2
,
int
xf2
,
int
yf2
,
int
style2
,
double
x
[]
=
NULL
,
double
y
[]
=
NULL
);
BOOL
FindLineEllipseIntersections
(
double
a
,
double
b
,
double
c
,
double
d
,
double
*
x1
,
double
*
x2
);
BOOL
FindVerticalLineEllipseIntersections
(
double
a
,
double
b
,
double
x
,
double
*
y1
,
double
*
y2
);
BOOL
TestForIntersectionOfStraightLineSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
*
x
=
NULL
,
int
*
y
=
NULL
,
double
*
dist
=
NULL
);
void
GetPadElements
(
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
,
int
*
nr
,
my_rect
r
[],
int
*
nc
,
my_circle
c
[],
int
*
ns
,
my_seg
s
[]
);
int
GetClearanceBetweenPads
(
int
type1
,
int
x1
,
int
y1
,
int
w1
,
int
l1
,
int
r1
,
int
angle1
,
int
type2
,
int
x2
,
int
y2
,
int
w2
,
int
l2
,
int
r2
,
int
angle2
);
int
GetClearanceBetweenSegmentAndPad
(
int
x1
,
int
y1
,
int
x2
,
int
y2
,
int
w
,
int
type
,
int
x
,
int
y
,
int
wid
,
int
len
,
int
radius
,
int
angle
);
int
GetClearanceBetweenSegments
(
int
x1i
,
int
y1i
,
int
x1f
,
int
y1f
,
int
style1
,
int
w1
,
int
x2i
,
int
y2i
,
int
x2f
,
int
y2f
,
int
style2
,
int
w2
,
int
max_cl
,
int
*
x
,
int
*
y
);
/** Function GetPointToLineSegmentDistance
* Get distance between line segment and point
* @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance
*/
double
GetPointToLineSegmentDistance
(
int
x
,
int
y
,
int
xi
,
int
yi
,
int
xf
,
int
yf
);
double
GetPointToLineDistance
(
double
a
,
double
b
,
int
x
,
int
y
,
double
*
xp
=
NULL
,
double
*
yp
=
NULL
);
BOOL
InRange
(
double
x
,
double
xi
,
double
xf
);
double
Distance
(
int
x1
,
int
y1
,
int
x2
,
int
y2
);
int
GetArcIntersections
(
EllipseKH
*
el1
,
EllipseKH
*
el2
,
double
*
x1
=
NULL
,
double
*
y1
=
NULL
,
double
*
x2
=
NULL
,
double
*
y2
=
NULL
);
CPoint
GetInflectionPoint
(
CPoint
pi
,
CPoint
pf
,
int
mode
);
// quicksort (2-way or 3-way)
void
quickSort
(
int
numbers
[],
int
index
[],
int
array_size
);
void
q_sort
(
int
numbers
[],
int
index
[],
int
left
,
int
right
);
void
q_sort_3way
(
int
a
[],
int
b
[],
int
left
,
int
right
);
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