From 4ac7dd5845bbdbecfbc2d87c82a3334c304d967d Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Wed, 1 May 2013 21:01:14 +0200 Subject: [PATCH] 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. --- 3d-viewer/3d_canvas.h | 52 +- 3d-viewer/3d_draw.cpp | 1046 ++++++----------- common/convert_basic_shapes_to_polygon.cpp | 141 ++- cvpcb/CMakeLists.txt | 1 + include/convert_basic_shapes_to_polygon.h | 41 + ...board_items_to_polygon_shape_transform.cpp | 477 ++++++-- pcbnew/class_drawsegment.h | 2 +- pcbnew/class_edge_mod.h | 11 +- pcbnew/class_module.h | 60 +- pcbnew/class_pad.h | 41 +- pcbnew/class_pad_draw_functions.cpp | 66 +- pcbnew/class_pcb_text.h | 25 +- pcbnew/class_track.h | 2 +- pcbnew/class_zone.h | 86 +- .../dialog_graphic_item_properties.cpp | 4 +- pcbnew/plot_board_layers.cpp | 62 +- pcbnew/zone_filling_algorithm.cpp | 18 +- pcbnew/zones_by_polygon_fill_functions.cpp | 2 +- ...nvert_brd_items_to_polygons_with_Boost.cpp | 117 +- ...ones_convert_to_polygons_aux_functions.cpp | 79 +- pcbnew/zones_test_and_combine_areas.cpp | 2 +- 21 files changed, 1249 insertions(+), 1086 deletions(-) diff --git a/3d-viewer/3d_canvas.h b/3d-viewer/3d_canvas.h index f8966b83a4..880522e4e0 100644 --- a/3d-viewer/3d_canvas.h +++ b/3d-viewer/3d_canvas.h @@ -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; } + /** + * Function BuildBoard3DView + * Called by CreateDrawGL_List() + * Fills the OpenGL draw list with board items draw list. + */ + void BuildBoard3DView(); + 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). - */ - void Draw3D_DrawSegment( DRAWSEGMENT* segment ); - - /** - * 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 Draw3DViaHole( SEGVIA * aVia ); + void Draw3DPadHole( D_PAD * aPad ); DECLARE_EVENT_TABLE() }; diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index b142d671a4..5629e13211 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -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 & 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 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,6 +145,277 @@ void EDA_3D_CANVAS::Redraw( bool finish ) SwapBuffers(); } +void EDA_3D_CANVAS::BuildBoard3DView() +{ + PCB_BASE_FRAME* pcbframe = Parent()->Parent(); + BOARD* pcb = pcbframe->GetBoard(); + + // 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 bufferPolys; + bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly) + std::vector bufferZonesPolys; + bufferPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly ) + std::vector currLayerHoles; // Contains holes for the current layer + std::vector 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++ ) + { + + if( layer != LAST_COPPER_LAYER && + layer >= g_Parm_3D_Visu.m_CopperLayersCount ) + continue; + + if( !g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ) + continue; + bufferPolys.clear(); + bufferZonesPolys.clear(); + currLayerHoles.clear(); + + // Draw tracks: + for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() ) + { + if( !track->IsOnLayer(layer) ) + continue; + + track->TransformShapeWithClearanceToPolygon( bufferPolys, + 0, segcountforcircle, + correctionFactor ); + + // 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 ); + } + } + + // draw pads + for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() ) + { + module->TransformPadsShapesWithClearanceToPolygon( layer, + bufferPolys, 0, segcountforcircle, correctionFactor ); + + // 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] ) + { + for( int ii = 0; ii < pcb->GetAreaCount(); ii++ ) + { + ZONE_CONTAINER * zone = pcb->GetArea( ii ); + LAYER_NUM zonelayer = zone->GetLayer(); + + if( zonelayer == layer ) + zone->TransformSolidAreasShapesToPolygonSet( + hightQualityMode ? bufferPolys : bufferZonesPolys, + segcountLowQuality, correctionFactorLQ ); + } + } + + // draw graphic items + for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() ) + { + if( ! item->IsOnLayer( layer ) ) + continue; + + switch( item->Type() ) + { + case PCB_LINE_T: + ((DRAWSEGMENT*) item)->TransformShapeWithClearanceToPolygon( + bufferPolys, 0, + segcountforcircle, + correctionFactor ); + break; + + case PCB_TEXT_T: + ((TEXTE_PCB*) item)->TransformShapeWithClearanceToPolygonSet( + bufferPolys, 0, segcountforcircle, correctionFactor ); + break; + + default: + break; + } + } + + // bufferPolys contains polygons to merge. Many overlaps . Calculate merged polygons + if( bufferPolys.size() == 0 ) + continue; + + KI_POLYGON_SET currLayerPolyset; + KI_POLYGON_SET polysetHoles; + + // Add polygons, without holes + AddPolygonCornersToKiPolygonList( bufferPolys, currLayerPolyset ); + + // 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 ) ); + + 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() ) + { + 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 ); + } + + // 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; + + bufferPolys.clear(); + for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() ) + { + if( ! item->IsOnLayer( layer ) ) + continue; + + switch( item->Type() ) + { + case PCB_LINE_T: + ((DRAWSEGMENT*) item)->TransformShapeWithClearanceToPolygon( + bufferPolys, 0, + segcountforcircle, + correctionFactor ); + break; + + case PCB_TEXT_T: + ((TEXTE_PCB*) item)->TransformShapeWithClearanceToPolygonSet( + bufferPolys, 0, segcountforcircle, correctionFactor ); + break; + + default: + break; + } + } + + for( MODULE* module = pcb->m_Modules; module != 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 ); + } + + // bufferPolys contains polygons to merge. Many overlaps . + // Calculate merged polygons and remove pads and vias holes + if( bufferPolys.size() == 0 ) + continue; + + KI_POLYGON_SET currLayerPolyset; + KI_POLYGON_SET polyset; + AddPolygonCornersToKiPolygonList( bufferPolys, polyset ); + // merge polys: + 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 ); + glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) ); + + bufferPolys.clear(); + CopyPolygonsFromKiPolygonListToPolysList( currLayerPolyset, bufferPolys ); + Draw3D_SolidHorizontalPolyPolygons( bufferPolys, 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 ); +} GLuint EDA_3D_CANVAS::CreateDrawGL_List() { @@ -156,69 +455,15 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List() -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits, 0.0F ); - // 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 - { - LAYER_NUM layer = track->GetLayer(); + // Draw Board: +// For testing purpose only display calculation time to generate 3D data +//#define PRINT_CALCULATION_TIME - if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ) - Draw3D_Track( track ); - } - } +#ifdef PRINT_CALCULATION_TIME + unsigned strtime = GetRunningMicroSecs(); +#endif - if (g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_ZONE]) - { - for( int ii = 0; ii < pcb->GetAreaCount(); ii++ ) - { - LAYER_NUM layer = pcb->GetArea( ii )->GetLayer(); - - if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( layer ) ) - Draw3D_Zone( pcb->GetArea( ii ) ); - } - } - - - // Draw epoxy limits: TODO - - // draw graphic items - EDA_ITEM* PtStruct; - - for( PtStruct = pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() ) - { - switch( PtStruct->Type() ) - { - case PCB_LINE_T: - { - DRAWSEGMENT* segment = (DRAWSEGMENT*) PtStruct; - - if( g_Parm_3D_Visu.m_BoardSettings->IsLayerVisible( segment->GetLayer() ) ) - Draw3D_DrawSegment( segment ); - } - break; - - case PCB_TEXT_T: - { - TEXTE_PCB* text = (TEXTE_PCB*) PtStruct; - - if( Is3DLayerEnabled( text->GetLayer() ) ) - Draw3D_DrawText( text ); - } - break; - - default: - break; - } - } - - // draw footprints - MODULE* Module = pcb->m_Modules; - - for( ; Module != NULL; Module = Module->Next() ) - Module->Draw3D( this ); + BuildBoard3DView(); // Draw grid if( g_Parm_3D_Visu.m_DrawFlags[g_Parm_3D_Visu.FL_GRID] ) @@ -229,97 +474,16 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List() // Test for errors CheckGLError(); +#ifdef PRINT_CALCULATION_TIME + unsigned endtime = GetRunningMicroSecs(); + wxString msg; + msg.Printf( "Built data %.1f ms", (double)(endtime-strtime)/1000 ); + Parent()->SetStatusText( msg, 0 ); +#endif + return m_gllist; } -/* Draw a zone (solid copper areas in aZone) - */ -void EDA_3D_CANVAS::Draw3D_Zone( ZONE_CONTAINER* aZone ) -{ - LAYER_NUM layer = aZone->GetLayer(); - EDA_COLOR_T color = g_ColorsSettings.GetLayerColor( layer ); - int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer ); - - 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 ) ); - - 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 - { - // 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 ); - } - - // Draw copper area outlines - std::vector polysList = aZone->GetFilledPolysList(); - - if( polysList.size() == 0 ) - return; - - if( aZone->GetMinThickness() <= 1 ) - return; - - int imax = polysList.size() - 1; - CPolyPt* firstcorner = &polysList[0]; - CPolyPt* begincorner = firstcorner; - - for( int ic = 1; ic <= imax; ic++ ) - { - CPolyPt* endcorner = &polysList[ic]; - - 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 ); - } - - 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 ); - } - - ic++; - - if( ic < imax - 1 ) - begincorner = firstcorner = &polysList[ic]; - } - else - { - begincorner = endcorner; - } - } -} - // draw a 3D grid: an horizontal grid (XY plane and Z = 0, // and a vertical grid (XZ plane and Y = 0) @@ -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 ); + Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius + thickness/2, height, + thickness, zpos, g_Parm_3D_Visu.m_BiuTo3Dunits ); } -void EDA_3D_CANVAS::Draw3D_DrawSegment( DRAWSEGMENT* segment ) +void MODULE::ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas ) { - 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; - } - } - } -} - - -// 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 ) -{ - 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; iCount(); 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 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; + // Draw the pad hole + wxSize drillsize = aPad->GetDrillSize(); + bool hasHole = drillsize.x && drillsize.y; - // Calculate the center of the pad shape. - wxPoint shape_pos = ReturnShapePos(); - - 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 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 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; + // Draw the hole + Draw3D_ZaxisOblongCylinder( start, end, hole_radius, holeHeight, + thickness, holeZpoz, g_Parm_3D_Visu.m_BiuTo3Dunits ); } - - 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 ); - } - } - } - } 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 ) diff --git a/common/convert_basic_shapes_to_polygon.cpp b/common/convert_basic_shapes_to_polygon.cpp index 2613a82311..620600a869 100644 --- a/common/convert_basic_shapes_to_polygon.cpp +++ b/common/convert_basic_shapes_to_polygon.cpp @@ -32,6 +32,82 @@ #include #include +/* 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) + * Copy polygons from a KI_POLYGON_SET set of polygons to + * a std::vector polygon list + * Therefore we need conversion functions between these 2 descriptions + */ +void CopyPolygonsFromKiPolygonListToPolysList( KI_POLYGON_SET& aKiPolyList, + std::vector& 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 description + * @param aCornersBuffer = source (set of polygons using CPolyPt corners descr) + * @param aPolysList = destination (set of polygons) + */ +void AddPolygonCornersToKiPolygonList( std::vector & aCornersBuffer, + KI_POLYGON_SET& aKiPolyList ) +{ + std::vector 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 & 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 & 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 ); } diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index be413648df..58ff1b34f5 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -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 diff --git a/include/convert_basic_shapes_to_polygon.h b/include/convert_basic_shapes_to_polygon.h index 18fa2b8d39..a64f6bb3cc 100644 --- a/include/convert_basic_shapes_to_polygon.h +++ b/include/convert_basic_shapes_to_polygon.h @@ -35,6 +35,33 @@ #include #include +/** + * 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) + * Copy polygons from a KI_POLYGON_SET set of polygons to + * a std::vector polygon list + * Therefore we need conversion functions between these 2 descriptions + * This function converts a KI_POLYGON_SET description to a + * std::vector 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& aPolysList ); + +/** + * Helper function AddPolygonCornersToKiPolygonList + * This function adds a KI_POLYGON_SET description to a + * std::vector description + * @param aCornersBuffer = source (set of polygons using CPolyPt corners descr) + * @param aPolysList = destination (set of polygons) + */ +void AddPolygonCornersToKiPolygonList( std::vector & 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 & 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 & aCornerBuffer, + wxPoint aCentre, int aRadius, + int aCircleToSegmentsCount, int aWidth ); + #endif // CONVERT_BASIC_SHAPES_TO_POLYGON_H diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index 4ff67dea10..10636c5055 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -18,24 +19,206 @@ #include #include #include +#include +#include #include +/* 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 & 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 & 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 & aCornerBuffer, + int aCircleToSegmentsCount, + double aCorrectionFactor ) +{ + unsigned cornerscount = GetFilledPolysList().size(); + std::vector 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 & aCornerBuffer, - int aClearanceValue, - int aCircleToSegmentsCount, - double aCorrectionFactor ) +void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon( + std::vector & aCornerBuffer, + int aClearanceValue ) const { if( GetText().Length() == 0 ) return; @@ -63,89 +246,80 @@ void TEXTE_PCB::TransformShapeWithClearanceToPolygon( std::vector & 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 & aCornerBuffer, - int aClearanceValue, - int aCircleToSegmentsCount, - double aCorrectionFactor, - bool aAddClearance ) + +/* 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 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 * 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 ) { - - /* 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 zoneOutines; - BuildFilledPolysListData( NULL, &zoneOutines ); - int clearance = 0; - if( aAddClearance ) - { - GetClearance(); - if( aClearanceValue > clearance ) - clearance = aClearanceValue; - } - - // 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 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 resultng polygon in buffer - 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 ); - } + TransformRoundedEndsSegmentToPolygon( *s_cornerBuffer, + wxPoint( x0, y0), wxPoint( xf, yf ), + s_textCircle2SegmentCount, s_textWidth ); } +void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet( + std::vector & aCornerBuffer, + int aClearanceValue, + int aCircleToSegmentsCount, + double aCorrectionFactor ) const +{ + wxSize size = GetSize(); + + if( IsMirrored() ) + NEGATE( size.x ); + + s_cornerBuffer = &aCornerBuffer; + s_textWidth = GetThickness() + ( 2 * aClearanceValue ); + s_textCircle2SegmentCount = aCircleToSegmentsCount; + EDA_COLOR_T color = BLACK; // not actually used, but needed by DrawGraphicText + + if( IsMultilineAllowed() ) + { + wxPoint pos = GetTextPosition(); + wxArrayString* list = wxStringSplit( GetText(), '\n' ); + wxPoint offset; + + offset.y = GetInterline(); + RotatePoint( &offset, GetOrientation() ); + + for( unsigned i = 0; iCount(); i++ ) + { + wxString txt = list->Item( i ); + DrawGraphicText( NULL, NULL, pos, color, + txt, GetOrientation(), size, + GetHorizJustify(), GetVertJustify(), + GetThickness(), IsItalic(), + true, addTextSegmToPoly ); + pos += offset; + } + + delete list; + } + else + { + DrawGraphicText( NULL, NULL, GetTextPosition(), (EDA_COLOR_T) color, + GetText(), GetOrientation(), size, + GetHorizJustify(), GetVertJustify(), + GetThickness(), IsItalic(), + true, addTextSegmToPoly ); + } +} /** @@ -163,20 +337,19 @@ void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( std::vector void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( std::vector & 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 & 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 & 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 & 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 diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index eabeba41bc..0de3ec243e 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -214,7 +214,7 @@ public: void TransformShapeWithClearanceToPolygon( std::vector & aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, - double aCorrectionFactor ); + double aCorrectionFactor ) const; virtual wxString GetSelectMenuText() const; diff --git a/pcbnew/class_edge_mod.h b/pcbnew/class_edge_mod.h index ff2a82bde2..e74eca9efc 100644 --- a/pcbnew/class_edge_mod.h +++ b/pcbnew/class_edge_mod.h @@ -1,9 +1,9 @@ /* * 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 - * 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 + * 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; diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index a8239fcb05..59c196d3f2 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -1,8 +1,8 @@ /* * 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 & 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 & aCornerBuffer, + int aInflateValue, + int aCircleToSegmentsCount, + double aCorrectionFactor ); + /** * Function DrawEdgesOnly diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 1c5de49642..7588629834 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -223,7 +223,7 @@ public: void TransformShapeWithClearanceToPolygon( std::vector & 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 & 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 & aCornerBuffer, + int aInflateValue, int aSegmentsPerCircle ) const; + /** * Function BuildSegmentFromOvalShape * Has meaning only for OVAL (and ROUND) pads diff --git a/pcbnew/class_pad_draw_functions.cpp b/pcbnew/class_pad_draw_functions.cpp index 32d1b9d4f4..215b25df33 100644 --- a/pcbnew/class_pad_draw_functions.cpp +++ b/pcbnew/class_pad_draw_functions.cpp @@ -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; - // be sure delta values are not to large - if( (delta.x < 0) && (delta.x <= -halfsize.y) ) - delta.x = -halfsize.y + 1; + case PAD_TRAPEZOID: + // Trapezoidal pad: verify delta values + delta.x = ( m_DeltaSize.x >> 1 ); + delta.y = ( m_DeltaSize.y >> 1 ); - 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.y < 0) && (delta.y <= -halfsize.x) ) - delta.y = -halfsize.x + 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; + + default: // is used only for rect and trap. pads + return; } // Build the basic rectangular or trapezoid shape diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index 1b83410253..f6264b6404 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -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 & 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 & aCornerBuffer, + void TransformShapeWithClearanceToPolygonSet( std::vector & aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, - double aCorrectionFactor ); + double aCorrectionFactor ) const; wxString GetSelectMenuText() const; diff --git a/pcbnew/class_track.h b/pcbnew/class_track.h index ec4c9b4d3d..598a68f4f9 100644 --- a/pcbnew/class_track.h +++ b/pcbnew/class_track.h @@ -178,7 +178,7 @@ public: void TransformShapeWithClearanceToPolygon( std::vector & aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, - double aCorrectionFactor ); + double aCorrectionFactor ) const; /** * Function SetDrill * sets the drill value for vias. diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 91ac3cdb04..0b6f9167a5 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -263,19 +263,40 @@ public: */ bool HitTestFilledArea( const wxPoint& aRefPos ) const; - /** - * Function BuildFilledPolysListData - * Build m_FilledPolysList data from real outlines (m_Poly) - * 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 + /** + * 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 */ - int BuildFilledPolysListData( BOARD* aPcb, std::vector * aCornerBuffer = NULL ); + void TransformSolidAreasShapesToPolygonSet( std::vector & aCornerBuffer, + int aCircleToSegmentsCount, + double aCorrectionFactor ); + /** + * 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 + * @param aPcb: the current board (can be NULL for non copper zones) + * @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 * 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 & 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 & 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 diff --git a/pcbnew/dialogs/dialog_graphic_item_properties.cpp b/pcbnew/dialogs/dialog_graphic_item_properties.cpp index 0c29dcfc14..6a6beef2b0 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties.cpp @@ -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; diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 7b8b9c9ad3..81aeb6ca4f 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -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: diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index b767aed295..86297f6f3a 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -38,8 +38,24 @@ #include #include +/* 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 * aCornerBuffer ) +bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, + std::vector * aCornerBuffer ) { if( aCornerBuffer == NULL ) m_FilledPolysList.clear(); diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp index 4fe1adc89b..61324cb6c7 100644 --- a/pcbnew/zones_by_polygon_fill_functions.cpp +++ b/pcbnew/zones_by_polygon_fill_functions.cpp @@ -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(); diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp index 8aafa64c78..14ca8d2790 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -61,6 +61,7 @@ #include #include +#include extern void BuildUnconnectedThermalStubsPolygonList( std::vector& aCornerBuffer, @@ -80,10 +81,6 @@ extern void CreateThermalReliefPadPolygon( std::vector& aCornerBuffer, double aCorrectionFactor, int aThermalRot ); -// Exported function -void AddPolygonCornersToKiPolygonList( std::vector & 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 & aCornersBuffer, - KI_POLYGON_SET& aKiPolyList ) -{ - unsigned ii; - - std::vector 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 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 ); } diff --git a/pcbnew/zones_convert_to_polygons_aux_functions.cpp b/pcbnew/zones_convert_to_polygons_aux_functions.cpp index f73b56df88..b981524b67 100644 --- a/pcbnew/zones_convert_to_polygons_aux_functions.cpp +++ b/pcbnew/zones_convert_to_polygons_aux_functions.cpp @@ -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 #include + /* 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 & aCornerBuffer, + int aClearanceValue, bool aAddClearance ) +{ + // Creates the zone outlines polygon (with linked holes if any) + std::vector 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 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 diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index 32a4a411c0..ed20b1e3e3 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -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: