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
53cd19a6
Commit
53cd19a6
authored
Jun 08, 2014
by
unknown
Committed by
jean-pierre charras
Jun 08, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
VRML export rewritten
parent
bd174ebf
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
328 additions
and
2143 deletions
+328
-2143
CMakeLists.txt
pcbnew/CMakeLists.txt
+0
-1
export_idf.cpp
pcbnew/exporters/export_idf.cpp
+1
-1
export_vrml.cpp
pcbnew/exporters/export_vrml.cpp
+287
-223
vrml_board.cpp
pcbnew/exporters/vrml_board.cpp
+0
-1501
vrml_board.h
pcbnew/exporters/vrml_board.h
+0
-379
idf_outlines.cpp
utils/idftools/idf_outlines.cpp
+9
-9
idf_parser.cpp
utils/idftools/idf_parser.cpp
+7
-7
vrml_layer.cpp
utils/idftools/vrml_layer.cpp
+23
-22
vrml_layer.h
utils/idftools/vrml_layer.h
+1
-0
No files found.
pcbnew/CMakeLists.txt
View file @
53cd19a6
...
...
@@ -140,7 +140,6 @@ set( PCBNEW_EXPORTERS
exporters/gen_drill_report_files.cpp
exporters/gen_modules_placefile.cpp
exporters/gendrill_Excellon_writer.cpp
exporters/vrml_board.cpp
)
set
(
PCBNEW_AUTOROUTER_SRCS
...
...
pcbnew/exporters/export_idf.cpp
View file @
53cd19a6
...
...
@@ -568,7 +568,7 @@ bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, bool aUseThou )
ok
=
false
;
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
wxString
msg
;
msg
<<
_
(
"IDF Export Failed:
\n
"
)
<<
FROM_UTF8
(
e
.
what
()
);
...
...
pcbnew/exporters/export_vrml.cpp
View file @
53cd19a6
...
...
@@ -24,6 +24,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* NOTE:
* 1. for improved looks, create a DRILL layer for PTH drills.
...
...
@@ -42,24 +43,17 @@
*
* 2. How can we suppress fiducials such as those in the corners of the pic-programmer demo?
*
* 3. Export Graphics to Layer objects (see 3d_draw.cpp for clues) to ensure that custom
* tracks/fills/logos are rendered.
* module->TransformGraphicShapesWithClearanceToPolygonSet
*
* For mechanical correctness, we should use the following settings with arcs:
* 1. max. deviation: the number of edges should be determined by the max.
* mechanical deviation and the minimum number of edges shall be 6.
* 2. for very large features we may introduce too many edges in a circle;
* to control this, we should specify a MAX number of edges or a threshold
* radius and a deviation for larger features
*
* For example, many mechanical fits are to within +/-0.05mm, so specifying
* a max. deviation of 0.02mm will yield a hole near the max. material
* condition. Calculating sides for a 10mm radius hole will yield about
* 312 points; such large holes (and arcs) will typically have a specified
* tolerance of +/-0.2mm in which case we can set the MAX edges to 32
* provided none of the important holes requires > 32 edges.
*/
/*
* KNOWN BUGS:
* 1. silk outlines are sometimes mangled; this is somehow due to
* many overlapping segments. This does not happen in 3Dviewer
* so it is worth inspecting that code to see what is different.
*
* These artefacts can be suppressed for exploratory purposes by
* removing the line width parameter from the length calculation in
* export_vrml_line()
*/
#include <fctsys.h>
...
...
@@ -70,6 +64,9 @@
#include <pgm_base.h>
#include <3d_struct.h>
#include <macros.h>
#include <exception>
#include <fstream>
#include <iomanip>
#include <pcbnew.h>
...
...
@@ -85,7 +82,13 @@
#include <vector>
#include <cmath>
#include <vrml_board.h>
#include <vrml_layer.h>
// minimum width (mm) of a VRML line
#define MIN_VRML_LINEWIDTH 0.12
// offset for art layers, mm (silk, paste, etc)
#define ART_OFFSET 0.02
/* helper function:
* some characters cannot be used in names,
...
...
@@ -167,6 +170,9 @@ private:
double
layer_z
[
NB_LAYERS
];
VRML_COLOR
colors
[
VRML_COLOR_LAST
];
int
iMaxSeg
;
// max. sides to a small circle
double
arcMinLen
,
arcMaxLen
;
// min and max lengths of an arc chord
public
:
VRML_LAYER
holes
;
...
...
@@ -179,6 +185,8 @@ public:
VRML_LAYER
bot_tin
;
double
scale
;
// board internal units to output scaling
double
minLineWidth
;
// minimum width of a VRML line segment
int
precision
;
// precision of output units
double
tx
;
// global translation along X
double
ty
;
// global translation along Y
...
...
@@ -193,6 +201,8 @@ public:
for
(
int
i
=
0
;
i
<
NB_LAYERS
;
++
i
)
layer_z
[
i
]
=
0
;
holes
.
GetArcParams
(
iMaxSeg
,
arcMinLen
,
arcMaxLen
);
// this default only makes sense if the output is in mm
board_thickness
=
1.6
;
...
...
@@ -208,6 +218,8 @@ public:
// pad silver
colors
[
VRML_COLOR_TIN
]
=
VRML_COLOR
(
.749
,
.756
,
.761
,
.749
,
.756
,
.761
,
0
,
0
,
0
,
0.8
,
0
,
0.8
);
precision
=
5
;
}
VRML_COLOR
&
GetColor
(
VRML_COLOR_INDEX
aIndex
)
...
...
@@ -234,31 +246,51 @@ public:
layer_z
[
aLayer
]
=
aValue
;
}
void
SetMaxDev
(
double
dev
)
// set the scaling of the VRML world
bool
SetScale
(
double
aWorldScale
)
{
holes
.
SetMaxDev
(
dev
);
board
.
SetMaxDev
(
dev
);
top_copper
.
SetMaxDev
(
dev
);
bot_copper
.
SetMaxDev
(
dev
);
top_silk
.
SetMaxDev
(
dev
);
bot_silk
.
SetMaxDev
(
dev
);
top_tin
.
SetMaxDev
(
dev
);
bot_tin
.
SetMaxDev
(
dev
);
if
(
aWorldScale
<
0.001
||
aWorldScale
>
10.0
)
throw
(
std
::
runtime_error
(
"WorldScale out of range (valid range is 0.001 to 10.0)"
)
);
scale
=
aWorldScale
*
MM_PER_IU
;
minLineWidth
=
aWorldScale
*
MIN_VRML_LINEWIDTH
;
// set the precision of the VRML coordinates
if
(
aWorldScale
<
0.01
)
precision
=
8
;
else
if
(
aWorldScale
<
0.1
)
precision
=
7
;
else
if
(
aWorldScale
<
1.0
)
precision
=
6
;
else
if
(
aWorldScale
<
10.0
)
precision
=
5
;
else
precision
=
4
;
double
smin
=
arcMinLen
*
aWorldScale
;
double
smax
=
arcMaxLen
*
aWorldScale
;
holes
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
board
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
top_copper
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
bot_copper
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
top_silk
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
bot_silk
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
top_tin
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
bot_tin
.
SetArcParams
(
iMaxSeg
,
smin
,
smax
);
return
true
;
}
};
// static var. for dealing with text
namespace
VRMLEXPORT
{
static
MODEL_VRML
*
model_vrml
;
bool
GetLayer
(
MODEL_VRML
&
aModel
,
LAYER_NUM
layer
,
VRML_LAYER
**
vlayer
);
}
static
MODEL_VRML
*
model_vrml
;
// select the VRML layer object to draw on; return true if
// a layer has been selected.
bool
VRMLEXPORT
::
GetLayer
(
MODEL_VRML
&
aModel
,
LAYER_NUM
layer
,
VRML_LAYER
**
vlayer
)
static
bool
GetLayer
(
MODEL_VRML
&
aModel
,
LAYER_NUM
layer
,
VRML_LAYER
**
vlayer
)
{
switch
(
layer
)
{
...
...
@@ -286,9 +318,9 @@ bool VRMLEXPORT::GetLayer( MODEL_VRML& aModel, LAYER_NUM layer, VRML_LAYER** vla
}
static
void
write_triangle_bag
(
FILE
*
output_file
,
VRML_COLOR
&
color
,
static
void
write_triangle_bag
(
std
::
ofstream
&
output_file
,
VRML_COLOR
&
color
,
VRML_LAYER
*
layer
,
bool
plane
,
bool
top
,
double
top_z
,
double
bottom_z
)
double
top_z
,
double
bottom_z
,
int
aPrecision
)
{
/* A lot of nodes are not required, but blender sometimes chokes
* without them */
...
...
@@ -328,7 +360,7 @@ static void write_triangle_bag( FILE* output_file, VRML_COLOR& color,
while
(
marker_found
<
4
)
{
if
(
shape_boiler
[
lineno
]
)
fputs
(
shape_boiler
[
lineno
],
output_file
)
;
output_file
<<
shape_boiler
[
lineno
]
;
else
{
marker_found
++
;
...
...
@@ -336,37 +368,34 @@ static void write_triangle_bag( FILE* output_file, VRML_COLOR& color,
switch
(
marker_found
)
{
case
1
:
// Material marker
fprintf
(
output_file
,
" diffuseColor %g %g %g
\n
"
,
color
.
diffuse_red
,
color
.
diffuse_grn
,
color
.
diffuse_blu
);
fprintf
(
output_file
,
" specularColor %g %g %g
\n
"
,
color
.
spec_red
,
color
.
spec_grn
,
color
.
spec_blu
);
fprintf
(
output_file
,
" emissiveColor %g %g %g
\n
"
,
color
.
emit_red
,
color
.
emit_grn
,
color
.
emit_blu
);
fprintf
(
output_file
,
" ambientIntensity %g
\n
"
,
color
.
ambient
);
fprintf
(
output_file
,
" transparency %g
\n
"
,
color
.
transp
);
fprintf
(
output_file
,
" shininess %g
\n
"
,
color
.
shiny
);
output_file
<<
" diffuseColor "
<<
std
::
setprecision
(
3
);
output_file
<<
color
.
diffuse_red
<<
" "
;
output_file
<<
color
.
diffuse_grn
<<
" "
;
output_file
<<
color
.
diffuse_blu
<<
"
\n
"
;
output_file
<<
" specularColor "
;
output_file
<<
color
.
spec_red
<<
" "
;
output_file
<<
color
.
spec_grn
<<
" "
;
output_file
<<
color
.
spec_blu
<<
"
\n
"
;
output_file
<<
" emissiveColor "
;
output_file
<<
color
.
emit_red
<<
" "
;
output_file
<<
color
.
emit_grn
<<
" "
;
output_file
<<
color
.
emit_blu
<<
"
\n
"
;
output_file
<<
" ambientIntensity "
<<
color
.
ambient
<<
"
\n
"
;
output_file
<<
" transparency "
<<
color
.
transp
<<
"
\n
"
;
output_file
<<
" shininess "
<<
color
.
shiny
<<
"
\n
"
;
break
;
case
2
:
if
(
plane
)
layer
->
WriteVertices
(
top_z
,
output_file
);
layer
->
WriteVertices
(
top_z
,
output_file
,
aPrecision
);
else
layer
->
Write3DVertices
(
top_z
,
bottom_z
,
output_file
);
layer
->
Write3DVertices
(
top_z
,
bottom_z
,
output_file
,
aPrecision
);
fprintf
(
output_file
,
"
\n
"
)
;
output_file
<<
"
\n
"
;
break
;
case
3
:
...
...
@@ -376,7 +405,7 @@ static void write_triangle_bag( FILE* output_file, VRML_COLOR& color,
else
layer
->
Write3DIndices
(
output_file
);
fprintf
(
output_file
,
"
\n
"
)
;
output_file
<<
"
\n
"
;
break
;
default:
...
...
@@ -389,49 +418,54 @@ static void write_triangle_bag( FILE* output_file, VRML_COLOR& color,
}
static
void
write_layers
(
MODEL_VRML
&
aModel
,
FILE
*
output_file
,
BOARD
*
aPcb
)
static
void
write_layers
(
MODEL_VRML
&
aModel
,
std
::
ofstream
&
output_file
,
BOARD
*
aPcb
)
{
// VRML_LAYER board;
aModel
.
board
.
Tesselate
(
&
aModel
.
holes
);
double
brdz
=
aModel
.
board_thickness
/
2.0
-
40000
*
aModel
.
scale
;
double
brdz
=
aModel
.
board_thickness
/
2.0
-
(
Millimeter2iu
(
ART_OFFSET
/
2.0
)
)
*
aModel
.
scale
;
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_PCB
),
&
aModel
.
board
,
false
,
false
,
brdz
,
-
brdz
);
&
aModel
.
board
,
false
,
false
,
brdz
,
-
brdz
,
aModel
.
precision
);
// VRML_LAYER top_copper;
aModel
.
top_copper
.
Tesselate
(
&
aModel
.
holes
);
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_TRACK
),
&
aModel
.
top_copper
,
true
,
true
,
aModel
.
GetLayerZ
(
LAST_COPPER_LAYER
),
0
);
aModel
.
GetLayerZ
(
LAST_COPPER_LAYER
),
0
,
aModel
.
precision
);
// VRML_LAYER top_tin;
aModel
.
top_tin
.
Tesselate
(
&
aModel
.
holes
);
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_TIN
),
&
aModel
.
top_tin
,
true
,
true
,
aModel
.
GetLayerZ
(
LAST_COPPER_LAYER
),
0
);
&
aModel
.
top_tin
,
true
,
true
,
aModel
.
GetLayerZ
(
LAST_COPPER_LAYER
)
+
Millimeter2iu
(
ART_OFFSET
/
2.0
)
*
aModel
.
scale
,
0
,
aModel
.
precision
);
// VRML_LAYER bot_copper;
aModel
.
bot_copper
.
Tesselate
(
&
aModel
.
holes
);
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_TRACK
),
&
aModel
.
bot_copper
,
true
,
false
,
aModel
.
GetLayerZ
(
FIRST_COPPER_LAYER
),
0
);
aModel
.
GetLayerZ
(
FIRST_COPPER_LAYER
),
0
,
aModel
.
precision
);
// VRML_LAYER bot_tin;
aModel
.
bot_tin
.
Tesselate
(
&
aModel
.
holes
);
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_TIN
),
&
aModel
.
bot_tin
,
true
,
false
,
aModel
.
GetLayerZ
(
FIRST_COPPER_LAYER
),
0
);
aModel
.
GetLayerZ
(
FIRST_COPPER_LAYER
)
-
Millimeter2iu
(
ART_OFFSET
/
2.0
)
*
aModel
.
scale
,
0
,
aModel
.
precision
);
// VRML_LAYER top_silk;
aModel
.
top_silk
.
Tesselate
(
&
aModel
.
holes
);
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_SILK
),
&
aModel
.
top_silk
,
true
,
true
,
aModel
.
GetLayerZ
(
SILKSCREEN_N_FRONT
),
0
);
aModel
.
GetLayerZ
(
SILKSCREEN_N_FRONT
),
0
,
aModel
.
precision
);
// VRML_LAYER bot_silk;
aModel
.
bot_silk
.
Tesselate
(
&
aModel
.
holes
);
write_triangle_bag
(
output_file
,
aModel
.
GetColor
(
VRML_COLOR_SILK
),
&
aModel
.
bot_silk
,
true
,
false
,
aModel
.
GetLayerZ
(
SILKSCREEN_N_BACK
),
0
);
aModel
.
GetLayerZ
(
SILKSCREEN_N_BACK
),
0
,
aModel
.
precision
);
}
...
...
@@ -454,7 +488,7 @@ static void compute_layer_Zs( MODEL_VRML& aModel, BOARD* pcb )
/* To avoid rounding interference, we apply an epsilon to each
* successive layer */
double
epsilon_z
=
Millimeter2iu
(
0.02
)
*
aModel
.
scale
;
double
epsilon_z
=
Millimeter2iu
(
ART_OFFSET
)
*
aModel
.
scale
;
aModel
.
SetLayerZ
(
SOLDERPASTE_N_BACK
,
-
half_thickness
-
epsilon_z
*
4
);
aModel
.
SetLayerZ
(
ADHESIVE_N_BACK
,
-
half_thickness
-
epsilon_z
*
3
);
aModel
.
SetLayerZ
(
SILKSCREEN_N_BACK
,
-
half_thickness
-
epsilon_z
*
2
);
...
...
@@ -477,18 +511,22 @@ static void export_vrml_line( MODEL_VRML& aModel, LAYER_NUM layer,
{
VRML_LAYER
*
vlayer
;
if
(
!
VRMLEXPORT
::
GetLayer
(
aModel
,
layer
,
&
vlayer
)
)
if
(
!
GetLayer
(
aModel
,
layer
,
&
vlayer
)
)
return
;
if
(
width
<
aModel
.
minLineWidth
)
width
=
aModel
.
minLineWidth
;
starty
=
-
starty
;
endy
=
-
endy
;
double
angle
=
atan2
(
endy
-
starty
,
endx
-
startx
);
double
angle
=
atan2
(
endy
-
starty
,
endx
-
startx
)
*
180.0
/
M_PI
;
double
length
=
Distance
(
startx
,
starty
,
endx
,
endy
)
+
width
;
double
cx
=
(
startx
+
endx
)
/
2.0
;
double
cy
=
(
starty
+
endy
)
/
2.0
;
vlayer
->
AddSlot
(
cx
,
cy
,
length
,
width
,
angle
,
1
,
false
);
if
(
!
vlayer
->
AddSlot
(
cx
,
cy
,
length
,
width
,
angle
,
false
)
)
throw
(
std
::
runtime_error
(
vlayer
->
GetError
()
)
);
}
...
...
@@ -498,9 +536,12 @@ static void export_vrml_circle( MODEL_VRML& aModel, LAYER_NUM layer,
{
VRML_LAYER
*
vlayer
;
if
(
!
VRMLEXPORT
::
GetLayer
(
aModel
,
layer
,
&
vlayer
)
)
if
(
!
GetLayer
(
aModel
,
layer
,
&
vlayer
)
)
return
;
if
(
width
<
aModel
.
minLineWidth
)
width
=
aModel
.
minLineWidth
;
starty
=
-
starty
;
endy
=
-
endy
;
...
...
@@ -509,11 +550,13 @@ static void export_vrml_circle( MODEL_VRML& aModel, LAYER_NUM layer,
radius
=
Distance
(
startx
,
starty
,
endx
,
endy
)
+
(
width
/
2
);
hole
=
radius
-
width
;
vlayer
->
AddCircle
(
startx
,
starty
,
radius
,
1
,
false
);
if
(
!
vlayer
->
AddCircle
(
startx
,
starty
,
radius
,
false
)
)
throw
(
std
::
runtime_error
(
vlayer
->
GetError
()
)
);
if
(
hole
>
0.0001
)
{
vlayer
->
AddCircle
(
startx
,
starty
,
hole
,
1
,
true
);
if
(
!
vlayer
->
AddCircle
(
startx
,
starty
,
hole
,
true
)
)
throw
(
std
::
runtime_error
(
vlayer
->
GetError
()
)
);
}
}
...
...
@@ -525,16 +568,19 @@ static void export_vrml_arc( MODEL_VRML& aModel, LAYER_NUM layer,
{
VRML_LAYER
*
vlayer
;
if
(
!
VRMLEXPORT
::
GetLayer
(
aModel
,
layer
,
&
vlayer
)
)
if
(
!
GetLayer
(
aModel
,
layer
,
&
vlayer
)
)
return
;
if
(
width
<
aModel
.
minLineWidth
)
width
=
aModel
.
minLineWidth
;
centery
=
-
centery
;
arc_starty
=
-
arc_starty
;
arc_angle
*=
-
M_PI
/
180
;
if
(
!
vlayer
->
AddArc
(
centerx
,
centery
,
arc_startx
,
arc_starty
,
width
,
arc_angle
,
false
)
)
throw
(
std
::
runtime_error
(
vlayer
->
GetError
()
)
);
vlayer
->
AddArc
(
centerx
,
centery
,
arc_startx
,
arc_starty
,
width
,
arc_angle
,
1
,
false
);
}
...
...
@@ -577,13 +623,13 @@ static void export_vrml_drawsegment( MODEL_VRML& aModel, DRAWSEGMENT* drawseg )
* for coupling the vrml_text_callback with the common parameters */
static
void
vrml_text_callback
(
int
x0
,
int
y0
,
int
xf
,
int
yf
)
{
LAYER_NUM
s_text_layer
=
VRMLEXPORT
::
model_vrml
->
s_text_layer
;
int
s_text_width
=
VRMLEXPORT
::
model_vrml
->
s_text_width
;
double
scale
=
VRMLEXPORT
::
model_vrml
->
scale
;
double
tx
=
VRMLEXPORT
::
model_vrml
->
tx
;
double
ty
=
VRMLEXPORT
::
model_vrml
->
ty
;
LAYER_NUM
s_text_layer
=
model_vrml
->
s_text_layer
;
int
s_text_width
=
model_vrml
->
s_text_width
;
double
scale
=
model_vrml
->
scale
;
double
tx
=
model_vrml
->
tx
;
double
ty
=
model_vrml
->
ty
;
export_vrml_line
(
*
VRMLEXPORT
::
model_vrml
,
s_text_layer
,
export_vrml_line
(
*
model_vrml
,
s_text_layer
,
x0
*
scale
+
tx
,
y0
*
scale
+
ty
,
xf
*
scale
+
tx
,
yf
*
scale
+
ty
,
s_text_width
*
scale
);
...
...
@@ -592,8 +638,8 @@ static void vrml_text_callback( int x0, int y0, int xf, int yf )
static
void
export_vrml_pcbtext
(
MODEL_VRML
&
aModel
,
TEXTE_PCB
*
text
)
{
VRMLEXPORT
::
model_vrml
->
s_text_layer
=
text
->
GetLayer
();
VRMLEXPORT
::
model_vrml
->
s_text_width
=
text
->
GetThickness
();
model_vrml
->
s_text_layer
=
text
->
GetLayer
();
model_vrml
->
s_text_width
=
text
->
GetThickness
();
wxSize
size
=
text
->
GetSize
();
...
...
@@ -707,12 +753,12 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
while
(
i
<
nvert
)
{
aModel
.
board
.
AddVertex
(
seg
,
bufferPcbOutlines
[
i
].
x
*
scale
+
dx
,
-
(
bufferPcbOutlines
[
i
].
y
*
scale
+
dy
)
);
if
(
bufferPcbOutlines
[
i
].
end_contour
)
break
;
aModel
.
board
.
AddVertex
(
seg
,
bufferPcbOutlines
[
i
].
x
*
scale
+
dx
,
-
(
bufferPcbOutlines
[
i
].
y
*
scale
+
dy
)
);
++
i
;
}
...
...
@@ -739,12 +785,12 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
while
(
i
<
nvert
)
{
aModel
.
holes
.
AddVertex
(
seg
,
allLayerHoles
[
i
].
x
*
scale
+
dx
,
-
(
allLayerHoles
[
i
].
y
*
scale
+
dy
)
);
if
(
allLayerHoles
[
i
].
end_contour
)
break
;
aModel
.
holes
.
AddVertex
(
seg
,
allLayerHoles
[
i
].
x
*
scale
+
dx
,
-
(
allLayerHoles
[
i
].
y
*
scale
+
dy
)
);
++
i
;
}
...
...
@@ -766,31 +812,26 @@ static void export_round_padstack( MODEL_VRML& aModel, BOARD* pcb,
if
(
top_layer
!=
LAST_COPPER_LAYER
||
bottom_layer
!=
FIRST_COPPER_LAYER
)
thru
=
false
;
if
(
thru
&&
hole
>
0
)
aModel
.
holes
.
AddCircle
(
x
,
-
y
,
hole
,
true
);
while
(
1
)
{
if
(
layer
==
FIRST_COPPER_LAYER
)
{
aModel
.
bot_copper
.
AddCircle
(
x
,
-
y
,
r
,
1
);
aModel
.
bot_copper
.
AddCircle
(
x
,
-
y
,
r
);
if
(
hole
>
0
&&
!
thru
)
aModel
.
bot_copper
.
AddCircle
(
x
,
-
y
,
hole
,
true
);
if
(
hole
>
0
)
{
if
(
thru
)
aModel
.
holes
.
AddCircle
(
x
,
-
y
,
hole
,
1
,
true
);
else
aModel
.
bot_copper
.
AddCircle
(
x
,
-
y
,
hole
,
1
,
true
);
}
}
else
if
(
layer
==
LAST_COPPER_LAYER
)
{
aModel
.
top_copper
.
AddCircle
(
x
,
-
y
,
r
,
1
);
aModel
.
top_copper
.
AddCircle
(
x
,
-
y
,
r
);
if
(
hole
>
0
&&
!
thru
)
aModel
.
top_copper
.
AddCircle
(
x
,
-
y
,
hole
,
true
);
if
(
hole
>
0
)
{
if
(
thru
)
aModel
.
holes
.
AddCircle
(
x
,
-
y
,
hole
,
1
,
true
);
else
aModel
.
top_copper
.
AddCircle
(
x
,
-
y
,
hole
,
1
,
true
);
}
}
if
(
layer
==
bottom_layer
)
...
...
@@ -856,7 +897,7 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
VRML_LAYER
*
vl
;
if
(
!
VRMLEXPORT
::
GetLayer
(
aModel
,
zone
->
GetLayer
(),
&
vl
)
)
if
(
!
GetLayer
(
aModel
,
zone
->
GetLayer
(),
&
vl
)
)
continue
;
if
(
!
zone
->
IsFilled
()
)
...
...
@@ -881,11 +922,13 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
{
x
=
poly
.
GetX
(
i
)
*
scale
+
dx
;
y
=
-
(
poly
.
GetY
(
i
)
*
scale
+
dy
);
vl
->
AddVertex
(
seg
,
x
,
y
);
if
(
poly
.
IsEndContour
(
i
)
)
break
;
if
(
!
vl
->
AddVertex
(
seg
,
x
,
y
)
)
throw
(
std
::
runtime_error
(
vl
->
GetError
()
)
);
++
i
;
}
...
...
@@ -911,8 +954,8 @@ static void export_vrml_text_module( TEXTE_MODULE* module )
if
(
module
->
IsMirrored
()
)
NEGATE
(
size
.
x
);
// Text is mirrored
VRMLEXPORT
::
model_vrml
->
s_text_layer
=
module
->
GetLayer
();
VRMLEXPORT
::
model_vrml
->
s_text_width
=
module
->
GetThickness
();
model_vrml
->
s_text_layer
=
module
->
GetLayer
();
model_vrml
->
s_text_width
=
module
->
GetThickness
();
DrawGraphicText
(
NULL
,
NULL
,
module
->
GetTextPosition
(),
BLACK
,
module
->
GetText
(),
module
->
GetDrawRotation
(),
size
,
...
...
@@ -952,10 +995,10 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
{
VRML_LAYER
*
vl
;
if
(
!
VRMLEXPORT
::
GetLayer
(
aModel
,
layer
,
&
vl
)
)
if
(
!
GetLayer
(
aModel
,
layer
,
&
vl
)
)
break
;
int
nvert
=
aOutline
->
GetPolyPoints
().
size
();
int
nvert
=
aOutline
->
GetPolyPoints
().
size
()
-
1
;
int
i
=
0
;
if
(
nvert
<
3
)
break
;
...
...
@@ -974,7 +1017,9 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
x
=
corner
.
x
*
aModel
.
scale
+
aModel
.
tx
;
y
=
-
(
corner
.
y
*
aModel
.
scale
+
aModel
.
ty
);
vl
->
AddVertex
(
seg
,
x
,
y
);
if
(
!
vl
->
AddVertex
(
seg
,
x
,
y
)
)
throw
(
std
::
runtime_error
(
vl
->
GetError
()
)
);
++
i
;
}
...
...
@@ -988,8 +1033,7 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
}
static
void
export_vrml_padshape
(
MODEL_VRML
&
aModel
,
VRML_LAYER
*
aLayer
,
VRML_LAYER
*
aTinLayer
,
D_PAD
*
aPad
)
static
void
export_vrml_padshape
(
MODEL_VRML
&
aModel
,
VRML_LAYER
*
aTinLayer
,
D_PAD
*
aPad
)
{
// The (maybe offset) pad position
wxPoint
pad_pos
=
aPad
->
ShapePos
();
...
...
@@ -1006,15 +1050,18 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aLayer,
switch
(
aPad
->
GetShape
()
)
{
case
PAD_CIRCLE
:
aLayer
->
AddCircle
(
pad_x
,
-
pad_y
,
pad_w
,
1
,
true
);
aTinLayer
->
AddCircle
(
pad_x
,
-
pad_y
,
pad_w
,
1
,
false
);
if
(
!
aTinLayer
->
AddCircle
(
pad_x
,
-
pad_y
,
pad_w
,
false
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
break
;
case
PAD_OVAL
:
aLayer
->
AddSlot
(
pad_x
,
-
pad_y
,
pad_w
*
2.0
,
pad_h
*
2.0
,
DECIDEG2RAD
(
aPad
->
GetOrientation
()
),
1
,
true
);
aTinLayer
->
AddSlot
(
pad_x
,
-
pad_y
,
pad_w
*
2.0
,
pad_h
*
2.0
,
DECIDEG2RAD
(
aPad
->
GetOrientation
()
),
1
,
false
);
if
(
!
aTinLayer
->
AddSlot
(
pad_x
,
-
pad_y
,
pad_w
*
2.0
,
pad_h
*
2.0
,
aPad
->
GetOrientation
()
/
10.0
,
false
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
break
;
case
PAD_RECT
:
...
...
@@ -1039,32 +1086,32 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aLayer,
coord
[
i
*
2
+
1
]
+=
pad_y
;
}
int
lines
=
aLayer
->
NewContour
();
int
lines
;
lines
=
aTinLayer
->
NewContour
();
if
(
lines
<
0
)
return
;
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
)
;
aLayer
->
AddVertex
(
lines
,
coord
[
2
],
-
coord
[
3
]
);
aLayer
->
AddVertex
(
lines
,
coord
[
6
],
-
coord
[
7
]
);
aLayer
->
AddVertex
(
lines
,
coord
[
4
],
-
coord
[
5
]
);
aLayer
->
AddVertex
(
lines
,
coord
[
0
],
-
coord
[
1
]
);
aLayer
->
EnsureWinding
(
lines
,
true
);
if
(
!
aTinLayer
->
AddVertex
(
lines
,
coord
[
0
],
-
coord
[
1
]
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
lines
=
aTinLayer
->
NewContour
();
if
(
!
aTinLayer
->
AddVertex
(
lines
,
coord
[
4
],
-
coord
[
5
]
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
if
(
lines
<
0
)
return
;
if
(
!
aTinLayer
->
AddVertex
(
lines
,
coord
[
6
],
-
coord
[
7
]
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
if
(
!
aTinLayer
->
AddVertex
(
lines
,
coord
[
2
],
-
coord
[
3
]
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
aTinLayer
->
AddVertex
(
lines
,
coord
[
0
],
-
coord
[
1
]
);
aTinLayer
->
AddVertex
(
lines
,
coord
[
4
],
-
coord
[
5
]
);
aTinLayer
->
AddVertex
(
lines
,
coord
[
6
],
-
coord
[
7
]
);
aTinLayer
->
AddVertex
(
lines
,
coord
[
2
],
-
coord
[
3
]
);
aTinLayer
->
EnsureWinding
(
lines
,
false
);
if
(
!
aTinLayer
->
EnsureWinding
(
lines
,
false
)
)
throw
(
std
::
runtime_error
(
aTinLayer
->
GetError
()
)
);
}
break
;
default:
;
break
;
}
}
...
...
@@ -1084,12 +1131,12 @@ static void export_vrml_pad( MODEL_VRML& aModel, BOARD* pcb, D_PAD* aPad )
{
// Oblong hole (slot)
aModel
.
holes
.
AddSlot
(
hole_x
,
-
hole_y
,
hole_drill_w
*
2.0
,
hole_drill_h
*
2.0
,
DECIDEG2RAD
(
aPad
->
GetOrientation
()
),
1
,
true
);
aPad
->
GetOrientation
()
/
10.0
,
true
);
}
else
{
// Drill a round hole
aModel
.
holes
.
AddCircle
(
hole_x
,
-
hole_y
,
hole_drill
,
1
,
true
);
aModel
.
holes
.
AddCircle
(
hole_x
,
-
hole_y
,
hole_drill
,
true
);
}
}
...
...
@@ -1098,12 +1145,12 @@ static void export_vrml_pad( MODEL_VRML& aModel, BOARD* pcb, D_PAD* aPad )
if
(
layer_mask
&
LAYER_BACK
)
{
export_vrml_padshape
(
aModel
,
&
aModel
.
bot_
copper
,
&
aModel
.
bot_
tin
,
aPad
);
export_vrml_padshape
(
aModel
,
&
aModel
.
bot_tin
,
aPad
);
}
if
(
layer_mask
&
LAYER_FRONT
)
{
export_vrml_padshape
(
aModel
,
&
aModel
.
top_
copper
,
&
aModel
.
top_
tin
,
aPad
);
export_vrml_padshape
(
aModel
,
&
aModel
.
top_tin
,
aPad
);
}
}
...
...
@@ -1150,7 +1197,7 @@ static void compose_quat( double q1[4], double q2[4], double qr[4] )
static
void
export_vrml_module
(
MODEL_VRML
&
aModel
,
BOARD
*
aPcb
,
MODULE
*
aModule
,
FILE
*
aOutputFile
,
std
::
ofstream
&
aOutputFile
,
double
aVRMLModelsToBiu
,
bool
aExport3DFiles
,
const
wxString
&
a3D_Subdir
)
{
...
...
@@ -1237,12 +1284,13 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule
compose_quat
(
q1
,
q2
,
q1
);
from_quat
(
q1
,
rot
);
fprintf
(
aOutputFile
,
"Transform {
\n
"
)
;
aOutputFile
<<
"Transform {
\n
"
;
// A null rotation would fail the acos!
if
(
rot
[
3
]
!=
0.0
)
{
fprintf
(
aOutputFile
,
" rotation %g %g %g %g
\n
"
,
rot
[
0
],
rot
[
1
],
rot
[
2
],
rot
[
3
]
);
aOutputFile
<<
" rotation "
<<
std
::
setprecision
(
3
);
aOutputFile
<<
rot
[
0
]
<<
" "
<<
rot
[
1
]
<<
" "
<<
rot
[
2
]
<<
" "
<<
rot
[
3
]
<<
"
\n
"
;
}
// adjust 3D shape local offset position
...
...
@@ -1258,15 +1306,15 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule
RotatePoint
(
&
offsetx
,
&
offsety
,
aModule
->
GetOrientation
()
);
fprintf
(
aOutputFile
,
" translation %g %g %g
\n
"
,
(
offsetx
+
aModule
->
GetPosition
().
x
)
*
aModel
.
scale
+
aModel
.
tx
,
-
(
offsety
+
aModule
->
GetPosition
().
y
)
*
aModel
.
scale
-
aModel
.
ty
,
(
offsetz
*
aModel
.
scale
)
+
aModel
.
GetLayerZ
(
aModule
->
GetLayer
()
)
)
;
aOutputFile
<<
" translation "
<<
std
::
setprecision
(
aModel
.
precision
);
aOutputFile
<<
((
offsetx
+
aModule
->
GetPosition
().
x
)
*
aModel
.
scale
+
aModel
.
tx
)
<<
" "
;
aOutputFile
<<
(
-
(
offsety
+
aModule
->
GetPosition
().
y
)
*
aModel
.
scale
-
aModel
.
ty
)
<<
" "
;
aOutputFile
<<
(
(
offsetz
*
aModel
.
scale
)
+
aModel
.
GetLayerZ
(
aModule
->
GetLayer
()
)
)
<<
"
\n
"
;
fprintf
(
aOutputFile
,
" scale %g %g %g
\n
"
,
vrmlm
->
m_MatScale
.
x
*
aVRMLModelsToBiu
,
vrmlm
->
m_MatScale
.
y
*
aVRMLModelsToBiu
,
vrmlm
->
m_MatScale
.
z
*
aVRMLModelsToBiu
)
;
aOutputFile
<<
" scale "
;
aOutputFile
<<
(
vrmlm
->
m_MatScale
.
x
*
aVRMLModelsToBiu
)
<<
" "
;
aOutputFile
<<
(
vrmlm
->
m_MatScale
.
y
*
aVRMLModelsToBiu
)
<<
" "
;
aOutputFile
<<
(
vrmlm
->
m_MatScale
.
z
*
aVRMLModelsToBiu
)
<<
"
\n
"
;
if
(
fname
.
EndsWith
(
wxT
(
"x3d"
)
)
)
{
...
...
@@ -1276,18 +1324,25 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule
{
// embed x3d model in vrml format
parser
->
Load
(
fname
);
fprintf
(
aOutputFile
,
" children [
\n
%s ]
\n
"
,
TO_UTF8
(
parser
->
VRML_representation
()
)
);
fprintf
(
aOutputFile
,
" }
\n
"
);
delete
parser
;
try
{
aOutputFile
<<
" children [
\n
"
;
aOutputFile
<<
TO_UTF8
(
parser
->
VRML_representation
()
)
<<
" ]
\n
"
;
aOutputFile
<<
" }
\n
"
;
}
catch
(
const
std
::
exception
&
e
)
{
delete
parser
;
throw
;
}
}
}
else
{
fprintf
(
aOutputFile
,
" children [
\n
Inline {
\n
url
\"
%s
\"\n
} ]
\n
"
,
TO_UTF8
(
fname
)
);
fprintf
(
aOutputFile
,
" }
\n
"
);
aOutputFile
<<
" children [
\n
Inline {
\n
url
\"
"
;
aOutputFile
<<
TO_UTF8
(
fname
)
<<
"
\"\n
} ]
\n
"
;
aOutputFile
<<
" }
\n
"
;
}
}
}
...
...
@@ -1297,89 +1352,98 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName,
double
aMMtoWRMLunit
,
bool
aExport3DFiles
,
const
wxString
&
a3D_Subdir
)
{
wxString
msg
;
FILE
*
output_file
;
BOARD
*
pcb
=
GetBoard
()
;
wxString
msg
;
BOARD
*
pcb
=
GetBoard
()
;
bool
ok
=
true
;
MODEL_VRML
model3d
;
VRMLEXPORT
::
model_vrml
=
&
model3d
;
model_vrml
=
&
model3d
;
std
::
ofstream
output_file
;
output_file
=
wxFopen
(
aFullFileName
,
wxT
(
"wt"
)
);
try
{
output_file
.
exceptions
(
std
::
ofstream
::
failbit
);
output_file
.
open
(
TO_UTF8
(
aFullFileName
),
std
::
ios_base
::
out
);
if
(
output_file
==
NULL
)
return
false
;
// Switch the locale to standard C (needed to print floating point numbers like 1.3
)
SetLocaleTo_C_standard
()
;
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
SetLocaleTo_C_standard
()
;
// Begin with the usual VRML boilerplate
wxString
name
=
aFullFileName
;
// Begin with the usual VRML boilerplate
wxString
name
=
aFullFileName
;
name
.
Replace
(
wxT
(
"
\\
"
),
wxT
(
"/"
)
);
ChangeIllegalCharacters
(
name
,
false
)
;
name
.
Replace
(
wxT
(
"
\\
"
),
wxT
(
"/"
)
);
ChangeIllegalCharacters
(
name
,
false
);
fprintf
(
output_file
,
"#VRML V2.0 utf8
\n
"
"WorldInfo {
\n
"
" title
\"
%s - Generated by Pcbnew
\"\n
"
"}
\n
"
,
TO_UTF8
(
name
)
);
output_file
<<
"#VRML V2.0 utf8
\n
"
;
output_file
<<
"WorldInfo {
\n
"
;
output_file
<<
" title
\"
"
<<
TO_UTF8
(
name
)
<<
" - Generated by Pcbnew
\"\n
"
;
output_file
<<
"}
\n
"
;
// Global VRML scale to export to a different scale.
model3d
.
scale
=
aMMtoWRMLunit
/
MM_PER_IU
;
// Set the VRML world scale factor
model3d
.
SetScale
(
aMMtoWRMLunit
)
;
// Set the mechanical deviation limit (in this case 0.02mm)
// XXX - NOTE: the value should be set via the GUI
model3d
.
SetMaxDev
(
20000
*
model3d
.
scale
);
output_file
<<
"Transform {
\n
"
;
fprintf
(
output_file
,
"Transform {
\n
"
);
// compute the offset to center the board on (0, 0, 0)
// XXX - NOTE: we should allow the user a GUI option to specify the offset
EDA_RECT
bbbox
=
pcb
->
ComputeBoundingBox
();
// compute the offset to center the board on (0, 0, 0)
// XXX - NOTE: we should allow the user a GUI option to specify the offset
EDA_RECT
bbbox
=
pcb
->
ComputeBoundingBox
();
model3d
.
SetOffset
(
-
model3d
.
scale
*
bbbox
.
Centre
().
x
,
-
model3d
.
scale
*
bbbox
.
Centre
().
y
);
model3d
.
SetOffset
(
-
model3d
.
scale
*
bbbox
.
Centre
().
x
,
-
model3d
.
scale
*
bbbox
.
Centre
().
y
)
;
output_file
<<
" children [
\n
"
;
fprintf
(
output_file
,
" children [
\n
"
);
// Preliminary computation: the z value for each layer
compute_layer_Zs
(
model3d
,
pcb
);
// Preliminary computation: the z value for each layer
compute_layer_Zs
(
model3d
,
pcb
);
// board edges and cutouts
export_vrml_board
(
model3d
,
pcb
);
// board edges and cutouts
export_vrml_board
(
model3d
,
pcb
);
// Drawing and text on the board
export_vrml_drawings
(
model3d
,
pcb
);
// Drawing and text on the board
export_vrml_drawing
s
(
model3d
,
pcb
);
// Export vias and trackage
export_vrml_track
s
(
model3d
,
pcb
);
// Export vias and trackage
export_vrml_tracks
(
model3d
,
pcb
);
// Export zone fills
export_vrml_zones
(
model3d
,
pcb
);
// Export zone fills
export_vrml_zones
(
model3d
,
pcb
);
/* scaling factor to convert 3D models to board units (decimils)
* Usually we use Wings3D to create thems.
* One can consider the 3D units is 0.1 inch (2.54 mm)
* So the scaling factor from 0.1 inch to board units
* is 2.54 * aMMtoWRMLunit
*/
double
wrml_3D_models_scaling_factor
=
2.54
*
aMMtoWRMLunit
;
/* scaling factor to convert 3D models to board units (decimils)
* Usually we use Wings3D to create thems.
* One can consider the 3D units is 0.1 inch (2.54 mm)
* So the scaling factor from 0.1 inch to board units
* is 2.54 * aMMtoWRMLunit
*/
double
wrml_3D_models_scaling_factor
=
2.54
*
aMMtoWRMLunit
;
// Export footprints
for
(
MODULE
*
module
=
pcb
->
m_Modules
;
module
!=
0
;
module
=
module
->
Next
()
)
export_vrml_module
(
model3d
,
pcb
,
module
,
output_file
,
wrml_3D_models_scaling_factor
,
aExport3DFiles
,
a3D_Subdir
);
// Export footprints
for
(
MODULE
*
module
=
pcb
->
m_Modules
;
module
!=
0
;
module
=
module
->
Next
()
)
export_vrml_module
(
model3d
,
pcb
,
module
,
output_file
,
wrml_3D_models_scaling_factor
,
aExport3DFiles
,
a3D_Subdir
);
// write out the board and all layers
write_layers
(
model3d
,
output_file
,
pcb
);
// write out the board and all layers
write_layers
(
model3d
,
output_file
,
pcb
);
// Close the outer 'transform' node
output_file
<<
"]
\n
}
\n
"
;
}
catch
(
const
std
::
exception
&
e
)
{
wxString
msg
;
msg
<<
_
(
"IDF Export Failed:
\n
"
)
<<
FROM_UTF8
(
e
.
what
()
);
wxMessageBox
(
msg
);
// Close the outer 'transform' node
fputs
(
"]
\n
}
\n
"
,
output_file
);
ok
=
false
;
}
// End of work
fclose
(
output_file
);
output_file
.
exceptions
(
std
::
ios_base
::
goodbit
);
output_file
.
close
();
SetLocaleTo_Default
();
// revert to the current locale
return
true
;
return
ok
;
}
...
...
pcbnew/exporters/vrml_board.cpp
deleted
100644 → 0
View file @
bd174ebf
/*
* file: vrml_board.cpp
*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 Cirilo Bernardo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* NOTES ON OUTPUT PRECISION:
*
* If we use %.6f then we have no need for special unit dependent formatting:
*
* inch: .0254 microns
* mm: 0.001 microns
* m: 1 micron
*
*/
#include <sstream>
#include <string>
#include <iomanip>
#include <cmath>
#include <fctsys.h>
#include <vrml_board.h>
#ifndef CALLBACK
#define CALLBACK
#endif
#define GLCALLBACK(x) (( void (CALLBACK*)() )&(x))
void
FormatDoublet
(
double
x
,
double
y
,
int
precision
,
std
::
string
&
strx
,
std
::
string
&
stry
)
{
std
::
ostringstream
ostr
;
ostr
<<
std
::
fixed
<<
std
::
setprecision
(
precision
);
ostr
<<
x
;
strx
=
ostr
.
str
();
ostr
.
str
(
""
);
ostr
<<
y
;
stry
=
ostr
.
str
();
while
(
*
strx
.
rbegin
()
==
'0'
)
strx
.
erase
(
strx
.
size
()
-
1
);
while
(
*
stry
.
rbegin
()
==
'0'
)
stry
.
erase
(
stry
.
size
()
-
1
);
}
void
FormatSinglet
(
double
x
,
int
precision
,
std
::
string
&
strx
)
{
std
::
ostringstream
ostr
;
ostr
<<
std
::
fixed
<<
std
::
setprecision
(
precision
);
ostr
<<
x
;
strx
=
ostr
.
str
();
while
(
*
strx
.
rbegin
()
==
'0'
)
strx
.
erase
(
strx
.
size
()
-
1
);
}
int
CalcNSides
(
double
rad
,
double
dev
)
{
if
(
dev
<=
0
||
rad
<=
0
)
return
6
;
int
csides
;
double
n
=
dev
/
rad
;
// note: in the following, the first comparison and csides is chosen to
// yield a maximum of 360 segments; in practice we probably want a smaller limit.
if
(
n
<
0.0001523048
)
csides
=
360
;
else
if
(
n
>=
0.5
)
// 0.5 yields an angle >= 60 deg. (6 or fewer sides)
csides
=
6
;
else
csides
=
M_PI
*
2.0
/
acos
(
1.0
-
n
)
+
1
;
if
(
csides
<
6
)
csides
=
6
;
return
csides
;
}
static
void
CALLBACK
vrml_tess_begin
(
GLenum
cmd
,
void
*
user_data
)
{
VRML_LAYER
*
lp
=
(
VRML_LAYER
*
)
user_data
;
lp
->
glStart
(
cmd
);
}
static
void
CALLBACK
vrml_tess_end
(
void
*
user_data
)
{
VRML_LAYER
*
lp
=
(
VRML_LAYER
*
)
user_data
;
lp
->
glEnd
();
}
static
void
CALLBACK
vrml_tess_vertex
(
void
*
vertex_data
,
void
*
user_data
)
{
VRML_LAYER
*
lp
=
(
VRML_LAYER
*
)
user_data
;
lp
->
glPushVertex
(
(
VERTEX_3D
*
)
vertex_data
);
}
static
void
CALLBACK
vrml_tess_err
(
GLenum
errorID
,
void
*
user_data
)
{
VRML_LAYER
*
lp
=
(
VRML_LAYER
*
)
user_data
;
lp
->
Fault
=
true
;
lp
->
SetGLError
(
errorID
);
}
static
void
CALLBACK
vrml_tess_combine
(
GLdouble
coords
[
3
],
void
*
vertex_data
[
4
],
GLfloat
weight
[
4
],
void
**
outData
,
void
*
user_data
)
{
VRML_LAYER
*
lp
=
(
VRML_LAYER
*
)
user_data
;
*
outData
=
lp
->
AddExtraVertex
(
coords
[
0
],
coords
[
1
]
);
}
VRML_LAYER
::
VRML_LAYER
()
{
fix
=
false
;
Fault
=
false
;
idx
=
0
;
ord
=
0
;
glcmd
=
0
;
pholes
=
NULL
;
maxdev
=
0.02
;
tess
=
gluNewTess
();
if
(
!
tess
)
return
;
// set up the tesselator callbacks
gluTessCallback
(
tess
,
GLU_TESS_BEGIN_DATA
,
GLCALLBACK
(
vrml_tess_begin
)
);
gluTessCallback
(
tess
,
GLU_TESS_VERTEX_DATA
,
GLCALLBACK
(
vrml_tess_vertex
)
);
gluTessCallback
(
tess
,
GLU_TESS_END_DATA
,
GLCALLBACK
(
vrml_tess_end
)
);
gluTessCallback
(
tess
,
GLU_TESS_ERROR_DATA
,
GLCALLBACK
(
vrml_tess_err
)
);
gluTessCallback
(
tess
,
GLU_TESS_COMBINE_DATA
,
GLCALLBACK
(
vrml_tess_combine
)
);
gluTessProperty
(
tess
,
GLU_TESS_WINDING_RULE
,
GLU_TESS_WINDING_POSITIVE
);
gluTessNormal
(
tess
,
0
,
0
,
1
);
}
VRML_LAYER
::~
VRML_LAYER
()
{
Clear
();
if
(
tess
)
{
gluDeleteTess
(
tess
);
tess
=
NULL
;
}
}
// clear all data
void
VRML_LAYER
::
Clear
(
void
)
{
int
i
;
fix
=
false
;
idx
=
0
;
for
(
i
=
contours
.
size
();
i
>
0
;
--
i
)
{
delete
contours
.
back
();
contours
.
pop_back
();
}
while
(
!
areas
.
empty
()
)
areas
.
pop_back
();
for
(
i
=
vertices
.
size
();
i
>
0
;
--
i
)
{
delete
vertices
.
back
();
vertices
.
pop_back
();
}
clearTmp
();
}
// set the max. deviation of an arc segment
bool
VRML_LAYER
::
SetMaxDev
(
double
max
)
{
// assure max. dev > 2 microns regardless of the
// prevailing units ( inch, mm, m, 0.1 inch )
if
(
max
<
0.000002
)
{
error
=
"SetMaxDev(): specified value is < 0.000002"
;
return
false
;
}
maxdev
=
max
;
return
true
;
}
// clear ephemeral data in between invocations of the tesselation routine
void
VRML_LAYER
::
clearTmp
(
void
)
{
unsigned
int
i
;
Fault
=
false
;
hidx
=
0
;
eidx
=
0
;
ord
=
0
;
glcmd
=
0
;
while
(
!
triplets
.
empty
()
)
triplets
.
pop_back
();
for
(
i
=
outline
.
size
();
i
>
0
;
--
i
)
{
delete
outline
.
back
();
outline
.
pop_back
();
}
for
(
i
=
ordmap
.
size
();
i
>
0
;
--
i
)
ordmap
.
pop_back
();
for
(
i
=
extra_verts
.
size
();
i
>
0
;
--
i
)
{
delete
extra_verts
.
back
();
extra_verts
.
pop_back
();
}
// note: unlike outline and extra_verts,
// vlist is not responsible for memory management
for
(
i
=
vlist
.
size
();
i
>
0
;
--
i
)
vlist
.
pop_back
();
// go through the vertex list and reset ephemeral parameters
for
(
i
=
0
;
i
<
vertices
.
size
();
++
i
)
{
vertices
[
i
]
->
o
=
-
1
;
}
}
// create a new contour to be populated; returns an index
// into the contour list or -1 if there are problems
int
VRML_LAYER
::
NewContour
(
void
)
{
if
(
fix
)
return
-
1
;
std
::
list
<
int
>*
contour
=
new
std
::
list
<
int
>
;
if
(
!
contour
)
return
-
1
;
contours
.
push_back
(
contour
);
areas
.
push_back
(
0.0
);
return
contours
.
size
()
-
1
;
}
// adds a vertex to the existing list and places its index in
// an existing contour; returns true if OK,
// false otherwise (indexed contour does not exist)
bool
VRML_LAYER
::
AddVertex
(
int
aContour
,
double
x
,
double
y
)
{
if
(
fix
)
{
error
=
"AddVertex(): no more vertices may be added (Tesselate was previously executed)"
;
return
false
;
}
if
(
aContour
<
0
||
(
unsigned
int
)
aContour
>=
contours
.
size
()
)
{
error
=
"AddVertex(): aContour is not within a valid range"
;
return
false
;
}
VERTEX_3D
*
vertex
=
new
VERTEX_3D
;
if
(
!
vertex
)
{
error
=
"AddVertex(): a new vertex could not be allocated"
;
return
false
;
}
vertex
->
x
=
x
;
vertex
->
y
=
y
;
vertex
->
i
=
idx
++
;
vertex
->
o
=
-
1
;
VERTEX_3D
*
v2
=
NULL
;
if
(
contours
[
aContour
]
->
size
()
>
0
)
v2
=
vertices
[
contours
[
aContour
]
->
back
()
];
vertices
.
push_back
(
vertex
);
contours
[
aContour
]
->
push_back
(
vertex
->
i
);
if
(
v2
)
areas
[
aContour
]
+=
(
x
-
v2
->
x
)
*
(
y
+
v2
->
y
);
return
true
;
}
// ensure the winding of a contour with respect to the normal (0, 0, 1);
// set 'hole' to true to ensure a hole (clockwise winding)
bool
VRML_LAYER
::
EnsureWinding
(
int
aContour
,
bool
hole
)
{
if
(
aContour
<
0
||
(
unsigned
int
)
aContour
>=
contours
.
size
()
)
{
error
=
"EnsureWinding(): aContour is outside the valid range"
;
return
false
;
}
std
::
list
<
int
>*
cp
=
contours
[
aContour
];
if
(
cp
->
size
()
<
3
)
{
error
=
"EnsureWinding(): there are fewer than 3 vertices"
;
return
false
;
}
double
dir
=
areas
[
aContour
];
VERTEX_3D
*
vp0
=
vertices
[
cp
->
back
()
];
VERTEX_3D
*
vp1
=
vertices
[
cp
->
front
()
];
dir
+=
(
vp1
->
x
-
vp0
->
x
)
*
(
vp1
->
y
+
vp0
->
y
);
// if dir is positive, winding is CW
if
(
(
hole
&&
dir
<
0
)
||
(
!
hole
&&
dir
>
0
)
)
{
cp
->
reverse
();
areas
[
aContour
]
=
-
areas
[
aContour
];
}
return
true
;
}
// adds a circle the existing list; if 'hole' is true the contour is
// a hole. Returns true if OK.
bool
VRML_LAYER
::
AddCircle
(
double
x
,
double
y
,
double
rad
,
int
csides
,
bool
hole
)
{
int
pad
=
NewContour
();
if
(
pad
<
0
)
{
error
=
"AddCircle(): failed to add a contour"
;
return
false
;
}
if
(
csides
<
6
)
csides
=
CalcNSides
(
rad
,
maxdev
);
// even numbers give prettier results
if
(
csides
&
1
)
csides
+=
1
;
double
da
=
M_PI
*
2.0
/
csides
;
bool
fail
=
false
;
if
(
hole
)
{
for
(
double
angle
=
0
;
angle
<
M_PI
*
2
;
angle
+=
da
)
fail
|=
!
AddVertex
(
pad
,
x
+
rad
*
cos
(
angle
),
y
-
rad
*
sin
(
angle
)
);
}
else
{
for
(
double
angle
=
0
;
angle
<
M_PI
*
2
;
angle
+=
da
)
fail
|=
!
AddVertex
(
pad
,
x
+
rad
*
cos
(
angle
),
y
+
rad
*
sin
(
angle
)
);
}
return
!
fail
;
}
// adds a slotted pad with orientation given by angle; if 'hole' is true the
// contour is a hole. Returns true if OK.
bool
VRML_LAYER
::
AddSlot
(
double
cx
,
double
cy
,
double
length
,
double
width
,
double
angle
,
int
csides
,
bool
hole
)
{
if
(
width
>
length
)
{
angle
+=
M_PI2
;
std
::
swap
(
length
,
width
);
}
width
/=
2.0
;
length
=
length
/
2.0
-
width
;
if
(
csides
<
6
)
csides
=
CalcNSides
(
width
,
maxdev
);
if
(
csides
&
1
)
csides
+=
1
;
csides
/=
2
;
double
capx
,
capy
;
capx
=
cx
+
cos
(
angle
)
*
length
;
capy
=
cy
+
sin
(
angle
)
*
length
;
double
ang
,
da
;
int
i
;
int
pad
=
NewContour
();
if
(
pad
<
0
)
{
error
=
"AddCircle(): failed to add a contour"
;
return
false
;
}
da
=
M_PI
/
csides
;
bool
fail
=
false
;
if
(
hole
)
{
for
(
ang
=
angle
+
M_PI2
,
i
=
0
;
i
<
csides
;
ang
-=
da
,
++
i
)
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
ang
=
angle
-
M_PI2
;
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
capx
=
cx
-
cos
(
angle
)
*
length
;
capy
=
cy
-
sin
(
angle
)
*
length
;
for
(
ang
=
angle
-
M_PI2
,
i
=
0
;
i
<
csides
;
ang
-=
da
,
++
i
)
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
ang
=
angle
+
M_PI2
;
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
}
else
{
for
(
ang
=
angle
-
M_PI2
,
i
=
0
;
i
<
csides
;
ang
+=
da
,
++
i
)
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
ang
=
angle
+
M_PI2
;
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
capx
=
cx
-
cos
(
angle
)
*
length
;
capy
=
cy
-
sin
(
angle
)
*
length
;
for
(
ang
=
angle
+
M_PI2
,
i
=
0
;
i
<
csides
;
ang
+=
da
,
++
i
)
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
ang
=
angle
-
M_PI2
;
fail
|=
!
AddVertex
(
pad
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
}
return
!
fail
;
}
// adds an arc with the given center, start point, pen width, and angle.
bool
VRML_LAYER
::
AddArc
(
double
cx
,
double
cy
,
double
startx
,
double
starty
,
double
width
,
double
angle
,
int
csides
,
bool
hole
)
{
// we don't accept small angles; in fact, 1 degree ( 0.01745 ) is already
// way too small but we must set a limit somewhere
if
(
angle
<
0.01745
&&
angle
>
-
0.01745
)
{
error
=
"AddArc(): angle is too small: abs( angle ) < 0.01745"
;
return
false
;
}
double
rad
=
sqrt
(
(
startx
-
cx
)
*
(
startx
-
cx
)
+
(
starty
-
cy
)
*
(
starty
-
cy
)
);
width
/=
2.0
;
// this is the radius of the caps
// we will not accept an arc with an inner radius close to zero so we
// set a limit here. the end result will vary somewhat depending on
// the output units
if
(
width
>=
(
rad
*
1.01
)
)
{
error
=
"AddArc(): width/2 exceeds radius*1.01"
;
return
false
;
}
// calculate the radii of the outer and inner arcs
double
orad
=
rad
+
width
;
double
irad
=
rad
-
width
;
int
osides
=
csides
*
angle
/
(
M_PI
*
2.0
);
int
isides
=
csides
*
angle
/
(
M_PI
*
2.0
);
if
(
osides
<
0
)
osides
=
-
osides
;
if
(
osides
<
3
)
{
osides
=
CalcNSides
(
orad
,
maxdev
)
*
angle
/
(
M_PI
*
2.0
);
if
(
osides
<
0
)
osides
=
-
osides
;
if
(
osides
<
3
)
osides
=
3
;
}
if
(
isides
<
0
)
isides
=
-
isides
;
if
(
isides
<
3
)
{
isides
=
CalcNSides
(
irad
,
maxdev
)
*
angle
/
(
M_PI
*
2.0
);
if
(
isides
<
0
)
isides
=
-
isides
;
if
(
isides
<
3
)
isides
=
3
;
}
if
(
csides
<
6
)
csides
=
CalcNSides
(
width
,
maxdev
);
if
(
csides
&
1
)
csides
+=
1
;
csides
/=
2
;
double
stAngle
=
atan2
(
starty
-
cy
,
startx
-
cx
);
double
endAngle
=
stAngle
+
angle
;
// calculate ends of inner and outer arc
double
oendx
=
cx
+
orad
*
cos
(
endAngle
);
double
oendy
=
cy
+
orad
*
sin
(
endAngle
);
double
ostx
=
cx
+
orad
*
cos
(
stAngle
);
double
osty
=
cy
+
orad
*
sin
(
stAngle
);
double
iendx
=
cx
+
irad
*
cos
(
endAngle
);
double
iendy
=
cy
+
irad
*
sin
(
endAngle
);
double
istx
=
cx
+
irad
*
cos
(
stAngle
);
double
isty
=
cy
+
irad
*
sin
(
stAngle
);
if
(
(
angle
<
0
&&
!
hole
)
||
(
angle
>
0
&&
hole
)
)
{
angle
=
-
angle
;
std
::
swap
(
stAngle
,
endAngle
);
std
::
swap
(
oendx
,
ostx
);
std
::
swap
(
oendy
,
osty
);
std
::
swap
(
iendx
,
istx
);
std
::
swap
(
iendy
,
isty
);
}
int
arc
=
NewContour
();
if
(
arc
<
0
)
{
error
=
"AddArc(): could not create a contour"
;
return
false
;
}
// trace the outer arc:
int
i
;
double
ang
;
double
da
=
angle
/
osides
;
for
(
ang
=
stAngle
,
i
=
0
;
i
<
osides
;
ang
+=
da
,
++
i
)
AddVertex
(
arc
,
cx
+
orad
*
cos
(
ang
),
cy
+
orad
*
sin
(
ang
)
);
// trace the first cap
double
capx
=
(
iendx
+
oendx
)
/
2.0
;
double
capy
=
(
iendy
+
oendy
)
/
2.0
;
if
(
hole
)
da
=
-
M_PI
/
csides
;
else
da
=
M_PI
/
csides
;
for
(
ang
=
endAngle
+
da
,
i
=
2
;
i
<
csides
;
ang
+=
da
,
++
i
)
AddVertex
(
arc
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
// trace the inner arc:
da
=
-
angle
/
isides
;
for
(
ang
=
endAngle
,
i
=
0
;
i
<
isides
;
ang
+=
da
,
++
i
)
AddVertex
(
arc
,
cx
+
irad
*
cos
(
ang
),
cy
+
irad
*
sin
(
ang
)
);
// trace the final cap
capx
=
(
istx
+
ostx
)
/
2.0
;
capy
=
(
isty
+
osty
)
/
2.0
;
if
(
hole
)
da
=
-
M_PI
/
csides
;
else
da
=
M_PI
/
csides
;
for
(
ang
=
stAngle
+
M_PI
+
da
,
i
=
2
;
i
<
csides
;
ang
+=
da
,
++
i
)
AddVertex
(
arc
,
capx
+
width
*
cos
(
ang
),
capy
+
width
*
sin
(
ang
)
);
return
true
;
}
// tesselates the contours in preparation for a 3D output;
// returns true if all was fine, false otherwise
bool
VRML_LAYER
::
Tesselate
(
VRML_LAYER
*
holes
)
{
if
(
!
tess
)
{
error
=
"Tesselate(): GLU tesselator was not initialized"
;
return
false
;
}
pholes
=
holes
;
Fault
=
false
;
if
(
contours
.
size
()
<
1
||
vertices
.
size
()
<
3
)
{
error
=
"Tesselate(): not enough vertices"
;
return
false
;
}
// finish the winding calculation on all vertices prior to setting 'fix'
if
(
!
fix
)
{
for
(
unsigned
int
i
=
0
;
i
<
contours
.
size
();
++
i
)
{
if
(
contours
[
i
]
->
size
()
<
3
)
continue
;
VERTEX_3D
*
vp0
=
vertices
[
contours
[
i
]
->
back
()
];
VERTEX_3D
*
vp1
=
vertices
[
contours
[
i
]
->
front
()
];
areas
[
i
]
+=
(
vp1
->
x
-
vp0
->
x
)
*
(
vp1
->
y
+
vp0
->
y
);
}
}
// prevent the addition of any further contours and contour vertices
fix
=
true
;
// clear temporary internals which may have been used in a previous run
clearTmp
();
// request an outline
gluTessProperty
(
tess
,
GLU_TESS_BOUNDARY_ONLY
,
GL_TRUE
);
// adjust internal indices for extra points and holes
if
(
holes
)
hidx
=
holes
->
GetSize
();
else
hidx
=
0
;
eidx
=
idx
+
hidx
;
// open the polygon
gluTessBeginPolygon
(
tess
,
this
);
pushVertices
(
false
);
// close the polygon
gluTessEndPolygon
(
tess
);
if
(
Fault
)
return
false
;
// push the (solid) outline to the tesselator
if
(
!
pushOutline
(
holes
)
)
return
false
;
// add the holes contained by this object
pushVertices
(
true
);
// import external holes (if any)
if
(
hidx
&&
(
holes
->
Import
(
idx
,
tess
)
<
0
)
)
{
std
::
ostringstream
ostr
;
ostr
<<
"Tesselate():FAILED: "
<<
holes
->
GetError
();
error
=
ostr
.
str
();
return
false
;
}
if
(
Fault
)
return
false
;
// erase the previous outline data and vertex order
// but preserve the extra vertices
for
(
int
i
=
outline
.
size
();
i
>
0
;
--
i
)
{
delete
outline
.
back
();
outline
.
pop_back
();
}
for
(
unsigned
int
i
=
ordmap
.
size
();
i
>
0
;
--
i
)
ordmap
.
pop_back
();
// go through the vertex lists and reset ephemeral parameters
for
(
unsigned
int
i
=
0
;
i
<
vertices
.
size
();
++
i
)
{
vertices
[
i
]
->
o
=
-
1
;
}
for
(
unsigned
int
i
=
0
;
i
<
extra_verts
.
size
();
++
i
)
{
extra_verts
[
i
]
->
o
=
-
1
;
}
ord
=
0
;
// close the polygon; we now have all the data necessary for the tesselation
gluTessEndPolygon
(
tess
);
// request a tesselated surface
gluTessProperty
(
tess
,
GLU_TESS_BOUNDARY_ONLY
,
GL_FALSE
);
if
(
!
pushOutline
(
holes
)
)
return
false
;
gluTessEndPolygon
(
tess
);
if
(
Fault
)
return
false
;
return
true
;
}
bool
VRML_LAYER
::
pushOutline
(
VRML_LAYER
*
holes
)
{
// traverse the outline list to push all used vertices
if
(
outline
.
size
()
<
1
)
{
error
=
"pushOutline() failed: no vertices to push"
;
return
false
;
}
gluTessBeginPolygon
(
tess
,
this
);
std
::
list
<
std
::
list
<
int
>*>::
const_iterator
obeg
=
outline
.
begin
();
std
::
list
<
std
::
list
<
int
>*>::
const_iterator
oend
=
outline
.
end
();
int
pi
;
std
::
list
<
int
>::
const_iterator
begin
;
std
::
list
<
int
>::
const_iterator
end
;
GLdouble
pt
[
3
];
VERTEX_3D
*
vp
;
while
(
obeg
!=
oend
)
{
if
(
(
*
obeg
)
->
size
()
<
3
)
{
++
obeg
;
continue
;
}
gluTessBeginContour
(
tess
);
begin
=
(
*
obeg
)
->
begin
();
end
=
(
*
obeg
)
->
end
();
while
(
begin
!=
end
)
{
pi
=
*
begin
;
if
(
pi
<
0
||
(
unsigned
int
)
pi
>
ordmap
.
size
()
)
{
error
=
"pushOutline():BUG: *outline.begin() is not a valid index to ordmap"
;
return
false
;
}
// retrieve the actual index
pi
=
ordmap
[
pi
];
vp
=
getVertexByIndex
(
pi
,
holes
);
if
(
!
vp
)
{
error
=
"pushOutline():: BUG: ordmap[n] is not a valid index to vertices[]"
;
return
false
;
}
pt
[
0
]
=
vp
->
x
;
pt
[
1
]
=
vp
->
y
;
pt
[
2
]
=
0.0
;
gluTessVertex
(
tess
,
pt
,
vp
);
++
begin
;
}
gluTessEndContour
(
tess
);
++
obeg
;
}
return
true
;
}
// writes out the vertex list;
// 'z' is the Z coordinate of every point
bool
VRML_LAYER
::
WriteVertices
(
double
z
,
FILE
*
fp
)
{
if
(
!
fp
)
{
error
=
"WriteVertices(): invalid file pointer"
;
return
false
;
}
if
(
ordmap
.
size
()
<
3
)
{
error
=
"WriteVertices(): not enough vertices"
;
return
false
;
}
int
i
,
j
;
VERTEX_3D
*
vp
=
getVertexByIndex
(
ordmap
[
0
],
pholes
);
if
(
!
vp
)
return
false
;
std
::
string
strx
,
stry
,
strz
;
FormatDoublet
(
vp
->
x
,
vp
->
y
,
6
,
strx
,
stry
);
FormatSinglet
(
z
,
6
,
strz
);
fprintf
(
fp
,
"%s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
for
(
i
=
1
,
j
=
ordmap
.
size
();
i
<
j
;
++
i
)
{
vp
=
getVertexByIndex
(
ordmap
[
i
],
pholes
);
if
(
!
vp
)
return
false
;
FormatDoublet
(
vp
->
x
,
vp
->
y
,
6
,
strx
,
stry
);
if
(
i
&
1
)
fprintf
(
fp
,
", %s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
else
fprintf
(
fp
,
",
\n
%s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
}
return
true
;
}
// writes out the vertex list for a 3D feature; top and bottom are the
// Z values for the top and bottom; top must be > bottom
bool
VRML_LAYER
::
Write3DVertices
(
double
top
,
double
bottom
,
FILE
*
fp
)
{
if
(
!
fp
)
{
error
=
"Write3DVertices(): NULL file pointer"
;
return
false
;
}
if
(
ordmap
.
size
()
<
3
)
{
error
=
"Write3DVertices(): insufficient vertices"
;
return
false
;
}
if
(
top
<=
bottom
)
{
error
=
"Write3DVertices(): top <= bottom"
;
return
false
;
}
int
i
,
j
;
VERTEX_3D
*
vp
=
getVertexByIndex
(
ordmap
[
0
],
pholes
);
if
(
!
vp
)
return
false
;
std
::
string
strx
,
stry
,
strz
;
FormatDoublet
(
vp
->
x
,
vp
->
y
,
6
,
strx
,
stry
);
FormatSinglet
(
top
,
6
,
strz
);
fprintf
(
fp
,
"%s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
for
(
i
=
1
,
j
=
ordmap
.
size
();
i
<
j
;
++
i
)
{
vp
=
getVertexByIndex
(
ordmap
[
i
],
pholes
);
if
(
!
vp
)
return
false
;
FormatDoublet
(
vp
->
x
,
vp
->
y
,
6
,
strx
,
stry
);
if
(
i
&
1
)
fprintf
(
fp
,
", %s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
else
fprintf
(
fp
,
",
\n
%s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
}
// repeat for the bottom layer
vp
=
getVertexByIndex
(
ordmap
[
0
],
pholes
);
FormatDoublet
(
vp
->
x
,
vp
->
y
,
6
,
strx
,
stry
);
FormatSinglet
(
bottom
,
6
,
strz
);
bool
endl
;
if
(
i
&
1
)
{
fprintf
(
fp
,
", %s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
endl
=
false
;
}
else
{
fprintf
(
fp
,
",
\n
%s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
endl
=
true
;
}
for
(
i
=
1
,
j
=
ordmap
.
size
();
i
<
j
;
++
i
)
{
vp
=
getVertexByIndex
(
ordmap
[
i
],
pholes
);
FormatDoublet
(
vp
->
x
,
vp
->
y
,
6
,
strx
,
stry
);
if
(
endl
)
{
fprintf
(
fp
,
", %s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
endl
=
false
;
}
else
{
fprintf
(
fp
,
",
\n
%s %s %s"
,
strx
.
c_str
(),
stry
.
c_str
(),
strz
.
c_str
()
);
endl
=
true
;
}
}
return
true
;
}
// writes out the index list;
// 'top' indicates the vertex ordering and should be
// true for a polygon visible from above the PCB
bool
VRML_LAYER
::
WriteIndices
(
bool
top
,
FILE
*
fp
)
{
if
(
triplets
.
empty
()
)
{
error
=
"WriteIndices(): no triplets (triangular facets) to write"
;
return
false
;
}
// go through the triplet list and write out the indices based on order
std
::
list
<
TRIPLET_3D
>::
const_iterator
tbeg
=
triplets
.
begin
();
std
::
list
<
TRIPLET_3D
>::
const_iterator
tend
=
triplets
.
end
();
int
i
=
1
;
if
(
top
)
fprintf
(
fp
,
"%d, %d, %d, -1"
,
tbeg
->
i1
,
tbeg
->
i2
,
tbeg
->
i3
);
else
fprintf
(
fp
,
"%d, %d, %d, -1"
,
tbeg
->
i2
,
tbeg
->
i1
,
tbeg
->
i3
);
++
tbeg
;
while
(
tbeg
!=
tend
)
{
if
(
(
i
++
&
7
)
==
4
)
{
i
=
1
;
if
(
top
)
fprintf
(
fp
,
",
\n
%d, %d, %d, -1"
,
tbeg
->
i1
,
tbeg
->
i2
,
tbeg
->
i3
);
else
fprintf
(
fp
,
",
\n
%d, %d, %d, -1"
,
tbeg
->
i2
,
tbeg
->
i1
,
tbeg
->
i3
);
}
else
{
if
(
top
)
fprintf
(
fp
,
", %d, %d, %d, -1"
,
tbeg
->
i1
,
tbeg
->
i2
,
tbeg
->
i3
);
else
fprintf
(
fp
,
", %d, %d, %d, -1"
,
tbeg
->
i2
,
tbeg
->
i1
,
tbeg
->
i3
);
}
++
tbeg
;
}
return
true
;
}
// writes out the index list for a 3D feature
bool
VRML_LAYER
::
Write3DIndices
(
FILE
*
fp
)
{
if
(
triplets
.
empty
()
)
{
error
=
"Write3DIndices(): no triplets (triangular facets) to write"
;
return
false
;
}
if
(
outline
.
empty
()
)
{
error
=
"WriteIndices(): no outline available"
;
return
false
;
}
// go through the triplet list and write out the indices based on order
std
::
list
<
TRIPLET_3D
>::
const_iterator
tbeg
=
triplets
.
begin
();
std
::
list
<
TRIPLET_3D
>::
const_iterator
tend
=
triplets
.
end
();
int
i
=
1
;
int
idx2
=
ordmap
.
size
();
// index to the bottom vertices
// print out the top vertices
fprintf
(
fp
,
"%d, %d, %d, -1"
,
tbeg
->
i1
,
tbeg
->
i2
,
tbeg
->
i3
);
++
tbeg
;
while
(
tbeg
!=
tend
)
{
if
(
(
i
++
&
7
)
==
4
)
{
i
=
1
;
fprintf
(
fp
,
",
\n
%d, %d, %d, -1"
,
tbeg
->
i1
,
tbeg
->
i2
,
tbeg
->
i3
);
}
else
{
fprintf
(
fp
,
", %d, %d, %d, -1"
,
tbeg
->
i1
,
tbeg
->
i2
,
tbeg
->
i3
);
}
++
tbeg
;
}
// print out the bottom vertices
tbeg
=
triplets
.
begin
();
while
(
tbeg
!=
tend
)
{
if
(
(
i
++
&
7
)
==
4
)
{
i
=
1
;
fprintf
(
fp
,
",
\n
%d, %d, %d, -1"
,
tbeg
->
i2
+
idx2
,
tbeg
->
i1
+
idx2
,
tbeg
->
i3
+
idx2
);
}
else
{
fprintf
(
fp
,
", %d, %d, %d, -1"
,
tbeg
->
i2
+
idx2
,
tbeg
->
i1
+
idx2
,
tbeg
->
i3
+
idx2
);
}
++
tbeg
;
}
int
firstPoint
;
int
lastPoint
;
int
curPoint
;
std
::
list
<
std
::
list
<
int
>*>::
const_iterator
obeg
=
outline
.
begin
();
std
::
list
<
std
::
list
<
int
>*>::
const_iterator
oend
=
outline
.
end
();
std
::
list
<
int
>*
cp
;
std
::
list
<
int
>::
const_iterator
cbeg
;
std
::
list
<
int
>::
const_iterator
cend
;
while
(
obeg
!=
oend
)
{
cp
=
*
obeg
;
if
(
cp
->
size
()
<
3
)
{
++
obeg
;
continue
;
}
cbeg
=
cp
->
begin
();
cend
=
cp
->
end
();
firstPoint
=
*
(
cbeg
++
);
lastPoint
=
firstPoint
;
while
(
cbeg
!=
cend
)
{
curPoint
=
*
(
cbeg
++
);
fprintf
(
fp
,
",
\n
%d, %d, %d, -1, %d, %d, %d, -1"
,
curPoint
,
lastPoint
,
curPoint
+
idx2
,
curPoint
+
idx2
,
lastPoint
,
lastPoint
+
idx2
);
lastPoint
=
curPoint
;
}
fprintf
(
fp
,
",
\n
%d, %d, %d, -1, %d, %d, %d, -1"
,
firstPoint
,
lastPoint
,
firstPoint
+
idx2
,
firstPoint
+
idx2
,
lastPoint
,
lastPoint
+
idx2
);
++
obeg
;
}
return
true
;
}
// add a triangular facet (triplet) to the ouptut index list
bool
VRML_LAYER
::
addTriplet
(
VERTEX_3D
*
p0
,
VERTEX_3D
*
p1
,
VERTEX_3D
*
p2
)
{
double
dx0
=
p1
->
x
-
p0
->
x
;
double
dx1
=
p2
->
x
-
p0
->
x
;
double
dy0
=
p1
->
y
-
p0
->
y
;
double
dy1
=
p2
->
y
-
p0
->
y
;
// this number is chosen because we shall only write 6 decimal places
// on the VRML output
double
err
=
0.000001
;
// test if the triangles are degenerate (parallel sides)
if
(
dx0
<
err
&&
dx0
>
-
err
&&
dx1
<
err
&&
dx1
>
-
err
)
return
false
;
if
(
dy0
<
err
&&
dy0
>
-
err
&&
dy1
<
err
&&
dy1
>
-
err
)
return
false
;
double
sl0
=
dy0
/
dx0
;
double
sl1
=
dy1
/
dx1
;
double
dsl
=
sl1
-
sl0
;
if
(
dsl
<
err
&&
dsl
>
-
err
)
return
false
;
triplets
.
push_back
(
TRIPLET_3D
(
p0
->
o
,
p1
->
o
,
p2
->
o
)
);
return
true
;
}
// add an extra vertex (to be called only by the COMBINE callback)
VERTEX_3D
*
VRML_LAYER
::
AddExtraVertex
(
double
x
,
double
y
)
{
VERTEX_3D
*
vertex
=
new
VERTEX_3D
;
if
(
!
vertex
)
{
error
=
"AddExtraVertex(): could not allocate a new vertex"
;
return
NULL
;
}
if
(
eidx
==
0
)
eidx
=
idx
+
hidx
;
vertex
->
x
=
x
;
vertex
->
y
=
y
;
vertex
->
i
=
eidx
++
;
vertex
->
o
=
-
1
;
extra_verts
.
push_back
(
vertex
);
return
vertex
;
}
// start a GL command list
void
VRML_LAYER
::
glStart
(
GLenum
cmd
)
{
glcmd
=
cmd
;
while
(
!
vlist
.
empty
()
)
vlist
.
pop_back
();
}
// process a vertex
void
VRML_LAYER
::
glPushVertex
(
VERTEX_3D
*
vertex
)
{
if
(
vertex
->
o
<
0
)
{
vertex
->
o
=
ord
++
;
ordmap
.
push_back
(
vertex
->
i
);
}
vlist
.
push_back
(
vertex
);
}
// end a GL command list
void
VRML_LAYER
::
glEnd
(
void
)
{
switch
(
glcmd
)
{
case
GL_LINE_LOOP
:
{
// add the loop to the list of outlines
std
::
list
<
int
>*
loop
=
new
std
::
list
<
int
>
;
if
(
!
loop
)
break
;
for
(
unsigned
int
i
=
0
;
i
<
vlist
.
size
();
++
i
)
{
loop
->
push_back
(
vlist
[
i
]
->
o
);
}
outline
.
push_back
(
loop
);
}
break
;
case
GL_TRIANGLE_FAN
:
processFan
();
break
;
case
GL_TRIANGLE_STRIP
:
processStrip
();
break
;
case
GL_TRIANGLES
:
processTri
();
break
;
default
:
break
;
}
while
(
!
vlist
.
empty
()
)
vlist
.
pop_back
();
glcmd
=
0
;
}
// set the error message
void
VRML_LAYER
::
SetGLError
(
GLenum
errorID
)
{
error
=
""
;
error
=
(
const
char
*
)
gluGetString
(
errorID
);
if
(
error
.
empty
()
)
{
std
::
ostringstream
ostr
;
ostr
<<
"Unknown OpenGL error: "
<<
errorID
;
error
=
ostr
.
str
();
}
}
// process a GL_TRIANGLE_FAN list
void
VRML_LAYER
::
processFan
(
void
)
{
if
(
vlist
.
size
()
<
3
)
return
;
VERTEX_3D
*
p0
=
vlist
[
0
];
int
i
;
int
end
=
vlist
.
size
();
for
(
i
=
2
;
i
<
end
;
++
i
)
{
addTriplet
(
p0
,
vlist
[
i
-
1
],
vlist
[
i
]
);
}
}
// process a GL_TRIANGLE_STRIP list
void
VRML_LAYER
::
processStrip
(
void
)
{
// note: (source: http://www.opengl.org/wiki/Primitive)
// GL_TRIANGLE_STRIP: Every group of 3 adjacent vertices forms a triangle.
// The face direction of the strip is determined by the winding of the
// first triangle. Each successive triangle will have its effective face
// order reverse, so the system compensates for that by testing it in the
// opposite way. A vertex stream of n length will generate n-2 triangles.
if
(
vlist
.
size
()
<
3
)
return
;
int
i
;
int
end
=
vlist
.
size
();
bool
flip
=
false
;
for
(
i
=
2
;
i
<
end
;
++
i
)
{
if
(
flip
)
{
addTriplet
(
vlist
[
i
-
1
],
vlist
[
i
-
2
],
vlist
[
i
]
);
flip
=
false
;
}
else
{
addTriplet
(
vlist
[
i
-
2
],
vlist
[
i
-
1
],
vlist
[
i
]
);
flip
=
true
;
}
}
}
// process a GL_TRIANGLES list
void
VRML_LAYER
::
processTri
(
void
)
{
// notes:
// 1. each successive group of 3 vertices is a triangle
// 2. as per OpenGL specification, any incomplete triangles are to be ignored
if
(
vlist
.
size
()
<
3
)
return
;
int
i
;
int
end
=
vlist
.
size
();
for
(
i
=
2
;
i
<
end
;
i
+=
3
)
addTriplet
(
vlist
[
i
-
2
],
vlist
[
i
-
1
],
vlist
[
i
]
);
}
// push the internally held vertices
void
VRML_LAYER
::
pushVertices
(
bool
holes
)
{
// push the internally held vertices
unsigned
int
i
;
std
::
list
<
int
>::
const_iterator
begin
;
std
::
list
<
int
>::
const_iterator
end
;
GLdouble
pt
[
3
];
VERTEX_3D
*
vp
;
for
(
i
=
0
;
i
<
contours
.
size
();
++
i
)
{
if
(
contours
[
i
]
->
size
()
<
3
)
continue
;
if
(
(
holes
&&
areas
[
i
]
<=
0.0
)
||
(
!
holes
&&
areas
[
i
]
>
0.0
)
)
continue
;
gluTessBeginContour
(
tess
);
begin
=
contours
[
i
]
->
begin
();
end
=
contours
[
i
]
->
end
();
while
(
begin
!=
end
)
{
vp
=
vertices
[
*
begin
];
pt
[
0
]
=
vp
->
x
;
pt
[
1
]
=
vp
->
y
;
pt
[
2
]
=
0.0
;
gluTessVertex
(
tess
,
pt
,
vp
);
++
begin
;
}
gluTessEndContour
(
tess
);
}
}
VERTEX_3D
*
VRML_LAYER
::
getVertexByIndex
(
int
index
,
VRML_LAYER
*
holes
)
{
if
(
index
<
0
||
(
unsigned
int
)
index
>=
(
idx
+
hidx
+
extra_verts
.
size
()
)
)
{
error
=
"getVertexByIndex():BUG: invalid index"
;
return
NULL
;
}
if
(
index
<
idx
)
{
// vertex is in the vertices[] list
return
vertices
[
index
];
}
else
if
(
index
>=
idx
+
hidx
)
{
// vertex is in the extra_verts[] list
return
extra_verts
[
index
-
idx
-
hidx
];
}
// vertex is in the holes object
if
(
!
holes
)
{
error
=
"getVertexByIndex():BUG: invalid index"
;
return
NULL
;
}
VERTEX_3D
*
vp
=
holes
->
GetVertexByIndex
(
index
);
if
(
!
vp
)
{
std
::
ostringstream
ostr
;
ostr
<<
"getVertexByIndex():FAILED: "
<<
holes
->
GetError
();
error
=
ostr
.
str
();
return
NULL
;
}
return
vp
;
}
// retrieve the total number of vertices
int
VRML_LAYER
::
GetSize
(
void
)
{
return
vertices
.
size
();
}
// Inserts all contours into the given tesselator; this results in the
// renumbering of all vertices from 'start'. Returns the end number.
// Take care when using this call since tesselators cannot work on
// the internal data concurrently
int
VRML_LAYER
::
Import
(
int
start
,
GLUtesselator
*
tess
)
{
if
(
start
<
0
)
{
error
=
"Import(): invalid index ( start < 0 )"
;
return
-
1
;
}
if
(
!
tess
)
{
error
=
"Import(): NULL tesselator pointer"
;
return
-
1
;
}
unsigned
int
i
,
j
;
// renumber from 'start'
for
(
i
=
0
,
j
=
vertices
.
size
();
i
<
j
;
++
i
)
{
vertices
[
i
]
->
i
=
start
++
;
vertices
[
i
]
->
o
=
-
1
;
}
// push each contour to the tesselator
VERTEX_3D
*
vp
;
GLdouble
pt
[
3
];
std
::
list
<
int
>::
const_iterator
cbeg
;
std
::
list
<
int
>::
const_iterator
cend
;
for
(
i
=
0
;
i
<
contours
.
size
();
++
i
)
{
if
(
contours
[
i
]
->
size
()
<
3
)
continue
;
cbeg
=
contours
[
i
]
->
begin
();
cend
=
contours
[
i
]
->
end
();
gluTessBeginContour
(
tess
);
while
(
cbeg
!=
cend
)
{
vp
=
vertices
[
*
cbeg
++
];
pt
[
0
]
=
vp
->
x
;
pt
[
1
]
=
vp
->
y
;
pt
[
2
]
=
0.0
;
gluTessVertex
(
tess
,
pt
,
vp
);
}
gluTessEndContour
(
tess
);
}
return
start
;
}
// return the vertex identified by index
VERTEX_3D
*
VRML_LAYER
::
GetVertexByIndex
(
int
index
)
{
int
i0
=
vertices
[
0
]
->
i
;
if
(
index
<
i0
||
index
>=
(
i0
+
(
int
)
vertices
.
size
()
)
)
{
error
=
"GetVertexByIndex(): invalid index"
;
return
NULL
;
}
return
vertices
[
index
-
i0
];
}
// return the error string
const
std
::
string
&
VRML_LAYER
::
GetError
(
void
)
{
return
error
;
}
pcbnew/exporters/vrml_board.h
deleted
100644 → 0
View file @
bd174ebf
/*
* file: vrml_board.h
*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 Cirilo Bernardo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vrml_board.h
*/
/*
* Classes and structures to support the tesselation of a
* PCB for VRML output.
*/
#ifndef VRML_BOARD_H
#define VRML_BOARD_H
#ifdef __WXMAC__
# ifdef __DARWIN__
# include <OpenGL/glu.h>
# else
# include <glu.h>
# endif
#else
# include <GL/glu.h>
#endif
#include <cstdio>
#include <vector>
#include <list>
#include <utility>
#ifndef M_PI2
#define M_PI2 ( M_PI / 2.0 )
#endif
#ifndef M_PI4
#define M_PI4 ( M_PI / 4.0 )
#endif
class
GLUtesselator
;
struct
VERTEX_3D
{
double
x
;
double
y
;
int
i
;
// vertex index
int
o
;
// vertex order
};
struct
TRIPLET_3D
{
int
i1
,
i2
,
i3
;
TRIPLET_3D
(
int
p1
,
int
p2
,
int
p3
)
{
i1
=
p1
;
i2
=
p2
;
i3
=
p3
;
}
};
class
VRML_LAYER
{
private
:
bool
fix
;
// when true, no more vertices may be added by the user
int
idx
;
// vertex index (number of contained vertices)
int
ord
;
// vertex order (number of ordered vertices)
std
::
vector
<
VERTEX_3D
*>
vertices
;
// vertices of all contours
std
::
vector
<
std
::
list
<
int
>*>
contours
;
// lists of vertices for each contour
std
::
vector
<
double
>
areas
;
// area of the contours (positive if winding is CCW)
std
::
list
<
TRIPLET_3D
>
triplets
;
// output facet triplet list (triplet of ORDER values)
std
::
list
<
std
::
list
<
int
>*>
outline
;
// indices for outline outputs (index by ORDER values)
std
::
vector
<
int
>
ordmap
;
// mapping of ORDER to INDEX
std
::
string
error
;
// error message
double
maxdev
;
// max. deviation from circle when calculating N sides
int
hidx
;
// number of vertices in the holes
int
eidx
;
// index for extra vertices
std
::
vector
<
VERTEX_3D
*>
extra_verts
;
// extra vertices added for outlines and facets
std
::
vector
<
VERTEX_3D
*>
vlist
;
// vertex list for the GL command in progress
VRML_LAYER
*
pholes
;
// pointer to another layer object used for tesselation;
// this object is normally expected to hold only holes
GLUtesselator
*
tess
;
// local instance of the GLU tesselator
GLenum
glcmd
;
// current GL command type ( fan, triangle, tri-strip, loop )
void
clearTmp
(
void
);
// clear ephemeral data used by the tesselation routine
// add a triangular facet (triplet) to the output index list
bool
addTriplet
(
VERTEX_3D
*
p0
,
VERTEX_3D
*
p1
,
VERTEX_3D
*
p2
);
// retrieve a vertex given its index; the vertex may be contained in the
// vertices vector, extra_verts vector, or foreign VRML_LAYER object
VERTEX_3D
*
getVertexByIndex
(
int
index
,
VRML_LAYER
*
holes
);
void
processFan
(
void
);
// process a GL_TRIANGLE_FAN list
void
processStrip
(
void
);
// process a GL_TRIANGLE_STRIP list
void
processTri
(
void
);
// process a GL_TRIANGLES list
void
pushVertices
(
bool
holes
);
// push the internal vertices
bool
pushOutline
(
VRML_LAYER
*
holes
);
// push the outline vertices
public
:
/// set to true when a fault is encountered during tesselation
bool
Fault
;
VRML_LAYER
();
virtual
~
VRML_LAYER
();
/**
* Function Clear
* erases all data.
*/
void
Clear
(
void
);
/**
* Function GetSize
* returns the total number of vertices indexed
*/
int
GetSize
(
void
);
/**
* Function SetMaxDev
* sets the maximum deviation from a circle; this parameter is
* used for the automatic calculation of segments within a
* circle or an arc.
*
* @param max is the maximum deviation from a perfect circle or arc;
* minimum value is 0.000002 units
*
* @return bool: true if the value was accepted
*/
bool
SetMaxDev
(
double
max
);
/**
* Function NewContour
* creates a new list of vertices and returns an index to the list
*
* @return int: index to the list or -1 if the operation failed
*/
int
NewContour
(
void
);
/**
* Function AddVertex
* adds a point to the requested contour
*
* @param aContour is an index previously returned by a call to NewContour()
* @param x is the X coordinate of the vertex
* @param y is the Y coordinate of the vertex
*
* @return bool: true if the vertex was added
*/
bool
AddVertex
(
int
aContour
,
double
x
,
double
y
);
/**
* Function EnsureWinding
* checks the winding of a contour and ensures that it is a hole or
* a solid depending on the value of @param hole
*
* @param aContour is an index to a contour as returned by NewContour()
* @param hole determines if the contour must be a hole
*
* @return bool: true if the operation suceeded
*/
bool
EnsureWinding
(
int
aContour
,
bool
hole
);
/**
* Function AddCircle
* creates a circular contour and adds it to the internal list
*
* @param x is the X coordinate of the hole center
* @param y is the Y coordinate of the hole center
* @param rad is the radius of the hole
* @param csides is the number of sides (segments) in a circle;
* use a value of 1 to automatically calculate a suitable number.
* @param hole determines if the contour to be created is a cutout
*
* @return bool: true if the new contour was successfully created
*/
bool
AddCircle
(
double
x
,
double
y
,
double
rad
,
int
csides
,
bool
hole
=
false
);
/**
* Function AddSlot
* creates and adds a slot feature to the list of contours
*
* @param cx is the X coordinate of the slot
* @param cy is the Y coordinate of the slot
* @param length is the length of the slot along the major axis
* @param width is the width of the slot along the minor axis
* @param angle (radians) is the orientation of the slot
* @param csides is the number of sides to a circle; use 1 to
* take advantage of automatic calculations.
* @param hole determines whether the slot is a hole or a solid
*
* @return bool: true if the slot was successfully created
*/
bool
AddSlot
(
double
cx
,
double
cy
,
double
length
,
double
width
,
double
angle
,
int
csides
,
bool
hole
=
false
);
/**
* Function AddArc
* creates an arc and adds it to the internal list of contours
*
* @param cx is the X coordinate of the arc's center
* @param cy is the Y coordinate of the arc's center
* @param startx is the X coordinate of the starting point
* @param starty is the Y coordinate of the starting point
* @param width is the width of the arc
* @param angle is the included angle
* @param csides is the number of segments in a circle; use 1
* to take advantage of automatic calculations of this number
* @param hole determined whether the arc is to be a hole or a solid
*
* @return bool: true if the feature was successfully created
*/
bool
AddArc
(
double
cx
,
double
cy
,
double
startx
,
double
starty
,
double
width
,
double
angle
,
int
csides
,
bool
hole
=
false
);
/**
* Function Tesselate
* creates a list of outline vertices as well as the
* vertex sets required to render the surface.
*
* @param holes is a pointer to cutouts to be imposed on the
* surface.
*
* @return bool: true if the operation succeeded
*/
bool
Tesselate
(
VRML_LAYER
*
holes
);
/**
* Function WriteVertices
* writes out the list of vertices required to render a
* planar surface.
*
* @param z is the Z coordinate of the plane
* @param fp is the file to write to
*
* @return bool: true if the operation succeeded
*/
bool
WriteVertices
(
double
z
,
FILE
*
fp
);
/**
* Function Write3DVertices
* writes out the list of vertices required to render an extruded solid
*
* @param top is the Z coordinate of the top plane
* @param bottom is the Z coordinate of the bottom plane
* @param fp is the file to write to
*
* @return bool: true if the operation succeeded
*/
bool
Write3DVertices
(
double
top
,
double
bottom
,
FILE
*
fp
);
/**
* Function WriteIndices
* writes out the vertex sets required to render a planar
* surface.
*
* @param top is true if the surface is to be visible from above;
* if false the surface will be visible from below.
* @param fp is the file to write to
*
* @return bool: true if the operation succeeded
*/
bool
WriteIndices
(
bool
top
,
FILE
*
fp
);
/**
* Function Write3DIndices
* writes out the vertex sets required to render an extruded solid
*
* @param fp is the file to write to
*
* @return bool: true if the operation succeeded
*/
bool
Write3DIndices
(
FILE
*
fp
);
/**
* Function AddExtraVertex
* adds an extra vertex as required by the GLU tesselator
*
* @return VERTEX_3D*: is the new vertex or NULL if a vertex
* could not be created.
*/
VERTEX_3D
*
AddExtraVertex
(
double
x
,
double
y
);
/**
* Function glStart
* is invoked by the GLU tesselator callback to notify this object
* of the type of GL command which is applicable to the upcoming
* vertex list.
*
* @param cmd is the GL command
*/
void
glStart
(
GLenum
cmd
);
/**
* Function glPushVertex
* is invoked by the GLU tesselator callback; the supplied vertex is
* added to the internal list of vertices awaiting processing upon
* execution of glEnd()
*
* @param vertex is a vertex forming part of the GL command as previously
* set by glStart
*/
void
glPushVertex
(
VERTEX_3D
*
vertex
);
/**
* Function glEnd
* is invoked by the GLU tesselator callback to notify this object
* that the vertex list is complete and ready for processing
*/
void
glEnd
(
void
);
/**
* Function SetGLError
* sets the error message according to the specified OpenGL error
*/
void
SetGLError
(
GLenum
error_id
);
/**
* Function Import
* inserts all contours into the given tesselator; this
* results in the renumbering of all vertices from @param start.
* Take care when using this call since tesselators cannot work on
* the internal data concurrently.
*
* @param start is the starting number for vertex indices
* @param tess is a pointer to a GLU Tesselator object
*
* @return int: the number of vertices exported
*/
int
Import
(
int
start
,
GLUtesselator
*
tess
);
/**
* Function GetVertexByIndex
* returns a pointer to the requested vertex or
* NULL if no such vertex exists.
*
* @param ptindex is a vertex index
*
* @return VERTEX_3D*: the requested vertex or NULL
*/
VERTEX_3D
*
GetVertexByIndex
(
int
ptindex
);
/*
* Function GetError
* Returns the error message related to the last failed operation
*/
const
std
::
string
&
GetError
(
void
);
};
#endif // VRML_BOARD_H
utils/idftools/idf_outlines.cpp
View file @
53cd19a6
...
...
@@ -775,7 +775,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
5
)
<<
aOutline
->
front
()
->
startPoint
.
x
<<
" "
<<
aOutline
->
front
()
->
startPoint
.
y
<<
" "
<<
setprecision
(
5
)
<<
-
aOutline
->
front
()
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
-
aOutline
->
front
()
->
angle
<<
"
\n
"
;
}
}
else
...
...
@@ -799,7 +799,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
1
)
<<
(
aOutline
->
front
()
->
startPoint
.
x
/
IDF_THOU_TO_MM
)
<<
" "
<<
(
aOutline
->
front
()
->
startPoint
.
y
/
IDF_THOU_TO_MM
)
<<
" "
<<
setprecision
(
5
)
<<
-
aOutline
->
front
()
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
-
aOutline
->
front
()
->
angle
<<
"
\n
"
;
}
}
...
...
@@ -819,7 +819,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
5
)
<<
(
*
bo
)
->
startPoint
.
x
<<
" "
<<
(
*
bo
)
->
startPoint
.
y
<<
" "
<<
setprecision
(
5
)
<<
-
(
*
bo
)
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
-
(
*
bo
)
->
angle
<<
"
\n
"
;
}
}
else
...
...
@@ -835,7 +835,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
1
)
<<
((
*
bo
)
->
startPoint
.
x
/
IDF_THOU_TO_MM
)
<<
" "
<<
((
*
bo
)
->
startPoint
.
y
/
IDF_THOU_TO_MM
)
<<
" "
<<
setprecision
(
5
)
<<
-
(
*
bo
)
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
-
(
*
bo
)
->
angle
<<
"
\n
"
;
}
}
...
...
@@ -869,7 +869,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
5
)
<<
(
*
bo
)
->
endPoint
.
x
<<
" "
<<
(
*
bo
)
->
endPoint
.
y
<<
" "
<<
setprecision
(
5
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
}
}
else
...
...
@@ -893,7 +893,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
1
)
<<
((
*
bo
)
->
endPoint
.
x
/
IDF_THOU_TO_MM
)
<<
" "
<<
((
*
bo
)
->
endPoint
.
y
/
IDF_THOU_TO_MM
)
<<
" "
<<
setprecision
(
5
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
}
}
...
...
@@ -915,7 +915,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
5
)
<<
(
*
bo
)
->
endPoint
.
x
<<
" "
<<
(
*
bo
)
->
endPoint
.
y
<<
" "
<<
setprecision
(
5
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
}
}
else
...
...
@@ -931,7 +931,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
aBoardFile
<<
aIndex
<<
" "
<<
setiosflags
(
ios
::
fixed
)
<<
setprecision
(
1
)
<<
((
*
bo
)
->
endPoint
.
x
/
IDF_THOU_TO_MM
)
<<
" "
<<
((
*
bo
)
->
endPoint
.
y
/
IDF_THOU_TO_MM
)
<<
" "
<<
setprecision
(
5
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
<<
setprecision
(
2
)
<<
(
*
bo
)
->
angle
<<
"
\n
"
;
}
}
...
...
@@ -1281,7 +1281,7 @@ bool BOARD_OUTLINE::addOutline( IDF_OUTLINE* aOutline )
outlines
.
push_back
(
aOutline
);
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
errormsg
=
e
.
what
();
...
...
utils/idftools/idf_parser.cpp
View file @
53cd19a6
...
...
@@ -2382,7 +2382,7 @@ void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstitute
}
}
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
brd
.
exceptions
(
std
::
ios_base
::
goodbit
);
...
...
@@ -2689,7 +2689,7 @@ void IDF3_BOARD::readLibFile( const std::string& aFileName )
while
(
lib
.
good
()
)
readLibSection
(
lib
,
state
,
this
);
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
lib
.
exceptions
(
std
::
ios_base
::
goodbit
);
...
...
@@ -2773,7 +2773,7 @@ bool IDF3_BOARD::ReadFile( const wxString& aFullFileName, bool aNoSubstituteOutl
// read the board file
readBoardFile
(
bfname
,
aNoSubstituteOutlines
);
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
Clear
();
errormsg
=
e
.
what
();
...
...
@@ -2821,7 +2821,7 @@ bool IDF3_BOARD::writeLibFile( const std::string& aFileName )
}
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
lib
.
exceptions
(
std
::
ios_base
::
goodbit
);
...
...
@@ -3065,7 +3065,7 @@ void IDF3_BOARD::writeBoardFile( const std::string& aFileName )
}
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
brd
.
exceptions
(
std
::
ios_base
::
goodbit
);
...
...
@@ -3137,7 +3137,7 @@ bool IDF3_BOARD::WriteFile( const wxString& aFullFileName, bool aUnitMM, bool aF
writeBoardFile
(
bfname
);
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
errormsg
=
e
.
what
();
...
...
@@ -3901,7 +3901,7 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( wxString aFullFileName )
}
}
// while( true )
}
catch
(
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
delete
cp
;
...
...
utils/idftools/vrml_layer.cpp
View file @
53cd19a6
...
...
@@ -230,8 +230,7 @@ void VRML_LAYER::Clear( void )
contours
.
pop_back
();
}
while
(
!
areas
.
empty
()
)
areas
.
pop_back
();
areas
.
clear
();
for
(
i
=
vertices
.
size
();
i
>
0
;
--
i
)
{
...
...
@@ -254,8 +253,7 @@ void VRML_LAYER::clearTmp( void )
ord
=
0
;
glcmd
=
0
;
while
(
!
triplets
.
empty
()
)
triplets
.
pop_back
();
triplets
.
clear
();
for
(
i
=
outline
.
size
();
i
>
0
;
--
i
)
{
...
...
@@ -263,8 +261,7 @@ void VRML_LAYER::clearTmp( void )
outline
.
pop_back
();
}
for
(
i
=
ordmap
.
size
();
i
>
0
;
--
i
)
ordmap
.
pop_back
();
ordmap
.
clear
();
for
(
i
=
extra_verts
.
size
();
i
>
0
;
--
i
)
{
...
...
@@ -274,8 +271,7 @@ void VRML_LAYER::clearTmp( void )
// note: unlike outline and extra_verts,
// vlist is not responsible for memory management
for
(
i
=
vlist
.
size
();
i
>
0
;
--
i
)
vlist
.
pop_back
();
vlist
.
clear
();
// go through the vertex list and reset ephemeral parameters
for
(
i
=
0
;
i
<
vertices
.
size
();
++
i
)
...
...
@@ -743,6 +739,7 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
// open the polygon
gluTessBeginPolygon
(
tess
,
this
);
// add solid outlines
pushVertices
(
false
);
// close the polygon
...
...
@@ -751,8 +748,10 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
if
(
Fault
)
return
false
;
// push the (solid) outline to the tesselator
if
(
!
pushOutline
(
holes
)
)
// at this point we have a solid outline; add it to the tesselator
gluTessBeginPolygon
(
tess
,
this
);
if
(
!
pushOutline
(
NULL
)
)
return
false
;
// add the holes contained by this object
...
...
@@ -772,14 +771,14 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
// erase the previous outline data and vertex order
// but preserve the extra vertices
for
(
int
i
=
outline
.
size
();
i
>
0
;
--
i
)
while
(
!
outline
.
empty
()
)
{
delete
outline
.
back
();
outline
.
pop_back
();
}
for
(
unsigned
int
i
=
ordmap
.
size
();
i
>
0
;
--
i
)
ordmap
.
pop_back
()
;
ordmap
.
clear
();
ord
=
0
;
// go through the vertex lists and reset ephemeral parameters
for
(
unsigned
int
i
=
0
;
i
<
vertices
.
size
();
++
i
)
...
...
@@ -792,14 +791,16 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
extra_verts
[
i
]
->
o
=
-
1
;
}
ord
=
0
;
// close the polygon; we now have all the data necessary for the tesselation
// close the polygon; this creates the outline points
// and the point ordering list 'ordmap'
gluTessEndPolygon
(
tess
);
// request a tesselated surface
// repeat the last operation but request a tesselated surface
// rather than an outline; this creates the triangles list.
gluTessProperty
(
tess
,
GLU_TESS_BOUNDARY_ONLY
,
GL_FALSE
);
gluTessBeginPolygon
(
tess
,
this
);
if
(
!
pushOutline
(
holes
)
)
return
false
;
...
...
@@ -821,8 +822,6 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
return
false
;
}
gluTessBeginPolygon
(
tess
,
this
);
std
::
list
<
std
::
list
<
int
>*>::
const_iterator
obeg
=
outline
.
begin
();
std
::
list
<
std
::
list
<
int
>*>::
const_iterator
oend
=
outline
.
end
();
...
...
@@ -851,6 +850,7 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
if
(
pi
<
0
||
(
unsigned
int
)
pi
>
ordmap
.
size
()
)
{
gluTessEndContour
(
tess
);
error
=
"pushOutline():BUG: *outline.begin() is not a valid index to ordmap"
;
return
false
;
}
...
...
@@ -862,6 +862,7 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
if
(
!
vp
)
{
gluTessEndContour
(
tess
);
error
=
"pushOutline():: BUG: ordmap[n] is not a valid index to vertices[]"
;
return
false
;
}
...
...
@@ -1194,9 +1195,9 @@ bool VRML_LAYER::addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 )
double
dy0
=
p1
->
y
-
p0
->
y
;
double
dy1
=
p2
->
y
-
p0
->
y
;
// this number is chosen because we shall only write
6
decimal places
// on the VRML output
double
err
=
0.000001
;
// this number is chosen because we shall only write
9
decimal places
//
at most
on the VRML output
double
err
=
0.00000
000
1
;
// test if the triangles are degenerate (parallel sides)
...
...
utils/idftools/vrml_layer.h
View file @
53cd19a6
...
...
@@ -96,6 +96,7 @@ private:
bool
fix
;
// when true, no more vertices may be added by the user
int
idx
;
// vertex index (number of contained vertices)
int
ord
;
// vertex order (number of ordered vertices)
unsigned
int
idxout
;
// outline index to first point in 3D outline
std
::
vector
<
VERTEX_3D
*>
vertices
;
// vertices of all contours
std
::
vector
<
std
::
list
<
int
>*>
contours
;
// lists of vertices for each contour
std
::
vector
<
double
>
areas
;
// area of the contours (positive if winding is CCW)
...
...
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