Use Clipper lib in 3D viewer, in calculations that crashed the 3D viewer when using boost:: polygon. Work in Progress.
This commit is contained in:
parent
a85964b8ad
commit
b9f1ada90b
|
@ -67,7 +67,7 @@
|
||||||
* B_Cu , B_Adhes, B_Paste ), B_SilkS
|
* B_Cu , B_Adhes, B_Paste ), B_SilkS
|
||||||
* used to calculate the Z orientation parameter for glNormal3f
|
* used to calculate the Z orientation parameter for glNormal3f
|
||||||
*/
|
*/
|
||||||
static GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
|
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -625,668 +625,6 @@ void EDA_3D_CANVAS::Redraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_3D_CANVAS::buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList )
|
|
||||||
{
|
|
||||||
// Board shadows are based on board dimension.
|
|
||||||
|
|
||||||
float xmin = m_boardAABBox.Min().x;
|
|
||||||
float xmax = m_boardAABBox.Max().x;
|
|
||||||
float ymin = m_boardAABBox.Min().y;
|
|
||||||
float ymax = m_boardAABBox.Max().y;
|
|
||||||
|
|
||||||
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;
|
|
||||||
|
|
||||||
// Shadow FRONT
|
|
||||||
glNewList( aFrontList, GL_COMPILE );
|
|
||||||
|
|
||||||
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );
|
|
||||||
|
|
||||||
glBegin (GL_QUADS);
|
|
||||||
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
|
|
||||||
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
|
|
||||||
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
|
|
||||||
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
|
|
||||||
|
|
||||||
// Shadow BACK
|
|
||||||
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;
|
|
||||||
|
|
||||||
glNewList( aBacklist, GL_COMPILE );
|
|
||||||
|
|
||||||
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( B_Paste ) );
|
|
||||||
|
|
||||||
glBegin (GL_QUADS);
|
|
||||||
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
|
|
||||||
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
|
|
||||||
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
|
|
||||||
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
|
|
||||||
// Shadow BOARD
|
|
||||||
|
|
||||||
// Floor shadow is based on axis alighned bounding box dimension
|
|
||||||
xmin = m_fastAABBox_Shadow.Min().x;
|
|
||||||
xmax = m_fastAABBox_Shadow.Max().x;
|
|
||||||
ymin = m_fastAABBox_Shadow.Min().y;
|
|
||||||
ymax = m_fastAABBox_Shadow.Max().y;
|
|
||||||
|
|
||||||
glNewList( aBoardList, GL_COMPILE );
|
|
||||||
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );
|
|
||||||
|
|
||||||
glBegin (GL_QUADS);
|
|
||||||
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, m_fastAABBox_Shadow.Min().z );
|
|
||||||
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, m_fastAABBox_Shadow.Min().z );
|
|
||||||
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, m_fastAABBox_Shadow.Min().z );
|
|
||||||
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, m_fastAABBox_Shadow.Min().z );
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
|
|
||||||
REPORTER* aErrorMessages, REPORTER* aActivity )
|
|
||||||
{
|
|
||||||
BOARD* pcb = GetBoard();
|
|
||||||
|
|
||||||
// If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas.
|
|
||||||
// If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas,
|
|
||||||
// but the calculation time is twice shorter.
|
|
||||||
bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES );
|
|
||||||
|
|
||||||
bool realistic_mode = isRealisticMode();
|
|
||||||
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
|
|
||||||
|
|
||||||
// Number of segments to convert a circle to polygon
|
|
||||||
// Boost polygon (at least v1.57 and previous) in very rare cases crashes
|
|
||||||
// when using 16 segments to approximate a circle.
|
|
||||||
// So using 18 segments is a workaround to try to avoid these crashes
|
|
||||||
// ( We already used this trick in plot_board_layers.cpp,
|
|
||||||
// see PlotSolderMaskLayer() )
|
|
||||||
const int segcountforcircle = 18;
|
|
||||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) );
|
|
||||||
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
|
||||||
// to reduce time calculations
|
|
||||||
// for holes and items which do not need
|
|
||||||
// a fine representation
|
|
||||||
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );
|
|
||||||
|
|
||||||
CPOLYGONS_LIST bufferPolys;
|
|
||||||
bufferPolys.reserve( 500000 ); // Reserve for large board: tracks mainly
|
|
||||||
// + zones when holes are removed from zones
|
|
||||||
|
|
||||||
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
|
|
||||||
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
|
|
||||||
allLayerHoles.reserve( 20000 );
|
|
||||||
|
|
||||||
// Build a polygon from edge cut items
|
|
||||||
wxString msg;
|
|
||||||
|
|
||||||
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
|
|
||||||
{
|
|
||||||
if( aErrorMessages )
|
|
||||||
{
|
|
||||||
msg << wxT("\n") <<
|
|
||||||
_("Unable to calculate the board outlines.\n"
|
|
||||||
"Therefore use the board boundary box.") << wxT("\n\n");
|
|
||||||
|
|
||||||
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CPOLYGONS_LIST bufferZonesPolys;
|
|
||||||
bufferZonesPolys.reserve( 300000 ); // Reserve for large board ( copper zones mainly )
|
|
||||||
// when holes are not removed from zones
|
|
||||||
|
|
||||||
CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer
|
|
||||||
bool throughHolesListBuilt = false; // flag to build the through hole polygon list only once
|
|
||||||
|
|
||||||
LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
LAYER_ID cu_seq[MAX_CU_LAYERS]; // preferred sequence, could have called CuStack()
|
|
||||||
// but I assume that's backwards
|
|
||||||
|
|
||||||
glNewList( aBoardList, GL_COMPILE );
|
|
||||||
|
|
||||||
for( unsigned i=0; i < DIM( cu_seq ); ++i )
|
|
||||||
cu_seq[i] = ToLAYER_ID( B_Cu - i );
|
|
||||||
|
|
||||||
for( LSEQ cu = cu_set.Seq( cu_seq, DIM(cu_seq) ); cu; ++cu )
|
|
||||||
#else
|
|
||||||
for( LSEQ cu = cu_set.CuStack(); cu; ++cu )
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
LAYER_ID layer = *cu;
|
|
||||||
|
|
||||||
// Skip non enabled layers in normal mode,
|
|
||||||
// and internal layers in realistic mode
|
|
||||||
if( !is3DLayerEnabled( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( aActivity )
|
|
||||||
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
|
|
||||||
|
|
||||||
bufferPolys.RemoveAllContours();
|
|
||||||
bufferZonesPolys.RemoveAllContours();
|
|
||||||
currLayerHoles.RemoveAllContours();
|
|
||||||
|
|
||||||
// Draw tracks:
|
|
||||||
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
|
|
||||||
{
|
|
||||||
if( !track->IsOnLayer( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
track->TransformShapeWithClearanceToPolygon( bufferPolys,
|
|
||||||
0, segcountforcircle,
|
|
||||||
correctionFactor );
|
|
||||||
|
|
||||||
// Add via hole
|
|
||||||
if( track->Type() == PCB_VIA_T )
|
|
||||||
{
|
|
||||||
VIA *via = static_cast<VIA*>( track );
|
|
||||||
VIATYPE_T viatype = via->GetViaType();
|
|
||||||
int holediameter = via->GetDrillValue();
|
|
||||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
|
||||||
int hole_outer_radius = (holediameter + thickness) / 2;
|
|
||||||
|
|
||||||
if( viatype != VIA_THROUGH )
|
|
||||||
TransformCircleToPolygon( currLayerHoles,
|
|
||||||
via->GetStart(), hole_outer_radius,
|
|
||||||
segcountLowQuality );
|
|
||||||
else if( !throughHolesListBuilt )
|
|
||||||
TransformCircleToPolygon( allLayerHoles,
|
|
||||||
via->GetStart(), hole_outer_radius,
|
|
||||||
segcountLowQuality );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw pads
|
|
||||||
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
|
||||||
// Note: NPTH pads are not drawn on copper layers when the pad
|
|
||||||
// has same shape as its hole
|
|
||||||
module->TransformPadsShapesWithClearanceToPolygon( layer,
|
|
||||||
bufferPolys,
|
|
||||||
0,
|
|
||||||
segcountforcircle,
|
|
||||||
correctionFactor, true );
|
|
||||||
|
|
||||||
// Micro-wave modules may have items on copper layers
|
|
||||||
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
|
|
||||||
bufferPolys,
|
|
||||||
0,
|
|
||||||
segcountforcircle,
|
|
||||||
correctionFactor );
|
|
||||||
|
|
||||||
// Add pad hole, if any
|
|
||||||
if( !throughHolesListBuilt )
|
|
||||||
{
|
|
||||||
D_PAD* pad = module->Pads();
|
|
||||||
|
|
||||||
for( ; pad; pad = pad->Next() )
|
|
||||||
{
|
|
||||||
// Calculate a factor to apply to segcount for large holes ( > 1 mm)
|
|
||||||
// (bigger pad drill size -> more segments) because holes in pads can have
|
|
||||||
// very different sizes and optimizing this segcount gives a better look
|
|
||||||
// Mainly mounting holes have a size bigger thon 1 mm
|
|
||||||
wxSize padHole = pad->GetDrillSize();
|
|
||||||
|
|
||||||
if( ! padHole.x ) // Not drilled pad like SMD pad
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// we use the hole diameter to calculate the seg count.
|
|
||||||
// for round holes, padHole.x == padHole.y
|
|
||||||
// for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
|
|
||||||
int diam = std::min( padHole.x, padHole.y );
|
|
||||||
double segFactor = (double)diam / Millimeter2iu( 1.0 );
|
|
||||||
|
|
||||||
int segcount = (int)(segcountLowQuality * segFactor);
|
|
||||||
|
|
||||||
// Clamp segcount between segcountLowQuality and 48.
|
|
||||||
// 48 segm for a circle is a very good approx.
|
|
||||||
segcount = Clamp( segcountLowQuality, segcount, 48 );
|
|
||||||
|
|
||||||
// The hole in the body is inflated by copper thickness.
|
|
||||||
int inflate = thickness;
|
|
||||||
|
|
||||||
// If not plated, no copper.
|
|
||||||
if( pad->GetAttribute () == PAD_HOLE_NOT_PLATED )
|
|
||||||
inflate = 0;
|
|
||||||
|
|
||||||
pad->BuildPadDrillShapePolygon( allLayerHoles, inflate, segcount );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw copper zones. Note:
|
|
||||||
// * if the holes are removed from copper zones
|
|
||||||
// the polygons are stored in bufferPolys (which contains all other polygons)
|
|
||||||
// * if the holes are NOT removed from copper zones
|
|
||||||
// the polygons are stored in bufferZonesPolys
|
|
||||||
if( isEnabled( FL_ZONE ) )
|
|
||||||
{
|
|
||||||
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
|
||||||
{
|
|
||||||
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
|
||||||
LAYER_NUM zonelayer = zone->GetLayer();
|
|
||||||
|
|
||||||
if( zonelayer == layer )
|
|
||||||
{
|
|
||||||
zone->TransformSolidAreasShapesToPolygonSet(
|
|
||||||
remove_Holes ? bufferPolys : bufferZonesPolys,
|
|
||||||
segcountLowQuality, correctionFactorLQ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw graphic items on copper layers (texts)
|
|
||||||
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
|
|
||||||
{
|
|
||||||
if( !item->IsOnLayer( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch( item->Type() )
|
|
||||||
{
|
|
||||||
case PCB_LINE_T: // should not exist on copper layers
|
|
||||||
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
|
||||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PCB_TEXT_T:
|
|
||||||
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
|
||||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bufferPolys contains polygons to merge. Many overlaps .
|
|
||||||
// Calculate merged polygons
|
|
||||||
if( bufferPolys.GetCornersCount() == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
KI_POLYGON_SET currLayerPolyset;
|
|
||||||
KI_POLYGON_SET polysetHoles;
|
|
||||||
|
|
||||||
// Add polygons, without holes
|
|
||||||
bufferPolys.ExportTo( currLayerPolyset );
|
|
||||||
|
|
||||||
// Add through holes (created only once) in current polygon holes list
|
|
||||||
currLayerHoles.Append( allLayerHoles );
|
|
||||||
|
|
||||||
if( currLayerHoles.GetCornersCount() > 0 )
|
|
||||||
currLayerHoles.ExportTo( polysetHoles );
|
|
||||||
|
|
||||||
// Merge polygons, and remove holes
|
|
||||||
currLayerPolyset -= polysetHoles;
|
|
||||||
|
|
||||||
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
|
|
||||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
|
|
||||||
|
|
||||||
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
|
|
||||||
|
|
||||||
// If we are not using thickness, then the znormal must face the layer direction
|
|
||||||
// because it will draw just one plane
|
|
||||||
if( !thickness )
|
|
||||||
zNormal = Get3DLayer_Z_Orientation( layer );
|
|
||||||
|
|
||||||
|
|
||||||
if( realistic_mode )
|
|
||||||
{
|
|
||||||
setGLCopperColor();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
|
|
||||||
SetGLColor( color );
|
|
||||||
}
|
|
||||||
|
|
||||||
bufferPolys.RemoveAllContours();
|
|
||||||
bufferPolys.ImportFrom( currLayerPolyset );
|
|
||||||
|
|
||||||
// If holes are removed from copper zones, bufferPolys contains all polygons
|
|
||||||
// to draw (tracks+zones+texts).
|
|
||||||
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness,
|
|
||||||
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
|
||||||
zNormal );
|
|
||||||
|
|
||||||
// If holes are not removed from copper zones (for calculation time reasons,
|
|
||||||
// the zone polygons are stored in bufferZonesPolys and have to be drawn now:
|
|
||||||
if( bufferZonesPolys.GetCornersCount() )
|
|
||||||
{
|
|
||||||
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
|
|
||||||
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
|
||||||
zNormal );
|
|
||||||
}
|
|
||||||
|
|
||||||
throughHolesListBuilt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( aActivity )
|
|
||||||
aActivity->Report( _( "Build board body" ) );
|
|
||||||
|
|
||||||
|
|
||||||
// Draw plated vertical holes inside the board, but not always. They are drawn:
|
|
||||||
// - if the board body is not shown, to show the holes.
|
|
||||||
// - or if the copper thickness is shown
|
|
||||||
if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) )
|
|
||||||
{
|
|
||||||
// Draw vias holes (vertical cylinders)
|
|
||||||
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
|
|
||||||
{
|
|
||||||
if( track->Type() == PCB_VIA_T )
|
|
||||||
{
|
|
||||||
const VIA *via = static_cast<const VIA*>(track);
|
|
||||||
draw3DViaHole( via );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw pads holes (vertical cylinders)
|
|
||||||
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
|
|
||||||
if( pad->GetAttribute () != PAD_HOLE_NOT_PLATED )
|
|
||||||
draw3DPadHole( pad );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
|
|
||||||
// Build the body board:
|
|
||||||
glNewList( aBodyOnlyList, GL_COMPILE );
|
|
||||||
|
|
||||||
if( isRealisticMode() )
|
|
||||||
{
|
|
||||||
setGLEpoxyColor( 1.00 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
|
|
||||||
SetGLColor( color, 0.7 );
|
|
||||||
}
|
|
||||||
|
|
||||||
float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
|
||||||
|
|
||||||
// a small offset between substrate and external copper layer to avoid artifacts
|
|
||||||
// when drawing copper items on board
|
|
||||||
float epsilon = Millimeter2iu( 0.01 );
|
|
||||||
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
|
||||||
float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
|
|
||||||
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
|
||||||
|
|
||||||
// items on copper layers and having a thickness = copper_thickness
|
|
||||||
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
|
|
||||||
// therefore substrate position is copper_thickness/2 to
|
|
||||||
// substrate_height - copper_thickness/2
|
|
||||||
zpos += (copper_thickness + epsilon) / 2.0f;
|
|
||||||
board_thickness -= copper_thickness + epsilon;
|
|
||||||
|
|
||||||
KI_POLYGON_SET currLayerPolyset;
|
|
||||||
KI_POLYGON_SET polysetHoles;
|
|
||||||
|
|
||||||
// Add polygons, without holes
|
|
||||||
bufferPcbOutlines.ExportTo( currLayerPolyset );
|
|
||||||
|
|
||||||
// Build holes list
|
|
||||||
allLayerHoles.ExportTo( polysetHoles );
|
|
||||||
|
|
||||||
// remove holes
|
|
||||||
currLayerPolyset -= polysetHoles;
|
|
||||||
|
|
||||||
bufferPcbOutlines.RemoveAllContours();
|
|
||||||
bufferPcbOutlines.ImportFrom( currLayerPolyset );
|
|
||||||
|
|
||||||
if( bufferPcbOutlines.GetCornersCount() )
|
|
||||||
{
|
|
||||||
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
|
|
||||||
board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
|
||||||
1.0f );
|
|
||||||
}
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
|
|
||||||
{
|
|
||||||
BOARD* pcb = GetBoard();
|
|
||||||
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
|
|
||||||
|
|
||||||
// Number of segments to draw a circle using segments
|
|
||||||
const int segcountforcircle = 18;
|
|
||||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
|
||||||
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
|
||||||
// to reduce time calculations
|
|
||||||
// for holes and items which do not need
|
|
||||||
// a fine representation
|
|
||||||
|
|
||||||
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );
|
|
||||||
|
|
||||||
CPOLYGONS_LIST bufferPolys;
|
|
||||||
bufferPolys.reserve( 100000 ); // Reserve for large board
|
|
||||||
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
|
|
||||||
allLayerHoles.reserve( 20000 );
|
|
||||||
|
|
||||||
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
|
|
||||||
|
|
||||||
// Build a polygon from edge cut items
|
|
||||||
wxString msg;
|
|
||||||
|
|
||||||
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
|
|
||||||
{
|
|
||||||
if( aErrorMessages )
|
|
||||||
{
|
|
||||||
msg << wxT("\n") <<
|
|
||||||
_("Unable to calculate the board outlines.\n"
|
|
||||||
"Therefore use the board boundary box.") << wxT("\n\n");
|
|
||||||
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
|
||||||
|
|
||||||
// Add via holes
|
|
||||||
for( VIA* via = GetFirstVia( pcb->m_Track ); via;
|
|
||||||
via = GetFirstVia( via->Next() ) )
|
|
||||||
{
|
|
||||||
VIATYPE_T viatype = via->GetViaType();
|
|
||||||
int holediameter = via->GetDrillValue();
|
|
||||||
int hole_outer_radius = (holediameter + thickness) / 2;
|
|
||||||
|
|
||||||
if( viatype == VIA_THROUGH )
|
|
||||||
TransformCircleToPolygon( allLayerHoles,
|
|
||||||
via->GetStart(), hole_outer_radius,
|
|
||||||
segcountLowQuality );
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw pads holes
|
|
||||||
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
// Add pad hole, if any
|
|
||||||
D_PAD* pad = module->Pads();
|
|
||||||
|
|
||||||
for( ; pad; pad = pad->Next() )
|
|
||||||
pad->BuildPadDrillShapePolygon( allLayerHoles, 0,
|
|
||||||
segcountLowQuality );
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw graphic items, on technical layers
|
|
||||||
|
|
||||||
KI_POLYGON_SET brdpolysetHoles;
|
|
||||||
allLayerHoles.ExportTo( brdpolysetHoles );
|
|
||||||
|
|
||||||
static const LAYER_ID teckLayerList[] = {
|
|
||||||
B_Adhes,
|
|
||||||
F_Adhes,
|
|
||||||
B_Paste,
|
|
||||||
F_Paste,
|
|
||||||
B_SilkS,
|
|
||||||
F_SilkS,
|
|
||||||
B_Mask,
|
|
||||||
F_Mask,
|
|
||||||
};
|
|
||||||
|
|
||||||
// User layers are not drawn here, only technical layers
|
|
||||||
for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) ); seq; ++seq )
|
|
||||||
{
|
|
||||||
LAYER_ID layer = *seq;
|
|
||||||
|
|
||||||
if( !is3DLayerEnabled( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( aActivity )
|
|
||||||
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
|
|
||||||
|
|
||||||
|
|
||||||
bufferPolys.RemoveAllContours();
|
|
||||||
|
|
||||||
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
|
|
||||||
{
|
|
||||||
if( !item->IsOnLayer( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch( item->Type() )
|
|
||||||
{
|
|
||||||
case PCB_LINE_T:
|
|
||||||
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
|
||||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PCB_TEXT_T:
|
|
||||||
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
|
||||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
if( layer == F_SilkS || layer == B_SilkS )
|
|
||||||
{
|
|
||||||
D_PAD* pad = module->Pads();
|
|
||||||
int linewidth = g_DrawDefaultLineThickness;
|
|
||||||
|
|
||||||
for( ; pad; pad = pad->Next() )
|
|
||||||
{
|
|
||||||
if( !pad->IsOnLayer( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
|
|
||||||
linewidth, segcountforcircle, correctionFactor );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
module->TransformPadsShapesWithClearanceToPolygon( layer,
|
|
||||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
|
||||||
|
|
||||||
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
|
|
||||||
bufferPolys, 0, segcountforcircle, correctionFactor );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw non copper zones
|
|
||||||
if( isEnabled( FL_ZONE ) )
|
|
||||||
{
|
|
||||||
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
|
||||||
{
|
|
||||||
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
|
||||||
|
|
||||||
if( !zone->IsOnLayer( layer ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
zone->TransformSolidAreasShapesToPolygonSet(
|
|
||||||
bufferPolys, segcountLowQuality, correctionFactorLQ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bufferPolys contains polygons to merge. Many overlaps .
|
|
||||||
// Calculate merged polygons and remove pads and vias holes
|
|
||||||
if( bufferPolys.GetCornersCount() == 0 )
|
|
||||||
continue;
|
|
||||||
KI_POLYGON_SET currLayerPolyset;
|
|
||||||
KI_POLYGON_SET polyset;
|
|
||||||
|
|
||||||
// Solder mask layers are "negative" layers.
|
|
||||||
// Shapes should be removed from the full board area.
|
|
||||||
if( layer == B_Mask || layer == F_Mask )
|
|
||||||
{
|
|
||||||
bufferPcbOutlines.ExportTo( currLayerPolyset );
|
|
||||||
bufferPolys.Append( allLayerHoles );
|
|
||||||
bufferPolys.ExportTo( polyset );
|
|
||||||
currLayerPolyset -= polyset;
|
|
||||||
}
|
|
||||||
// Remove holes from Solder paste layers and siklscreen
|
|
||||||
else if( layer == B_Paste || layer == F_Paste
|
|
||||||
|| layer == B_SilkS || layer == F_SilkS )
|
|
||||||
{
|
|
||||||
bufferPolys.ExportTo( currLayerPolyset );
|
|
||||||
currLayerPolyset -= brdpolysetHoles;
|
|
||||||
}
|
|
||||||
else // usuall layers, merge polys built from each item shape:
|
|
||||||
{
|
|
||||||
bufferPolys.ExportTo( polyset );
|
|
||||||
currLayerPolyset += polyset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int thickness = 0;
|
|
||||||
|
|
||||||
if( layer != B_Mask && layer != F_Mask )
|
|
||||||
thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
|
|
||||||
|
|
||||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
|
|
||||||
|
|
||||||
if( layer == Edge_Cuts )
|
|
||||||
{
|
|
||||||
thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
|
|
||||||
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
|
||||||
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
|
|
||||||
+ (thickness / 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
|
|
||||||
// sides.
|
|
||||||
// However for top layers, zpos should be the bottom layer pos,
|
|
||||||
// and for bottom layers, zpos should be the top layer pos.
|
|
||||||
if( Get3DLayer_Z_Orientation( layer ) > 0 )
|
|
||||||
zpos += thickness/2;
|
|
||||||
else
|
|
||||||
zpos -= thickness/2 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufferPolys.RemoveAllContours();
|
|
||||||
bufferPolys.ImportFrom( currLayerPolyset );
|
|
||||||
|
|
||||||
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
|
|
||||||
|
|
||||||
// If we are not using thickness, then the znormal must face the layer direction
|
|
||||||
// because it will draw just one plane
|
|
||||||
if( !thickness )
|
|
||||||
zNormal = Get3DLayer_Z_Orientation( layer );
|
|
||||||
|
|
||||||
|
|
||||||
setGLTechLayersColor( layer );
|
|
||||||
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
|
|
||||||
thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
|
||||||
zNormal );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function buildBoard3DAuxLayers
|
* Function buildBoard3DAuxLayers
|
||||||
* Called by CreateDrawGL_List()
|
* Called by CreateDrawGL_List()
|
||||||
|
@ -1398,6 +736,70 @@ void EDA_3D_CANVAS::buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EDA_3D_CANVAS::buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList )
|
||||||
|
{
|
||||||
|
// Board shadows are based on board dimension.
|
||||||
|
|
||||||
|
float xmin = m_boardAABBox.Min().x;
|
||||||
|
float xmax = m_boardAABBox.Max().x;
|
||||||
|
float ymin = m_boardAABBox.Min().y;
|
||||||
|
float ymax = m_boardAABBox.Max().y;
|
||||||
|
|
||||||
|
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;
|
||||||
|
|
||||||
|
// Shadow FRONT
|
||||||
|
glNewList( aFrontList, GL_COMPILE );
|
||||||
|
|
||||||
|
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );
|
||||||
|
|
||||||
|
glBegin (GL_QUADS);
|
||||||
|
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
|
||||||
|
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
|
||||||
|
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
|
||||||
|
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glEndList();
|
||||||
|
|
||||||
|
|
||||||
|
// Shadow BACK
|
||||||
|
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits;
|
||||||
|
|
||||||
|
glNewList( aBacklist, GL_COMPILE );
|
||||||
|
|
||||||
|
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( B_Paste ) );
|
||||||
|
|
||||||
|
glBegin (GL_QUADS);
|
||||||
|
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmin, ymin, zpos );
|
||||||
|
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmin, ymax, zpos );
|
||||||
|
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmax, ymax, zpos );
|
||||||
|
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmax, ymin, zpos );
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glEndList();
|
||||||
|
|
||||||
|
// Shadow BOARD
|
||||||
|
|
||||||
|
// Floor shadow is based on axis alighned bounding box dimension
|
||||||
|
xmin = m_fastAABBox_Shadow.Min().x;
|
||||||
|
xmax = m_fastAABBox_Shadow.Max().x;
|
||||||
|
ymin = m_fastAABBox_Shadow.Min().y;
|
||||||
|
ymax = m_fastAABBox_Shadow.Max().y;
|
||||||
|
|
||||||
|
glNewList( aBoardList, GL_COMPILE );
|
||||||
|
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) );
|
||||||
|
|
||||||
|
glBegin (GL_QUADS);
|
||||||
|
glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, m_fastAABBox_Shadow.Min().z );
|
||||||
|
glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, m_fastAABBox_Shadow.Min().z );
|
||||||
|
glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, m_fastAABBox_Shadow.Min().z );
|
||||||
|
glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, m_fastAABBox_Shadow.Min().z );
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glEndList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_3D_CANVAS::CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity )
|
void EDA_3D_CANVAS::CreateDrawGL_List( REPORTER* aErrorMessages, REPORTER* aActivity )
|
||||||
{
|
{
|
||||||
BOARD* pcb = GetBoard();
|
BOARD* pcb = GetBoard();
|
||||||
|
@ -1817,18 +1219,3 @@ bool EDA_3D_CANVAS::is3DLayerEnabled( LAYER_ID aLayer ) const
|
||||||
// The layer has a flag, return the flag
|
// The layer has a flag, return the flag
|
||||||
return isEnabled( flg );
|
return isEnabled( flg );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer )
|
|
||||||
{
|
|
||||||
double nZ = 1.0;
|
|
||||||
|
|
||||||
if( ( aLayer == B_Cu )
|
|
||||||
|| ( aLayer == B_Adhes )
|
|
||||||
|| ( aLayer == B_Paste )
|
|
||||||
|| ( aLayer == B_SilkS )
|
|
||||||
|| ( aLayer == B_Mask ) )
|
|
||||||
nZ = -1.0;
|
|
||||||
|
|
||||||
return nZ;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,746 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||||
|
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3d_draw_board_body.cpp
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fctsys.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <trigo.h>
|
||||||
|
#include <pcbstruct.h>
|
||||||
|
#include <drawtxt.h>
|
||||||
|
#include <layers_id_colors_and_visibility.h>
|
||||||
|
|
||||||
|
#include <wxBasePcbFrame.h>
|
||||||
|
#include <class_board.h>
|
||||||
|
#include <class_module.h>
|
||||||
|
#include <class_track.h>
|
||||||
|
#include <class_edge_mod.h>
|
||||||
|
#include <class_zone.h>
|
||||||
|
#include <class_drawsegment.h>
|
||||||
|
#include <class_pcb_text.h>
|
||||||
|
#include <colors_selection.h>
|
||||||
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
|
#define GLM_FORCE_RADIANS
|
||||||
|
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <gal/opengl/opengl_compositor.h>
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
#include <GL/glew.h> // must be included before gl.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <3d_viewer.h>
|
||||||
|
#include <3d_canvas.h>
|
||||||
|
#include <info3d_visu.h>
|
||||||
|
#include <trackball.h>
|
||||||
|
#include <3d_draw_basic_functions.h>
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
|
|
||||||
|
#include <CImage.h>
|
||||||
|
#include <reporter.h>
|
||||||
|
|
||||||
|
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer
|
||||||
|
* Z orientation is 1.0 for all layers but "back" layers:
|
||||||
|
* B_Cu , B_Adhes, B_Paste ), B_SilkS
|
||||||
|
* used to calculate the Z orientation parameter for glNormal3f
|
||||||
|
*/
|
||||||
|
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
|
||||||
|
|
||||||
|
|
||||||
|
// FIX ME: these 2 functions are fully duplicate of the same 2 functions in
|
||||||
|
// pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
|
||||||
|
static const SHAPE_POLY_SET convertPolyListToPolySet(const CPOLYGONS_LIST& aList)
|
||||||
|
{
|
||||||
|
SHAPE_POLY_SET rv;
|
||||||
|
unsigned corners_count = aList.GetCornersCount();
|
||||||
|
|
||||||
|
// Enter main outline: this is the first contour
|
||||||
|
unsigned ic = 0;
|
||||||
|
|
||||||
|
if(!corners_count)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
while( ic < corners_count )
|
||||||
|
{
|
||||||
|
rv.NewOutline( );
|
||||||
|
|
||||||
|
while( ic < corners_count )
|
||||||
|
{
|
||||||
|
rv.AppendVertex( aList.GetX(ic), aList.GetY(ic) );
|
||||||
|
if( aList.IsEndContour( ic ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
ic++;
|
||||||
|
}
|
||||||
|
ic++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const CPOLYGONS_LIST convertPolySetToPolyList(const SHAPE_POLY_SET& aPolyset)
|
||||||
|
{
|
||||||
|
CPOLYGONS_LIST list;
|
||||||
|
CPolyPt corner, firstCorner;
|
||||||
|
|
||||||
|
for( int ii = 0; ii < aPolyset.OutlineCount(); ii++ )
|
||||||
|
{
|
||||||
|
for( int jj = 0; jj < aPolyset.VertexCount(ii); jj++ )
|
||||||
|
{
|
||||||
|
VECTOR2I v = aPolyset.GetVertex( jj, ii );
|
||||||
|
corner.x = v.x;
|
||||||
|
corner.y = v.y;
|
||||||
|
corner.end_contour = false;
|
||||||
|
|
||||||
|
if(!jj)
|
||||||
|
firstCorner = corner;
|
||||||
|
|
||||||
|
list.AddCorner( corner );
|
||||||
|
}
|
||||||
|
|
||||||
|
firstCorner.end_contour = true;
|
||||||
|
list.AddCorner( firstCorner );
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
|
||||||
|
REPORTER* aErrorMessages, REPORTER* aActivity )
|
||||||
|
{
|
||||||
|
BOARD* pcb = GetBoard();
|
||||||
|
|
||||||
|
// If FL_RENDER_SHOW_HOLES_IN_ZONES is true, holes are correctly removed from copper zones areas.
|
||||||
|
// If FL_RENDER_SHOW_HOLES_IN_ZONES is false, holes are not removed from copper zones areas,
|
||||||
|
// but the calculation time is twice shorter.
|
||||||
|
bool remove_Holes = isEnabled( FL_RENDER_SHOW_HOLES_IN_ZONES );
|
||||||
|
|
||||||
|
bool realistic_mode = isRealisticMode();
|
||||||
|
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
|
||||||
|
|
||||||
|
// Number of segments to convert a circle to polygon
|
||||||
|
// Boost polygon (at least v1.57 and previous) in very rare cases crashes
|
||||||
|
// when using 16 segments to approximate a circle.
|
||||||
|
// So using 18 segments is a workaround to try to avoid these crashes
|
||||||
|
// ( We already used this trick in plot_board_layers.cpp,
|
||||||
|
// see PlotSolderMaskLayer() )
|
||||||
|
const int segcountforcircle = 18;
|
||||||
|
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) );
|
||||||
|
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
||||||
|
// to reduce time calculations
|
||||||
|
// for holes and items which do not need
|
||||||
|
// a fine representation
|
||||||
|
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );
|
||||||
|
|
||||||
|
CPOLYGONS_LIST bufferPolys;
|
||||||
|
bufferPolys.reserve( 500000 ); // Reserve for large board: tracks mainly
|
||||||
|
// + zones when holes are removed from zones
|
||||||
|
|
||||||
|
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
|
||||||
|
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
|
||||||
|
allLayerHoles.reserve( 20000 );
|
||||||
|
|
||||||
|
// Build a polygon from edge cut items
|
||||||
|
wxString msg;
|
||||||
|
|
||||||
|
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
|
||||||
|
{
|
||||||
|
if( aErrorMessages )
|
||||||
|
{
|
||||||
|
msg << wxT("\n") <<
|
||||||
|
_("Unable to calculate the board outlines.\n"
|
||||||
|
"Therefore use the board boundary box.") << wxT("\n\n");
|
||||||
|
|
||||||
|
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPOLYGONS_LIST bufferZonesPolys;
|
||||||
|
bufferZonesPolys.reserve( 300000 ); // Reserve for large board ( copper zones mainly )
|
||||||
|
// when holes are not removed from zones
|
||||||
|
|
||||||
|
CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer
|
||||||
|
bool throughHolesListBuilt = false; // flag to build the through hole polygon list only once
|
||||||
|
|
||||||
|
LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
LAYER_ID cu_seq[MAX_CU_LAYERS]; // preferred sequence, could have called CuStack()
|
||||||
|
// but I assume that's backwards
|
||||||
|
|
||||||
|
glNewList( aBoardList, GL_COMPILE );
|
||||||
|
|
||||||
|
for( unsigned i=0; i < DIM( cu_seq ); ++i )
|
||||||
|
cu_seq[i] = ToLAYER_ID( B_Cu - i );
|
||||||
|
|
||||||
|
for( LSEQ cu = cu_set.Seq( cu_seq, DIM(cu_seq) ); cu; ++cu )
|
||||||
|
#else
|
||||||
|
for( LSEQ cu = cu_set.CuStack(); cu; ++cu )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
LAYER_ID layer = *cu;
|
||||||
|
|
||||||
|
// Skip non enabled layers in normal mode,
|
||||||
|
// and internal layers in realistic mode
|
||||||
|
if( !is3DLayerEnabled( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( aActivity )
|
||||||
|
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
|
||||||
|
|
||||||
|
bufferPolys.RemoveAllContours();
|
||||||
|
bufferZonesPolys.RemoveAllContours();
|
||||||
|
currLayerHoles.RemoveAllContours();
|
||||||
|
|
||||||
|
// Draw tracks:
|
||||||
|
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
|
||||||
|
{
|
||||||
|
if( !track->IsOnLayer( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
track->TransformShapeWithClearanceToPolygon( bufferPolys,
|
||||||
|
0, segcountforcircle,
|
||||||
|
correctionFactor );
|
||||||
|
|
||||||
|
// Add via hole
|
||||||
|
if( track->Type() == PCB_VIA_T )
|
||||||
|
{
|
||||||
|
VIA *via = static_cast<VIA*>( track );
|
||||||
|
VIATYPE_T viatype = via->GetViaType();
|
||||||
|
int holediameter = via->GetDrillValue();
|
||||||
|
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||||
|
int hole_outer_radius = (holediameter + thickness) / 2;
|
||||||
|
|
||||||
|
if( viatype != VIA_THROUGH )
|
||||||
|
TransformCircleToPolygon( currLayerHoles,
|
||||||
|
via->GetStart(), hole_outer_radius,
|
||||||
|
segcountLowQuality );
|
||||||
|
else if( !throughHolesListBuilt )
|
||||||
|
TransformCircleToPolygon( allLayerHoles,
|
||||||
|
via->GetStart(), hole_outer_radius,
|
||||||
|
segcountLowQuality );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw pads
|
||||||
|
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||||
|
{
|
||||||
|
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||||
|
// Note: NPTH pads are not drawn on copper layers when the pad
|
||||||
|
// has same shape as its hole
|
||||||
|
module->TransformPadsShapesWithClearanceToPolygon( layer,
|
||||||
|
bufferPolys,
|
||||||
|
0,
|
||||||
|
segcountforcircle,
|
||||||
|
correctionFactor, true );
|
||||||
|
|
||||||
|
// Micro-wave modules may have items on copper layers
|
||||||
|
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
|
||||||
|
bufferPolys,
|
||||||
|
0,
|
||||||
|
segcountforcircle,
|
||||||
|
correctionFactor );
|
||||||
|
|
||||||
|
// Add pad hole, if any
|
||||||
|
if( !throughHolesListBuilt )
|
||||||
|
{
|
||||||
|
D_PAD* pad = module->Pads();
|
||||||
|
|
||||||
|
for( ; pad; pad = pad->Next() )
|
||||||
|
{
|
||||||
|
// Calculate a factor to apply to segcount for large holes ( > 1 mm)
|
||||||
|
// (bigger pad drill size -> more segments) because holes in pads can have
|
||||||
|
// very different sizes and optimizing this segcount gives a better look
|
||||||
|
// Mainly mounting holes have a size bigger thon 1 mm
|
||||||
|
wxSize padHole = pad->GetDrillSize();
|
||||||
|
|
||||||
|
if( ! padHole.x ) // Not drilled pad like SMD pad
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// we use the hole diameter to calculate the seg count.
|
||||||
|
// for round holes, padHole.x == padHole.y
|
||||||
|
// for oblong holes, the diameter is the smaller of (padHole.x, padHole.y)
|
||||||
|
int diam = std::min( padHole.x, padHole.y );
|
||||||
|
double segFactor = (double)diam / Millimeter2iu( 1.0 );
|
||||||
|
|
||||||
|
int segcount = (int)(segcountLowQuality * segFactor);
|
||||||
|
|
||||||
|
// Clamp segcount between segcountLowQuality and 48.
|
||||||
|
// 48 segm for a circle is a very good approx.
|
||||||
|
segcount = Clamp( segcountLowQuality, segcount, 48 );
|
||||||
|
|
||||||
|
// The hole in the body is inflated by copper thickness.
|
||||||
|
int inflate = thickness;
|
||||||
|
|
||||||
|
// If not plated, no copper.
|
||||||
|
if( pad->GetAttribute () == PAD_HOLE_NOT_PLATED )
|
||||||
|
inflate = 0;
|
||||||
|
|
||||||
|
pad->BuildPadDrillShapePolygon( allLayerHoles, inflate, segcount );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw copper zones. Note:
|
||||||
|
// * if the holes are removed from copper zones
|
||||||
|
// the polygons are stored in bufferPolys (which contains all other polygons)
|
||||||
|
// * if the holes are NOT removed from copper zones
|
||||||
|
// the polygons are stored in bufferZonesPolys
|
||||||
|
if( isEnabled( FL_ZONE ) )
|
||||||
|
{
|
||||||
|
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
||||||
|
{
|
||||||
|
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
||||||
|
LAYER_NUM zonelayer = zone->GetLayer();
|
||||||
|
|
||||||
|
if( zonelayer == layer )
|
||||||
|
{
|
||||||
|
zone->TransformSolidAreasShapesToPolygonSet(
|
||||||
|
remove_Holes ? bufferPolys : bufferZonesPolys,
|
||||||
|
segcountLowQuality, correctionFactorLQ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw graphic items on copper layers (texts)
|
||||||
|
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
|
||||||
|
{
|
||||||
|
if( !item->IsOnLayer( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch( item->Type() )
|
||||||
|
{
|
||||||
|
case PCB_LINE_T: // should not exist on copper layers
|
||||||
|
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
||||||
|
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PCB_TEXT_T:
|
||||||
|
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
||||||
|
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufferPolys contains polygons to merge. Many overlaps .
|
||||||
|
// Calculate merged polygons
|
||||||
|
if( bufferPolys.GetCornersCount() == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if 0 // Set to 1 to use boost::polygon to subtract holes to copper areas
|
||||||
|
// (due to bugs in boost::polygon, this is deprecated and Clipper is used instead
|
||||||
|
KI_POLYGON_SET currLayerPolyset;
|
||||||
|
KI_POLYGON_SET polysetHoles;
|
||||||
|
|
||||||
|
// Add polygons, without holes
|
||||||
|
bufferPolys.ExportTo( currLayerPolyset );
|
||||||
|
|
||||||
|
// Add through holes (created only once) in current polygon holes list
|
||||||
|
currLayerHoles.Append( allLayerHoles );
|
||||||
|
|
||||||
|
if( currLayerHoles.GetCornersCount() > 0 )
|
||||||
|
currLayerHoles.ExportTo( polysetHoles );
|
||||||
|
|
||||||
|
// Merge polygons, and remove holes
|
||||||
|
currLayerPolyset -= polysetHoles;
|
||||||
|
|
||||||
|
bufferPolys.RemoveAllContours();
|
||||||
|
bufferPolys.ImportFrom( currLayerPolyset );
|
||||||
|
#else
|
||||||
|
// Use Clipper lib to subtract holes to copper areas
|
||||||
|
SHAPE_POLY_SET solidAreas = convertPolyListToPolySet( bufferPolys );
|
||||||
|
solidAreas.Simplify();
|
||||||
|
|
||||||
|
// Add through holes (created only once) in current polygon holes list
|
||||||
|
currLayerHoles.Append( allLayerHoles );
|
||||||
|
if( currLayerHoles.GetCornersCount() > 0 )
|
||||||
|
{
|
||||||
|
SHAPE_POLY_SET holes = convertPolyListToPolySet( currLayerHoles );
|
||||||
|
holes.Simplify();
|
||||||
|
solidAreas.Subtract ( holes );
|
||||||
|
}
|
||||||
|
SHAPE_POLY_SET fractured = solidAreas;
|
||||||
|
fractured.Fracture();
|
||||||
|
bufferPolys.RemoveAllContours();
|
||||||
|
bufferPolys = convertPolySetToPolyList( fractured );
|
||||||
|
#endif
|
||||||
|
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
|
||||||
|
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
|
||||||
|
|
||||||
|
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
|
||||||
|
|
||||||
|
// If we are not using thickness, then the znormal must face the layer direction
|
||||||
|
// because it will draw just one plane
|
||||||
|
if( !thickness )
|
||||||
|
zNormal = Get3DLayer_Z_Orientation( layer );
|
||||||
|
|
||||||
|
|
||||||
|
if( realistic_mode )
|
||||||
|
{
|
||||||
|
setGLCopperColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
|
||||||
|
SetGLColor( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If holes are removed from copper zones, bufferPolys contains all polygons
|
||||||
|
// to draw (tracks+zones+texts).
|
||||||
|
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness,
|
||||||
|
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||||
|
zNormal );
|
||||||
|
|
||||||
|
// If holes are not removed from copper zones (for calculation time reasons,
|
||||||
|
// the zone polygons are stored in bufferZonesPolys and have to be drawn now:
|
||||||
|
if( bufferZonesPolys.GetCornersCount() )
|
||||||
|
{
|
||||||
|
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
|
||||||
|
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||||
|
zNormal );
|
||||||
|
}
|
||||||
|
|
||||||
|
throughHolesListBuilt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aActivity )
|
||||||
|
aActivity->Report( _( "Build board body" ) );
|
||||||
|
|
||||||
|
|
||||||
|
// Draw plated vertical holes inside the board, but not always. They are drawn:
|
||||||
|
// - if the board body is not shown, to show the holes.
|
||||||
|
// - or if the copper thickness is shown
|
||||||
|
if( !isEnabled( FL_SHOW_BOARD_BODY ) || isEnabled( FL_USE_COPPER_THICKNESS ) )
|
||||||
|
{
|
||||||
|
// Draw vias holes (vertical cylinders)
|
||||||
|
for( const TRACK* track = pcb->m_Track; track; track = track->Next() )
|
||||||
|
{
|
||||||
|
if( track->Type() == PCB_VIA_T )
|
||||||
|
{
|
||||||
|
const VIA *via = static_cast<const VIA*>(track);
|
||||||
|
draw3DViaHole( via );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw pads holes (vertical cylinders)
|
||||||
|
for( const MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||||
|
{
|
||||||
|
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
|
||||||
|
if( pad->GetAttribute () != PAD_HOLE_NOT_PLATED )
|
||||||
|
draw3DPadHole( pad );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glEndList();
|
||||||
|
|
||||||
|
// Build the body board:
|
||||||
|
glNewList( aBodyOnlyList, GL_COMPILE );
|
||||||
|
|
||||||
|
if( isRealisticMode() )
|
||||||
|
{
|
||||||
|
setGLEpoxyColor( 1.00 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( Edge_Cuts );
|
||||||
|
SetGLColor( color, 0.7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
float copper_thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||||
|
|
||||||
|
// a small offset between substrate and external copper layer to avoid artifacts
|
||||||
|
// when drawing copper items on board
|
||||||
|
float epsilon = Millimeter2iu( 0.01 );
|
||||||
|
float zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||||
|
float board_thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
|
||||||
|
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||||
|
|
||||||
|
// items on copper layers and having a thickness = copper_thickness
|
||||||
|
// are drawn from zpos - copper_thickness/2 to zpos + copper_thickness
|
||||||
|
// therefore substrate position is copper_thickness/2 to
|
||||||
|
// substrate_height - copper_thickness/2
|
||||||
|
zpos += (copper_thickness + epsilon) / 2.0f;
|
||||||
|
board_thickness -= copper_thickness + epsilon;
|
||||||
|
|
||||||
|
KI_POLYGON_SET currLayerPolyset;
|
||||||
|
KI_POLYGON_SET polysetHoles;
|
||||||
|
|
||||||
|
// Add polygons, without holes
|
||||||
|
bufferPcbOutlines.ExportTo( currLayerPolyset );
|
||||||
|
|
||||||
|
// Build holes list
|
||||||
|
allLayerHoles.ExportTo( polysetHoles );
|
||||||
|
|
||||||
|
// remove holes
|
||||||
|
currLayerPolyset -= polysetHoles;
|
||||||
|
|
||||||
|
bufferPcbOutlines.RemoveAllContours();
|
||||||
|
bufferPcbOutlines.ImportFrom( currLayerPolyset );
|
||||||
|
|
||||||
|
if( bufferPcbOutlines.GetCornersCount() )
|
||||||
|
{
|
||||||
|
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
|
||||||
|
board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||||
|
1.0f );
|
||||||
|
}
|
||||||
|
|
||||||
|
glEndList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* aActivity )
|
||||||
|
{
|
||||||
|
BOARD* pcb = GetBoard();
|
||||||
|
bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES );
|
||||||
|
|
||||||
|
// Number of segments to draw a circle using segments
|
||||||
|
const int segcountforcircle = 18;
|
||||||
|
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
||||||
|
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
||||||
|
// to reduce time calculations
|
||||||
|
// for holes and items which do not need
|
||||||
|
// a fine representation
|
||||||
|
|
||||||
|
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );
|
||||||
|
|
||||||
|
CPOLYGONS_LIST bufferPolys;
|
||||||
|
bufferPolys.reserve( 100000 ); // Reserve for large board
|
||||||
|
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
|
||||||
|
allLayerHoles.reserve( 20000 );
|
||||||
|
|
||||||
|
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
|
||||||
|
|
||||||
|
// Build a polygon from edge cut items
|
||||||
|
wxString msg;
|
||||||
|
|
||||||
|
if( !pcb->GetBoardPolygonOutlines( bufferPcbOutlines, allLayerHoles, &msg ) )
|
||||||
|
{
|
||||||
|
if( aErrorMessages )
|
||||||
|
{
|
||||||
|
msg << wxT("\n") <<
|
||||||
|
_("Unable to calculate the board outlines.\n"
|
||||||
|
"Therefore use the board boundary box.") << wxT("\n\n");
|
||||||
|
aErrorMessages->Report( msg, REPORTER::RPT_WARNING );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||||
|
|
||||||
|
// Add via holes
|
||||||
|
for( VIA* via = GetFirstVia( pcb->m_Track ); via;
|
||||||
|
via = GetFirstVia( via->Next() ) )
|
||||||
|
{
|
||||||
|
VIATYPE_T viatype = via->GetViaType();
|
||||||
|
int holediameter = via->GetDrillValue();
|
||||||
|
int hole_outer_radius = (holediameter + thickness) / 2;
|
||||||
|
|
||||||
|
if( viatype == VIA_THROUGH )
|
||||||
|
TransformCircleToPolygon( allLayerHoles,
|
||||||
|
via->GetStart(), hole_outer_radius,
|
||||||
|
segcountLowQuality );
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw pads holes
|
||||||
|
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||||
|
{
|
||||||
|
// Add pad hole, if any
|
||||||
|
D_PAD* pad = module->Pads();
|
||||||
|
|
||||||
|
for( ; pad; pad = pad->Next() )
|
||||||
|
pad->BuildPadDrillShapePolygon( allLayerHoles, 0,
|
||||||
|
segcountLowQuality );
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw graphic items, on technical layers
|
||||||
|
|
||||||
|
KI_POLYGON_SET brdpolysetHoles;
|
||||||
|
allLayerHoles.ExportTo( brdpolysetHoles );
|
||||||
|
|
||||||
|
static const LAYER_ID teckLayerList[] = {
|
||||||
|
B_Adhes,
|
||||||
|
F_Adhes,
|
||||||
|
B_Paste,
|
||||||
|
F_Paste,
|
||||||
|
B_SilkS,
|
||||||
|
F_SilkS,
|
||||||
|
B_Mask,
|
||||||
|
F_Mask,
|
||||||
|
};
|
||||||
|
|
||||||
|
// User layers are not drawn here, only technical layers
|
||||||
|
for( LSEQ seq = LSET::AllTechMask().Seq( teckLayerList, DIM( teckLayerList ) ); seq; ++seq )
|
||||||
|
{
|
||||||
|
LAYER_ID layer = *seq;
|
||||||
|
|
||||||
|
if( !is3DLayerEnabled( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( layer == Edge_Cuts && isEnabled( FL_SHOW_BOARD_BODY ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( aActivity )
|
||||||
|
aActivity->Report( wxString::Format( _( "Build layer %s" ), LSET::Name( layer ) ) );
|
||||||
|
|
||||||
|
|
||||||
|
bufferPolys.RemoveAllContours();
|
||||||
|
|
||||||
|
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
|
||||||
|
{
|
||||||
|
if( !item->IsOnLayer( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch( item->Type() )
|
||||||
|
{
|
||||||
|
case PCB_LINE_T:
|
||||||
|
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
||||||
|
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PCB_TEXT_T:
|
||||||
|
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
||||||
|
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( MODULE* module = pcb->m_Modules; module; module = module->Next() )
|
||||||
|
{
|
||||||
|
if( layer == F_SilkS || layer == B_SilkS )
|
||||||
|
{
|
||||||
|
D_PAD* pad = module->Pads();
|
||||||
|
int linewidth = g_DrawDefaultLineThickness;
|
||||||
|
|
||||||
|
for( ; pad; pad = pad->Next() )
|
||||||
|
{
|
||||||
|
if( !pad->IsOnLayer( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
buildPadShapeThickOutlineAsPolygon( pad, bufferPolys,
|
||||||
|
linewidth, segcountforcircle, correctionFactor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
module->TransformPadsShapesWithClearanceToPolygon( layer,
|
||||||
|
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||||
|
|
||||||
|
module->TransformGraphicShapesWithClearanceToPolygonSet( layer,
|
||||||
|
bufferPolys, 0, segcountforcircle, correctionFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw non copper zones
|
||||||
|
if( isEnabled( FL_ZONE ) )
|
||||||
|
{
|
||||||
|
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
||||||
|
{
|
||||||
|
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
||||||
|
|
||||||
|
if( !zone->IsOnLayer( layer ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
zone->TransformSolidAreasShapesToPolygonSet(
|
||||||
|
bufferPolys, segcountLowQuality, correctionFactorLQ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufferPolys contains polygons to merge. Many overlaps .
|
||||||
|
// Calculate merged polygons and remove pads and vias holes
|
||||||
|
if( bufferPolys.GetCornersCount() == 0 )
|
||||||
|
continue;
|
||||||
|
KI_POLYGON_SET currLayerPolyset;
|
||||||
|
KI_POLYGON_SET polyset;
|
||||||
|
|
||||||
|
// Solder mask layers are "negative" layers.
|
||||||
|
// Shapes should be removed from the full board area.
|
||||||
|
if( layer == B_Mask || layer == F_Mask )
|
||||||
|
{
|
||||||
|
bufferPcbOutlines.ExportTo( currLayerPolyset );
|
||||||
|
bufferPolys.Append( allLayerHoles );
|
||||||
|
bufferPolys.ExportTo( polyset );
|
||||||
|
currLayerPolyset -= polyset;
|
||||||
|
}
|
||||||
|
// Remove holes from Solder paste layers and siklscreen
|
||||||
|
else if( layer == B_Paste || layer == F_Paste
|
||||||
|
|| layer == B_SilkS || layer == F_SilkS )
|
||||||
|
{
|
||||||
|
bufferPolys.ExportTo( currLayerPolyset );
|
||||||
|
currLayerPolyset -= brdpolysetHoles;
|
||||||
|
}
|
||||||
|
else // usuall layers, merge polys built from each item shape:
|
||||||
|
{
|
||||||
|
bufferPolys.ExportTo( polyset );
|
||||||
|
currLayerPolyset += polyset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int thickness = 0;
|
||||||
|
|
||||||
|
if( layer != B_Mask && layer != F_Mask )
|
||||||
|
thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
|
||||||
|
|
||||||
|
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
|
||||||
|
|
||||||
|
if( layer == Edge_Cuts )
|
||||||
|
{
|
||||||
|
thickness = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu )
|
||||||
|
- GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
|
||||||
|
zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu )
|
||||||
|
+ (thickness / 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// for Draw3D_SolidHorizontalPolyPolygons, zpos it the middle between bottom and top
|
||||||
|
// sides.
|
||||||
|
// However for top layers, zpos should be the bottom layer pos,
|
||||||
|
// and for bottom layers, zpos should be the top layer pos.
|
||||||
|
if( Get3DLayer_Z_Orientation( layer ) > 0 )
|
||||||
|
zpos += thickness/2;
|
||||||
|
else
|
||||||
|
zpos -= thickness/2 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferPolys.RemoveAllContours();
|
||||||
|
bufferPolys.ImportFrom( currLayerPolyset );
|
||||||
|
|
||||||
|
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
|
||||||
|
|
||||||
|
// If we are not using thickness, then the znormal must face the layer direction
|
||||||
|
// because it will draw just one plane
|
||||||
|
if( !thickness )
|
||||||
|
zNormal = Get3DLayer_Z_Orientation( layer );
|
||||||
|
|
||||||
|
|
||||||
|
setGLTechLayersColor( layer );
|
||||||
|
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
|
||||||
|
thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
|
||||||
|
zNormal );
|
||||||
|
}
|
||||||
|
}
|
|
@ -464,3 +464,17 @@ void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer )
|
||||||
|
{
|
||||||
|
double nZ = 1.0;
|
||||||
|
|
||||||
|
if( ( aLayer == B_Cu )
|
||||||
|
|| ( aLayer == B_Adhes )
|
||||||
|
|| ( aLayer == B_Paste )
|
||||||
|
|| ( aLayer == B_SilkS )
|
||||||
|
|| ( aLayer == B_Mask ) )
|
||||||
|
nZ = -1.0;
|
||||||
|
|
||||||
|
return nZ;
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ set(3D-VIEWER_SRCS
|
||||||
3d_canvas.cpp
|
3d_canvas.cpp
|
||||||
3d_class.cpp
|
3d_class.cpp
|
||||||
3d_draw.cpp
|
3d_draw.cpp
|
||||||
|
3d_draw_board_body.cpp
|
||||||
3d_draw_basic_functions.cpp
|
3d_draw_basic_functions.cpp
|
||||||
3d_draw_helper_functions.cpp
|
3d_draw_helper_functions.cpp
|
||||||
3d_frame.cpp
|
3d_frame.cpp
|
||||||
|
|
|
@ -506,7 +506,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
|
||||||
SHAPE_POLY_SET solidAreas = convertPolyListToPolySet( tmp );
|
SHAPE_POLY_SET solidAreas = convertPolyListToPolySet( tmp );
|
||||||
|
|
||||||
if(g_DumpZonesWhenFilling)
|
if(g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( &solidAreas, "solid-areas" );
|
dumper->Write( &solidAreas, "solid-areas" );
|
||||||
|
|
||||||
|
|
||||||
tmp.RemoveAllContours();
|
tmp.RemoveAllContours();
|
||||||
|
@ -514,17 +514,17 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
|
||||||
SHAPE_POLY_SET holes = convertPolyListToPolySet( tmp );
|
SHAPE_POLY_SET holes = convertPolyListToPolySet( tmp );
|
||||||
|
|
||||||
if(g_DumpZonesWhenFilling)
|
if(g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( &holes, "feature-holes" );
|
dumper->Write( &holes, "feature-holes" );
|
||||||
|
|
||||||
holes.Simplify();
|
holes.Simplify();
|
||||||
|
|
||||||
if (g_DumpZonesWhenFilling)
|
if (g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( &holes, "feature-holes-postsimplify" );
|
dumper->Write( &holes, "feature-holes-postsimplify" );
|
||||||
|
|
||||||
solidAreas.Subtract ( holes );
|
solidAreas.Subtract( holes );
|
||||||
|
|
||||||
if (g_DumpZonesWhenFilling)
|
if (g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( &solidAreas, "solid-areas-minus-holes" );
|
dumper->Write( &solidAreas, "solid-areas-minus-holes" );
|
||||||
|
|
||||||
m_FilledPolysList.RemoveAllContours();
|
m_FilledPolysList.RemoveAllContours();
|
||||||
|
|
||||||
|
@ -532,14 +532,14 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
|
||||||
fractured.Fracture();
|
fractured.Fracture();
|
||||||
|
|
||||||
if (g_DumpZonesWhenFilling)
|
if (g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( &fractured, "fractured" );
|
dumper->Write( &fractured, "fractured" );
|
||||||
|
|
||||||
m_FilledPolysList = convertPolySetToPolyList( fractured );
|
m_FilledPolysList = convertPolySetToPolyList( fractured );
|
||||||
|
|
||||||
if (g_DumpZonesWhenFilling)
|
if (g_DumpZonesWhenFilling)
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET dupa = convertPolyListToPolySet ( m_FilledPolysList );
|
SHAPE_POLY_SET dupa = convertPolyListToPolySet ( m_FilledPolysList );
|
||||||
dumper->Write ( &dupa, "verify-conv" );
|
dumper->Write( &dupa, "verify-conv" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
if( polyset_zone_solid_areas.size() == 0 )
|
if( polyset_zone_solid_areas.size() == 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_DumpZonesWhenFilling)
|
if (g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "solid-areas" );
|
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "solid-areas" );
|
||||||
|
|
||||||
buildFeatureHoleList( aPcb, cornerBufferPolysToSubstract );
|
buildFeatureHoleList( aPcb, cornerBufferPolysToSubstract );
|
||||||
|
@ -653,7 +653,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
|
|
||||||
// Remove holes from initial area.:
|
// Remove holes from initial area.:
|
||||||
polyset_zone_solid_areas -= polyset_holes;
|
polyset_zone_solid_areas -= polyset_holes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// put solid areas in m_FilledPolysList:
|
// put solid areas in m_FilledPolysList:
|
||||||
m_FilledPolysList.RemoveAllContours();
|
m_FilledPolysList.RemoveAllContours();
|
||||||
|
@ -693,8 +693,8 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (g_DumpZonesWhenFilling)
|
if (g_DumpZonesWhenFilling)
|
||||||
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "complete" );
|
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "complete" );
|
||||||
|
|
||||||
cornerBufferPolysToSubstract.RemoveAllContours();
|
cornerBufferPolysToSubstract.RemoveAllContours();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue