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
f63492f5
Commit
f63492f5
authored
Jan 04, 2008
by
raburton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
set eol-style native on new file
parent
ffd3a713
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
975 additions
and
975 deletions
+975
-975
zones_test_and_combine_areas.cpp
pcbnew/zones_test_and_combine_areas.cpp
+975
-975
No files found.
pcbnew/zones_test_and_combine_areas.cpp
View file @
f63492f5
/****************************************************************************/
/* functions to test, merges and cut polygons used as copper areas outlines */
/****************************************************************************/
#include <vector>
#include "fctsys.h"
#include "common.h"
#include "pcbnew.h"
using
namespace
std
;
#undef ASSERT
#define ASSERT wxASSERT
bool
bDontShowSelfIntersectionArcsWarning
;
bool
bDontShowSelfIntersectionWarning
;
bool
bDontShowIntersectionArcsWarning
;
bool
bDontShowIntersectionWarning
;
#define poly m_Poly
// carea: describes a copper area
#define carea ZONE_CONTAINER
/**
* Function AddArea
* add empty copper area to net
* @return pointer to the new area
*/
ZONE_CONTAINER
*
BOARD
::
AddArea
(
int
netcode
,
int
layer
,
int
x
,
int
y
,
int
hatch
)
{
ZONE_CONTAINER
*
new_area
=
InsertArea
(
netcode
,
m_ZoneDescriptorList
.
size
(
)
-
1
,
layer
,
x
,
y
,
hatch
);
return
new_area
;
}
/**
* remove copper area from net
* @param area = area to remove
* @return 0
*/
int
BOARD
::
RemoveArea
(
ZONE_CONTAINER
*
area_to_remove
)
{
Delete
(
area_to_remove
);
return
0
;
}
/**
* Function InsertArea
* add empty copper area to net, inserting after m_ZoneDescriptorList[iarea]
* @return pointer to the new area
*/
ZONE_CONTAINER
*
BOARD
::
InsertArea
(
int
netcode
,
int
iarea
,
int
layer
,
int
x
,
int
y
,
int
hatch
)
{
ZONE_CONTAINER
*
new_area
=
new
ZONE_CONTAINER
(
this
);
new_area
->
SetNet
(
netcode
);
new_area
->
SetLayer
(
layer
);
new_area
->
m_TimeStamp
=
GetTimeStamp
();
if
(
iarea
<
(
int
)
(
m_ZoneDescriptorList
.
size
()
-
1
)
)
m_ZoneDescriptorList
.
insert
(
m_ZoneDescriptorList
.
begin
()
+
iarea
+
1
,
new_area
);
else
m_ZoneDescriptorList
.
push_back
(
new_area
);
new_area
->
poly
->
Start
(
layer
,
1
,
10
*
NM_PER_MIL
,
x
,
y
,
hatch
);
return
new_area
;
}
/**
* Function CompleteArea
* complete copper area contour by adding a line from last to first corner
* if there is only 1 or 2 corners, remove (delete) the area
* @param area_to_complete = area to complete or remove
* @param style = style of last corner
* @return 1 if Ok, 0 if area removed
*/
int
BOARD
::
CompleteArea
(
ZONE_CONTAINER
*
area_to_complete
,
int
style
)
{
if
(
area_to_complete
->
poly
->
GetNumCorners
()
>
2
)
{
area_to_complete
->
poly
->
Close
(
style
);
return
1
;
}
else
{
RemoveArea
(
area_to_complete
);
}
return
0
;
}
/**
* Function TestAreaPolygon
* Test an area for self-intersection.
*
* @param CurrArea = copper area to test
* @return :
* -1 if arcs intersect other sides
* 0 if no intersecting sides
* 1 if intersecting sides, but no intersecting arcs
* Also sets utility2 flag of area with return value
*/
int
BOARD
::
TestAreaPolygon
(
ZONE_CONTAINER
*
CurrArea
)
{
CPolyLine
*
p
=
CurrArea
->
poly
;
// first, check for sides intersecting other sides, especially arcs
bool
bInt
=
false
;
bool
bArcInt
=
false
;
int
n_cont
=
p
->
GetNumContours
();
// make bounding rect for each contour
std
::
vector
<
CRect
>
cr
;
cr
.
reserve
(
n_cont
);
for
(
int
icont
=
0
;
icont
<
n_cont
;
icont
++
)
cr
.
push_back
(
p
->
GetCornerBounds
(
icont
)
);
for
(
int
icont
=
0
;
icont
<
n_cont
;
icont
++
)
{
int
is_start
=
p
->
GetContourStart
(
icont
);
int
is_end
=
p
->
GetContourEnd
(
icont
);
for
(
int
is
=
is_start
;
is
<=
is_end
;
is
++
)
{
int
is_prev
=
is
-
1
;
if
(
is_prev
<
is_start
)
is_prev
=
is_end
;
int
is_next
=
is
+
1
;
if
(
is_next
>
is_end
)
is_next
=
is_start
;
int
style
=
p
->
GetSideStyle
(
is
);
int
x1i
=
p
->
GetX
(
is
);
int
y1i
=
p
->
GetY
(
is
);
int
x1f
=
p
->
GetX
(
is_next
);
int
y1f
=
p
->
GetY
(
is_next
);
// check for intersection with any other sides
for
(
int
icont2
=
icont
;
icont2
<
n_cont
;
icont2
++
)
{
if
(
cr
[
icont
].
left
>
cr
[
icont2
].
right
||
cr
[
icont
].
bottom
>
cr
[
icont2
].
top
||
cr
[
icont2
].
left
>
cr
[
icont
].
right
||
cr
[
icont2
].
bottom
>
cr
[
icont
].
top
)
{
// rectangles don't overlap, do nothing
}
else
{
int
is2_start
=
p
->
GetContourStart
(
icont2
);
int
is2_end
=
p
->
GetContourEnd
(
icont2
);
for
(
int
is2
=
is2_start
;
is2
<=
is2_end
;
is2
++
)
{
int
is2_prev
=
is2
-
1
;
if
(
is2_prev
<
is2_start
)
is2_prev
=
is2_end
;
int
is2_next
=
is2
+
1
;
if
(
is2_next
>
is2_end
)
is2_next
=
is2_start
;
if
(
icont
!=
icont2
||
(
is2
!=
is
&&
is2
!=
is_prev
&&
is2
!=
is_next
&&
is
!=
is2_prev
&&
is
!=
is2_next
)
)
{
int
style2
=
p
->
GetSideStyle
(
is2
);
int
x2i
=
p
->
GetX
(
is2
);
int
y2i
=
p
->
GetY
(
is2
);
int
x2f
=
p
->
GetX
(
is2_next
);
int
y2f
=
p
->
GetY
(
is2_next
);
int
ret
=
FindSegmentIntersections
(
x1i
,
y1i
,
x1f
,
y1f
,
style
,
x2i
,
y2i
,
x2f
,
y2f
,
style2
);
if
(
ret
)
{
// intersection between non-adjacent sides
bInt
=
TRUE
;
if
(
style
!=
CPolyLine
::
STRAIGHT
||
style2
!=
CPolyLine
::
STRAIGHT
)
{
bArcInt
=
TRUE
;
break
;
}
}
}
}
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
CurrArea
->
utility2
=
-
1
;
else
if
(
bInt
)
CurrArea
->
utility2
=
1
;
else
CurrArea
->
utility2
=
0
;
return
CurrArea
->
utility2
;
}
/**
* Function ClipAreaPolygon
* Process an area that has been modified, by clipping its polygon against itself.
* This may change the number and order of copper areas in the net.
* @param bMessageBoxInt == TRUE, shows message when clipping occurs.
* @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs.
* @return:
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides
* Also sets areas->utility1 flags if areas are modified
*/
int
BOARD
::
ClipAreaPolygon
(
ZONE_CONTAINER
*
CurrArea
,
bool
bMessageBoxArc
,
bool
bMessageBoxInt
,
bool
bRetainArcs
)
{
CPolyLine
*
p
=
CurrArea
->
poly
;
int
test
=
TestAreaPolygon
(
CurrArea
);
// this sets utility2 flag
if
(
test
==
-
1
&&
!
bRetainArcs
)
test
=
1
;
if
(
test
==
-
1
)
{
// arc intersections, don't clip unless bRetainArcs == false
if
(
bMessageBoxArc
&&
bDontShowSelfIntersectionArcsWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Area %X of net
\"
%s
\"
has arcs intersecting other sides.
\n
"
),
CurrArea
->
m_TimeStamp
,
CurrArea
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"This may cause problems with other editing operations,
\n
"
);
str
+=
wxT
(
"such as adding cutouts. It can't be fixed automatically.
\n
"
);
str
+=
wxT
(
"Manual correction is recommended."
);
wxMessageBox
(
str
);
// bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState;
}
return
-
1
;
// arcs intersect with other sides, error
}
// mark all areas as unmodified except this one
for
(
unsigned
ia
=
0
;
ia
<
m_ZoneDescriptorList
.
size
();
ia
++
)
m_ZoneDescriptorList
[
ia
]
->
utility
=
0
;
CurrArea
->
utility
=
1
;
if
(
test
==
1
)
{
// non-arc intersections, clip the polygon
if
(
bMessageBoxInt
&&
bDontShowSelfIntersectionWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Area %d of net
\"
%s
\"
is self-intersecting and will be clipped.
\n
"
),
CurrArea
->
m_TimeStamp
,
CurrArea
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"This may result in splitting the area.
\n
"
);
str
+=
wxT
(
"If the area is complex, this may take a few seconds."
);
wxMessageBox
(
str
);
// bDontShowSelfIntersectionWarning = dlg.bDontShowBoxState;
}
}
//** TODO test for cutouts outside of area
//** if( test == 1 )
{
std
::
vector
<
CPolyLine
*>
*
pa
=
new
std
::
vector
<
CPolyLine
*>
;
p
->
Undraw
();
int
n_poly
=
CurrArea
->
poly
->
NormalizeWithGpc
(
pa
,
bRetainArcs
);
if
(
n_poly
>
1
)
// i.e if clippinf has created some polygons, we must add these new copper areas
{
for
(
int
ip
=
1
;
ip
<
n_poly
;
ip
++
)
{
// create new copper area and copy poly into it
CPolyLine
*
new_p
=
(
*
pa
)[
ip
-
1
];
CurrArea
=
AddArea
(
CurrArea
->
GetNet
(),
CurrArea
->
GetLayer
(),
0
,
0
,
0
);
// remove the poly that was automatically created for the new area
// and replace it with a poly from NormalizeWithGpc
delete
CurrArea
->
poly
;
CurrArea
->
poly
=
new_p
;
CurrArea
->
poly
->
Draw
();
CurrArea
->
utility
=
1
;
}
}
p
->
Draw
();
delete
pa
;
}
return
test
;
}
/**
* Process an area that has been modified, by clipping its polygon against
* itself and the polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net.
* @param modified_area = area to test
* @param bMessageBox : if TRUE, shows message boxes when clipping occurs.
* @return :
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
*/
int
BOARD
::
AreaPolygonModified
(
ZONE_CONTAINER
*
modified_area
,
bool
bMessageBoxArc
,
bool
bMessageBoxInt
)
{
// clip polygon against itself
int
test
=
ClipAreaPolygon
(
modified_area
,
bMessageBoxArc
,
bMessageBoxInt
);
if
(
test
==
-
1
)
return
test
;
// now see if we need to clip against other areas
bool
bCheckAllAreas
=
false
;
if
(
test
==
1
)
bCheckAllAreas
=
TRUE
;
else
bCheckAllAreas
=
TestAreaIntersections
(
modified_area
);
if
(
bCheckAllAreas
)
CombineAllAreasInNet
(
modified_area
->
GetNet
(),
bMessageBoxInt
,
TRUE
);
return
test
;
}
/**
* Function CombineAllAreasInNet
* Checks all copper areas in net for intersections, combining them if found
* @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* Sets utility flag = 1 for any areas modified
* If an area has self-intersecting arcs, doesn't try to combine it
*/
int
BOARD
::
CombineAllAreasInNet
(
int
aNetCode
,
bool
bMessageBox
,
bool
bUseUtility
)
{
if
(
m_ZoneDescriptorList
.
size
()
>
1
)
{
// start by testing all area polygons to set utility2 flags
for
(
unsigned
ia
=
0
;
ia
<
m_ZoneDescriptorList
.
size
();
ia
++
)
if
(
m_ZoneDescriptorList
[
ia
]
->
GetNet
()
==
aNetCode
)
TestAreaPolygon
(
m_ZoneDescriptorList
[
ia
]
);
// now loop through all combinations
for
(
unsigned
ia1
=
0
;
ia1
<
m_ZoneDescriptorList
.
size
()
-
1
;
ia1
++
)
{
ZONE_CONTAINER
*
curr_area
=
m_ZoneDescriptorList
[
ia1
];
if
(
curr_area
->
GetNet
()
!=
aNetCode
)
continue
;
// legal polygon
CRect
b1
=
curr_area
->
poly
->
GetCornerBounds
();
bool
mod_ia1
=
false
;
for
(
unsigned
ia2
=
m_ZoneDescriptorList
.
size
()
-
1
;
ia2
>
ia1
;
ia2
--
)
{
ZONE_CONTAINER
*
area2
=
m_ZoneDescriptorList
[
ia2
];
if
(
curr_area
->
poly
->
GetLayer
()
==
area2
->
poly
->
GetLayer
()
&&
curr_area
->
utility2
!=
-
1
&&
area2
->
utility2
!=
-
1
)
{
CRect
b2
=
area2
->
poly
->
GetCornerBounds
();
if
(
!
(
b1
.
left
>
b2
.
right
||
b1
.
right
<
b2
.
left
||
b1
.
bottom
>
b2
.
top
||
b1
.
top
<
b2
.
bottom
)
)
{
// check ia2 against 1a1
if
(
curr_area
->
utility
||
area2
->
utility
||
bUseUtility
==
false
)
{
int
ret
=
TestAreaIntersection
(
curr_area
,
area2
);
if
(
ret
==
1
)
ret
=
CombineAreas
(
curr_area
,
area2
);
if
(
ret
==
1
)
{
if
(
bMessageBox
&&
bDontShowIntersectionWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Areas %d and %d of net
\"
%s
\"
intersect and will be combined.
\n
"
),
ia1
+
1
,
ia2
+
1
,
curr_area
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"If they are complex, this may take a few seconds."
);
wxMessageBox
(
str
);
// bDontShowIntersectionWarning = dlg.bDontShowBoxState;
}
mod_ia1
=
TRUE
;
}
else
if
(
ret
==
2
)
{
if
(
bMessageBox
&&
bDontShowIntersectionArcsWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Areas %d and %d of net
\"
%s
\"
intersect, but some of the intersecting sides are arcs.
\n
"
),
ia1
+
1
,
ia2
+
1
,
curr_area
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"Therefore, these areas can't be combined."
);
wxMessageBox
(
str
);
// bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState;
}
}
}
}
}
}
if
(
mod_ia1
)
ia1
--
;
// if modified, we need to check it again
}
}
return
0
;
}
/**
* Function TestAreaIntersections
* Check for intersection of a given copper area with other areas in same net
* @param area_to_test = area to compare to all other areas in the same net
*/
bool
BOARD
::
TestAreaIntersections
(
ZONE_CONTAINER
*
area_to_test
)
{
CPolyLine
*
poly1
=
area_to_test
->
poly
;
for
(
unsigned
ia2
=
0
;
ia2
<
m_ZoneDescriptorList
.
size
();
ia2
++
)
{
ZONE_CONTAINER
*
area2
=
m_ZoneDescriptorList
[
ia2
];
if
(
area_to_test
->
GetNet
()
!=
area_to_test
->
GetNet
()
)
continue
;
if
(
area_to_test
!=
area2
)
{
// see if areas are on same layer
if
(
area_to_test
->
GetLayer
()
!=
area2
->
GetLayer
()
)
continue
;
CPolyLine
*
poly2
=
area2
->
poly
;
// test bounding rects
CRect
b1
=
poly1
->
GetCornerBounds
();
CRect
b2
=
poly2
->
GetCornerBounds
();
if
(
b1
.
bottom
>
b2
.
top
||
b1
.
top
<
b2
.
bottom
||
b1
.
left
>
b2
.
right
||
b1
.
right
<
b2
.
left
)
continue
;
// test for intersecting segments
for
(
int
icont1
=
0
;
icont1
<
poly1
->
GetNumContours
();
icont1
++
)
{
int
is1
=
poly1
->
GetContourStart
(
icont1
);
int
ie1
=
poly1
->
GetContourEnd
(
icont1
);
for
(
int
ic1
=
is1
;
ic1
<=
ie1
;
ic1
++
)
{
int
xi1
=
poly1
->
GetX
(
ic1
);
int
yi1
=
poly1
->
GetY
(
ic1
);
int
xf1
,
yf1
,
style1
;
if
(
ic1
<
ie1
)
{
xf1
=
poly1
->
GetX
(
ic1
+
1
);
yf1
=
poly1
->
GetY
(
ic1
+
1
);
}
else
{
xf1
=
poly1
->
GetX
(
is1
);
yf1
=
poly1
->
GetY
(
is1
);
}
style1
=
poly1
->
GetSideStyle
(
ic1
);
for
(
int
icont2
=
0
;
icont2
<
poly2
->
GetNumContours
();
icont2
++
)
{
int
is2
=
poly2
->
GetContourStart
(
icont2
);
int
ie2
=
poly2
->
GetContourEnd
(
icont2
);
for
(
int
ic2
=
is2
;
ic2
<=
ie2
;
ic2
++
)
{
int
xi2
=
poly2
->
GetX
(
ic2
);
int
yi2
=
poly2
->
GetY
(
ic2
);
int
xf2
,
yf2
,
style2
;
if
(
ic2
<
ie2
)
{
xf2
=
poly2
->
GetX
(
ic2
+
1
);
yf2
=
poly2
->
GetY
(
ic2
+
1
);
}
else
{
xf2
=
poly2
->
GetX
(
is2
);
yf2
=
poly2
->
GetY
(
is2
);
}
style2
=
poly2
->
GetSideStyle
(
ic2
);
int
n_int
=
FindSegmentIntersections
(
xi1
,
yi1
,
xf1
,
yf1
,
style1
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
);
if
(
n_int
)
return
TRUE
;
}
}
}
}
}
}
return
false
;
}
/**
* Function TestAreaIntersection
* Test for intersection of 2 copper areas
* area_to_test must be after area_ref in m_ZoneDescriptorList
* @param area_ref = area reference
* @param area_to_test = area to compare for intersection calculations
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int
BOARD
::
TestAreaIntersection
(
ZONE_CONTAINER
*
area_ref
,
ZONE_CONTAINER
*
area_to_test
)
{
// see if areas are on same layer
if
(
area_ref
->
GetLayer
()
!=
area_to_test
->
GetLayer
()
)
return
0
;
CPolyLine
*
poly1
=
area_ref
->
poly
;
CPolyLine
*
poly2
=
area_to_test
->
poly
;
// test bounding rects
CRect
b1
=
poly1
->
GetCornerBounds
();
CRect
b2
=
poly2
->
GetCornerBounds
();
if
(
b1
.
bottom
>
b2
.
top
||
b1
.
top
<
b2
.
bottom
||
b1
.
left
>
b2
.
right
||
b1
.
right
<
b2
.
left
)
return
0
;
// now test for intersecting segments
bool
bInt
=
false
;
bool
bArcInt
=
false
;
for
(
int
icont1
=
0
;
icont1
<
poly1
->
GetNumContours
();
icont1
++
)
{
int
is1
=
poly1
->
GetContourStart
(
icont1
);
int
ie1
=
poly1
->
GetContourEnd
(
icont1
);
for
(
int
ic1
=
is1
;
ic1
<=
ie1
;
ic1
++
)
{
int
xi1
=
poly1
->
GetX
(
ic1
);
int
yi1
=
poly1
->
GetY
(
ic1
);
int
xf1
,
yf1
,
style1
;
if
(
ic1
<
ie1
)
{
xf1
=
poly1
->
GetX
(
ic1
+
1
);
yf1
=
poly1
->
GetY
(
ic1
+
1
);
}
else
{
xf1
=
poly1
->
GetX
(
is1
);
yf1
=
poly1
->
GetY
(
is1
);
}
style1
=
poly1
->
GetSideStyle
(
ic1
);
for
(
int
icont2
=
0
;
icont2
<
poly2
->
GetNumContours
();
icont2
++
)
{
int
is2
=
poly2
->
GetContourStart
(
icont2
);
int
ie2
=
poly2
->
GetContourEnd
(
icont2
);
for
(
int
ic2
=
is2
;
ic2
<=
ie2
;
ic2
++
)
{
int
xi2
=
poly2
->
GetX
(
ic2
);
int
yi2
=
poly2
->
GetY
(
ic2
);
int
xf2
,
yf2
,
style2
;
if
(
ic2
<
ie2
)
{
xf2
=
poly2
->
GetX
(
ic2
+
1
);
yf2
=
poly2
->
GetY
(
ic2
+
1
);
}
else
{
xf2
=
poly2
->
GetX
(
is2
);
yf2
=
poly2
->
GetY
(
is2
);
}
style2
=
poly2
->
GetSideStyle
(
ic2
);
int
n_int
=
FindSegmentIntersections
(
xi1
,
yi1
,
xf1
,
yf1
,
style1
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
);
if
(
n_int
)
{
bInt
=
TRUE
;
if
(
style1
!=
CPolyLine
::
STRAIGHT
||
style2
!=
CPolyLine
::
STRAIGHT
)
bArcInt
=
TRUE
;
break
;
}
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
!
bInt
)
return
0
;
if
(
bArcInt
)
return
2
;
return
1
;
}
/**
* Function CombineAreas
* If possible, combine 2 copper areas
* area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int
BOARD
::
CombineAreas
(
ZONE_CONTAINER
*
area_ref
,
ZONE_CONTAINER
*
area_to_combine
)
{
if
(
area_ref
==
area_to_combine
)
ASSERT
(
0
);
#if 0
// test for intersection
int test = TestAreaIntersection( area_ref, area_to_combine );
if( test != 1 )
return test; // no intersection
#endif
// polygons intersect, combine them
CPolyLine
*
poly1
=
area_ref
->
poly
;
CPolyLine
*
poly2
=
area_to_combine
->
poly
;
std
::
vector
<
CArc
>
arc_array1
;
std
::
vector
<
CArc
>
arc_array2
;
poly1
->
MakeGpcPoly
(
-
1
,
&
arc_array1
);
poly2
->
MakeGpcPoly
(
-
1
,
&
arc_array2
);
int
n_ext_cont1
=
0
;
for
(
int
ic
=
0
;
ic
<
poly1
->
GetGpcPoly
()
->
num_contours
;
ic
++
)
if
(
!
(
(
poly1
->
GetGpcPoly
()
->
hole
)[
ic
]
)
)
n_ext_cont1
++
;
int
n_ext_cont2
=
0
;
for
(
int
ic
=
0
;
ic
<
poly2
->
GetGpcPoly
()
->
num_contours
;
ic
++
)
if
(
!
(
(
poly2
->
GetGpcPoly
()
->
hole
)[
ic
]
)
)
n_ext_cont2
++
;
gpc_polygon
*
union_gpc
=
new
gpc_polygon
;
gpc_polygon_clip
(
GPC_UNION
,
poly1
->
GetGpcPoly
(),
poly2
->
GetGpcPoly
(),
union_gpc
);
// get number of outside contours
int
n_union_ext_cont
=
0
;
for
(
int
ic
=
0
;
ic
<
union_gpc
->
num_contours
;
ic
++
)
if
(
!
(
(
union_gpc
->
hole
)[
ic
]
)
)
n_union_ext_cont
++
;
// if no intersection, free new gpc and return
if
(
n_union_ext_cont
==
n_ext_cont1
+
n_ext_cont2
)
{
gpc_free_polygon
(
union_gpc
);
delete
union_gpc
;
return
0
;
}
// intersection, replace area_ref->m_Poly with combined areas and remove area_to_combine
RemoveArea
(
area_to_combine
);
area_ref
->
m_Poly
->
RemoveAllContours
();
// create area with external contour
for
(
int
ic
=
0
;
ic
<
union_gpc
->
num_contours
;
ic
++
)
{
if
(
!
(
union_gpc
->
hole
)[
ic
]
)
{
// external contour, replace this poly
for
(
int
i
=
0
;
i
<
union_gpc
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
x
;
int
y
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
y
;
if
(
i
==
0
)
{
area_ref
->
m_Poly
->
Start
(
area_ref
->
GetLayer
(),
0
,
0
,
x
,
y
,
area_ref
->
m_Poly
->
GetHatchStyle
()
);
}
else
area_ref
->
m_Poly
->
AppendCorner
(
x
,
y
);
}
area_ref
->
m_Poly
->
Close
();
}
}
// add holes
for
(
int
ic
=
0
;
ic
<
union_gpc
->
num_contours
;
ic
++
)
{
if
(
(
union_gpc
->
hole
)[
ic
]
)
{
// hole
for
(
int
i
=
0
;
i
<
union_gpc
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
x
;
int
y
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
y
;
area_ref
->
m_Poly
->
AppendCorner
(
x
,
y
);
}
area_ref
->
m_Poly
->
Close
();
}
}
area_ref
->
utility
=
1
;
area_ref
->
m_Poly
->
RestoreArcs
(
&
arc_array1
);
area_ref
->
m_Poly
->
RestoreArcs
(
&
arc_array2
);
area_ref
->
m_Poly
->
Draw
();
gpc_free_polygon
(
union_gpc
);
delete
union_gpc
;
return
1
;
}
#if 0
void dra_areas( CDlgLog* log, int copper_layers,
int units, BOOL check_unrouted,
CArray<CPolyLine> * board_outline,
DesignRules* dr, DRErrorList* drelist )
{
CString d_str, x_str, y_str;
CString str;
CString str2;
long nerrors = 0;
// now iterate through all areas
for( int ia = 0; ia<net->nareas; ia++ )
{
carea* a = &net->area[ia];
// iterate through all nets again
POSITION pos2 = pos;
void* ptr2;
CString name2;
while( pos2 != NULL )
{
m_nlist->m_map.GetNextAssoc( pos2, name2, ptr2 );
cnet* net2 = (cnet*) ptr2;
for( int ia2 = 0; ia2<net2->nareas; ia2++ )
{
carea* a2 = &net2->area[ia2];
// test for same layer
if( a->poly->GetLayer() == a2->poly->GetLayer() )
{
// test for points inside one another
for( int ic = 0; ic<a->poly->GetNumCorners(); ic++ )
{
int x = a->poly->GetX( ic );
int y = a->poly->GetY( ic );
if( a2->poly->TestPointInside( x, y ) )
{
// COPPERAREA_COPPERAREA error
id id_a = net->id;
id_a.st = ID_AREA;
id_a.i = ia;
id_a.sst = ID_SEL_CORNER;
id_a.ii = ic;
str.Format(
"%ld: \"%s\" copper area inside \"%s\" inside copper area\r\n",
nerrors + 1,
net->name,
net2->name );
DRError* dre = drelist->Add( nerrors,
DRError::COPPERAREA_INSIDE_COPPERAREA,
&str,
&net->name,
&net2->name,
id_a,
id_a,
x,
y,
x,
y,
0,
0 );
if( dre )
{
nerrors++;
if( log )
log->AddLine( str );
}
}
}
for( int ic2 = 0; ic2<a2->poly->GetNumCorners(); ic2++ )
{
int x = a2->poly->GetX( ic2 );
int y = a2->poly->GetY( ic2 );
if( a->poly->TestPointInside( x, y ) )
{
// COPPERAREA_COPPERAREA error
id id_a = net2->id;
id_a.st = ID_AREA;
id_a.i = ia2;
id_a.sst = ID_SEL_CORNER;
id_a.ii = ic2;
str.Format( "%ld: \"%s\" copper area inside \"%s\" copper area\r\n",
nerrors + 1, net2->name, net->name );
DRError* dre = drelist->Add( nerrors,
DRError::COPPERAREA_INSIDE_COPPERAREA,
&str,
&net2->name,
&net->name,
id_a,
id_a,
x,
y,
x,
y,
0,
0 );
if( dre )
{
nerrors++;
if( log )
log->AddLine( str );
}
}
}
// now test spacing between areas
for( int icont = 0; icont<a->poly->GetNumContours(); icont++ )
{
int ic_start = a->poly->GetContourStart( icont );
int ic_end = a->poly->GetContourEnd( icont );
for( int ic = ic_start; ic<=ic_end; ic++ )
{
id id_a = net->id;
id_a.st = ID_AREA;
id_a.i = ia;
id_a.sst = ID_SIDE;
id_a.ii = ic;
int ax1 = a->poly->GetX( ic );
int ay1 = a->poly->GetY( ic );
int ax2, ay2;
if( ic == ic_end )
{
ax2 = a->poly->GetX( ic_start );
ay2 = a->poly->GetY( ic_start );
}
else
{
ax2 = a->poly->GetX( ic + 1 );
ay2 = a->poly->GetY( ic + 1 );
}
int astyle = a->poly->GetSideStyle( ic );
for( int icont2 = 0; icont2<a2->poly->GetNumContours(); icont2++ )
{
int ic_start2 = a2->poly->GetContourStart( icont2 );
int ic_end2 = a2->poly->GetContourEnd( icont2 );
for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ )
{
id id_b = net2->id;
id_b.st = ID_AREA;
id_b.i = ia2;
id_b.sst = ID_SIDE;
id_b.ii = ic2;
int bx1 = a2->poly->GetX( ic2 );
int by1 = a2->poly->GetY( ic2 );
int bx2, by2;
if( ic2 == ic_end2 )
{
bx2 = a2->poly->GetX( ic_start2 );
by2 = a2->poly->GetY( ic_start2 );
}
else
{
bx2 = a2->poly->GetX( ic2 + 1 );
by2 = a2->poly->GetY( ic2 + 1 );
}
int bstyle = a2->poly->GetSideStyle( ic2 );
int x, y;
int d = ::GetClearanceBetweenSegments( bx1,
by1,
bx2,
by2,
bstyle,
0,
ax1,
ay1,
ax2,
ay2,
astyle,
0,
dr->copper_copper,
&x,
&y );
if( d < dr->copper_copper )
{
// COPPERAREA_COPPERAREA error
::MakeCStringFromDimension( &d_str,
d,
units,
TRUE,
TRUE,
TRUE,
1 );
::MakeCStringFromDimension( &x_str,
x,
units,
FALSE,
TRUE,
TRUE,
1 );
::MakeCStringFromDimension( &y_str,
y,
units,
FALSE,
TRUE,
TRUE,
1 );
str.Format(
"%ld: \"%s\" copper area to \"%s\" copper area = %s, x=%s, y=%s\r\n",
nerrors + 1,
net->name,
net2->name,
d_str,
x_str,
y_str );
DRError* dre = drelist->Add(
nerrors,
DRError::
COPPERAREA_COPPERAREA,
&str,
&net->name,
&net2->name,
id_a,
id_b,
x,
y,
x,
y,
0,
0 );
if( dre )
{
nerrors++;
if( log )
log->AddLine( str );
}
}
}
}
}
}
}
}
}
}
}
#endif
/****************************************************************************/
/* functions to test, merges and cut polygons used as copper areas outlines */
/****************************************************************************/
#include <vector>
#include "fctsys.h"
#include "common.h"
#include "pcbnew.h"
using
namespace
std
;
#undef ASSERT
#define ASSERT wxASSERT
bool
bDontShowSelfIntersectionArcsWarning
;
bool
bDontShowSelfIntersectionWarning
;
bool
bDontShowIntersectionArcsWarning
;
bool
bDontShowIntersectionWarning
;
#define poly m_Poly
// carea: describes a copper area
#define carea ZONE_CONTAINER
/**
* Function AddArea
* add empty copper area to net
* @return pointer to the new area
*/
ZONE_CONTAINER
*
BOARD
::
AddArea
(
int
netcode
,
int
layer
,
int
x
,
int
y
,
int
hatch
)
{
ZONE_CONTAINER
*
new_area
=
InsertArea
(
netcode
,
m_ZoneDescriptorList
.
size
(
)
-
1
,
layer
,
x
,
y
,
hatch
);
return
new_area
;
}
/**
* remove copper area from net
* @param area = area to remove
* @return 0
*/
int
BOARD
::
RemoveArea
(
ZONE_CONTAINER
*
area_to_remove
)
{
Delete
(
area_to_remove
);
return
0
;
}
/**
* Function InsertArea
* add empty copper area to net, inserting after m_ZoneDescriptorList[iarea]
* @return pointer to the new area
*/
ZONE_CONTAINER
*
BOARD
::
InsertArea
(
int
netcode
,
int
iarea
,
int
layer
,
int
x
,
int
y
,
int
hatch
)
{
ZONE_CONTAINER
*
new_area
=
new
ZONE_CONTAINER
(
this
);
new_area
->
SetNet
(
netcode
);
new_area
->
SetLayer
(
layer
);
new_area
->
m_TimeStamp
=
GetTimeStamp
();
if
(
iarea
<
(
int
)
(
m_ZoneDescriptorList
.
size
()
-
1
)
)
m_ZoneDescriptorList
.
insert
(
m_ZoneDescriptorList
.
begin
()
+
iarea
+
1
,
new_area
);
else
m_ZoneDescriptorList
.
push_back
(
new_area
);
new_area
->
poly
->
Start
(
layer
,
1
,
10
*
NM_PER_MIL
,
x
,
y
,
hatch
);
return
new_area
;
}
/**
* Function CompleteArea
* complete copper area contour by adding a line from last to first corner
* if there is only 1 or 2 corners, remove (delete) the area
* @param area_to_complete = area to complete or remove
* @param style = style of last corner
* @return 1 if Ok, 0 if area removed
*/
int
BOARD
::
CompleteArea
(
ZONE_CONTAINER
*
area_to_complete
,
int
style
)
{
if
(
area_to_complete
->
poly
->
GetNumCorners
()
>
2
)
{
area_to_complete
->
poly
->
Close
(
style
);
return
1
;
}
else
{
RemoveArea
(
area_to_complete
);
}
return
0
;
}
/**
* Function TestAreaPolygon
* Test an area for self-intersection.
*
* @param CurrArea = copper area to test
* @return :
* -1 if arcs intersect other sides
* 0 if no intersecting sides
* 1 if intersecting sides, but no intersecting arcs
* Also sets utility2 flag of area with return value
*/
int
BOARD
::
TestAreaPolygon
(
ZONE_CONTAINER
*
CurrArea
)
{
CPolyLine
*
p
=
CurrArea
->
poly
;
// first, check for sides intersecting other sides, especially arcs
bool
bInt
=
false
;
bool
bArcInt
=
false
;
int
n_cont
=
p
->
GetNumContours
();
// make bounding rect for each contour
std
::
vector
<
CRect
>
cr
;
cr
.
reserve
(
n_cont
);
for
(
int
icont
=
0
;
icont
<
n_cont
;
icont
++
)
cr
.
push_back
(
p
->
GetCornerBounds
(
icont
)
);
for
(
int
icont
=
0
;
icont
<
n_cont
;
icont
++
)
{
int
is_start
=
p
->
GetContourStart
(
icont
);
int
is_end
=
p
->
GetContourEnd
(
icont
);
for
(
int
is
=
is_start
;
is
<=
is_end
;
is
++
)
{
int
is_prev
=
is
-
1
;
if
(
is_prev
<
is_start
)
is_prev
=
is_end
;
int
is_next
=
is
+
1
;
if
(
is_next
>
is_end
)
is_next
=
is_start
;
int
style
=
p
->
GetSideStyle
(
is
);
int
x1i
=
p
->
GetX
(
is
);
int
y1i
=
p
->
GetY
(
is
);
int
x1f
=
p
->
GetX
(
is_next
);
int
y1f
=
p
->
GetY
(
is_next
);
// check for intersection with any other sides
for
(
int
icont2
=
icont
;
icont2
<
n_cont
;
icont2
++
)
{
if
(
cr
[
icont
].
left
>
cr
[
icont2
].
right
||
cr
[
icont
].
bottom
>
cr
[
icont2
].
top
||
cr
[
icont2
].
left
>
cr
[
icont
].
right
||
cr
[
icont2
].
bottom
>
cr
[
icont
].
top
)
{
// rectangles don't overlap, do nothing
}
else
{
int
is2_start
=
p
->
GetContourStart
(
icont2
);
int
is2_end
=
p
->
GetContourEnd
(
icont2
);
for
(
int
is2
=
is2_start
;
is2
<=
is2_end
;
is2
++
)
{
int
is2_prev
=
is2
-
1
;
if
(
is2_prev
<
is2_start
)
is2_prev
=
is2_end
;
int
is2_next
=
is2
+
1
;
if
(
is2_next
>
is2_end
)
is2_next
=
is2_start
;
if
(
icont
!=
icont2
||
(
is2
!=
is
&&
is2
!=
is_prev
&&
is2
!=
is_next
&&
is
!=
is2_prev
&&
is
!=
is2_next
)
)
{
int
style2
=
p
->
GetSideStyle
(
is2
);
int
x2i
=
p
->
GetX
(
is2
);
int
y2i
=
p
->
GetY
(
is2
);
int
x2f
=
p
->
GetX
(
is2_next
);
int
y2f
=
p
->
GetY
(
is2_next
);
int
ret
=
FindSegmentIntersections
(
x1i
,
y1i
,
x1f
,
y1f
,
style
,
x2i
,
y2i
,
x2f
,
y2f
,
style2
);
if
(
ret
)
{
// intersection between non-adjacent sides
bInt
=
TRUE
;
if
(
style
!=
CPolyLine
::
STRAIGHT
||
style2
!=
CPolyLine
::
STRAIGHT
)
{
bArcInt
=
TRUE
;
break
;
}
}
}
}
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
CurrArea
->
utility2
=
-
1
;
else
if
(
bInt
)
CurrArea
->
utility2
=
1
;
else
CurrArea
->
utility2
=
0
;
return
CurrArea
->
utility2
;
}
/**
* Function ClipAreaPolygon
* Process an area that has been modified, by clipping its polygon against itself.
* This may change the number and order of copper areas in the net.
* @param bMessageBoxInt == TRUE, shows message when clipping occurs.
* @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs.
* @return:
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides
* Also sets areas->utility1 flags if areas are modified
*/
int
BOARD
::
ClipAreaPolygon
(
ZONE_CONTAINER
*
CurrArea
,
bool
bMessageBoxArc
,
bool
bMessageBoxInt
,
bool
bRetainArcs
)
{
CPolyLine
*
p
=
CurrArea
->
poly
;
int
test
=
TestAreaPolygon
(
CurrArea
);
// this sets utility2 flag
if
(
test
==
-
1
&&
!
bRetainArcs
)
test
=
1
;
if
(
test
==
-
1
)
{
// arc intersections, don't clip unless bRetainArcs == false
if
(
bMessageBoxArc
&&
bDontShowSelfIntersectionArcsWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Area %X of net
\"
%s
\"
has arcs intersecting other sides.
\n
"
),
CurrArea
->
m_TimeStamp
,
CurrArea
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"This may cause problems with other editing operations,
\n
"
);
str
+=
wxT
(
"such as adding cutouts. It can't be fixed automatically.
\n
"
);
str
+=
wxT
(
"Manual correction is recommended."
);
wxMessageBox
(
str
);
// bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState;
}
return
-
1
;
// arcs intersect with other sides, error
}
// mark all areas as unmodified except this one
for
(
unsigned
ia
=
0
;
ia
<
m_ZoneDescriptorList
.
size
();
ia
++
)
m_ZoneDescriptorList
[
ia
]
->
utility
=
0
;
CurrArea
->
utility
=
1
;
if
(
test
==
1
)
{
// non-arc intersections, clip the polygon
if
(
bMessageBoxInt
&&
bDontShowSelfIntersectionWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Area %d of net
\"
%s
\"
is self-intersecting and will be clipped.
\n
"
),
CurrArea
->
m_TimeStamp
,
CurrArea
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"This may result in splitting the area.
\n
"
);
str
+=
wxT
(
"If the area is complex, this may take a few seconds."
);
wxMessageBox
(
str
);
// bDontShowSelfIntersectionWarning = dlg.bDontShowBoxState;
}
}
//** TODO test for cutouts outside of area
//** if( test == 1 )
{
std
::
vector
<
CPolyLine
*>
*
pa
=
new
std
::
vector
<
CPolyLine
*>
;
p
->
Undraw
();
int
n_poly
=
CurrArea
->
poly
->
NormalizeWithGpc
(
pa
,
bRetainArcs
);
if
(
n_poly
>
1
)
// i.e if clippinf has created some polygons, we must add these new copper areas
{
for
(
int
ip
=
1
;
ip
<
n_poly
;
ip
++
)
{
// create new copper area and copy poly into it
CPolyLine
*
new_p
=
(
*
pa
)[
ip
-
1
];
CurrArea
=
AddArea
(
CurrArea
->
GetNet
(),
CurrArea
->
GetLayer
(),
0
,
0
,
0
);
// remove the poly that was automatically created for the new area
// and replace it with a poly from NormalizeWithGpc
delete
CurrArea
->
poly
;
CurrArea
->
poly
=
new_p
;
CurrArea
->
poly
->
Draw
();
CurrArea
->
utility
=
1
;
}
}
p
->
Draw
();
delete
pa
;
}
return
test
;
}
/**
* Process an area that has been modified, by clipping its polygon against
* itself and the polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net.
* @param modified_area = area to test
* @param bMessageBox : if TRUE, shows message boxes when clipping occurs.
* @return :
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
*/
int
BOARD
::
AreaPolygonModified
(
ZONE_CONTAINER
*
modified_area
,
bool
bMessageBoxArc
,
bool
bMessageBoxInt
)
{
// clip polygon against itself
int
test
=
ClipAreaPolygon
(
modified_area
,
bMessageBoxArc
,
bMessageBoxInt
);
if
(
test
==
-
1
)
return
test
;
// now see if we need to clip against other areas
bool
bCheckAllAreas
=
false
;
if
(
test
==
1
)
bCheckAllAreas
=
TRUE
;
else
bCheckAllAreas
=
TestAreaIntersections
(
modified_area
);
if
(
bCheckAllAreas
)
CombineAllAreasInNet
(
modified_area
->
GetNet
(),
bMessageBoxInt
,
TRUE
);
return
test
;
}
/**
* Function CombineAllAreasInNet
* Checks all copper areas in net for intersections, combining them if found
* @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* Sets utility flag = 1 for any areas modified
* If an area has self-intersecting arcs, doesn't try to combine it
*/
int
BOARD
::
CombineAllAreasInNet
(
int
aNetCode
,
bool
bMessageBox
,
bool
bUseUtility
)
{
if
(
m_ZoneDescriptorList
.
size
()
>
1
)
{
// start by testing all area polygons to set utility2 flags
for
(
unsigned
ia
=
0
;
ia
<
m_ZoneDescriptorList
.
size
();
ia
++
)
if
(
m_ZoneDescriptorList
[
ia
]
->
GetNet
()
==
aNetCode
)
TestAreaPolygon
(
m_ZoneDescriptorList
[
ia
]
);
// now loop through all combinations
for
(
unsigned
ia1
=
0
;
ia1
<
m_ZoneDescriptorList
.
size
()
-
1
;
ia1
++
)
{
ZONE_CONTAINER
*
curr_area
=
m_ZoneDescriptorList
[
ia1
];
if
(
curr_area
->
GetNet
()
!=
aNetCode
)
continue
;
// legal polygon
CRect
b1
=
curr_area
->
poly
->
GetCornerBounds
();
bool
mod_ia1
=
false
;
for
(
unsigned
ia2
=
m_ZoneDescriptorList
.
size
()
-
1
;
ia2
>
ia1
;
ia2
--
)
{
ZONE_CONTAINER
*
area2
=
m_ZoneDescriptorList
[
ia2
];
if
(
curr_area
->
poly
->
GetLayer
()
==
area2
->
poly
->
GetLayer
()
&&
curr_area
->
utility2
!=
-
1
&&
area2
->
utility2
!=
-
1
)
{
CRect
b2
=
area2
->
poly
->
GetCornerBounds
();
if
(
!
(
b1
.
left
>
b2
.
right
||
b1
.
right
<
b2
.
left
||
b1
.
bottom
>
b2
.
top
||
b1
.
top
<
b2
.
bottom
)
)
{
// check ia2 against 1a1
if
(
curr_area
->
utility
||
area2
->
utility
||
bUseUtility
==
false
)
{
int
ret
=
TestAreaIntersection
(
curr_area
,
area2
);
if
(
ret
==
1
)
ret
=
CombineAreas
(
curr_area
,
area2
);
if
(
ret
==
1
)
{
if
(
bMessageBox
&&
bDontShowIntersectionWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Areas %d and %d of net
\"
%s
\"
intersect and will be combined.
\n
"
),
ia1
+
1
,
ia2
+
1
,
curr_area
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"If they are complex, this may take a few seconds."
);
wxMessageBox
(
str
);
// bDontShowIntersectionWarning = dlg.bDontShowBoxState;
}
mod_ia1
=
TRUE
;
}
else
if
(
ret
==
2
)
{
if
(
bMessageBox
&&
bDontShowIntersectionArcsWarning
==
false
)
{
wxString
str
;
str
.
Printf
(
wxT
(
"Areas %d and %d of net
\"
%s
\"
intersect, but some of the intersecting sides are arcs.
\n
"
),
ia1
+
1
,
ia2
+
1
,
curr_area
->
m_Netname
.
GetData
()
);
str
+=
wxT
(
"Therefore, these areas can't be combined."
);
wxMessageBox
(
str
);
// bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState;
}
}
}
}
}
}
if
(
mod_ia1
)
ia1
--
;
// if modified, we need to check it again
}
}
return
0
;
}
/**
* Function TestAreaIntersections
* Check for intersection of a given copper area with other areas in same net
* @param area_to_test = area to compare to all other areas in the same net
*/
bool
BOARD
::
TestAreaIntersections
(
ZONE_CONTAINER
*
area_to_test
)
{
CPolyLine
*
poly1
=
area_to_test
->
poly
;
for
(
unsigned
ia2
=
0
;
ia2
<
m_ZoneDescriptorList
.
size
();
ia2
++
)
{
ZONE_CONTAINER
*
area2
=
m_ZoneDescriptorList
[
ia2
];
if
(
area_to_test
->
GetNet
()
!=
area_to_test
->
GetNet
()
)
continue
;
if
(
area_to_test
!=
area2
)
{
// see if areas are on same layer
if
(
area_to_test
->
GetLayer
()
!=
area2
->
GetLayer
()
)
continue
;
CPolyLine
*
poly2
=
area2
->
poly
;
// test bounding rects
CRect
b1
=
poly1
->
GetCornerBounds
();
CRect
b2
=
poly2
->
GetCornerBounds
();
if
(
b1
.
bottom
>
b2
.
top
||
b1
.
top
<
b2
.
bottom
||
b1
.
left
>
b2
.
right
||
b1
.
right
<
b2
.
left
)
continue
;
// test for intersecting segments
for
(
int
icont1
=
0
;
icont1
<
poly1
->
GetNumContours
();
icont1
++
)
{
int
is1
=
poly1
->
GetContourStart
(
icont1
);
int
ie1
=
poly1
->
GetContourEnd
(
icont1
);
for
(
int
ic1
=
is1
;
ic1
<=
ie1
;
ic1
++
)
{
int
xi1
=
poly1
->
GetX
(
ic1
);
int
yi1
=
poly1
->
GetY
(
ic1
);
int
xf1
,
yf1
,
style1
;
if
(
ic1
<
ie1
)
{
xf1
=
poly1
->
GetX
(
ic1
+
1
);
yf1
=
poly1
->
GetY
(
ic1
+
1
);
}
else
{
xf1
=
poly1
->
GetX
(
is1
);
yf1
=
poly1
->
GetY
(
is1
);
}
style1
=
poly1
->
GetSideStyle
(
ic1
);
for
(
int
icont2
=
0
;
icont2
<
poly2
->
GetNumContours
();
icont2
++
)
{
int
is2
=
poly2
->
GetContourStart
(
icont2
);
int
ie2
=
poly2
->
GetContourEnd
(
icont2
);
for
(
int
ic2
=
is2
;
ic2
<=
ie2
;
ic2
++
)
{
int
xi2
=
poly2
->
GetX
(
ic2
);
int
yi2
=
poly2
->
GetY
(
ic2
);
int
xf2
,
yf2
,
style2
;
if
(
ic2
<
ie2
)
{
xf2
=
poly2
->
GetX
(
ic2
+
1
);
yf2
=
poly2
->
GetY
(
ic2
+
1
);
}
else
{
xf2
=
poly2
->
GetX
(
is2
);
yf2
=
poly2
->
GetY
(
is2
);
}
style2
=
poly2
->
GetSideStyle
(
ic2
);
int
n_int
=
FindSegmentIntersections
(
xi1
,
yi1
,
xf1
,
yf1
,
style1
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
);
if
(
n_int
)
return
TRUE
;
}
}
}
}
}
}
return
false
;
}
/**
* Function TestAreaIntersection
* Test for intersection of 2 copper areas
* area_to_test must be after area_ref in m_ZoneDescriptorList
* @param area_ref = area reference
* @param area_to_test = area to compare for intersection calculations
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int
BOARD
::
TestAreaIntersection
(
ZONE_CONTAINER
*
area_ref
,
ZONE_CONTAINER
*
area_to_test
)
{
// see if areas are on same layer
if
(
area_ref
->
GetLayer
()
!=
area_to_test
->
GetLayer
()
)
return
0
;
CPolyLine
*
poly1
=
area_ref
->
poly
;
CPolyLine
*
poly2
=
area_to_test
->
poly
;
// test bounding rects
CRect
b1
=
poly1
->
GetCornerBounds
();
CRect
b2
=
poly2
->
GetCornerBounds
();
if
(
b1
.
bottom
>
b2
.
top
||
b1
.
top
<
b2
.
bottom
||
b1
.
left
>
b2
.
right
||
b1
.
right
<
b2
.
left
)
return
0
;
// now test for intersecting segments
bool
bInt
=
false
;
bool
bArcInt
=
false
;
for
(
int
icont1
=
0
;
icont1
<
poly1
->
GetNumContours
();
icont1
++
)
{
int
is1
=
poly1
->
GetContourStart
(
icont1
);
int
ie1
=
poly1
->
GetContourEnd
(
icont1
);
for
(
int
ic1
=
is1
;
ic1
<=
ie1
;
ic1
++
)
{
int
xi1
=
poly1
->
GetX
(
ic1
);
int
yi1
=
poly1
->
GetY
(
ic1
);
int
xf1
,
yf1
,
style1
;
if
(
ic1
<
ie1
)
{
xf1
=
poly1
->
GetX
(
ic1
+
1
);
yf1
=
poly1
->
GetY
(
ic1
+
1
);
}
else
{
xf1
=
poly1
->
GetX
(
is1
);
yf1
=
poly1
->
GetY
(
is1
);
}
style1
=
poly1
->
GetSideStyle
(
ic1
);
for
(
int
icont2
=
0
;
icont2
<
poly2
->
GetNumContours
();
icont2
++
)
{
int
is2
=
poly2
->
GetContourStart
(
icont2
);
int
ie2
=
poly2
->
GetContourEnd
(
icont2
);
for
(
int
ic2
=
is2
;
ic2
<=
ie2
;
ic2
++
)
{
int
xi2
=
poly2
->
GetX
(
ic2
);
int
yi2
=
poly2
->
GetY
(
ic2
);
int
xf2
,
yf2
,
style2
;
if
(
ic2
<
ie2
)
{
xf2
=
poly2
->
GetX
(
ic2
+
1
);
yf2
=
poly2
->
GetY
(
ic2
+
1
);
}
else
{
xf2
=
poly2
->
GetX
(
is2
);
yf2
=
poly2
->
GetY
(
is2
);
}
style2
=
poly2
->
GetSideStyle
(
ic2
);
int
n_int
=
FindSegmentIntersections
(
xi1
,
yi1
,
xf1
,
yf1
,
style1
,
xi2
,
yi2
,
xf2
,
yf2
,
style2
);
if
(
n_int
)
{
bInt
=
TRUE
;
if
(
style1
!=
CPolyLine
::
STRAIGHT
||
style2
!=
CPolyLine
::
STRAIGHT
)
bArcInt
=
TRUE
;
break
;
}
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
bArcInt
)
break
;
}
if
(
!
bInt
)
return
0
;
if
(
bArcInt
)
return
2
;
return
1
;
}
/**
* Function CombineAreas
* If possible, combine 2 copper areas
* area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int
BOARD
::
CombineAreas
(
ZONE_CONTAINER
*
area_ref
,
ZONE_CONTAINER
*
area_to_combine
)
{
if
(
area_ref
==
area_to_combine
)
ASSERT
(
0
);
#if 0
// test for intersection
int test = TestAreaIntersection( area_ref, area_to_combine );
if( test != 1 )
return test; // no intersection
#endif
// polygons intersect, combine them
CPolyLine
*
poly1
=
area_ref
->
poly
;
CPolyLine
*
poly2
=
area_to_combine
->
poly
;
std
::
vector
<
CArc
>
arc_array1
;
std
::
vector
<
CArc
>
arc_array2
;
poly1
->
MakeGpcPoly
(
-
1
,
&
arc_array1
);
poly2
->
MakeGpcPoly
(
-
1
,
&
arc_array2
);
int
n_ext_cont1
=
0
;
for
(
int
ic
=
0
;
ic
<
poly1
->
GetGpcPoly
()
->
num_contours
;
ic
++
)
if
(
!
(
(
poly1
->
GetGpcPoly
()
->
hole
)[
ic
]
)
)
n_ext_cont1
++
;
int
n_ext_cont2
=
0
;
for
(
int
ic
=
0
;
ic
<
poly2
->
GetGpcPoly
()
->
num_contours
;
ic
++
)
if
(
!
(
(
poly2
->
GetGpcPoly
()
->
hole
)[
ic
]
)
)
n_ext_cont2
++
;
gpc_polygon
*
union_gpc
=
new
gpc_polygon
;
gpc_polygon_clip
(
GPC_UNION
,
poly1
->
GetGpcPoly
(),
poly2
->
GetGpcPoly
(),
union_gpc
);
// get number of outside contours
int
n_union_ext_cont
=
0
;
for
(
int
ic
=
0
;
ic
<
union_gpc
->
num_contours
;
ic
++
)
if
(
!
(
(
union_gpc
->
hole
)[
ic
]
)
)
n_union_ext_cont
++
;
// if no intersection, free new gpc and return
if
(
n_union_ext_cont
==
n_ext_cont1
+
n_ext_cont2
)
{
gpc_free_polygon
(
union_gpc
);
delete
union_gpc
;
return
0
;
}
// intersection, replace area_ref->m_Poly with combined areas and remove area_to_combine
RemoveArea
(
area_to_combine
);
area_ref
->
m_Poly
->
RemoveAllContours
();
// create area with external contour
for
(
int
ic
=
0
;
ic
<
union_gpc
->
num_contours
;
ic
++
)
{
if
(
!
(
union_gpc
->
hole
)[
ic
]
)
{
// external contour, replace this poly
for
(
int
i
=
0
;
i
<
union_gpc
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
x
;
int
y
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
y
;
if
(
i
==
0
)
{
area_ref
->
m_Poly
->
Start
(
area_ref
->
GetLayer
(),
0
,
0
,
x
,
y
,
area_ref
->
m_Poly
->
GetHatchStyle
()
);
}
else
area_ref
->
m_Poly
->
AppendCorner
(
x
,
y
);
}
area_ref
->
m_Poly
->
Close
();
}
}
// add holes
for
(
int
ic
=
0
;
ic
<
union_gpc
->
num_contours
;
ic
++
)
{
if
(
(
union_gpc
->
hole
)[
ic
]
)
{
// hole
for
(
int
i
=
0
;
i
<
union_gpc
->
contour
[
ic
].
num_vertices
;
i
++
)
{
int
x
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
x
;
int
y
=
(
(
union_gpc
->
contour
)[
ic
].
vertex
)[
i
].
y
;
area_ref
->
m_Poly
->
AppendCorner
(
x
,
y
);
}
area_ref
->
m_Poly
->
Close
();
}
}
area_ref
->
utility
=
1
;
area_ref
->
m_Poly
->
RestoreArcs
(
&
arc_array1
);
area_ref
->
m_Poly
->
RestoreArcs
(
&
arc_array2
);
area_ref
->
m_Poly
->
Draw
();
gpc_free_polygon
(
union_gpc
);
delete
union_gpc
;
return
1
;
}
#if 0
void dra_areas( CDlgLog* log, int copper_layers,
int units, BOOL check_unrouted,
CArray<CPolyLine> * board_outline,
DesignRules* dr, DRErrorList* drelist )
{
CString d_str, x_str, y_str;
CString str;
CString str2;
long nerrors = 0;
// now iterate through all areas
for( int ia = 0; ia<net->nareas; ia++ )
{
carea* a = &net->area[ia];
// iterate through all nets again
POSITION pos2 = pos;
void* ptr2;
CString name2;
while( pos2 != NULL )
{
m_nlist->m_map.GetNextAssoc( pos2, name2, ptr2 );
cnet* net2 = (cnet*) ptr2;
for( int ia2 = 0; ia2<net2->nareas; ia2++ )
{
carea* a2 = &net2->area[ia2];
// test for same layer
if( a->poly->GetLayer() == a2->poly->GetLayer() )
{
// test for points inside one another
for( int ic = 0; ic<a->poly->GetNumCorners(); ic++ )
{
int x = a->poly->GetX( ic );
int y = a->poly->GetY( ic );
if( a2->poly->TestPointInside( x, y ) )
{
// COPPERAREA_COPPERAREA error
id id_a = net->id;
id_a.st = ID_AREA;
id_a.i = ia;
id_a.sst = ID_SEL_CORNER;
id_a.ii = ic;
str.Format(
"%ld: \"%s\" copper area inside \"%s\" inside copper area\r\n",
nerrors + 1,
net->name,
net2->name );
DRError* dre = drelist->Add( nerrors,
DRError::COPPERAREA_INSIDE_COPPERAREA,
&str,
&net->name,
&net2->name,
id_a,
id_a,
x,
y,
x,
y,
0,
0 );
if( dre )
{
nerrors++;
if( log )
log->AddLine( str );
}
}
}
for( int ic2 = 0; ic2<a2->poly->GetNumCorners(); ic2++ )
{
int x = a2->poly->GetX( ic2 );
int y = a2->poly->GetY( ic2 );
if( a->poly->TestPointInside( x, y ) )
{
// COPPERAREA_COPPERAREA error
id id_a = net2->id;
id_a.st = ID_AREA;
id_a.i = ia2;
id_a.sst = ID_SEL_CORNER;
id_a.ii = ic2;
str.Format( "%ld: \"%s\" copper area inside \"%s\" copper area\r\n",
nerrors + 1, net2->name, net->name );
DRError* dre = drelist->Add( nerrors,
DRError::COPPERAREA_INSIDE_COPPERAREA,
&str,
&net2->name,
&net->name,
id_a,
id_a,
x,
y,
x,
y,
0,
0 );
if( dre )
{
nerrors++;
if( log )
log->AddLine( str );
}
}
}
// now test spacing between areas
for( int icont = 0; icont<a->poly->GetNumContours(); icont++ )
{
int ic_start = a->poly->GetContourStart( icont );
int ic_end = a->poly->GetContourEnd( icont );
for( int ic = ic_start; ic<=ic_end; ic++ )
{
id id_a = net->id;
id_a.st = ID_AREA;
id_a.i = ia;
id_a.sst = ID_SIDE;
id_a.ii = ic;
int ax1 = a->poly->GetX( ic );
int ay1 = a->poly->GetY( ic );
int ax2, ay2;
if( ic == ic_end )
{
ax2 = a->poly->GetX( ic_start );
ay2 = a->poly->GetY( ic_start );
}
else
{
ax2 = a->poly->GetX( ic + 1 );
ay2 = a->poly->GetY( ic + 1 );
}
int astyle = a->poly->GetSideStyle( ic );
for( int icont2 = 0; icont2<a2->poly->GetNumContours(); icont2++ )
{
int ic_start2 = a2->poly->GetContourStart( icont2 );
int ic_end2 = a2->poly->GetContourEnd( icont2 );
for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ )
{
id id_b = net2->id;
id_b.st = ID_AREA;
id_b.i = ia2;
id_b.sst = ID_SIDE;
id_b.ii = ic2;
int bx1 = a2->poly->GetX( ic2 );
int by1 = a2->poly->GetY( ic2 );
int bx2, by2;
if( ic2 == ic_end2 )
{
bx2 = a2->poly->GetX( ic_start2 );
by2 = a2->poly->GetY( ic_start2 );
}
else
{
bx2 = a2->poly->GetX( ic2 + 1 );
by2 = a2->poly->GetY( ic2 + 1 );
}
int bstyle = a2->poly->GetSideStyle( ic2 );
int x, y;
int d = ::GetClearanceBetweenSegments( bx1,
by1,
bx2,
by2,
bstyle,
0,
ax1,
ay1,
ax2,
ay2,
astyle,
0,
dr->copper_copper,
&x,
&y );
if( d < dr->copper_copper )
{
// COPPERAREA_COPPERAREA error
::MakeCStringFromDimension( &d_str,
d,
units,
TRUE,
TRUE,
TRUE,
1 );
::MakeCStringFromDimension( &x_str,
x,
units,
FALSE,
TRUE,
TRUE,
1 );
::MakeCStringFromDimension( &y_str,
y,
units,
FALSE,
TRUE,
TRUE,
1 );
str.Format(
"%ld: \"%s\" copper area to \"%s\" copper area = %s, x=%s, y=%s\r\n",
nerrors + 1,
net->name,
net2->name,
d_str,
x_str,
y_str );
DRError* dre = drelist->Add(
nerrors,
DRError::
COPPERAREA_COPPERAREA,
&str,
&net->name,
&net2->name,
id_a,
id_b,
x,
y,
x,
y,
0,
0 );
if( dre )
{
nerrors++;
if( log )
log->AddLine( str );
}
}
}
}
}
}
}
}
}
}
}
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment