Commit 22987934 authored by jean-pierre charras's avatar jean-pierre charras

3D board display: better rendering of the board: the board polygon outlines...

3D board display: better rendering of the board: the board polygon outlines (generated by the specctra function which calclaltes outlines) is now used to create the 3D body of the board,
in pcbnew and cvpcb.
parents 964933db 7a259383
......@@ -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 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 );
}
bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly)
CPOLYGONS_LIST bufferZonesPolys;
bufferPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly )
bufferZonesPolys.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
allLayerHoles.reserve( 20000 );
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;
......
......@@ -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 );
}
......
......@@ -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_
......@@ -139,6 +139,9 @@ set(PCB_COMMON_SRCS
../pcbnew/kicad_plugin.cpp
../pcbnew/gpcb_plugin.cpp
../pcbnew/pcb_netlist.cpp
../pcbnew/specctra.cpp
../pcbnew/specctra_export.cpp
../pcbnew/specctra_keywords.cpp
pcb_plot_params_keywords.cpp
pcb_keywords.cpp
../pcbnew/pcb_parser.cpp
......@@ -155,6 +158,17 @@ set_source_files_properties( ${PCB_COMMON_SRCS} PROPERTIES
add_library(pcbcommon STATIC ${PCB_COMMON_SRCS})
# auto-generate specctra_lexer.h and specctra_keywords.cpp
make_lexer(
${PROJECT_SOURCE_DIR}/pcbnew/specctra.keywords
${PROJECT_SOURCE_DIR}/pcbnew/specctra_lexer.h
${PROJECT_SOURCE_DIR}/pcbnew/specctra_keywords.cpp
DSN
# Pass header file with dependency on *_lexer.h as extra_arg
specctra.h
)
# auto-generate netlist_lexer.h and netlist_keywords.cpp
make_lexer(
${CMAKE_CURRENT_SOURCE_DIR}/netlist.keywords
......
......@@ -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 );
......
......@@ -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++;
......
......@@ -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;
......
......@@ -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 );
};
......
......@@ -199,10 +199,10 @@ set( PCBNEW_CLASS_SRCS
print_board_functions.cpp
printout_controler.cpp
ratsnest.cpp
specctra.cpp
specctra_export.cpp
# specctra.cpp #moved in pcbcommon lib
# specctra_export.cpp
# specctra_keywords.cpp
specctra_import.cpp
specctra_keywords.cpp
swap_layers.cpp
target_edit.cpp
tool_modedit.cpp
......
......@@ -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 );
}
......@@ -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
......
......@@ -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 );
};
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment