3D board display: better rendering of the board: the board polygon outlines (generated by the specctra function) is now used to create the 3D body of the board.

This commit is contained in:
jean-pierre charras 2013-10-04 10:42:09 +02:00
parent 964933db00
commit dd64b2f284
12 changed files with 295 additions and 50 deletions

View File

@ -49,7 +49,6 @@
#include <3d_draw_basic_functions.h>
// Imported function:
extern void SetGLColor( EDA_COLOR_T color );
extern void Set_Object_Data( std::vector<S3D_VERTEX>& aVertices, double aBiuTo3DUnits );
extern void CheckGLError();
@ -161,14 +160,28 @@ void EDA_3D_CANVAS::BuildBoard3DView()
// 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( 200000 ); // Reserve for large board (tracks mainly)
CPOLYGONS_LIST bufferZonesPolys;
bufferPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly )
CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
CPOLYGONS_LIST bufferPolys;
bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly)
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 ) )
{
msg << wxT("\n\n") <<
_("Unable to calculate the board outlines, will use the outlines boundary box");
wxMessageBox( msg );
}
CPOLYGONS_LIST bufferZonesPolys;
bufferZonesPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly )
CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer
bool throughHolesListBuilt = false; // flag to build the through hole polygon list only once
bool hightQualityMode = false;
@ -282,7 +295,8 @@ void EDA_3D_CANVAS::BuildBoard3DView()
}
}
// bufferPolys contains polygons to merge. Many overlaps . Calculate merged polygons
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons
if( bufferPolys.GetCornersCount() == 0 )
continue;
@ -346,6 +360,9 @@ void EDA_3D_CANVAS::BuildBoard3DView()
if( !g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
continue;
if( layer == EDGE_N )
continue;
bufferPolys.RemoveAllContours();
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
@ -407,26 +424,29 @@ void EDA_3D_CANVAS::BuildBoard3DView()
// Calculate merged polygons and remove pads and vias holes
if( bufferPolys.GetCornersCount() == 0 )
continue;
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polyset;
bufferPolys.ExportTo( polyset );
// merge polys:
currLayerPolyset += polyset;
// Solder mask layers are "negative" layers.
// Shapes should be removed from the full board area.
if( layer == SOLDERMASK_N_BACK || layer == SOLDERMASK_N_FRONT )
{
bufferPcbOutlines.ExportTo( currLayerPolyset );
bufferPolys.Append( allLayerHoles );
bufferPolys.ExportTo( polyset );
currLayerPolyset -= polyset;
}
else // usuall layers, merge polys built from each item shape:
{
bufferPolys.ExportTo( polyset );
currLayerPolyset += polyset;
}
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
if( layer == EDGE_N )
{
thickness = g_Parm_3D_Visu.GetLayerZcoordBIU( LAYER_N_FRONT )
- g_Parm_3D_Visu.GetLayerZcoordBIU( LAYER_N_BACK );
zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( LAYER_N_BACK )
+ (thickness / 2);
}
SetGLColor( color );
SetGLColor( color, 0.7 );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
bufferPolys.RemoveAllContours();
@ -435,6 +455,37 @@ void EDA_3D_CANVAS::BuildBoard3DView()
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
// Draw board substrate:
if( bufferPcbOutlines.GetCornersCount() )
{
int copper_thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( LAYER_N_BACK );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( LAYER_N_BACK );
int thickness = g_Parm_3D_Visu.GetLayerZcoordBIU( LAYER_N_FRONT )
- g_Parm_3D_Visu.GetLayerZcoordBIU( LAYER_N_BACK );
zpos += (thickness/2) + (copper_thickness/2);
thickness -= copper_thickness;
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( EDGE_N );
SetGLColor( color, 0.8 );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( LAYER_N_FRONT ) );
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 );
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos,
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
// draw modules 3D shapes
for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() )
module->ReadAndInsert3DComponentShape( this );
@ -517,6 +568,7 @@ void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM )
EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines
EDA_COLOR_T gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines
double scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
double transparency = 0.4;
glNormal3f( 0.0, 0.0, 1.0 );
@ -539,9 +591,9 @@ void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM )
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor );
SetGLColor( gridcolor, transparency );
else
SetGLColor( gridcolor_marker );
SetGLColor( gridcolor_marker, transparency );
int delta = KiROUND( ii * aGriSizeMM * IU_PER_MM );
@ -588,9 +640,9 @@ void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM )
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor );
SetGLColor( gridcolor, transparency );
else
SetGLColor( gridcolor_marker );
SetGLColor( gridcolor_marker, transparency );
double delta = ii * aGriSizeMM * IU_PER_MM;
@ -615,9 +667,9 @@ void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM )
for( int ii = 0; ; ii++ )
{
if( (ii % 5) )
SetGLColor( gridcolor );
SetGLColor( gridcolor, transparency);
else
SetGLColor( gridcolor_marker );
SetGLColor( gridcolor_marker, transparency );
double delta = ii * aGriSizeMM * IU_PER_MM * scale;

View File

@ -34,7 +34,6 @@
#include <info3d_visu.h>
#include <3d_draw_basic_functions.h>
// Imported function:
extern void Set_Object_Data( std::vector<S3D_VERTEX>& aVertices, double aBiuTo3DUnits );
extern void CheckGLError();
@ -122,7 +121,7 @@ static void Draw3D_VerticalPolygonalCylinder( const CPOLYGONS_LIST& aPolysList,
}
void SetGLColor( EDA_COLOR_T color )
void SetGLColor( EDA_COLOR_T color, double alpha )
{
double red, green, blue;
const StructColors &colordata = g_ColorRefs[ColorGetBase( color )];
@ -130,7 +129,7 @@ void SetGLColor( EDA_COLOR_T color )
red = colordata.m_Red / 255.0;
blue = colordata.m_Blue / 255.0;
green = colordata.m_Green / 255.0;
glColor3f( red, green, blue );
glColor4f( red, green, blue, alpha );
}

View File

@ -118,5 +118,12 @@ void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
int aRadius, int aHeight, int aThickness,
int aZpos, double aBiuTo3DUnits );
/**
* Set the current 3D color from a Kicad color, with optional transparency
* @param aColor = a EDA_COLOR_T kicad color index
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
*/
void SetGLColor( EDA_COLOR_T aColor, double aTransparency = 1.0 );
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_

View File

@ -67,6 +67,10 @@ bool GERBER_PLOTTER::StartPlot()
if( outputFile == NULL )
return false;
/* Set coordinate format to 3.4 absolute, leading zero omitted */
fputs( "%FSLAX34Y34*%\n", outputFile );
fputs( "G04 Gerber Fmt 3.4, Leading zero omitted, Abs format*\n", outputFile );
wxString Title = creator + wxT( " " ) + GetBuildVersion();
fprintf( outputFile, "G04 (created by %s) date %s*\n",
TO_UTF8( Title ), TO_UTF8( DateAndTime() ) );
@ -74,10 +78,6 @@ bool GERBER_PLOTTER::StartPlot()
/* Mass parameter: unit = INCHES */
fputs( "%MOIN*%\n", outputFile );
/* Set coordinate format to 3.4 absolute, leading zero omitted */
fputs( "G04 Gerber Fmt 3.4, Leading zero omitted, Abs format*\n%FSLAX34Y34*%\n",
outputFile );
/* Specify linear interpol (G01), unit = INCH (G70), abs format (G90) */
fputs( "G01*\nG70*\nG90*\n", outputFile );
fputs( "G04 APERTURE LIST*\n", outputFile );

View File

@ -31,6 +31,9 @@ set( CVPCB_SRCS
../common/base_units.cpp
../pcbnew/board_items_to_polygon_shape_transform.cpp
../pcbnew/class_drc_item.cpp
../pcbnew/specctra.cpp
../pcbnew/specctra_export.cpp
../pcbnew/specctra_keywords.cpp
autosel.cpp
cfg.cpp
class_components_listbox.cpp

View File

@ -58,8 +58,8 @@
*/
/*
* Note there are some variant of tool definition:
* T1F00S00C... Feed Rate and Spindle Speed of Tool 1
* Feed Rate and Spindle Speed are just skipped because they are not used in a viwer
* T1F00S00C0.2 or T1C0.02F00S00 ... Feed Rate and Spindle Speed of Tool 1
* Feed Rate and Spindle Speed are just skipped because they are not used in a viewer
*/
#include <fctsys.h>
@ -348,7 +348,7 @@ bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
m_State = READ_PROGRAM_STATE;
break;
case DRILL_REWIND_STOP: // TODO: what this command really is ?
case DRILL_REWIND_STOP: // End of header. No action in a viewer
m_State = READ_PROGRAM_STATE;
break;
@ -440,11 +440,11 @@ bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
case DRILL_TOOL_INFORMATION:
// Read a tool definition like T1C0.02:
// or T1F00S00C0.02000
// or T1F00S00C0.02 or T1C0.02F00S00
// Read tool number:
iprm = ReadInt( text, false );
// Skip Feed rate and Spindle speed
// Skip Feed rate and Spindle speed, if any here
while( *text && ( *text == 'F' || *text == 'S' ) )
{
text++;

View File

@ -141,7 +141,7 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )
wxFileDialog filedlg( this, _( "Board file name:" ),
path, fileName, LegacyPcbFileWildcard,
wxFD_OPEN );
wxFD_SAVE );
if( filedlg.ShowModal() == wxID_CANCEL )
return;
@ -233,7 +233,7 @@ void GBR_TO_PCB_EXPORTER::export_non_copper_item( GERBER_DRAW_ITEM* aGbrItem, LA
#define SEG_SHAPE 0
#define ARC_SHAPE 2
int shape = SEG_SHAPE;
// please note: the old PCB format only has integer support for angles
int angle = 0;
wxPoint seg_start, seg_end;

View File

@ -6,8 +6,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2011 jean-pierre.charras
* Copyright (C) 2011 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2013 jean-pierre.charras jp.charras at wanadoo.fr
* Copyright (C) 2013 KiCad Developers, see change_log.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
@ -31,13 +31,13 @@
#define _BITMAP_BASE_H_
#include <plot_common.h>
class PLOTTER;
/**
* This class handle bitmap images in KiCad.
* It is not intended to be used alone, but inside an other class,
* so all methods are protected ( or private )
* It is used in SCH_BITMAP class (and other in futute)
* It is used in SCH_BITMAP class and WS_DRAW_ITEM_BITMAP (and other in future)
*
* Remember not all plotters are able to plot a bitmap
* Mainly GERBER plotters cannot.
@ -106,13 +106,13 @@ public: BITMAP_BASE( const wxPoint& pos = wxPoint( 0, 0 ) );
/**
* Function GetSize
* @returns the actual size (in user units, not in pixels) of the image
* @return the actual size (in user units, not in pixels) of the image
*/
wxSize GetSize() const;
/**
* Function GetSizePixels
* @returns the size in pixels of the image
* @return the size in pixels of the image
*/
wxSize GetSizePixels() const
{
@ -136,8 +136,8 @@ public: BITMAP_BASE( const wxPoint& pos = wxPoint( 0, 0 ) );
/**
* Function ReadImageFile
* Reads and stores an image file. Init the bitmap used to draw this item
* format.
* Reads and stores in memory an image file.
* Init the bitmap format used to draw this item.
* supported images formats are format supported by wxImage
* if all handlers are loaded
* by default, .png, .jpeg are alway loaded
@ -191,7 +191,7 @@ public: BITMAP_BASE( const wxPoint& pos = wxPoint( 0, 0 ) );
* @param aDefaultColor = the color used to plot the rectangle when bitmap is not supported
* @param aDefaultPensize = the pen size used to plot the rectangle when bitmap is not supported
*/
void PlotImage( PLOTTER* aPlotter, const wxPoint& aPos,
void PlotImage( PLOTTER* aPlotter, const wxPoint& aPos,
EDA_COLOR_T aDefaultColor, int aDefaultPensize );
};

View File

@ -2715,3 +2715,19 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets,
}
}
/* Extracts the board outlines and build a closed polygon
* from lines, arcs and circle items on edge cut layer
* Any closed outline inside the main outline is a hole
* All contours should be closed, i.e. are valid vertices for a closed polygon
* return true if success, false if a contour is not valid
*/
#include <specctra.h>
bool BOARD::GetBoardPolygonOutlines( CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
wxString* aErrorText )
{
// the SPECCTRA_DB function to extract board outlines:
SPECCTRA_DB dummy;
return dummy.GetBoardPolygonOutlines( this, aOutlines,
aHoles, aErrorText );
}

View File

@ -628,6 +628,23 @@ public:
m_colorsSettings = aColorsSettings;
}
/**
* Function GetBoardPolygonOutlines
* Extracts the board outlines and build a closed polygon
* from lines, arcs and circle items on edge cut layer
* Any closed outline inside the main outline is a hole
* All contours should be closed, i.e. have valid vertices to build a closed polygon
* @param aOutlines The CPOLYGONS_LIST to fill in with main outlines.
* @param aHoles The empty CPOLYGONS_LIST to fill in with holes, if any.
* @param aErrorText = a wxString reference to display an error message
* with the coordinate of the point which creates the error
* (default = NULL , no message returned on error)
* @return true if success, false if a contour is not valid
*/
bool GetBoardPolygonOutlines( CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
wxString* aErrorText = NULL );
/**
* Function GetLayerName
* returns the name of a layer given by aLayer. Copper layers may

View File

@ -465,6 +465,9 @@ public:
point1.FixNegativeZero();
}
POINT GetOrigin() { return point0; }
POINT GetEnd() { return point1; }
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR )
{
const char* newline = nestLevel ? "\n" : "";
@ -593,6 +596,8 @@ public:
points.push_back( aPoint );
}
POINTS& GetPoints() {return points; }
void SetLayerId( const char* aLayerId )
{
layer_id = aLayerId;
@ -662,6 +667,40 @@ public:
delete rectangle;
}
/**
* GetCorners fills aBuffer with a list of coordinates (x,y) of corners
*/
void GetCorners( std::vector<double>& aBuffer )
{
if( rectangle )
{
aBuffer.push_back( rectangle->GetOrigin().x );
aBuffer.push_back( rectangle->GetOrigin().y );
aBuffer.push_back( rectangle->GetOrigin().x );
aBuffer.push_back( rectangle->GetEnd().y );
aBuffer.push_back( rectangle->GetEnd().x );
aBuffer.push_back( rectangle->GetEnd().y );
aBuffer.push_back( rectangle->GetEnd().x );
aBuffer.push_back( rectangle->GetOrigin().y );
}
else
{
for( PATHS::iterator i=paths.begin(); i!=paths.end(); ++i )
{
POINTS& plist = i->GetPoints();
for( unsigned jj = 0; jj < plist.size(); jj++ )
{
aBuffer.push_back( plist[jj].x );
aBuffer.push_back( plist[jj].y );
}
}
}
}
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR )
{
out->Print( nestLevel, "(%s\n", Name() );
@ -3926,6 +3965,26 @@ public:
* flips the modules which were on the back side of the board back to the back.
*/
void RevertMODULEs( BOARD* aBoard );
/**
* Function GetBoardPolygonOutlines
* Is not used in SPECCTRA export, but uses a lot of functions from it
* and is used to extract a board outlines (3D view, automatic zones build ...)
* makes the board perimeter by filling the BOUNDARY element
* any closed outline inside the main outline is a hole
* All contours should be closed, i.e. have valid vertices to build a closed polygon
* @param aBoard The BOARD to get information from in order to make the outlines.
* @param aOutlines The CPOLYGONS_LIST to fill in with main outlines.
* @param aHoles The empty CPOLYGONS_LIST to fill in with holes, if any.
* @param aErrorText = a wxString reference to display an error message
* with the coordinate of the point which creates the error
* (default = NULL , no message returned on error)
* @return true if success, false if a contour is not valid
*/
bool GetBoardPolygonOutlines( BOARD* aBoard,
CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
wxString* aErrorText = NULL );
};

View File

@ -1251,6 +1251,98 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
}
}
/* This function is not used in SPECCTRA export,
* but uses a lot of functions from it
* and is used to extract a board outlines (3D view, automatic zones build ...)
* makes the board perimeter for the DSN file by filling the BOUNDARY element.
* Any closed outline inside the main outline is a hole
* All contours should be closed, i.e. valid closed polygon vertices
*/
bool SPECCTRA_DB::GetBoardPolygonOutlines( BOARD* aBoard,
CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
wxString* aErrorText )
{
bool success = true;
double specctra2UIfactor = IU_PER_MM / 1000.0; // Specctra unite = micron
if( ! pcb )
{
pcb = new PCB();
pcb->structure = new STRUCTURE( pcb );
}
CPolyPt corner;
BOUNDARY* boundary = new BOUNDARY( 0 );
pcb->structure->SetBOUNDARY( boundary );
try
{
fillBOUNDARY( aBoard, boundary );
std::vector<double> buffer;
boundary->GetCorners( buffer );
for( unsigned ii = 0; ii < buffer.size(); ii+=2 )
{
corner.x = buffer[ii] * specctra2UIfactor;
corner.y = - buffer[ii+1] * specctra2UIfactor;
aOutlines.Append( corner );
}
aOutlines.CloseLastContour();
// Export holes, stored as keepouts polygonal shapes.
// by fillBOUNDARY()
KEEPOUTS& holes = pcb->structure->keepouts;
for( KEEPOUTS::iterator i=holes.begin(); i!=holes.end(); ++i )
{
KEEPOUT& keepout = *i;
PATH* poly_hole = (PATH*)keepout.shape;
POINTS& plist = poly_hole->GetPoints();
for( unsigned ii = 0; ii < plist.size(); ii+=2 )
{
corner.x = plist[ii].x * specctra2UIfactor;
corner.y = - plist[ii].y * specctra2UIfactor;
aHoles.Append( corner );
}
aHoles.CloseLastContour();
}
}
catch( IO_ERROR ioe )
{
// Creates a valid polygon outline is not possible.
// So uses the board edge cuts bounding box to create a
// rectangular outline
// (when no edge cuts items, fillBOUNDARY biuld n outline
// from global bounding box
success = false;
if( aErrorText )
*aErrorText = ioe.errorText;
EDA_RECT bbbox = aBoard->ComputeBoundingBox( true );
corner.x = bbbox.GetOrigin().x;
corner.y = bbbox.GetOrigin().y;
aOutlines.Append( corner );
corner.x = bbbox.GetOrigin().x;
corner.y = bbbox.GetEnd().y;
aOutlines.Append( corner );
corner.x = bbbox.GetEnd().x;
corner.y = bbbox.GetEnd().y;
aOutlines.Append( corner );
corner.x = bbbox.GetEnd().x;
corner.y = bbbox.GetOrigin().y;
aOutlines.Append( corner );
aOutlines.CloseLastContour();
}
return success;
}
typedef std::set<std::string> STRINGSET;
typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;