Apply vrml_layer_pth, from Cirilo Bernardo

This commit is contained in:
unknown 2014-06-16 14:02:15 +02:00 committed by jean-pierre charras
parent 52d2e7eb59
commit a91eabb805
3 changed files with 396 additions and 155 deletions

View File

@ -25,37 +25,6 @@
*/
/*
* NOTE:
* 1. for improved looks, create a DRILL layer for PTH drills.
* To render the improved board, render the vertical outline only
* for the board (no added drill holes), then render the
* outline only for PTH, and finally render the top and bottom
* of the board. NOTE: if we don't want extra eye-candy then
* we must maintain the current board export.
* Additional bits needed for improved eyecandy:
* + CalcOutline: calculates only the outline of a VRML_LAYER or
* a VERTICAL_HOLES
* + WriteVerticalIndices: writes the indices of only the vertical
* facets of a VRML_LAYER or a VRML_HOLES.
* + WriteVerticalVertices: writes only the outline vertices to
* form vertical walls; applies to VRML_LAYER and VRML_HOLES
*
* 2. How can we suppress fiducials such as those in the corners of the pic-programmer demo?
*
*/
/*
* 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>
#include <kicad_string.h>
#include <wxPcbStruct.h>
@ -88,7 +57,7 @@
#define MIN_VRML_LINEWIDTH 0.12
// offset for art layers, mm (silk, paste, etc)
#define ART_OFFSET 0.02
#define ART_OFFSET 0.025
/* helper function:
* some characters cannot be used in names,
@ -183,6 +152,7 @@ public:
VRML_LAYER bot_silk;
VRML_LAYER top_tin;
VRML_LAYER bot_tin;
VRML_LAYER plated_holes;
double scale; // board internal units to output scaling
double minLineWidth; // minimum width of a VRML line segment
@ -229,8 +199,18 @@ public:
void SetOffset( double aXoff, double aYoff )
{
tx = aXoff;
ty = aYoff;
tx = aXoff;
ty = -aYoff;
holes.SetVertexOffsets( aXoff, aYoff );
board.SetVertexOffsets( aXoff, aYoff );
top_copper.SetVertexOffsets( aXoff, aYoff );
bot_copper.SetVertexOffsets( aXoff, aYoff );
top_silk.SetVertexOffsets( aXoff, aYoff );
bot_silk.SetVertexOffsets( aXoff, aYoff );
top_tin.SetVertexOffsets( aXoff, aYoff );
bot_tin.SetVertexOffsets( aXoff, aYoff );
plated_holes.SetVertexOffsets( aXoff, aYoff );
}
double GetLayerZ( LAYER_NUM aLayer )
@ -278,6 +258,7 @@ public:
bot_silk.SetArcParams( iMaxSeg, smin, smax );
top_tin.SetArcParams( iMaxSeg, smin, smax );
bot_tin.SetArcParams( iMaxSeg, smin, smax );
plated_holes.SetArcParams( iMaxSeg, smin, smax );
return true;
}
@ -455,6 +436,16 @@ static void write_layers( MODEL_VRML& aModel, std::ofstream& output_file, BOARD*
- Millimeter2iu( ART_OFFSET / 2.0 ) * aModel.scale,
0, aModel.precision );
// VRML_LAYER PTH;
aModel.plated_holes.Tesselate( NULL, true );
write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TIN ),
&aModel.plated_holes, false, false,
aModel.GetLayerZ( LAST_COPPER_LAYER )
+ Millimeter2iu( ART_OFFSET / 2.0 ) * aModel.scale,
aModel.GetLayerZ( FIRST_COPPER_LAYER )
- Millimeter2iu( ART_OFFSET / 2.0 ) * aModel.scale,
aModel.precision );
// VRML_LAYER top_silk;
aModel.top_silk.Tesselate( &aModel.holes );
write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_SILK ),
@ -588,10 +579,10 @@ static void export_vrml_drawsegment( MODEL_VRML& aModel, DRAWSEGMENT* drawseg )
{
LAYER_NUM layer = drawseg->GetLayer();
double w = drawseg->GetWidth() * aModel.scale;
double x = drawseg->GetStart().x * aModel.scale + aModel.tx;
double y = drawseg->GetStart().y * aModel.scale + aModel.ty;
double xf = drawseg->GetEnd().x * aModel.scale + aModel.tx;
double yf = drawseg->GetEnd().y * aModel.scale + aModel.ty;
double x = drawseg->GetStart().x * aModel.scale;
double y = drawseg->GetStart().y * aModel.scale;
double xf = drawseg->GetEnd().x * aModel.scale;
double yf = drawseg->GetEnd().y * aModel.scale;
// Items on the edge layer are handled elsewhere; just return
if( layer == EDGE_N )
@ -626,12 +617,10 @@ static void vrml_text_callback( int x0, int y0, int xf, int yf )
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( *model_vrml, s_text_layer,
x0 * scale + tx, y0 * scale + ty,
xf * scale + tx, yf * scale + ty,
x0 * scale, y0 * scale,
xf * scale, yf * scale,
s_text_width * scale );
}
@ -729,8 +718,6 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
}
double scale = aModel.scale;
double dx = aModel.tx;
double dy = aModel.ty;
int i = 0;
int seg;
@ -756,8 +743,8 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
if( bufferPcbOutlines[i].end_contour )
break;
aModel.board.AddVertex( seg, bufferPcbOutlines[i].x * scale + dx,
-(bufferPcbOutlines[i].y * scale + dy) );
aModel.board.AddVertex( seg, bufferPcbOutlines[i].x * scale,
-(bufferPcbOutlines[i].y * scale ) );
++i;
}
@ -788,8 +775,8 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
if( allLayerHoles[i].end_contour )
break;
aModel.holes.AddVertex( seg, allLayerHoles[i].x * scale + dx,
-(allLayerHoles[i].y * scale + dy) );
aModel.holes.AddVertex( seg, allLayerHoles[i].x * scale,
-(allLayerHoles[i].y * scale ) );
++i;
}
@ -849,8 +836,8 @@ static void export_vrml_via( MODEL_VRML& aModel, BOARD* pcb, const VIA* via )
hole = via->GetDrillValue() * aModel.scale / 2.0;
r = via->GetWidth() * aModel.scale / 2.0;
x = via->GetStart().x * aModel.scale + aModel.tx;
y = via->GetStart().y * aModel.scale + aModel.ty;
x = via->GetStart().x * aModel.scale;
y = via->GetStart().y * aModel.scale;
via->LayerPair( &top_layer, &bottom_layer );
// do not render a buried via
@ -873,10 +860,10 @@ static void export_vrml_tracks( MODEL_VRML& aModel, BOARD* pcb )
else if( track->GetLayer() == FIRST_COPPER_LAYER
|| track->GetLayer() == LAST_COPPER_LAYER )
export_vrml_line( aModel, track->GetLayer(),
track->GetStart().x * aModel.scale + aModel.tx,
track->GetStart().y * aModel.scale + aModel.ty,
track->GetEnd().x * aModel.scale + aModel.tx,
track->GetEnd().y * aModel.scale + aModel.ty,
track->GetStart().x * aModel.scale,
track->GetStart().y * aModel.scale,
track->GetEnd().x * aModel.scale,
track->GetEnd().y * aModel.scale,
track->GetWidth() * aModel.scale );
}
}
@ -886,9 +873,6 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
{
double scale = aModel.scale;
double dx = aModel.tx;
double dy = aModel.ty;
double x, y;
for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
@ -920,8 +904,8 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
while( i < nvert )
{
x = poly.GetX(i) * scale + dx;
y = -(poly.GetY(i) * scale + dy);
x = poly.GetX(i) * scale;
y = -(poly.GetY(i) * scale);
if( poly.IsEndContour(i) )
break;
@ -971,10 +955,10 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
double aOrientation )
{
LAYER_NUM layer = aOutline->GetLayer();
double x = aOutline->GetStart().x * aModel.scale + aModel.tx;
double y = aOutline->GetStart().y * aModel.scale + aModel.ty;
double xf = aOutline->GetEnd().x * aModel.scale + aModel.tx;
double yf = aOutline->GetEnd().y * aModel.scale + aModel.ty;
double x = aOutline->GetStart().x * aModel.scale;
double y = aOutline->GetStart().y * aModel.scale;
double xf = aOutline->GetEnd().x * aModel.scale;
double yf = aOutline->GetEnd().y * aModel.scale;
double w = aOutline->GetWidth() * aModel.scale;
switch( aOutline->GetShape() )
@ -1015,8 +999,8 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
corner.x += aOutline->GetPosition().x;
corner.y += aOutline->GetPosition().y;
x = corner.x * aModel.scale + aModel.tx;
y = - ( corner.y * aModel.scale + aModel.ty );
x = corner.x * aModel.scale;
y = - ( corner.y * aModel.scale );
if( !vl->AddVertex( seg, x, y ) )
throw( std::runtime_error( vl->GetError() ) );
@ -1037,8 +1021,8 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
{
// The (maybe offset) pad position
wxPoint pad_pos = aPad->ShapePos();
double pad_x = pad_pos.x * aModel.scale + aModel.tx;
double pad_y = pad_pos.y * aModel.scale + aModel.ty;
double pad_x = pad_pos.x * aModel.scale;
double pad_y = pad_pos.y * aModel.scale;
wxSize pad_delta = aPad->GetDelta();
double pad_dx = pad_delta.x * aModel.scale / 2.0;
@ -1121,22 +1105,36 @@ static void export_vrml_pad( MODEL_VRML& aModel, BOARD* pcb, D_PAD* aPad )
double hole_drill_w = (double) aPad->GetDrillSize().x * aModel.scale / 2.0;
double hole_drill_h = (double) aPad->GetDrillSize().y * aModel.scale / 2.0;
double hole_drill = std::min( hole_drill_w, hole_drill_h );
double hole_x = aPad->GetPosition().x * aModel.scale + aModel.tx;
double hole_y = aPad->GetPosition().y * aModel.scale + aModel.ty;
double hole_x = aPad->GetPosition().x * aModel.scale;
double hole_y = aPad->GetPosition().y * aModel.scale;
// Export the hole on the edge layer
if( hole_drill > 0 )
{
bool pth = false;
if( aPad->GetAttribute() != PAD_HOLE_NOT_PLATED )
pth = true;
if( aPad->GetDrillShape() == PAD_DRILL_OBLONG )
{
// Oblong hole (slot)
aModel.holes.AddSlot( hole_x, -hole_y, hole_drill_w * 2.0, hole_drill_h * 2.0,
aPad->GetOrientation()/10.0, true );
aPad->GetOrientation()/10.0, true, pth );
if( pth )
aModel.plated_holes.AddSlot( hole_x, -hole_y,
hole_drill_w * 2.0, hole_drill_h * 2.0,
aPad->GetOrientation()/10.0, true, false );
}
else
{
// Drill a round hole
aModel.holes.AddCircle( hole_x, -hole_y, hole_drill, true );
aModel.holes.AddCircle( hole_x, -hole_y, hole_drill, true, pth );
if( pth )
aModel.plated_holes.AddCircle( hole_x, -hole_y, hole_drill, true, false );
}
}
@ -1390,7 +1388,7 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName,
EDA_RECT bbbox = pcb->ComputeBoundingBox();
model3d.SetOffset( -model3d.scale * bbbox.Centre().x,
-model3d.scale * bbbox.Centre().y );
model3d.scale * bbbox.Centre().y );
output_file << " children [\n";

View File

@ -23,6 +23,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
// Wishlist:
// 1. crop anything outside the board outline on PTH, silk, and copper layers
// 2. on the PTH layer, handle cropped holes differently from others;
// these are assumed to be castellated edges and the profile is not
// a closed loop as assumed for all other outlines.
// 3. a scheme is needed to tell a castellated edge from a plain board edge
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
@ -137,12 +145,24 @@ static void CALLBACK vrml_tess_err( GLenum errorID, void* user_data )
}
static void CALLBACK vrml_tess_combine( GLdouble coords[3], void* vertex_data[4],
static void CALLBACK vrml_tess_combine( GLdouble coords[3], VERTEX_3D* 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] );
// the plating is set to true only if all are plated
bool plated = vertex_data[0]->pth;
if( !vertex_data[1]->pth )
plated = false;
if( vertex_data[2] && !vertex_data[2]->pth )
plated = false;
if( vertex_data[3] && !vertex_data[3]->pth )
plated = false;
*outData = lp->AddExtraVertex( coords[0], coords[1], plated );
}
@ -152,6 +172,8 @@ VRML_LAYER::VRML_LAYER()
maxArcSeg = 48;
minSegLength = 0.1;
maxSegLength = 0.5;
offsetX = 0.0;
offsetY = 0.0;
fix = false;
Fault = false;
@ -230,6 +252,8 @@ void VRML_LAYER::Clear( void )
contours.pop_back();
}
pth.clear();
areas.clear();
for( i = vertices.size(); i > 0; --i )
@ -254,6 +278,7 @@ void VRML_LAYER::clearTmp( void )
glcmd = 0;
triplets.clear();
solid.clear();
for( i = outline.size(); i > 0; --i )
{
@ -283,7 +308,7 @@ void VRML_LAYER::clearTmp( void )
// 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 )
int VRML_LAYER::NewContour( bool aPlatedHole )
{
if( fix )
return -1;
@ -296,6 +321,8 @@ int VRML_LAYER::NewContour( void )
contours.push_back( contour );
areas.push_back( 0.0 );
pth.push_back( aPlatedHole );
return contours.size() - 1;
}
@ -329,6 +356,7 @@ bool VRML_LAYER::AddVertex( int aContourID, double aXpos, double aYpos )
vertex->y = aYpos;
vertex->i = idx++;
vertex->o = -1;
vertex->pth = pth[ aContourID ];
VERTEX_3D* v2 = NULL;
@ -440,9 +468,15 @@ bool VRML_LAYER::AppendCircle( double aXpos, double aYpos,
// adds a circle the existing list; if 'hole' is true the contour is
// a hole. Returns true if OK.
bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag )
bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius,
bool aHoleFlag, bool aPlatedHole )
{
int pad = NewContour();
int pad;
if( aHoleFlag && aPlatedHole )
pad = NewContour( true );
else
pad = NewContour( false );
if( pad < 0 )
{
@ -458,7 +492,7 @@ bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, bool aHo
// contour is a hole. Returns true if OK.
bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY,
double aSlotLength, double aSlotWidth,
double aAngle, bool aHoleFlag )
double aAngle, bool aHoleFlag, bool aPlatedHole )
{
aAngle *= M_PI / 180.0;
@ -480,7 +514,12 @@ bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY,
double ang, da;
int i;
int pad = NewContour();
int pad;
if( aHoleFlag && aPlatedHole )
pad = NewContour( true );
else
pad = NewContour( false );
if( pad < 0 )
{
@ -578,7 +617,7 @@ bool VRML_LAYER::AppendArc( double aCenterX, double aCenterY, double aRadius,
// adds an arc with the given center, start point, pen width, and angle (degrees).
bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY,
double aArcWidth, double aAngle, bool aHoleFlag )
double aArcWidth, double aAngle, bool aHoleFlag, bool aPlatedHole )
{
aAngle *= M_PI / 180.0;
@ -636,7 +675,12 @@ bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, doubl
std::swap( iendy, isty );
}
int arc = NewContour();
int arc;
if( aHoleFlag && aPlatedHole )
arc = NewContour( true );
else
arc = NewContour( false );
if( arc < 0 )
{
@ -688,7 +732,7 @@ bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, doubl
// tesselates the contours in preparation for a 3D output;
// returns true if all was fine, false otherwise
bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
bool VRML_LAYER::Tesselate( VRML_LAYER* holes, bool aHolesOnly )
{
if( !tess )
{
@ -699,6 +743,12 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
pholes = holes;
Fault = false;
if( aHolesOnly )
gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NEGATIVE );
else
gluTessProperty( tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
if( contours.size() < 1 || vertices.size() < 3 )
{
error = "Tesselate(): not enough vertices";
@ -736,9 +786,37 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
eidx = idx + hidx;
if( aHolesOnly && ( checkNContours( true ) == 0 ) )
{
error = "tesselate(): no hole contours";
return false;
}
else if( !aHolesOnly && ( checkNContours( false ) == 0 ) )
{
error = "tesselate(): no solid contours";
return false;
}
// open the polygon
gluTessBeginPolygon( tess, this );
if( aHolesOnly )
{
pholes = NULL; // do not accept foreign holes
hidx = 0;
eidx = idx;
// add holes
pushVertices( true );
gluTessEndPolygon( tess );
if( Fault )
return false;
return true;
}
// add solid outlines
pushVertices( false );
@ -748,6 +826,13 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
if( Fault )
return false;
// if there are no outlines we cannot proceed
if( outline.empty() )
{
error = "tesselate(): no points in result";
return false;
}
// at this point we have a solid outline; add it to the tesselator
gluTessBeginPolygon( tess, this );
@ -793,6 +878,7 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes )
// close the polygon; this creates the outline points
// and the point ordering list 'ordmap'
solid.clear();
gluTessEndPolygon( tess );
// repeat the last operation but request a tesselated surface
@ -825,6 +911,8 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
std::list<std::list<int>*>::const_iterator obeg = outline.begin();
std::list<std::list<int>*>::const_iterator oend = outline.end();
int nc = 0; // number of contours pushed
int pi;
std::list<int>::const_iterator begin;
std::list<int>::const_iterator end;
@ -876,6 +964,13 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
gluTessEndContour( tess );
++obeg;
++nc;
}
if( !nc )
{
error = "pushOutline():: no valid contours available";
return false;
}
return true;
@ -902,7 +997,7 @@ bool VRML_LAYER::WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPr
return false;
std::string strx, stry, strz;
FormatDoublet( vp->x, vp->y, aPrecision, strx, stry );
FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
FormatSinglet( aZcoord, aPrecision, strz );
aOutFile << strx << " " << stry << " " << strz;
@ -914,7 +1009,7 @@ bool VRML_LAYER::WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPr
if( !vp )
return false;
FormatDoublet( vp->x, vp->y, aPrecision, strx, stry );
FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
if( i & 1 )
aOutFile << ", " << strx << " " << stry << " " << strz;
@ -954,7 +1049,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
return false;
std::string strx, stry, strz;
FormatDoublet( vp->x, vp->y, aPrecision, strx, stry );
FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
FormatSinglet( aTopZ, aPrecision, strz );
aOutFile << strx << " " << stry << " " << strz;
@ -966,7 +1061,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
if( !vp )
return false;
FormatDoublet( vp->x, vp->y, aPrecision, strx, stry );
FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
if( i & 1 )
aOutFile << ", " << strx << " " << stry << " " << strz;
@ -976,7 +1071,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
// repeat for the bottom layer
vp = getVertexByIndex( ordmap[0], pholes );
FormatDoublet( vp->x, vp->y, aPrecision, strx, stry );
FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
FormatSinglet( aBottomZ, aPrecision, strz );
bool endl;
@ -995,7 +1090,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
for( i = 1, j = ordmap.size(); i < j; ++i )
{
vp = getVertexByIndex( ordmap[i], pholes );
FormatDoublet( vp->x, vp->y, aPrecision, strx, stry );
FormatDoublet( vp->x + offsetX, vp->y + offsetY, aPrecision, strx, stry );
if( endl )
{
@ -1064,68 +1159,73 @@ bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ofstream& aOutFile )
// writes out the index list for a 3D feature
bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile )
bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile, bool aIncludePlatedHoles )
{
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();
char mark;
bool holes_only = triplets.empty();
int i = 1;
int idx2 = ordmap.size(); // index to the bottom vertices
// print out the top vertices
aOutFile << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
++tbeg;
while( tbeg != tend )
if( !holes_only )
{
if( (i++ & 7) == 4 )
{
i = 1;
aOutFile << ",\n" << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
}
else
{
aOutFile << ", " << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
}
mark = ',';
// 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();
// print out the top vertices
aOutFile << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
++tbeg;
}
// print out the bottom vertices
tbeg = triplets.begin();
while( tbeg != tend )
{
if( (i++ & 7) == 4 )
{
i = 1;
aOutFile << ",\n" << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
}
else
{
aOutFile << ", " << tbeg->i1 << ", " << tbeg->i2 << ", " << tbeg->i3 << ", -1";
}
while( tbeg != tend )
{
if( (i++ & 7) == 4 )
{
i = 1;
aOutFile << ",\n" << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1";
}
else
{
aOutFile << ", " << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1";
++tbeg;
}
++tbeg;
// print out the bottom vertices
tbeg = triplets.begin();
while( tbeg != tend )
{
if( (i++ & 7) == 4 )
{
i = 1;
aOutFile << ",\n" << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1";
}
else
{
aOutFile << ", " << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1";
}
++tbeg;
}
}
else
mark = ' ';
// print out indices for the walls joining top to bottom
int firstPoint;
int lastPoint;
int curPoint;
int curContour = 0;
std::list<std::list<int>*>::const_iterator obeg = outline.begin();
std::list<std::list<int>*>::const_iterator oend = outline.end();
@ -1141,22 +1241,71 @@ bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile )
if( cp->size() < 3 )
{
++obeg;
++curContour;
continue;
}
cbeg = cp->begin();
cend = cp->end();
cbeg = cp->begin();
cend = cp->end();
lastPoint = *(cbeg++);
firstPoint = *(cbeg++);
lastPoint = firstPoint;
// skip all PTH vertices which are not in a solid outline
if( !aIncludePlatedHoles && !solid[curContour]
&& getVertexByIndex( ordmap[lastPoint], pholes )->pth )
{
++obeg;
++curContour;
continue;
}
while( cbeg != cend )
{
curPoint = *(cbeg++);
if( !holes_only )
{
if( (i++ & 3) == 2 )
{
i = 1;
aOutFile << mark << "\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
}
else
{
aOutFile << mark << " " << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
}
}
else
{
if( (i++ & 3) == 2 )
{
i = 1;
aOutFile << mark << "\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
}
else
{
aOutFile << mark << " " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
}
}
mark = ',';
lastPoint = curPoint;
}
// check if the loop needs to be closed
cbeg = cp->begin();
cend = --cp->end();
curPoint = *(cbeg);
lastPoint = *(cend);
if( !holes_only )
{
if( (i++ & 3) == 2 )
{
i = 1;
aOutFile << ",\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
}
@ -1165,21 +1314,23 @@ bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile )
aOutFile << ", " << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
}
lastPoint = curPoint;
}
if( (i++ & 3) == 2 )
{
aOutFile << ",\n" << firstPoint << ", " << lastPoint << ", " << firstPoint + idx2;
aOutFile << ", -1, " << firstPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
}
else
{
aOutFile << ", " << firstPoint << ", " << lastPoint << ", " << firstPoint + idx2;
aOutFile << ", -1, " << firstPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
if( (i++ & 3) == 2 )
{
aOutFile << ",\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
}
else
{
aOutFile << ", " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
}
}
++obeg;
++curContour;
}
return !aOutFile.fail();
@ -1222,7 +1373,7 @@ bool VRML_LAYER::addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 )
// add an extra vertex (to be called only by the COMBINE callback)
VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos )
VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole )
{
VERTEX_3D* vertex = new VERTEX_3D;
@ -1239,6 +1390,7 @@ VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos )
vertex->y = aYpos;
vertex->i = eidx++;
vertex->o = -1;
vertex->pth = aPlatedHole;
extra_verts.push_back( vertex );
@ -1282,12 +1434,39 @@ void VRML_LAYER::glEnd( void )
if( !loop )
break;
for( unsigned int i = 0; i < vlist.size(); ++i )
double firstX = 0.0;
double firstY = 0.0;
double lastX, lastY;
double curX, curY;
double area = 0.0;
if( vlist.size() > 0 )
{
loop->push_back( vlist[i]->o );
loop->push_back( vlist[0]->o );
firstX = vlist[0]->x;
firstY = vlist[0]->y;
lastX = firstX;
lastY = firstY;
}
for( size_t i = 1; i < vlist.size(); ++i )
{
loop->push_back( vlist[i]->o );
curX = vlist[i]->x;
curY = vlist[i]->y;
area += ( curX - lastX ) * ( curY + lastY );
lastX = curX;
lastY = curY;
}
area += ( firstX - lastX ) * ( firstY + lastY );
outline.push_back( loop );
if( area <= 0.0 )
solid.push_back( true );
else
solid.push_back( false );
}
break;
@ -1398,6 +1577,31 @@ void VRML_LAYER::processTri( void )
}
int VRML_LAYER::checkNContours( bool holes )
{
int nc = 0; // number of contours
if( contours.empty() )
return 0;
std::list<int>::const_iterator begin;
std::list<int>::const_iterator end;
for( size_t i = 0; i < contours.size(); ++i )
{
if( contours[i]->size() < 3 )
continue;
if( ( holes && areas[i] <= 0.0 ) || ( !holes && areas[i] > 0.0 ) )
continue;
++nc;
}
return nc;
}
// push the internally held vertices
void VRML_LAYER::pushVertices( bool holes )
{
@ -1434,6 +1638,8 @@ void VRML_LAYER::pushVertices( bool holes )
gluTessEndContour( tess );
}
return;
}
@ -1564,3 +1770,11 @@ const std::string& VRML_LAYER::GetError( void )
{
return error;
}
void VRML_LAYER::SetVertexOffsets( double aXoffset, double aYoffset )
{
offsetX = aXoffset;
offsetY = aYoffset;
return;
}

View File

@ -70,6 +70,7 @@ struct VERTEX_3D
double y;
int i; // vertex index
int o; // vertex order
bool pth; // true for plate-through hole
};
struct TRIPLET_3D
@ -93,12 +94,18 @@ private:
double minSegLength; // min. segment length
double maxSegLength; // max. segment length
// Vertex offsets to work around a suspected GLU tesselator bug
double offsetX;
double offsetY;
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<bool>pth; // indicates whether a 'contour' is a PTH or not
std::vector<bool>solid; // indicates whether a 'contour' is a solid or a hole
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)
@ -136,6 +143,9 @@ private:
// calculate number of sides on an arc (angle is in radians)
int calcNSides( double aRadius, double aAngle );
// returns the number of solid or hole contours
int checkNContours( bool holes );
public:
/// set to true when a fault is encountered during tesselation
bool Fault;
@ -191,9 +201,11 @@ public:
* Function NewContour
* creates a new list of vertices and returns an index to the list
*
* @param aPlatedHole is true if the new contour will represent a plated hole
*
* @return int: index to the list or -1 if the operation failed
*/
int NewContour( void );
int NewContour( bool aPlatedHole = false );
/**
* Function AddVertex
@ -231,7 +243,8 @@ public:
*
* @return bool: true if the new contour was successfully created
*/
bool AppendCircle( double aXpos, double aYpos, double aRadius, int aContourID, bool aHoleFlag = false );
bool AppendCircle( double aXpos, double aYpos, double aRadius,
int aContourID, bool aHoleFlag = false );
/**
* Function AddCircle
@ -241,10 +254,12 @@ public:
* @param aYpos is the Y coordinate of the hole center
* @param aRadius is the radius of the hole
* @param aHoleFlag determines if the contour to be created is a cutout
* @param aPlatedHole is true if this is a plated hole
*
* @return bool: true if the new contour was successfully created
*/
bool AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag = false );
bool AddCircle( double aXpos, double aYpos, double aRadius,
bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Function AddSlot
@ -256,11 +271,12 @@ public:
* @param aSlotWidth is the width of the slot along the minor axis
* @param aAngle (degrees) is the orientation of the slot
* @param aHoleFlag determines whether the slot is a hole or a solid
* @param aPlatedHole is true if this is a plated slot
*
* @return bool: true if the slot was successfully created
*/
bool AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth,
double aAngle, bool aHoleFlag = false );
double aAngle, bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Function AppendArc
@ -289,11 +305,14 @@ public:
* @param aArcWidth is the width of the arc
* @param aAngle is the included angle (degrees)
* @param aHoleFlag determines whether the arc is to be a hole or a solid
* @param aPlatedHole is true if this is a plated slotted arc
*
* @return bool: true if the feature was successfully created
*/
bool AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY,
double aArcWidth, double aAngle, bool aHoleFlag = false );
bool AddArc( double aCenterX, double aCenterY,
double aStartX, double aStartY,
double aArcWidth, double aAngle,
bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Function Tesselate
@ -301,11 +320,12 @@ public:
* vertex sets required to render the surface.
*
* @param holes is an optional pointer to cutouts to be imposed on the
* surface.
* surface.
* @param aHolesOnly is true if the outline contains only holes
*
* @return bool: true if the operation succeeded
*/
bool Tesselate( VRML_LAYER* holes = NULL );
bool Tesselate( VRML_LAYER* holes = NULL, bool aHolesOnly = false );
/**
* Function WriteVertices
@ -351,19 +371,26 @@ public:
* writes out the vertex sets required to render an extruded solid
*
* @param aOutFile is the file to write to
* @param aIncludePlatedHoles is true if holes marked as plated should
* be rendered. Default is false since the user will usually
* render these holes in a different color
*
* @return bool: true if the operation succeeded
*/
bool Write3DIndices( std::ofstream& aOutFile );
bool Write3DIndices( std::ofstream& aOutFile, bool aIncludePlatedHoles = false );
/**
* Function AddExtraVertex
* adds an extra vertex as required by the GLU tesselator
* adds an extra vertex as required by the GLU tesselator.
*
* @param aXpos is the X coordinate of the newly created point
* @param aYpos is the Y coordinate of the newly created point
* @param aPlatedHole is true if this point is part of a plated hole
*
* @return VERTEX_3D*: is the new vertex or NULL if a vertex
* could not be created.
*/
VERTEX_3D* AddExtraVertex( double aXpos, double aYpos );
VERTEX_3D* AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole );
/**
* Function glStart
@ -429,6 +456,8 @@ public:
* Returns the error message related to the last failed operation
*/
const std::string& GetError( void );
void SetVertexOffsets( double aXoffset, double aYoffset );
};
#endif // VRML_LAYER_H