Commit 4ac7dd58 authored by jean-pierre charras's avatar jean-pierre charras

3D viewer: Modify yhe way board items shapes are built:

* All items shapes  are converted to polygons.
* Polygons are merged layer by layer (for calculation time reasons,zones are not merged)
* for copper layers, vias and pads holes are substracted from polygons (but, for calculation time reasons,  not inside zones areas).
* the look is better, mainly when displaying the copper thickness
* solder and paste layers are now shown in 3D viewer.
* the code was seriously cleaned (but still needs to be enhanced).
* Note this is a work in progress which needs refinements.
parent 0e903dba
......@@ -100,7 +100,8 @@ public:
/**
* Function CreateDrawGL_List
* creates the OpenGL draw list items.
* Prepares the parameters of the OpenGL draw list
* creates the OpenGL draw list items (board, grid ...
*/
GLuint CreateDrawGL_List();
void InitGL();
......@@ -111,47 +112,16 @@ public:
m_draw3dOffset.y = aPosY;
}
void DrawGrid( double aGriSizeMM );
/**
* Function Draw3D_Track
* @param aTrack = the aTrack to draw
*/
void Draw3D_Track( TRACK* aTrack );
/**
* Function Draw3D_Via
* draws 3D via as a cylinder and filled circles.
*/
void Draw3D_Via( SEGVIA* via );
/**
* Function Draw3D_DrawSegment
* draws a 3D segment (line, arc or circle).
* Function BuildBoard3DView
* Called by CreateDrawGL_List()
* Fills the OpenGL draw list with board items draw list.
*/
void Draw3D_DrawSegment( DRAWSEGMENT* segment );
void BuildBoard3DView();
/**
* Function Draw3D_Zone
* draw all solid areas in aZone
* @param aZone = the zone to draw
*/
void Draw3D_Zone( ZONE_CONTAINER* aZone );
/**
* Function Draw3D_DrawText
* draws 3D segments to create text objects.
* When DrawGraphicText is called to draw a text to an OpenGL DC
* it calls Draw3dTextSegm to each segment to draw.
* 2 parameters used by Draw3D_FilledSegment are not handled by DrawGraphicText
* but are used in Draw3D_FilledSegment().
* they are 2 local variables. This is an ugly, but trivial code.
* Using DrawGraphicText to draw all texts ensure texts have the same shape
* in all contexts
*/
void Draw3D_DrawText( TEXTE_PCB* text );
//int Get3DLayerEnable(int act_layer);
void DrawGrid( double aGriSizeMM );
void Draw3DViaHole( SEGVIA * aVia );
void Draw3DPadHole( D_PAD * aPad );
DECLARE_EVENT_TABLE()
};
......
......@@ -53,7 +53,6 @@ extern void SetGLColor( EDA_COLOR_T color );
extern void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
extern void CheckGLError();
/* returns true if aLayer should be displayed, false otherwise
*/
static bool Is3DLayerEnabled( LAYER_NUM aLayer );
......@@ -65,6 +64,39 @@ static bool Is3DLayerEnabled( LAYER_NUM aLayer );
*/
static GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
/* Helper function BuildPadShapeThickOutlineAsPolygon:
* Build a pad shape outline as polygon, to draw pads on silkscreen layer
* with a line thickness = aWidth
* Used only to draw pads outlines on silkscreen layers.
*/
static void BuildPadShapeThickOutlineAsPolygon( D_PAD * aPad,
std::vector <CPolyPt>& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
if( aPad->GetShape() == PAD_CIRCLE ) // Draw a ring
{
TransformRingToPolygon( aCornerBuffer, aPad->ReturnShapePos(),
aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth );
return;
}
// For other shapes, draw polygon outlines
std::vector <CPolyPt> corners;
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
aCircleToSegmentsCount, aCorrectionFactor );
// Add outlines as thick segments in polygon buffer
for( unsigned ii = 0, jj = corners.size() - 1; ii < corners.size(); jj = ii, ii++ )
{
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
wxPoint( corners[jj].x, corners[jj].y ),
wxPoint( corners[ii].x, corners[ii].y ),
aCircleToSegmentsCount, aWidth );
}
}
void EDA_3D_CANVAS::Redraw( bool finish )
{
// SwapBuffer requires the window to be shown before calling
......@@ -101,13 +133,9 @@ void EDA_3D_CANVAS::Redraw( bool finish )
glRotatef( g_Parm_3D_Visu.m_Rot[2], 0.0, 0.0, 1.0 );
if( m_gllist )
{
glCallList( m_gllist );
}
else
{
CreateDrawGL_List();
}
glFlush();
......@@ -117,207 +145,343 @@ void EDA_3D_CANVAS::Redraw( bool finish )
SwapBuffers();
}
GLuint EDA_3D_CANVAS::CreateDrawGL_List()
void EDA_3D_CANVAS::BuildBoard3DView()
{
PCB_BASE_FRAME* pcbframe = Parent()->Parent();
BOARD* pcb = pcbframe->GetBoard();
wxBusyCursor dummy;
// Number of segments to draw a circle using segments
const int segcountforcircle = 16;
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) );
std::vector <CPolyPt> bufferPolys;
bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly)
std::vector <CPolyPt> bufferZonesPolys;
bufferPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly )
std::vector <CPolyPt> currLayerHoles; // Contains holes for the current layer
std::vector <CPolyPt> 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;
for( LAYER_NUM layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER;
layer++ )
{
m_gllist = glGenLists( 1 );
if( layer != LAST_COPPER_LAYER &&
layer >= g_Parm_3D_Visu.m_CopperLayersCount )
continue;
// Build 3D board parameters:
g_Parm_3D_Visu.InitSettings( pcb );
if( !g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
continue;
bufferPolys.clear();
bufferZonesPolys.clear();
currLayerHoles.clear();
glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
// Draw tracks:
for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() )
{
if( !track->IsOnLayer(layer) )
continue;
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
track->TransformShapeWithClearanceToPolygon( bufferPolys,
0, segcountforcircle,
correctionFactor );
// draw axis
if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS])
{
glEnable( GL_COLOR_MATERIAL );
SetGLColor( WHITE );
glBegin( GL_LINES );
glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 1.0f, 0.0f, 0.0f ); // X axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, -1.0f, 0.0f ); // Y axis
glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.3f ); // Z axis
glEnd();
}
// Add via hole
if( track->Type() == PCB_VIA_T )
{
int shape = track->GetShape();
int holediameter = track->GetDrillValue();
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
int hole_outer_radius = (holediameter + thickness) / 2;
if( shape != VIA_THROUGH )
TransformCircleToPolygon( currLayerHoles,
track->GetStart(), hole_outer_radius,
segcountLowQuality );
else if( ! throughHolesListBuilt )
TransformCircleToPolygon( allLayerHoles,
track->GetStart(), hole_outer_radius,
segcountLowQuality );
}
}
// move the board in order to draw it with its center at 0,0 3D coordinates
glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
0.0F );
// draw pads
for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() )
{
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys, 0, segcountforcircle, correctionFactor );
// draw tracks and vias :
for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() )
{
if( track->Type() == PCB_VIA_T )
Draw3D_Via( (SEGVIA*) track );
else
// Micro-wave modukes 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 != NULL; pad = pad->Next() )
pad->BuildPadDrillShapePolygon( allLayerHoles, 0,
segcountLowQuality );
}
}
// Draw copper zones
if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE] )
{
LAYER_NUM layer = track->GetLayer();
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
{
ZONE_CONTAINER * zone = pcb->GetArea( ii );
LAYER_NUM zonelayer = zone->GetLayer();
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
Draw3D_Track( track );
if( zonelayer == layer )
zone->TransformSolidAreasShapesToPolygonSet(
hightQualityMode ? bufferPolys : bufferZonesPolys,
segcountLowQuality, correctionFactorLQ );
}
}
}
if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE])
{
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
// draw graphic items
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
{
LAYER_NUM layer = pcb->GetArea( ii )->GetLayer();
if( ! item->IsOnLayer( layer ) )
continue;
switch( item->Type() )
{
case PCB_LINE_T:
((DRAWSEGMENT*) item)->TransformShapeWithClearanceToPolygon(
bufferPolys, 0,
segcountforcircle,
correctionFactor );
break;
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
Draw3D_Zone( pcb->GetArea( ii ) );
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.size() == 0 )
continue;
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polysetHoles;
// Draw epoxy limits: TODO
// Add polygons, without holes
AddPolygonCornersToKiPolygonList( bufferPolys, currLayerPolyset );
// draw graphic items
EDA_ITEM* PtStruct;
// Add holes in polygon list
currLayerHoles.insert( currLayerHoles.begin(),
allLayerHoles.begin(), allLayerHoles.end() );
if( currLayerHoles.size() > 0 )
AddPolygonCornersToKiPolygonList( currLayerHoles, polysetHoles );
// Merge polygons, remove holes
currLayerPolyset -= polysetHoles;
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
SetGLColor( color );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
for( PtStruct = pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
bufferPolys.clear();
CopyPolygonsFromKiPolygonListToPolysList( currLayerPolyset, bufferPolys );
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
thickness,
g_Parm_3D_Visu.m_BiuTo3Dunits );
if( bufferZonesPolys.size() )
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos,
thickness,
g_Parm_3D_Visu.m_BiuTo3Dunits );
throughHolesListBuilt = true;
}
// Draw vias holes (vertical cylinders)
for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() )
{
switch( PtStruct->Type() )
{
case PCB_LINE_T:
{
DRAWSEGMENT* segment = (DRAWSEGMENT*) PtStruct;
if( track->Type() == PCB_VIA_T )
Draw3DViaHole( (SEGVIA *) track );
}
// Draw pads holes (vertical cylinders)
for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() )
{
for( D_PAD* pad = module->Pads(); pad != NULL; pad = pad->Next() )
Draw3DPadHole( pad );
}
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( segment->GetLayer() ) )
Draw3D_DrawSegment( segment );
}
break;
// draw graphic items, not on copper layers
for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER; layer <= LAST_NON_COPPER_LAYER;
layer++ )
{
if( ! Is3DLayerEnabled( layer ) )
continue;
if( !g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) )
continue;
case PCB_TEXT_T:
bufferPolys.clear();
for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() )
{
TEXTE_PCB* text = (TEXTE_PCB*) PtStruct;
if( ! item->IsOnLayer( layer ) )
continue;
if( Is3DLayerEnabled( text->GetLayer() ) )
Draw3D_DrawText( text );
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;
}
}
break;
default:
break;
for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() )
{
if( layer == SILKSCREEN_N_FRONT || layer == SILKSCREEN_N_BACK )
{
D_PAD* pad = module->Pads();
int linewidth = g_DrawDefaultLineThickness;
for( ; pad != NULL; 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 footprints
MODULE* Module = pcb->m_Modules;
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons and remove pads and vias holes
if( bufferPolys.size() == 0 )
continue;
for( ; Module != NULL; Module = Module->Next() )
Module->Draw3D( this );
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polyset;
AddPolygonCornersToKiPolygonList( bufferPolys, polyset );
// merge polys:
currLayerPolyset += polyset;
// Draw grid
if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_GRID] )
DrawGrid( g_Parm_3D_Visu.m_3D_Grid );
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);
}
glEndList();
SetGLColor( color );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
// Test for errors
CheckGLError();
bufferPolys.clear();
CopyPolygonsFromKiPolygonListToPolysList( currLayerPolyset, bufferPolys );
Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos,
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
return m_gllist;
// draw modules 3D shapes
for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() )
module->ReadAndInsert3DComponentShape( this );
}
/* Draw a zone (solid copper areas in aZone)
*/
void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone )
GLuint EDA_3D_CANVAS::CreateDrawGL_List()
{
LAYER_NUM layer = aZone->GetLayer();
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
PCB_BASE_FRAME* pcbframe = Parent()->Parent();
BOARD* pcb = pcbframe->GetBoard();
if( layer == LAST_COPPER_LAYER )
layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
wxBusyCursor dummy;
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
m_gllist = glGenLists( 1 );
SetGLColor( color );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
// Build 3D board parameters:
g_Parm_3D_Visu.InitSettings( pcb );
if( aZone->GetFillMode() == 0 )
{
// solid polygons only are used to fill areas
if( aZone->GetFilledPolysList().size() > 3 )
{
Draw3D_SolidHorizontalPolyPolygons( aZone->GetFilledPolysList(),
g_Parm_3D_Visu.GetLayerZcoordBIU( layer ),
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
}
else
glNewList( m_gllist, GL_COMPILE_AND_EXECUTE );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
// draw axis
if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_AXIS])
{
// segments are used to fill areas
for( unsigned iseg = 0; iseg < aZone->FillSegments().size(); iseg++ )
Draw3D_SolidSegment( aZone->FillSegments()[iseg].m_Start,
aZone->FillSegments()[iseg].m_End,
aZone->GetMinThickness(), thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
glEnable( GL_COLOR_MATERIAL );
SetGLColor( WHITE );
glBegin( GL_LINES );
glNormal3f( 0.0f, 0.0f, 1.0f ); // Normal is Z axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 1.0f, 0.0f, 0.0f ); // X axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, -1.0f, 0.0f ); // Y axis
glNormal3f( 1.0f, 0.0f, 0.0f ); // Normal is Y axis
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.3f ); // Z axis
glEnd();
}
// Draw copper area outlines
std::vector<CPolyPt> polysList = aZone->GetFilledPolysList();
// move the board in order to draw it with its center at 0,0 3D coordinates
glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits,
-g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits,
0.0F );
if( polysList.size() == 0 )
return;
// Draw Board:
// For testing purpose only display calculation time to generate 3D data
//#define PRINT_CALCULATION_TIME
if( aZone->GetMinThickness() <= 1 )
return;
#ifdef PRINT_CALCULATION_TIME
unsigned strtime = GetRunningMicroSecs();
#endif
int imax = polysList.size() - 1;
CPolyPt* firstcorner = &polysList[0];
CPolyPt* begincorner = firstcorner;
BuildBoard3DView();
for( int ic = 1; ic <= imax; ic++ )
{
CPolyPt* endcorner = &polysList[ic];
// Draw grid
if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_GRID] )
DrawGrid( g_Parm_3D_Visu.m_3D_Grid );
if( begincorner->m_utility == 0 )
{
// Draw only basic outlines, not extra segments
wxPoint start( begincorner->x, begincorner->y );
wxPoint end( endcorner->x, endcorner->y );
Draw3D_SolidSegment( start, end,
aZone->GetMinThickness(), thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
glEndList();
if( (endcorner->end_contour) || (ic == imax) )
{
// the last corner of a filled area is found: draw it
if( endcorner->m_utility == 0 )
{
// Draw only basic outlines, not extra segments
wxPoint start( endcorner->x, endcorner->y );
wxPoint end( firstcorner->x, firstcorner->y );
Draw3D_SolidSegment( start, end,
aZone->GetMinThickness(), thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
// Test for errors
CheckGLError();
ic++;
#ifdef PRINT_CALCULATION_TIME
unsigned endtime = GetRunningMicroSecs();
wxString msg;
msg.Printf( "Built data %.1f ms", (double)(endtime-strtime)/1000 );
Parent()->SetStatusText( msg, 0 );
#endif
if( ic < imax - 1 )
begincorner = firstcorner = &polysList[ic];
}
else
{
begincorner = endcorner;
}
}
return m_gllist;
}
......@@ -451,236 +615,32 @@ void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM )
if( ( delta > zmax ) && ( delta > -zmin ) )
break;
}
}
void EDA_3D_CANVAS::Draw3D_Track( TRACK* aTrack )
void EDA_3D_CANVAS::Draw3DViaHole( SEGVIA * aVia )
{
LAYER_NUM layer = aTrack->GetLayer();
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
LAYER_NUM top_layer, bottom_layer;
int inner_radius = aVia->GetDrillValue() / 2;
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
if( layer == LAST_COPPER_LAYER )
layer = g_Parm_3D_Visu.m_CopperLayersCount - 1;
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
SetGLColor( color );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
Draw3D_SolidSegment( aTrack->GetStart(), aTrack->GetEnd(),
aTrack->GetWidth(), thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
void EDA_3D_CANVAS::Draw3D_Via( SEGVIA* via )
{
LAYER_NUM layer, top_layer, bottom_layer;
EDA_COLOR_T color;
double biu_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits ;
int outer_radius = via->GetWidth() / 2;
int inner_radius = via->GetDrillValue() / 2;
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
via->ReturnLayerPair( &top_layer, &bottom_layer );
// Drawing horizontal thick rings:
for( layer = bottom_layer; layer < g_Parm_3D_Visu.m_CopperLayersCount; ++layer )
{
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
if( layer < g_Parm_3D_Visu.m_CopperLayersCount - 1 )
{
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
continue;
color = g_ColorsSettings.GetLayerColor( layer );
}
else
{
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( LAYER_N_FRONT ) == false )
continue;
color = g_ColorsSettings.GetLayerColor( LAYER_N_FRONT );
}
SetGLColor( color );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
Draw3D_ZaxisCylinder( via->GetStart(), (outer_radius + inner_radius)/2,
thickness, outer_radius - inner_radius,
zpos - (thickness/2), biu_to_3Dunits );
if( layer >= top_layer )
break;
}
aVia->ReturnLayerPair( &top_layer, &bottom_layer );
// Drawing via hole:
color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + via->GetShape() );
EDA_COLOR_T color = g_ColorsSettings.GetItemColor( VIAS_VISIBLE + aVia->GetShape() );
SetGLColor( color );
int height = g_Parm_3D_Visu.GetLayerZcoordBIU(top_layer) -
g_Parm_3D_Visu.GetLayerZcoordBIU( bottom_layer ) - thickness;
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(bottom_layer) + thickness/2;
Draw3D_ZaxisCylinder( via->GetStart(), inner_radius + thickness/2, height,
thickness, zpos, biu_to_3Dunits );
}
void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment )
{
LAYER_NUM layer = segment->GetLayer();
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
SetGLColor( color );
if( layer == EDGE_N )
{
for( layer = FIRST_LAYER; layer < g_Parm_3D_Visu.m_CopperLayersCount; ++layer )
{
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(layer);
switch( segment->GetShape() )
{
case S_ARC:
Draw3D_ArcSegment( segment->GetCenter(), segment->GetArcStart(),
segment->GetAngle(), segment->GetWidth(), thickness,
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_CIRCLE:
{
int radius = KiROUND( GetLineLength( segment->GetStart(),
segment->GetEnd() ) );
Draw3D_ZaxisCylinder( segment->GetStart(), radius,
thickness, segment->GetWidth(),
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
default:
Draw3D_SolidSegment( segment->GetStart(), segment->GetEnd(),
segment->GetWidth(), thickness,
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
}
}
}
else
{
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(layer);
if( Is3DLayerEnabled( layer ) )
{
switch( segment->GetShape() )
{
case S_ARC:
Draw3D_ArcSegment( segment->GetCenter(), segment->GetArcStart(),
segment->GetAngle(), segment->GetWidth(), thickness,
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_CIRCLE:
{
int radius = KiROUND( GetLineLength( segment->GetStart(),
segment->GetEnd() ) );
Draw3D_ZaxisCylinder( segment->GetStart(), radius,
thickness, segment->GetWidth(),
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
default:
Draw3D_SolidSegment( segment->GetStart(), segment->GetEnd(),
segment->GetWidth(), thickness,
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
}
}
}
Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius + thickness/2, height,
thickness, zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
// These variables are used in Draw3dTextSegm.
// But Draw3dTextSegm is a call back function, so we cannot send them as arguments,
// so they are static.
int s_Text3DWidth, s_Text3DZPos, s_thickness;
// This is a call back function, used by DrawGraphicText to draw the 3D text shape:
static void Draw3dTextSegm( int x0, int y0, int xf, int yf )
void MODULE::ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas )
{
Draw3D_SolidSegment( wxPoint( x0, y0), wxPoint( xf, yf ),
s_Text3DWidth, s_thickness, s_Text3DZPos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
}
void EDA_3D_CANVAS::Draw3D_DrawText( TEXTE_PCB* text )
{
LAYER_NUM layer = text->GetLayer();
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer );
SetGLColor( color );
s_Text3DZPos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
s_Text3DWidth = text->GetThickness();
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
wxSize size = text->GetSize();
s_thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer );
if( text->IsMirrored() )
NEGATE( size.x );
if( text->IsMultilineAllowed() )
{
wxPoint pos = text->GetTextPosition();
wxArrayString* list = wxStringSplit( text->GetText(), '\n' );
wxPoint offset;
offset.y = text->GetInterline();
RotatePoint( &offset, text->GetOrientation() );
for( unsigned i = 0; i<list->Count(); i++ )
{
wxString txt = list->Item( i );
DrawGraphicText( NULL, NULL, pos, (EDA_COLOR_T) color,
txt, text->GetOrientation(), size,
text->GetHorizJustify(), text->GetVertJustify(),
text->GetThickness(), text->IsItalic(),
true, Draw3dTextSegm );
pos += offset;
}
delete list;
}
else
{
DrawGraphicText( NULL, NULL, text->GetTextPosition(), (EDA_COLOR_T) color,
text->GetText(), text->GetOrientation(), size,
text->GetHorizJustify(), text->GetVertJustify(),
text->GetThickness(), text->IsItalic(),
true,
Draw3dTextSegm );
}
}
void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
{
D_PAD* pad = m_Pads;
// Draw pads
for( ; pad != NULL; pad = pad->Next() )
pad->Draw3D( glcanvas );
// Draw module shape: 3D shape if exists (or module outlines if not exists)
S3D_MASTER* Struct3D = m_3D_Drawings;
bool As3dShape = false;
S3D_MASTER* struct3D = m_3D_Drawings;
if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_MODULE] )
{
......@@ -698,9 +658,7 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
zpos );
if( m_Orient )
{
glRotatef( (double) m_Orient / 10, 0.0, 0.0, 1.0 );
}
if( IsFlipped() )
{
......@@ -708,349 +666,69 @@ void MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
glRotatef( 180.0, 0.0, 0.0, 1.0 );
}
for( ; Struct3D != NULL; Struct3D = Struct3D->Next() )
for( ; struct3D != NULL; struct3D = struct3D->Next() )
{
if( !Struct3D->m_Shape3DName.IsEmpty() )
{
As3dShape = true;
Struct3D->ReadData();
}
if( !struct3D->m_Shape3DName.IsEmpty() )
struct3D->ReadData();
}
glPopMatrix();
}
EDA_ITEM* Struct = m_Drawings;
for( ; Struct != NULL; Struct = Struct->Next() )
{
switch( Struct->Type() )
{
case PCB_MODULE_TEXT_T:
break;
case PCB_MODULE_EDGE_T:
{
EDGE_MODULE* edge = (EDGE_MODULE*) Struct;
// Draw module edges when no 3d shape exists.
// Always draw pcb edges.
if( !As3dShape || edge->GetLayer() == EDGE_N )
edge->Draw3D( glcanvas );
}
break;
default:
break;
}
}
}
void EDGE_MODULE::Draw3D( EDA_3D_CANVAS* glcanvas )
{
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( m_Layer ) == false )
return;
EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( m_Layer );
SetGLColor( color );
// for outline shape = S_POLYGON:
// We must compute true coordinates from m_PolyPoints
// which are relative to module position and module orientation = 0
std::vector<CPolyPt> polycorners;
if( m_Shape == S_POLYGON )
{
polycorners.reserve( m_PolyPoints.size() );
MODULE* module = (MODULE*) m_Parent;
CPolyPt corner;
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
{
corner.x = m_PolyPoints[ii].x;
corner.y = m_PolyPoints[ii].y;
RotatePoint( &corner.x, &corner.y, module->GetOrientation() );
if( module )
{
corner.x += module->GetPosition().x;
corner.y += module->GetPosition().y;
}
polycorners.push_back( corner );
}
polycorners.back().end_contour = true;
}
if( m_Layer == EDGE_N )
{
for( LAYER_NUM layer = FIRST_LAYER; layer < g_Parm_3D_Visu.m_CopperLayersCount; ++layer )
{
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( m_Layer );
switch( m_Shape )
{
case S_SEGMENT:
Draw3D_SolidSegment( m_Start, m_End, m_Width,
thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_CIRCLE:
{
int radius = KiROUND( GetLineLength( m_Start, m_End ) );
Draw3D_ZaxisCylinder( m_Start, radius,
thickness, GetWidth(),
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
case S_ARC:
Draw3D_ArcSegment( GetCenter(), GetArcStart(),
GetAngle(), GetWidth(), thickness,
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_POLYGON:
Draw3D_SolidHorizontalPolyPolygons( polycorners, zpos, thickness,
g_Parm_3D_Visu.m_BiuTo3Dunits);
break;
default:
D( printf( "Error: Shape nr %d not implemented!\n", m_Shape ); )
break;
}
}
}
else
{
int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( m_Layer );
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( m_Layer ) );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU(m_Layer);
switch( m_Shape )
{
case S_SEGMENT:
Draw3D_SolidSegment( m_Start, m_End, m_Width,
thickness, zpos,
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_CIRCLE:
{
int radius = KiROUND( GetLineLength( m_Start, m_End ) );
Draw3D_ZaxisCylinder( m_Start, radius,
thickness, GetWidth(),
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
break;
case S_ARC:
Draw3D_ArcSegment( GetCenter(), GetArcStart(),
GetAngle(), GetWidth(), thickness,
zpos, g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
case S_POLYGON:
Draw3D_SolidHorizontalPolyPolygons( polycorners, zpos, thickness,
g_Parm_3D_Visu.m_BiuTo3Dunits );
break;
default:
D( printf( "Error: Shape nr %d not implemented!\n", m_Shape ); )
break;
}
}
}
// Draw 3D pads.
void D_PAD::Draw3D( EDA_3D_CANVAS* glcanvas )
void EDA_3D_CANVAS::Draw3DPadHole( D_PAD * aPad )
{
double scale = g_Parm_3D_Visu.m_BiuTo3Dunits;
// Calculate the center of the pad shape.
wxPoint shape_pos = ReturnShapePos();
// Draw the pad hole
wxSize drillsize = aPad->GetDrillSize();
bool hasHole = drillsize.x && drillsize.y;
int height = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_FRONT) -
g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK);
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
if( ! hasHole )
return;
// Store here the points to approximate hole by segments
std::vector <CPolyPt> holecornersBuffer;
const int slice = 12; // number of segments to approximate a circle
int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU();
int height = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_FRONT) -
g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK);
// Draw the pad hole
bool hasHole = m_Drill.x && m_Drill.y;
SetGLColor( DARKGRAY );
int holeZpoz = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK) + thickness/2;
int holeHeight = height - thickness;
if( hasHole )
if( drillsize.x == drillsize.y ) // usual round hole
{
SetGLColor( DARKGRAY );
int holeZpoz = g_Parm_3D_Visu.GetLayerZcoordBIU(LAYER_N_BACK) + thickness/2;
int holeHeight = height - thickness;
if( m_Drill.x == m_Drill.y ) // usual round hole
{
Draw3D_ZaxisCylinder( m_Pos, (m_Drill.x + thickness) / 2, holeHeight,
thickness, holeZpoz, scale );
TransformCircleToPolygon( holecornersBuffer, m_Pos, m_Drill.x/2, slice );
}
else // Oblong hole
{
wxPoint ends_offset;
int width;
if( m_Drill.x > m_Drill.y ) // Horizontal oval
{
ends_offset.x = ( m_Drill.x - m_Drill.y ) / 2;
width = m_Drill.y;
}
else // Vertical oval
{
ends_offset.y = ( m_Drill.y - m_Drill.x ) / 2;
width = m_Drill.x;
}
RotatePoint( &ends_offset, m_Orient );
wxPoint start = m_Pos + ends_offset;
wxPoint end = m_Pos - ends_offset;
int hole_radius = ( width + thickness ) / 2;
// Prepare the shape creation
TransformRoundedEndsSegmentToPolygon( holecornersBuffer, start, end, slice, width );
// Draw the hole
Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
thickness, holeZpoz, scale );
}
Draw3D_ZaxisCylinder( aPad->GetPosition(),
(drillsize.x + thickness) / 2, holeHeight,
thickness, holeZpoz, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
glNormal3f( 0.0, 0.0, 1.0 ); // Normal is Z axis
int nlmax = g_Parm_3D_Visu.m_CopperLayersCount - 1;
// Store here the points to approximate pad shape by segments
std::vector<CPolyPt> polyPadShape;
switch( GetShape() )
else // Oblong hole
{
case PAD_CIRCLE:
for( LAYER_NUM layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; ++layer )
{
if( layer && (layer == nlmax) )
layer = LAYER_N_FRONT;
if( !IsOnLayer( layer ) )
continue;
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
continue;
SetGLColor( g_ColorsSettings.GetLayerColor( layer ) );
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
int ring_radius = (m_Size.x + m_Drill.x) / 4;
if( thickness == 0 )
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
Draw3D_ZaxisCylinder(shape_pos, ring_radius,
thickness, ( m_Size.x - m_Drill.x) / 2,
zpos - (thickness/2), scale );
}
break;
case PAD_OVAL:
{
wxPoint ends_offset;
int width;
if( m_Size.x > m_Size.y ) // Horizontal ellipse
if( drillsize.x > drillsize.y ) // Horizontal oval
{
ends_offset.x = ( m_Size.x - m_Size.y ) / 2;
width = m_Size.y;
ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
width = drillsize.y;
}
else // Vertical ellipse
else // Vertical oval
{
ends_offset.y = ( m_Size.y - m_Size.x ) / 2;
width = m_Size.x;
ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
width = drillsize.x;
}
RotatePoint( &ends_offset, m_Orient );
wxPoint start = shape_pos + ends_offset;
wxPoint end = shape_pos - ends_offset;
TransformRoundedEndsSegmentToPolygon( polyPadShape, start, end, slice, width );
RotatePoint( &ends_offset, aPad->GetOrientation() );
if( hasHole )
polyPadShape.insert( polyPadShape.end(), holecornersBuffer.begin(),
holecornersBuffer.end() );
}
break;
wxPoint start = aPad->GetPosition() + ends_offset;
wxPoint end = aPad->GetPosition() - ends_offset;
int hole_radius = ( width + thickness ) / 2;
case PAD_RECT:
case PAD_TRAPEZOID:
{
wxPoint coord[5];
BuildPadPolygon( coord, wxSize(0,0), m_Orient );
for( int ii = 0; ii < 4; ii ++ )
{
CPolyPt pt( coord[ii].x + shape_pos.x, coord[ii].y+ shape_pos.y );
polyPadShape.push_back( pt );
}
polyPadShape.back().end_contour = true;
if( hasHole )
polyPadShape.insert( polyPadShape.end(), holecornersBuffer.begin(),
holecornersBuffer.end() );
}
break;
default:
break;
}
if( polyPadShape.size() )
{
for( LAYER_NUM layer = FIRST_COPPER_LAYER; layer <= LAST_COPPER_LAYER; ++layer )
{
if( layer && (layer == nlmax) )
layer = LAYER_N_FRONT;
if( !IsOnLayer( layer ) )
continue;
if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) == false )
continue;
SetGLColor( g_ColorsSettings.GetLayerColor( layer ) );
if( thickness == 0 )
glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) );
// If not hole: draw a single polygon
int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer );
if( hasHole )
{
Draw3D_SolidHorizontalPolygonWithHoles( polyPadShape, zpos,
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
else
{
Draw3D_SolidHorizontalPolyPolygons( polyPadShape, zpos,
thickness, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
}
// Draw the hole
Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight,
thickness, holeZpoz, g_Parm_3D_Visu.m_BiuTo3Dunits );
}
}
bool Is3DLayerEnabled( LAYER_NUM aLayer )
......@@ -1089,9 +767,7 @@ bool Is3DLayerEnabled( LAYER_NUM aLayer )
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer )
{
double nZ;
nZ = 1.0;
double nZ = 1.0;
if( ( aLayer == LAYER_N_BACK )
|| ( aLayer == ADHESIVE_N_BACK )
......
......@@ -32,6 +32,82 @@
#include <common.h>
#include <convert_basic_shapes_to_polygon.h>
/* Helper functions:
* We are using a lots polygons in calculations.
* and we are using 2 descriptions,
* one easy to use with boost::polygon (KI_POLYGON_SET)
* one easy to use in zones and in draw functions (std::vector<CPolyPt>)
* Copy polygons from a KI_POLYGON_SET set of polygons to
* a std::vector<CPolyPt> polygon list
* Therefore we need conversion functions between these 2 descriptions
*/
void CopyPolygonsFromKiPolygonListToPolysList( KI_POLYGON_SET& aKiPolyList,
std::vector<CPolyPt>& aPolysList )
{
for( unsigned ii = 0; ii < aKiPolyList.size(); ii++ )
{
KI_POLYGON& poly = aKiPolyList[ii];
CPolyPt corner( 0, 0, false );
for( unsigned jj = 0; jj < poly.size(); jj++ )
{
KI_POLY_POINT point = *(poly.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
aPolysList.push_back( corner );
}
corner.end_contour = true;
aPolysList.pop_back();
aPolysList.push_back( corner );
}
}
/**
* Helper function AddPolygonCornersToKiPolygonList
* This function adds a KI_POLYGON_SET description to a
* std::vector<CPolyPt> description
* @param aCornersBuffer = source (set of polygons using CPolyPt corners descr)
* @param aPolysList = destination (set of polygons)
*/
void AddPolygonCornersToKiPolygonList( std::vector <CPolyPt>& aCornersBuffer,
KI_POLYGON_SET& aKiPolyList )
{
std::vector<KI_POLY_POINT> cornerslist;
unsigned corners_count = aCornersBuffer.size();
// Count the number of polygons in aCornersBuffer
int polycount = 0;
for( unsigned ii = 0; ii < corners_count; ii++ )
{
if( aCornersBuffer[ii].end_contour )
polycount++;
}
aKiPolyList.reserve( polycount );
for( unsigned icnt = 0; icnt < corners_count; )
{
KI_POLYGON poly;
cornerslist.clear();
unsigned ii;
for( ii = icnt; ii < aCornersBuffer.size(); ii++ )
{
cornerslist.push_back( KI_POLY_POINT( aCornersBuffer[ii].x, aCornersBuffer[ii].y ) );
if( aCornersBuffer[ii].end_contour )
break;
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
aKiPolyList.push_back( poly );
icnt = ii + 1;
}
}
/**
* Function TransformCircleToPolygon
* convert a circle to a polygon, using multiple straight lines
......@@ -192,5 +268,68 @@ void TransformArcToPolygon( std::vector <CPolyPt>& aCornerBuffer,
if( curr_end != arc_end )
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
curr_end, arc_end, aCircleToSegmentsCount, aWidth );
curr_end, arc_end,
aCircleToSegmentsCount, aWidth );
}
/**
* Function TransformRingToPolygon
* Creates a polygon from a ring
* Convert arcs to multiple straight segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aCentre = centre of the arc or circle
* @param aRadius = radius of the circle
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aWidth = width (thickness) of the ring
*/
void TransformRingToPolygon( std::vector <CPolyPt>& aCornerBuffer,
wxPoint aCentre, int aRadius,
int aCircleToSegmentsCount, int aWidth )
{
int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
// Compute the corners posituions and creates poly
wxPoint curr_point;
int inner_radius = aRadius - ( aWidth / 2 );
int outer_radius = inner_radius + aWidth;
CPolyPt polycorner;
// Draw the inner circle of the ring
for( int ii = 0; ii < 3600; ii += delta )
{
curr_point.x = inner_radius;
curr_point.y = 0;
RotatePoint( &curr_point, ii );
curr_point += aCentre;
polycorner.x = curr_point.x;
polycorner.y = curr_point.y;
aCornerBuffer.push_back( polycorner );
}
// Draw the last point of inner circle
polycorner.x = aCentre.x + inner_radius;
polycorner.y = aCentre.y;
aCornerBuffer.push_back( polycorner );
// Draw the outer circle of the ring
for( int ii = 0; ii < 3600; ii += delta )
{
curr_point.x = outer_radius;
curr_point.y = 0;
RotatePoint( &curr_point, -ii );
curr_point += aCentre;
polycorner.x = curr_point.x;
polycorner.y = curr_point.y;
aCornerBuffer.push_back( polycorner );
}
// Draw the last point of outer circle
polycorner.x = aCentre.x + outer_radius;
polycorner.y = aCentre.y;
aCornerBuffer.push_back( polycorner );
// Close the polygon
polycorner.x = aCentre.x + inner_radius;
polycorner.end_contour = true;
aCornerBuffer.push_back( polycorner );
}
......@@ -27,6 +27,7 @@ set(CVPCB_DIALOGS
set(CVPCB_SRCS
../common/base_units.cpp
../pcbnew/board_items_to_polygon_shape_transform.cpp
../pcbnew/class_drc_item.cpp
autosel.cpp
cfg.cpp
......
......@@ -35,6 +35,33 @@
#include <macros.h>
#include <PolyLine.h>
/**
* Helper function CopyPolygonsFromKiPolygonListToPolysList
* We are using a lots polygons in calculations.
* and we are using 2 descriptions,
* one easy to use with boost::polygon (KI_POLYGON_SET)
* one easy to use in zones and in draw functions (std::vector<CPolyPt>)
* Copy polygons from a KI_POLYGON_SET set of polygons to
* a std::vector<CPolyPt> polygon list
* Therefore we need conversion functions between these 2 descriptions
* This function converts a KI_POLYGON_SET description to a
* std::vector<CPolyPt> description
* @param aKiPolyList = source (set of polygons)
* @param aPolysList = destination (set of polygons using CPolyPt corners descr)
*/
void CopyPolygonsFromKiPolygonListToPolysList( KI_POLYGON_SET& aKiPolyList,
std::vector<CPolyPt>& aPolysList );
/**
* Helper function AddPolygonCornersToKiPolygonList
* This function adds a KI_POLYGON_SET description to a
* std::vector<CPolyPt> description
* @param aCornersBuffer = source (set of polygons using CPolyPt corners descr)
* @param aPolysList = destination (set of polygons)
*/
void AddPolygonCornersToKiPolygonList( std::vector <CPolyPt>& aCornersBuffer,
KI_POLYGON_SET& aKiPolyList );
/**
* Function TransformCircleToPolygon
* convert a circle to a polygon, using multiple straight lines
......@@ -82,4 +109,18 @@ void TransformArcToPolygon( std::vector <CPolyPt>& aCornerBuffer,
wxPoint aCentre, wxPoint aStart, int aArcAngle,
int aCircleToSegmentsCount, int aWidth );
/**
* Function TransformRingToPolygon
* Creates a polygon from a ring
* Convert arcs to multiple straight segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aCentre = centre of the arc or circle
* @param aRadius = radius of the circle
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aWidth = width (thickness) of the ring
*/
void TransformRingToPolygon( std::vector <CPolyPt>& aCornerBuffer,
wxPoint aCentre, int aRadius,
int aCircleToSegmentsCount, int aWidth );
#endif // CONVERT_BASIC_SHAPES_TO_POLYGON_H
......@@ -10,6 +10,7 @@
#include <fctsys.h>
#include <polygons_defs.h>
#include <drawtxt.h>
#include <pcbnew.h>
#include <wxPcbStruct.h>
#include <trigo.h>
......@@ -18,24 +19,206 @@
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <class_zone.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <convert_basic_shapes_to_polygon.h>
/* generate pads shapes on layer aLayer as polygons,
* and adds these polygons to aCornerBuffer
* aCornerBuffer = the buffer to store polygons
* aInflateValue = an additionnal size to add to pad shapes
* aCircleToSegmentsCount = number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to a circle radius
* to generate the polygon.
* if aCorrectionFactor = 1.0, the polygon is inside the circle
* the radius of circle approximated by segments is
* initial radius * aCorrectionFactor
*/
void MODULE::TransformPadsShapesWithClearanceToPolygon( LAYER_NUM aLayer,
std::vector <CPolyPt>& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
D_PAD* pad = Pads();
wxSize margin;
for( ; pad != NULL; pad = pad->Next() )
{
if( !pad->IsOnLayer(aLayer) )
continue;
switch( aLayer )
{
case SOLDERMASK_N_FRONT:
case SOLDERMASK_N_BACK:
margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
break;
case SOLDERPASTE_N_FRONT:
case SOLDERPASTE_N_BACK:
margin = pad->GetSolderPasteMargin();
margin.x += aInflateValue;
margin.y += aInflateValue;
break;
default:
margin.x = margin.y = aInflateValue;
break;
}
pad->BuildPadShapePolygon( aCornerBuffer, margin,
aCircleToSegmentsCount, aCorrectionFactor );
}
}
/* generate shapes of graphic items (outlines) on layer aLayer as polygons,
* and adds these polygons to aCornerBuffer
* aCornerBuffer = the buffer to store polygons
* aInflateValue = a value to inflate shapes
* aCircleToSegmentsCount = number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to the circle radius
* to generate the polygon.
* if aCorrectionFactor = 1.0, the polygon is inside the circle
* the radius of circle approximated by segments is
* initial radius * aCorrectionFactor
*/
void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
LAYER_NUM aLayer,
std::vector <CPolyPt>& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
EDGE_MODULE* outline;
for( EDA_ITEM* item = GraphicalItems(); item != NULL; item = item->Next() )
{
switch( item->Type() )
{
case PCB_MODULE_TEXT_T:
break;
case PCB_MODULE_EDGE_T:
outline = (EDGE_MODULE*) item;
if( outline->GetLayer() != aLayer )
break;
switch( outline->GetShape() )
{
case S_SEGMENT:
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
outline->GetStart(),
outline->GetEnd(),
aCircleToSegmentsCount,
outline->GetWidth() );
break;
case S_CIRCLE:
TransformRingToPolygon( aCornerBuffer, outline->GetCenter(),
outline->GetRadius(), aCircleToSegmentsCount,
outline->GetWidth() );
break;
case S_ARC:
TransformArcToPolygon( aCornerBuffer,
outline->GetCenter(), outline->GetArcStart(),
outline->GetAngle(),
aCircleToSegmentsCount, outline->GetWidth() );
break;
case S_POLYGON:
// for outline shape = S_POLYGON:
// We must compute true coordinates from m_PolyPoints
// which are relative to module position and module orientation = 0
for( unsigned ii = 0; ii < outline->GetPolyPoints().size(); ii++ )
{
CPolyPt corner( outline->GetPolyPoints()[ii] );
RotatePoint( &corner.x, &corner.y, GetOrientation() );
corner.x += GetPosition().x;
corner.y += GetPosition().y;
aCornerBuffer.push_back( corner );
}
aCornerBuffer.back().end_contour = true;
break;
default:
D( printf( "Error: Shape %d not implemented!\n",
((EDGE_MODULE*) item)->m_Shape ); )
break;
}
break;
default:
break;
}
}
}
/* Function TransformSolidAreasShapesToPolygonSet
* Convert solid areas full shapes to polygon set
* (the full shape is the polygon area with a thick outline)
* Used in 3D view
* Arcs (ends of segments) are approximated by segments
* aCornerBuffer = a buffer to store the polygons
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to arcs radius to roughly
* keep arc radius when approximated by segments
*/
void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
std::vector <CPolyPt>& aCornerBuffer,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
unsigned cornerscount = GetFilledPolysList().size();
std::vector <CPolyPt> polygonslist;
if( cornerscount == 0 )
return;
// add filled areas polygons
aCornerBuffer.insert( aCornerBuffer.end(), m_FilledPolysList.begin(),
m_FilledPolysList.end() );
// add filled areas outlines, which are drawn with thich lines
wxPoint seg_start, seg_end;
int i_start_contour = 0;
for( unsigned ic = 0; ic < cornerscount; ic++ )
{
seg_start.x = m_FilledPolysList[ ic ].x;
seg_start.y = m_FilledPolysList[ ic ].y;
unsigned ic_next = ic+1;
if( !m_FilledPolysList[ic].end_contour &&
ic_next < cornerscount )
{
seg_end.x = m_FilledPolysList[ ic_next ].x;
seg_end.y = m_FilledPolysList[ ic_next ].y;
}
else
{
seg_end.x = m_FilledPolysList[ i_start_contour ].x;
seg_end.y = m_FilledPolysList[ i_start_contour ].y;
i_start_contour = ic_next;
}
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, seg_start, seg_end,
aCircleToSegmentsCount,
GetMinThickness() );
}
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Function TransformBoundingBoxWithClearanceToPolygon
* Convert the text bonding box to a rectangular polygon
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TEXTE_PCB::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue ) const
{
if( GetText().Length() == 0 )
return;
......@@ -63,91 +246,82 @@ void TEXTE_PCB::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCo
aCornerBuffer.back().end_contour = true;
}
/* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* param aCornerBuffer = a buffer to store the polygon
* param aClearanceValue = the clearance around the pad
* param aCircleToSegmentsCount = the number of segments to approximate a circle
* param aCorrectionFactor = the correction to apply to circles radius to keep
* param aAddClearance = true to add a clearance area to the polygon
* false to create the outline polygon.
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool aAddClearance )
{
/* Creates the main polygon (i.e. the filled area using only one outline)
* and reserve a clearance margin around the outlines and holes
*/
std::vector <CPolyPt> zoneOutines;
BuildFilledPolysListData( NULL, &zoneOutines );
int clearance = 0;
if( aAddClearance )
{
GetClearance();
if( aClearanceValue > clearance )
clearance = aClearanceValue;
}
/* Function TransformShapeWithClearanceToPolygonSet
* Convert the text shape to a set of polygons (one by segment)
* Used in filling zones calculations and 3D view
* Circles and arcs are approximated by segments
* aCornerBuffer = vector <CPolyPt> to store the polygon corners
* aClearanceValue = the clearance around the text
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
// These variables are parameters used in addTextSegmToPoly.
// But addTextSegmToPoly is a call-back function,
// so we cannot send them as arguments.
int s_textWidth;
int s_textCircle2SegmentCount;
std::vector <CPolyPt>* s_cornerBuffer;
// This is a call back function, used by DrawGraphicText to draw the 3D text shape:
static void addTextSegmToPoly( int x0, int y0, int xf, int yf )
{
TransformRoundedEndsSegmentToPolygon( *s_cornerBuffer,
wxPoint( x0, y0), wxPoint( xf, yf ),
s_textCircle2SegmentCount, s_textWidth );
}
// Calculate the polygon with clearance and holes
// holes are linked to the main outline, so only one polygon should be created.
KI_POLYGON_SET polyset_zone_solid_areas;
std::vector<KI_POLY_POINT> cornerslist;
unsigned ic = 0;
unsigned corners_count = zoneOutines.size();
while( ic < corners_count )
{
cornerslist.clear();
KI_POLYGON poly;
{
for( ; ic < corners_count; ic++ )
{
CPolyPt* corner = &zoneOutines[ic];
cornerslist.push_back( KI_POLY_POINT( corner->x, corner->y ) );
if( corner->end_contour )
{
ic++;
break;
}
}
void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet(
std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
{
wxSize size = GetSize();
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
polyset_zone_solid_areas.push_back( poly );
}
}
if( IsMirrored() )
NEGATE( size.x );
polyset_zone_solid_areas += clearance;
s_cornerBuffer = &aCornerBuffer;
s_textWidth = GetThickness() + ( 2 * aClearanceValue );
s_textCircle2SegmentCount = aCircleToSegmentsCount;
EDA_COLOR_T color = BLACK; // not actually used, but needed by DrawGraphicText
// Put the resultng polygon in buffer
for( unsigned ii = 0; ii < polyset_zone_solid_areas.size(); ii++ )
if( IsMultilineAllowed() )
{
KI_POLYGON& poly = polyset_zone_solid_areas[ii];
CPolyPt corner( 0, 0, false );
wxPoint pos = GetTextPosition();
wxArrayString* list = wxStringSplit( GetText(), '\n' );
wxPoint offset;
offset.y = GetInterline();
RotatePoint( &offset, GetOrientation() );
for( unsigned jj = 0; jj < poly.size(); jj++ )
for( unsigned i = 0; i<list->Count(); i++ )
{
KI_POLY_POINT point = *(poly.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
aCornerBuffer.push_back( corner );
wxString txt = list->Item( i );
DrawGraphicText( NULL, NULL, pos, color,
txt, GetOrientation(), size,
GetHorizJustify(), GetVertJustify(),
GetThickness(), IsItalic(),
true, addTextSegmToPoly );
pos += offset;
}
corner.end_contour = true;
aCornerBuffer.pop_back();
aCornerBuffer.push_back( corner );
delete list;
}
else
{
DrawGraphicText( NULL, NULL, GetTextPosition(), (EDA_COLOR_T) color,
GetText(), GetOrientation(), size,
GetHorizJustify(), GetVertJustify(),
GetThickness(), IsItalic(),
true, addTextSegmToPoly );
}
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
......@@ -163,20 +337,19 @@ void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
double aCorrectionFactor ) const
{
switch( m_Shape )
{
case S_CIRCLE:
TransformArcToPolygon( aCornerBuffer, m_Start, // Circle centre
m_End, 3600,
aCircleToSegmentsCount,
m_Width + (2 * aClearanceValue) );
TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius(),
aCircleToSegmentsCount,
m_Width + (2 * aClearanceValue) ) ;
break;
case S_ARC:
TransformArcToPolygon( aCornerBuffer, m_Start,
m_End, m_Angle,
TransformArcToPolygon( aCornerBuffer, GetCenter(),
GetArcStart(), m_Angle,
aCircleToSegmentsCount,
m_Width + (2 * aClearanceValue) );
break;
......@@ -199,13 +372,13 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& a
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approxiamted by segment bigger or equal
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TRACK:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
double aCorrectionFactor ) const
{
switch( Type() )
{
......@@ -227,22 +400,21 @@ void TRACK:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCor
}
/**
* Function TransformShapeWithClearanceToPolygon
/* Function TransformShapeWithClearanceToPolygon
* Convert the pad shape to a closed polygon
* Used in filling zones calculations
* Used in filling zones calculations and 3D view generation
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approxiamted by segment bigger or equal
* aCornerBuffer = a vector < CPolyPt> to store the polygon corners
* aClearanceValue = the clearance around the pad
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void D_PAD:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
double aCorrectionFactor ) const
{
wxPoint corner_position;
int angle;
......@@ -368,6 +540,95 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( std:: vector < CPolyPt>& aCor
}
}
/*
* Function BuildPadShapePolygon
* Build the Corner list of the polygonal shape,
* depending on shape, extra size (clearance ...) pad and orientation
* Note: for Round and oval pads this function is equivalent to
* TransformShapeWithClearanceToPolygon, but not for other shapes
*/
void D_PAD::BuildPadShapePolygon( std::vector <CPolyPt>& aCornerBuffer,
wxSize aInflateValue, int aSegmentsPerCircle,
double aCorrectionFactor ) const
{
wxPoint corners[4];
wxPoint PadShapePos = ReturnShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
switch( m_PadShape )
{
case PAD_CIRCLE:
case PAD_OVAL:
TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
aSegmentsPerCircle, aCorrectionFactor );
break;
default:
case PAD_TRAPEZOID:
case PAD_RECT:
BuildPadPolygon( corners, aInflateValue, m_Orient );
for( int ii = 0; ii < 4; ii++ )
{
corners[ii] += PadShapePos; // Shift origin to position
CPolyPt polypoint( corners[ii].x, corners[ii].y );
aCornerBuffer.push_back( polypoint );
}
aCornerBuffer.back().end_contour = true;
break;
}
}
/*
* Function BuildPadDrillShapePolygon
* Build the Corner list of the polygonal drill shape,
* depending on shape pad hole and orientation
* return false if the pad has no hole, true otherwise
*/
bool D_PAD::BuildPadDrillShapePolygon( std::vector <CPolyPt>& aCornerBuffer,
int aInflateValue, int aSegmentsPerCircle ) const
{
wxSize drillsize = GetDrillSize();
bool hasHole = drillsize.x && drillsize.y;
if( ! hasHole )
return false;
drillsize.x += aInflateValue;
drillsize.y += aInflateValue;
if( drillsize.x == drillsize.y ) // usual round hole
{
TransformCircleToPolygon( aCornerBuffer, GetPosition(),
drillsize.x /2, aSegmentsPerCircle );
}
else // Oblong hole
{
wxPoint ends_offset;
int width;
if( drillsize.x > drillsize.y ) // Horizontal oval
{
ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
width = drillsize.y;
}
else // Vertical oval
{
ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
width = drillsize.x;
}
RotatePoint( &ends_offset, GetOrientation() );
wxPoint start = GetPosition() + ends_offset;
wxPoint end = GetPosition() - ends_offset;
// Prepare the shape creation
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, start, end,
aSegmentsPerCircle, width );
}
return true;
}
/**
* Function CreateThermalReliefPadPolygon
......
......@@ -214,7 +214,7 @@ public:
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );
double aCorrectionFactor ) const;
virtual wxString GetSelectMenuText() const;
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2013 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
......@@ -36,7 +36,6 @@
class LINE_READER;
class EDA_3D_CANVAS;
class MSG_PANEL_ITEM;
......@@ -67,15 +66,11 @@ public:
void Draw( EDA_DRAW_PANEL* panel, wxDC* DC,
GR_DRAWMODE aDrawMode, const wxPoint& offset = ZeroOffset );
void Draw3D( EDA_3D_CANVAS* glcanvas );
void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList );
wxString GetClass() const
{
return wxT( "MGRAPHIC" );
// return wxT( "EDGE" ); ?
}
wxString GetSelectMenuText() const;
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2013 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
......@@ -46,6 +46,7 @@ class EDA_DRAW_PANEL;
class D_PAD;
class BOARD;
class MSG_PANEL_ITEM;
class CPolyPt;
/**
......@@ -242,7 +243,60 @@ public:
GR_DRAWMODE aDrawMode,
const wxPoint& aOffset = ZeroOffset );
void Draw3D( EDA_3D_CANVAS* glcanvas );
/**
* function ReadandInsert3DComponentShape
* read the 3D component shape(s) of the footprint (physical shape)
* and insert mesh in gl list
*/
void ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas );
/**
* function TransformPadsShapesWithClearanceToPolygon
* generate pads shapes on layer aLayer as polygons,
* and adds these polygons to aCornerBuffer
* Useful to generate a polygonal representation of a footprint
* in 3D view and plot functions, when a full polygonal approach is needed
* @param aLayer = the current layer: pads on this layer are considered
* @param aCornerBuffer = the buffer to store polygons
* @param aInflateValue = an additionnal size to add to pad shapes
* aInflateValue = 0 to have the exact pad size
* @param aCircleToSegmentsCount = number of segments to generate a circle
* @param aCorrectionFactor = the correction to apply to a circle radius
* to approximate a circle by the polygon.
* if aCorrectionFactor = 1.0, the polygon is inside the circle
* the radius of circle approximated by segments is
* initial radius * aCorrectionFactor
*/
void TransformPadsShapesWithClearanceToPolygon( LAYER_NUM aLayer,
std::vector <CPolyPt>& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
* function TransformGraphicShapesWithClearanceToPolygonSet
* generate shapes of graphic items (outlines) on layer aLayer as polygons,
* and adds these polygons to aCornerBuffer
* Useful to generate a polygonal representation of a footprint
* in 3D view and plot functions, when a full polygonal approach is needed
* @param aLayer = the current layer: items on this layer are considered
* @param aCornerBuffer = the buffer to store polygons
* @param aInflateValue = a value to inflate shapes
* aInflateValue = 0 to have the exact shape size
* @param aCircleToSegmentsCount = number of segments to generate a circle
* @param aCorrectionFactor = the correction to apply to a circle radius
* to approximate a circle by the polygon.
* if aCorrectionFactor = 1.0, the polygon is inside the circle
* the radius of circle approximated by segments is
* initial radius * aCorrectionFactor
*/
void TransformGraphicShapesWithClearanceToPolygonSet(
LAYER_NUM aLayer,
std::vector <CPolyPt>& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
* Function DrawEdgesOnly
......
......@@ -223,7 +223,7 @@ public:
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );
double aCorrectionFactor ) const;;
/**
* Function GetClearance
......@@ -274,8 +274,6 @@ public:
void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
GR_DRAWMODE aDrawMode, const wxPoint& aOffset = ZeroOffset );
void Draw3D( EDA_3D_CANVAS* glcanvas );
/**
* Function DrawShape
* basic function to draw a pad.
......@@ -300,6 +298,43 @@ public:
*/
void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, int aRotation ) const;
/**
* Function BuildPadShapePolygon
* Build the Corner list of the polygonal shape,
* depending on shape, extra size (clearance ...) pad and orientation
* This function is similar to TransformShapeWithClearanceToPolygon,
* but the difference is BuildPadShapePolygon creates a polygon shape exactly
* similar to pad shape, which a size inflated by aInflateValue
* and TransformShapeWithClearanceToPolygon creates a more complex shape (for instance
* a rectangular pad is converted in a rectangulr shape with ronded corners)
* @param aCornerBuffer = a buffer to fill.
* @param aInflateValue = the clearance or margin value.
* value > 0: inflate, < 0 deflate, = 0 : no change
* the clearance can have different values for x and y directions
* (relative to the pad)
* @param aSegmentsPerCircle = number of segments to approximate a circle
* (used for round and oblong shapes only (16 to 32 is a good value)
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* the pad size when the circle is approximated by segments
*/
void BuildPadShapePolygon( std::vector <CPolyPt>& aCornerBuffer,
wxSize aInflateValue, int aSegmentsPerCircle,
double aCorrectionFactor ) const;
/**
* Function BuildPadDrillShapePolygon
* Build the Corner list of the polygonal drill shape,
* depending on shape pad hole and orientation
* @param aCornerBuffer = a buffer to fill.
* @param aInflateValue = the clearance or margin value.
* value > 0: inflate, < 0 deflate, = 0 : no change
* @param aSegmentsPerCircle = number of segments to approximate a circle
* (used for round and oblong shapes only(16 to 32 is a good value)
* @return false if the pad has no hole, true otherwise
*/
bool BuildPadDrillShapePolygon( std::vector <CPolyPt>& aCornerBuffer,
int aInflateValue, int aSegmentsPerCircle ) const;
/**
* Function BuildSegmentFromOvalShape
* Has meaning only for OVAL (and ROUND) pads
......
......@@ -482,7 +482,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
GRLine( aClipBox, aDC, holepos.x - dx0, holepos.y - dx0,
holepos.x + dx0, holepos.y + dx0, 0, nc_color );
if( m_layerMask & LAYER_BACK ) // Draw /
if( m_layerMask & LAYER_BACK ) // Draw /
GRLine( aClipBox, aDC, holepos.x + dx0, holepos.y - dx0,
holepos.x - dx0, holepos.y + dx0, 0, nc_color );
}
......@@ -552,8 +552,8 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
{
// tsize reserve room for marges and segments thickness
tsize = ( tsize * 7 ) / 10;
DrawGraphicHaloText( aDrawInfo.m_DrawPanel, aDC, tpos,
aDrawInfo.m_Color, BLACK, WHITE,
DrawGraphicHaloText( aDrawInfo.m_DrawPanel, aDC, tpos,
aDrawInfo.m_Color, BLACK, WHITE,
buffer, t_angle,
wxSize( tsize , tsize ), GR_TEXT_HJUSTIFY_CENTER,
GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false );
......@@ -579,8 +579,8 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
// tsize reserve room for marges and segments thickness
tsize = ( tsize * 7 ) / 10;
DrawGraphicHaloText( aDrawInfo.m_DrawPanel, aDC, tpos,
aDrawInfo.m_Color, BLACK, WHITE,
DrawGraphicHaloText( aDrawInfo.m_DrawPanel, aDC, tpos,
aDrawInfo.m_Color, BLACK, WHITE,
m_ShortNetname, t_angle,
wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER,
GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false );
......@@ -632,46 +632,48 @@ int D_PAD::BuildSegmentFromOvalShape(wxPoint& aSegStart, wxPoint& aSegEnd,
void D_PAD::BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue,
int aRotation ) const
{
if( (GetShape() != PAD_RECT) && (GetShape() != PAD_TRAPEZOID) )
return;
wxSize delta;
wxSize halfsize;
halfsize.x = m_Size.x >> 1;
halfsize.y = m_Size.y >> 1;
// For rectangular shapes, inflate is easy
if( GetShape() == PAD_RECT )
switch( GetShape() )
{
halfsize += aInflateValue;
case PAD_RECT:
// For rectangular shapes, inflate is easy
halfsize += aInflateValue;
// Verify if do not deflate more than than size
// Only possible for inflate negative values.
if( halfsize.x < 0 )
halfsize.x = 0;
// Verify if do not deflate more than than size
// Only possible for inflate negative values.
if( halfsize.x < 0 )
halfsize.x = 0;
if( halfsize.y < 0 )
halfsize.y = 0;
}
else
{
// Trapezoidal pad: verify delta values
delta.x = ( m_DeltaSize.x >> 1 );
delta.y = ( m_DeltaSize.y >> 1 );
if( halfsize.y < 0 )
halfsize.y = 0;
break;
case PAD_TRAPEZOID:
// Trapezoidal pad: verify delta values
delta.x = ( m_DeltaSize.x >> 1 );
delta.y = ( m_DeltaSize.y >> 1 );
// be sure delta values are not to large
if( (delta.x < 0) && (delta.x <= -halfsize.y) )
delta.x = -halfsize.y + 1;
// be sure delta values are not to large
if( (delta.x < 0) && (delta.x <= -halfsize.y) )
delta.x = -halfsize.y + 1;
if( (delta.x > 0) && (delta.x >= halfsize.y) )
delta.x = halfsize.y - 1;
if( (delta.x > 0) && (delta.x >= halfsize.y) )
delta.x = halfsize.y - 1;
if( (delta.y < 0) && (delta.y <= -halfsize.x) )
delta.y = -halfsize.x + 1;
if( (delta.y < 0) && (delta.y <= -halfsize.x) )
delta.y = -halfsize.x + 1;
if( (delta.y > 0) && (delta.y >= halfsize.x) )
delta.y = halfsize.x - 1;
break;
if( (delta.y > 0) && (delta.y >= halfsize.x) )
delta.y = halfsize.x - 1;
default: // is used only for rect and trap. pads
return;
}
// Build the basic rectangular or trapezoid shape
......
......@@ -82,21 +82,36 @@ public:
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Function TransformBoundingBoxWithClearanceToPolygon
* Convert the text bounding box to a rectangular polygon
* depending on the text orientation, the bounding box
* is not always horizontal or vertical
* Used in filling zones calculations
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aClearanceValue = the clearance around the text bounding box
* to the real clearance value (usually near from 1.0)
*/
void TransformBoundingBoxWithClearanceToPolygon(
std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue ) const;
/**
* Function TransformShapeWithClearanceToPolygonSet
* Convert the text shape to a set of polygons (one by segment)
* Used in 3D viewer
* Circles and arcs are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the text
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
void TransformShapeWithClearanceToPolygonSet( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );
double aCorrectionFactor ) const;
wxString GetSelectMenuText() const;
......
......@@ -178,7 +178,7 @@ public:
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );
double aCorrectionFactor ) const;
/**
* Function SetDrill
* sets the drill value for vias.
......
......@@ -263,19 +263,40 @@ public:
*/
bool HitTestFilledArea( const wxPoint& aRefPos ) const;
/**
* Function TransformSolidAreasShapesToPolygonSet
* Convert solid areas full shapes to polygon set
* (the full shape is the polygon area with a thick outline)
* Used in 3D view
* Arcs (ends of segments) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygons
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to arcs radius to roughly
* keep arc radius when approximated by segments
*/
void TransformSolidAreasShapesToPolygonSet( std::vector <CPolyPt>& aCornerBuffer,
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
* Function BuildFilledPolysListData
* Build m_FilledPolysList data from real outlines (m_Poly)
* Function BuildFilledSolidAreasPolygons
* Build the filled solid areas data from real outlines (stored in m_Poly)
* The solid areas can be more thna one on copper layers, and do not have holes
( holes are linked by overlapping segments to the main outline)
* in order to have drawable (and plottable) filled polygons
* drawable filled polygons are polygons without hole
* @param aPcb: the current board (can be NULL for non copper zones)
* @param aCornerBuffer: A reference to a buffer to put polygon corners, or NULL
* if NULL (default), uses m_FilledPolysList and fill current zone.
* @return number of polygons
* This function does not add holes for pads and tracks but calls
* AddClearanceAreasPolygonsToPolysList() to do that for copper layers
*/
int BuildFilledPolysListData( BOARD* aPcb, std::vector <CPolyPt>* aCornerBuffer = NULL );
* @param aCornerBuffer: A reference to a buffer to store polygon corners, or NULL
* if NULL (default:
* - m_FilledPolysList is used to store solid areas polygons.
* - on copper layers, tracks and other items shapes of other nets are
* removed from solid areas
* if not null:
* Only the zone outline (with holes, if any) are stored in aCornerBuffer
* with holes linked. Therfore only one polygon is created
* @return true if OK, false if the solid areas cannot be calculated
* This function calls AddClearanceAreasPolygonsToPolysList()
* to add holes for pads and tracks and other items not in net.
*/
bool BuildFilledSolidAreasPolygons( BOARD* aPcb, std::vector <CPolyPt>* aCornerBuffer = NULL );
/**
* Function CopyPolygonsFromKiPolygonListToFilledPolysList
......@@ -296,15 +317,31 @@ public:
* Function AddClearanceAreasPolygonsToPolysList
* Add non copper areas polygons (pads and tracks with clearance)
* to a filled copper area
* used in BuildFilledPolysListData when calculating filled areas in a zone
* used in BuildFilledSolidAreasPolygons when calculating filled areas in a zone
* Non copper areas are pads and track and their clearance area
* The filled copper area must be computed before
* BuildFilledPolysListData() call this function just after creating the
* BuildFilledSolidAreasPolygons() call this function just after creating the
* filled copper area polygon (without clearance areas
* @param aPcb: the current board
*/
void AddClearanceAreasPolygonsToPolysList( BOARD* aPcb );
/**
* Function TransformOutlinesShapeWithClearanceToPolygon
* Convert the outlines shape to a polygon with no holes
* inflated (optional) by max( aClearanceValue, the zone clearance)
* (holes are linked to external outline by overlapping segments)
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aAddClearance = true to add a clearance area to the polygon
* false to create the outline polygon.
*/
void TransformOutlinesShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
bool aAddClearance );
/**
* Function HitTestForCorner
* tests if the given wxPoint near a corner
......@@ -446,26 +483,7 @@ public:
m_Poly->SetHatchStyle( aStyle );
}
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the track shape to a closed polygon
* Used in filling zones calculations
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearanceValue = the clearance around the pad
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* @param aAddClearance = true to add a clearance area to the polygon
* false to create the outline polygon.
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TransformShapeWithClearanceToPolygon( std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
bool aAddClearance );
/**
/**
* Function IsSame
* tests if 2 zones are equivalent:
* 2 zones are equivalent if they have same parameters and same outlines
......
......@@ -156,14 +156,14 @@ void DIALOG_GRAPHIC_ITEM_PROPERTIES::initDlg( )
PutValueInLocalUnits( *m_DefaultThicknessCtrl, thickness );
for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER;
for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER;
layer <= LAST_NON_COPPER_LAYER; ++layer )
{
m_LayerSelectionCtrl->Append( m_parent->GetBoard()->GetLayerName( layer ) );
}
LAYER_NUM layer = m_Item->GetLayer();
// It has to be an aux layer
if ( layer < FIRST_NON_COPPER_LAYER )
layer = FIRST_NON_COPPER_LAYER;
......
......@@ -134,7 +134,7 @@ void PlotSilkScreen( BOARD *aBoard, PLOTTER* aPlotter, LAYER_MSK aLayerMask,
// compatibility):
for( SEGZONE* seg = aBoard->m_Zone; seg != NULL; seg = seg->Next() )
{
if( ( GetLayerMask( seg->GetLayer() ) & aLayerMask ) == 0 )
if( ( GetLayerMask( seg->GetLayer() ) & aLayerMask ) == 0 )
continue;
aPlotter->ThickSegment( seg->GetStart(), seg->GetEnd(), seg->GetWidth(),
......@@ -515,53 +515,16 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
double correction = 1.0 / cos( M_PI / circleToSegmentsCount );
// Plot pads
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
{
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
{
if( (pad->GetLayerMask() & aLayerMask) == 0 )
continue;
int clearance = pad->GetSolderMaskMargin();
int margin = clearance + inflate;
// For rect and trap. pads, use a polygon with the same shape
// (i.e. with no rounded corners)
if( (pad->GetShape() == PAD_RECT) || (pad->GetShape() == PAD_TRAPEZOID) )
{
wxPoint coord[4];
CPolyPt corner;
pad->BuildPadPolygon( coord, wxSize( margin, margin ),
pad->GetOrientation() );
for( int ii = 0; ii < 4; ii++ )
{
coord[ii] += pad->ReturnShapePos();
corner.x = coord[ii].x;
corner.y = coord[ii].y;
corner.end_contour = (ii == 3);
bufferPolys.push_back( corner );
}
pad->BuildPadPolygon( coord, wxSize( clearance, clearance ),
pad->GetOrientation() );
for( int ii = 0; ii < 4; ii++ )
{
coord[ii] += pad->ReturnShapePos();
corner.x = coord[ii].x;
corner.y = coord[ii].y;
corner.end_contour = (ii == 3);
initialPolys.push_back( corner );
}
}
else
{
pad->TransformShapeWithClearanceToPolygon( bufferPolys, clearance + inflate,
circleToSegmentsCount,
correction );
pad->TransformShapeWithClearanceToPolygon( initialPolys, clearance,
circleToSegmentsCount,
correction );
}
}
// add shapes with exact size
module->TransformPadsShapesWithClearanceToPolygon( layer,
initialPolys, 0,
circleToSegmentsCount, correction );
// add shapes inflated by aMinThickness/2
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys, inflate,
circleToSegmentsCount, correction );
}
// Plot vias on solder masks, if aPlotOpt.GetPlotViaOnMaskLayer() is true,
......@@ -608,9 +571,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( zone->GetLayer() != layer )
continue;
zone->TransformShapeWithClearanceToPolygon( bufferPolys,
inflate, circleToSegmentsCount,
correction, true );
zone->TransformOutlinesShapeWithClearanceToPolygon( bufferPolys,
inflate, true );
}
// Now:
......
......@@ -38,8 +38,24 @@
#include <pcbnew.h>
#include <zones.h>
/* Build the filled solid areas data from real outlines (stored in m_Poly)
* The solid areas can be more than one on copper layers, and do not have holes
( holes are linked by overlapping segments to the main outline)
* aPcb: the current board (can be NULL for non copper zones)
* aCornerBuffer: A reference to a buffer to store polygon corners, or NULL
* if NULL:
* - m_FilledPolysList is used to store solid areas polygons.
* - on copper layers, tracks and other items shapes of other nets are
* removed from solid areas
* if not null:
* Only the zone outline (with holes, if any) are stored in aCornerBuffer
* with holes linked. Therfore only one polygon is created
* This function calls AddClearanceAreasPolygonsToPolysList()
* to add holes for pads and tracks and other items not in net.
*/
int ZONE_CONTAINER::BuildFilledPolysListData( BOARD* aPcb, std::vector <CPolyPt>* aCornerBuffer )
bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb,
std::vector <CPolyPt>* aCornerBuffer )
{
if( aCornerBuffer == NULL )
m_FilledPolysList.clear();
......
......@@ -112,7 +112,7 @@ int PCB_EDIT_FRAME::Fill_Zone( ZONE_CONTAINER* aZone )
wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor)
aZone->BuildFilledPolysListData( GetBoard() );
aZone->BuildFilledSolidAreasPolygons( GetBoard() );
OnModify();
......
......@@ -61,6 +61,7 @@
#include <pcbnew.h>
#include <zones.h>
#include <convert_basic_shapes_to_polygon.h>
extern void BuildUnconnectedThermalStubsPolygonList( std::vector<CPolyPt>& aCornerBuffer,
......@@ -80,10 +81,6 @@ extern void CreateThermalReliefPadPolygon( std::vector<CPolyPt>& aCornerBuffer,
double aCorrectionFactor,
int aThermalRot );
// Exported function
void AddPolygonCornersToKiPolygonList( std::vector <CPolyPt>& aCornersBuffer,
KI_POLYGON_SET& aKiPolyList );
// Local Variables:
static int s_thermalRot = 450; // angle of stubs in thermal reliefs for round pads
......@@ -100,13 +97,13 @@ double s_Correction; /* mult coeff used to enlarge rounded and oval pads (an
/**
* Function AddClearanceAreasPolygonsToPolysList
* Supports a min thickness area constraint.
* Add non copper areas polygons (pads and tracks with clearence)
* Add non copper areas polygons (pads and tracks with clearance)
* to the filled copper area found
* in BuildFilledPolysListData after calculating filled areas in a zone
* Non filled copper areas are pads and track and their clearance areas
* The filled copper area must be computed just before.
* BuildFilledPolysListData() call this function just after creating the
* filled copper area polygon (without clearence areas
* filled copper area polygon (without clearance areas)
* to do that this function:
* 1 - Creates the main outline (zone outline) using a correction to shrink the resulting area
* with m_ZoneMinThickness/2 value.
......@@ -329,17 +326,12 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
cornerBufferPolysToSubstract,
zone_clearance,
s_CircleToSegmentsCount,
s_Correction );
zone_clearance, s_CircleToSegmentsCount, s_Correction );
break;
case PCB_TEXT_T:
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygon(
cornerBufferPolysToSubstract,
zone_clearance,
s_CircleToSegmentsCount,
s_Correction );
( (TEXTE_PCB*) item )->TransformBoundingBoxWithClearanceToPolygon(
cornerBufferPolysToSubstract, zone_clearance );
break;
default:
......@@ -379,10 +371,9 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
clearance = m_ZoneMinThickness / 2;
}
zone->TransformShapeWithClearanceToPolygon(
zone->TransformOutlinesShapeWithClearanceToPolygon(
cornerBufferPolysToSubstract,
clearance, s_CircleToSegmentsCount,
s_Correction, addclearance );
clearance, addclearance );
}
// Remove thermal symbols
......@@ -468,103 +459,15 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
cornerBufferPolysToSubstract.clear();
}
void AddPolygonCornersToKiPolygonList( std::vector <CPolyPt>& aCornersBuffer,
KI_POLYGON_SET& aKiPolyList )
{
unsigned ii;
std::vector<KI_POLY_POINT> cornerslist;
int polycount = 0;
for( unsigned ii = 0; ii < aCornersBuffer.size(); ii++ )
{
if( aCornersBuffer[ii].end_contour )
polycount++;
}
aKiPolyList.reserve( polycount );
for( unsigned icnt = 0; icnt < aCornersBuffer.size(); )
{
KI_POLYGON poly;
cornerslist.clear();
for( ii = icnt; ii < aCornersBuffer.size(); ii++ )
{
cornerslist.push_back( KI_POLY_POINT( aCornersBuffer[ii].x, aCornersBuffer[ii].y ) );
if( aCornersBuffer[ii].end_contour )
break;
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
aKiPolyList.push_back( poly );
icnt = ii + 1;
}
}
void ZONE_CONTAINER::CopyPolygonsFromKiPolygonListToFilledPolysList( KI_POLYGON_SET& aKiPolyList )
{
m_FilledPolysList.clear();
for( unsigned ii = 0; ii < aKiPolyList.size(); ii++ )
{
KI_POLYGON& poly = aKiPolyList[ii];
CPolyPt corner( 0, 0, false );
for( unsigned jj = 0; jj < poly.size(); jj++ )
{
KI_POLY_POINT point = *(poly.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
m_FilledPolysList.push_back( corner );
}
corner.end_contour = true;
m_FilledPolysList.pop_back();
m_FilledPolysList.push_back( corner );
}
CopyPolygonsFromKiPolygonListToPolysList( aKiPolyList, m_FilledPolysList );
}
void ZONE_CONTAINER::CopyPolygonsFromFilledPolysListToKiPolygonList( KI_POLYGON_SET& aKiPolyList )
{
unsigned corners_count = m_FilledPolysList.size();
unsigned ic = 0;
int polycount = 0;
for( unsigned ii = 0; ii < corners_count; ii++ )
{
const CPolyPt& corner = m_FilledPolysList[ii];
if( corner.end_contour )
polycount++;
}
aKiPolyList.reserve( polycount );
std::vector<KI_POLY_POINT> cornerslist;
while( ic < corners_count )
{
cornerslist.clear();
KI_POLYGON poly;
{
while( ic < corners_count )
{
const CPolyPt& corner = m_FilledPolysList[ic++];
cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
if( corner.end_contour )
break;
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
aKiPolyList.push_back( poly );
}
}
AddPolygonCornersToKiPolygonList( m_FilledPolysList, aKiPolyList );
}
......@@ -5,8 +5,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2013 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 1992-2013 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
......@@ -39,6 +39,81 @@
#include <pcbnew.h>
#include <zones.h>
/* Function TransformOutlinesShapeWithClearanceToPolygon
* Convert the zone filled areas polygons to polygons
* inflated (optional) by max( aClearanceValue, the zone clearance)
* and copy them in aCornerBuffer
* param aClearanceValue = the clearance around polygons
* param aAddClearance = true to add a clearance area to the polygon
* false to create the outline polygon.
*/
void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
std::vector <CPolyPt>& aCornerBuffer,
int aClearanceValue, bool aAddClearance )
{
// Creates the zone outlines polygon (with linked holes if any)
std::vector <CPolyPt> zoneOutines;
BuildFilledSolidAreasPolygons( NULL, &zoneOutines );
// add clearance to outline
int clearance = 0;
if( aAddClearance )
{
clearance = GetClearance();
if( aClearanceValue > clearance )
clearance = aClearanceValue;
}
// Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon should be created.
KI_POLYGON_SET polyset_zone_solid_areas;
std::vector<KI_POLY_POINT> cornerslist;
unsigned ic = 0;
unsigned corners_count = zoneOutines.size();
while( ic < corners_count )
{
cornerslist.clear();
KI_POLYGON poly;
{
for( ; ic < corners_count; ic++ )
{
CPolyPt* corner = &zoneOutines[ic];
cornerslist.push_back( KI_POLY_POINT( corner->x, corner->y ) );
if( corner->end_contour )
{
ic++;
break;
}
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
polyset_zone_solid_areas.push_back( poly );
}
}
polyset_zone_solid_areas += clearance;
// Put the resulting polygon in aCornerBuffer corners list
for( unsigned ii = 0; ii < polyset_zone_solid_areas.size(); ii++ )
{
KI_POLYGON& poly = polyset_zone_solid_areas[ii];
CPolyPt corner( 0, 0, false );
for( unsigned jj = 0; jj < poly.size(); jj++ )
{
KI_POLY_POINT point = *(poly.begin() + jj);
corner.x = point.x();
corner.y = point.y();
corner.end_contour = false;
aCornerBuffer.push_back( corner );
}
corner.end_contour = true;
aCornerBuffer.pop_back();
aCornerBuffer.push_back( corner );
}
}
/**
* Function BuildUnconnectedThermalStubsPolygonList
......
......@@ -66,7 +66,7 @@ bool BOARD::OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
{
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
m_ZoneDescriptorList[ia]->BuildFilledSolidAreasPolygons( this );
}
// Test for bad areas: all zones must have more than 2 corners:
......
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