36#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
58#ifdef PRINT_STATISTICS_3D_VIEWER
69 int aWidth,
int aMaxError,
ERROR_LOC aErrorLoc )
74 aWidth, aMaxError, aErrorLoc );
81 for(
int ii = 0; ii <
path.PointCount(); ++ii )
99 if( item->GetLayer() == aLayer )
100 item->TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
108#define DELETE_AND_FREE( ptr ) \
114#define DELETE_AND_FREE_MAP( map ) \
116 for( auto& [ layer, poly ] : map ) \
160#ifdef PRINT_STATISTICS_3D_VIEWER
163 int64_t start_Time = stats_startCopperLayersTime;
181 std::vector<const PCB_TRACK*> trackList;
198 trackList.push_back( track );
220 std::vector<PCB_LAYER_ID> layer_ids;
229 layer_ids.push_back( layer );
258 if( aStatusReporter )
259 aStatusReporter->
Report(
_(
"Create tracks and vias" ) );
268 for(
const PCB_TRACK* track : trackList )
271 if( !track->IsOnLayer( layer ) )
290 unsigned int nTracks = trackList.size();
292 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
294 const PCB_TRACK *track = trackList[trackIdx];
309 const float thickness =
static_cast<float>( plating / 2.0f );
310 const float hole_inner_radius =
static_cast<float>( holediameter / 2.0f );
311 const float ring_radius =
static_cast<float>( viasize / 2.0f );
316 if( viatype != VIATYPE::THROUGH )
336 hole_inner_radius + thickness,
339 else if( layer == layer_ids[0] )
350 if( hole_inner_radius > 0.0 )
372 const unsigned int nTracks = trackList.size();
374 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
376 const PCB_TRACK *track = trackList[trackIdx];
387 if( viatype != VIATYPE::THROUGH )
417 const int holediameter =
via->GetDrillValue();
426 else if( layer == layer_ids[0] )
428 const int holediameter =
via->GetDrillValue();
430 const int hole_outer_ring_radius =
KiROUND(
via->GetWidth( layer ) / 2.0 );
460 unsigned int nTracks = trackList.size();
462 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
464 const PCB_TRACK *track = trackList[trackIdx];
485 for(
PAD*
pad : footprint->Pads() )
495 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
499 double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
517 for(
PAD*
pad : footprint->Pads() )
527 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
576 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE,
607 if( !item->IsOnLayer( layer ) )
610 switch( item->Type() )
637 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
648 else if( layer ==
B_Cu )
667 if( !item->IsOnLayer( layer ) )
670 switch( item->Type() )
673 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
697 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
707 if( aStatusReporter )
708 aStatusReporter->
Report(
_(
"Create zones" ) );
710 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
711 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
717 zones.emplace_back( std::make_pair( zone, layer ) );
718 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
734 std::atomic<size_t> nextZone( 0 );
735 std::atomic<size_t> threadsFinished( 0 );
737 size_t parallelThreadCount = std::min<size_t>( zones.size(),
738 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
740 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
742 std::thread t = std::thread( [&]()
744 for(
size_t areaId = nextZone.fetch_add( 1 );
745 areaId < zones.size();
746 areaId = nextZone.fetch_add( 1 ) )
748 ZONE* zone = zones[areaId].first;
750 if( zone == nullptr )
753 PCB_LAYER_ID layer = zones[areaId].second;
755 auto layerContainer = m_layerMap.find( layer );
756 auto layerPolyContainer = m_layers_poly.find( layer );
758 if( layerContainer != m_layerMap.end() )
759 addSolidAreasShapes( zone, layerContainer->second, layer );
761 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
762 && layerPolyContainer != m_layers_poly.end() )
764 auto mut_it = layer_lock.find( layer );
766 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
767 zone->TransformSolidAreasShapesToPolygon( layer, *layerPolyContainer->second );
777 while( threadsFinished < parallelThreadCount )
778 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
791 if( aStatusReporter )
792 aStatusReporter->Report(
_(
"Build Tech layers" ) );
813 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
815 if( cfg.subtract_mask_from_silk || cfg.DifferentiatePlatedCopper() )
823 if( aStatusReporter )
824 aStatusReporter->Report( wxString::Format(
_(
"Build Tech layer %d" ), (
int) layer ) );
826 if( !Is3dLayerEnabled( layer, enabledFlags ) )
830 m_layerMap[layer] = layerContainer;
833 m_layers_poly[layer] = layerPoly;
835 if( Is3dLayerEnabled( layer, visibilityFlags ) )
840 if( !item->IsOnLayer( layer ) )
843 switch( item->Type() )
846 addShape(
static_cast<PCB_SHAPE*
>( item ), layerContainer, item, layer );
850 addText(
static_cast<PCB_TEXT*
>( item ), layerContainer, item );
854 addShape(
static_cast<PCB_TEXTBOX*
>( item ), layerContainer, item );
877 for(
PCB_TRACK* track : m_board->Tracks() )
879 if( !track->IsOnLayer( layer ) )
889 int maskExpansion = track->GetSolderMaskExpansion();
890 createTrackWithMargin( track, layerContainer, layer, maskExpansion );
895 for(
FOOTPRINT* footprint : m_board->Footprints() )
899 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
901 for(
PAD*
pad : footprint->Pads() )
903 if( !
pad->IsOnLayer( layer ) )
906 buildPadOutlineAsSegments(
pad, layer, layerContainer, linewidth );
911 addPads( footprint, layerContainer, layer,
false,
false );
914 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
920 for(
ZONE* zone : m_board->Zones() )
922 if( zone->IsOnLayer( layer ) )
923 addSolidAreasShapes( zone, layerContainer, layer );
931 || ( cfg.DifferentiatePlatedCopper() && ( layer ==
F_Mask || layer ==
B_Mask ) ) )
936 if( !item->IsOnLayer( layer ) )
939 switch( item->Type() )
942 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
975 for(
PCB_TRACK* track : m_board->Tracks() )
981 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, maxError,
988 for(
FOOTPRINT* footprint : m_board->Footprints() )
992 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
994 for(
PAD*
pad : footprint->Pads() )
996 if(
pad->IsOnLayer( layer ) )
1005 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1009 footprint->TransformFPTextToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1015 if( cfg.show_zones || layer ==
F_Mask || layer ==
B_Mask )
1017 for(
ZONE* zone : m_board->Zones() )
1019 if( zone->IsOnLayer( layer ) )
1020 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1032 if( cfg.show_off_board_silk )
1034 BOX2I boardBBox = m_board_poly.BBox();
1036 for(
FOOTPRINT* footprint : m_board->Footprints() )
1038 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1040 if( footprint->IsFlipped() )
1041 addPads( footprint, m_offboardPadsBack,
B_Cu,
false,
false );
1043 addPads( footprint, m_offboardPadsFront,
F_Cu,
false,
false );
1047 m_offboardPadsFront->BuildBVH();
1048 m_offboardPadsBack->BuildBVH();
1053 if( aStatusReporter )
1054 aStatusReporter->Report(
_(
"Simplifying copper layer polygons" ) );
1056 if( cfg.DifferentiatePlatedCopper() )
1058 if( aStatusReporter )
1059 aStatusReporter->Report(
_(
"Calculating plated copper" ) );
1062 if( m_layers_poly.find(
F_Mask ) != m_layers_poly.end() )
1064 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
F_Mask ),
1068 if( m_layers_poly.find(
B_Mask ) != m_layers_poly.end() )
1070 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
B_Mask ),
1075 bool hasF_Cu =
false;
1076 bool hasB_Cu =
false;
1078 if( m_layers_poly.find(
F_Cu ) != m_layers_poly.end() )
1085 if( m_layers_poly.find(
B_Cu ) != m_layers_poly.end() )
1093 if( hasF_Cu && m_frontPlatedCopperPolys->OutlineCount() )
1094 m_frontPlatedPadAndGraphicPolys->Append( *m_frontPlatedCopperPolys );
1096 if( hasB_Cu && m_backPlatedCopperPolys->OutlineCount() )
1097 m_backPlatedPadAndGraphicPolys->Append( *m_backPlatedCopperPolys );
1105 for(
FOOTPRINT* footprint : m_board->Footprints() )
1107 addPads( footprint, m_platedPadsFront,
F_Cu,
false,
true );
1108 addPads( footprint, m_platedPadsBack,
B_Cu,
false,
true );
1113 *m_board->GetItem(
niluuid ) );
1116 *m_board->GetItem(
niluuid ) );
1118 m_platedPadsFront->BuildBVH();
1119 m_platedPadsBack->BuildBVH();
1124 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1125 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1127 if( cfg.DifferentiatePlatedCopper() )
1129 layer_id_without_F_and_B.clear();
1130 layer_id_without_F_and_B.reserve( layer_ids.size() );
1134 if( layer !=
F_Cu && layer !=
B_Cu )
1135 layer_id_without_F_and_B.push_back( layer );
1138 selected_layer_id = layer_id_without_F_and_B;
1141 if( selected_layer_id.size() > 0 )
1143 if( aStatusReporter )
1145 aStatusReporter->Report( wxString::Format(
_(
"Simplifying %d copper layers" ),
1146 (
int) selected_layer_id.size() ) );
1149 std::atomic<size_t> nextItem( 0 );
1150 std::atomic<size_t> threadsFinished( 0 );
1152 size_t parallelThreadCount = std::min<size_t>(
1153 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1154 selected_layer_id.size() );
1156 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1158 std::thread t = std::thread(
1159 [&nextItem, &threadsFinished, &selected_layer_id,
this]()
1161 for(
size_t i = nextItem.fetch_add( 1 );
1162 i < selected_layer_id.size();
1163 i = nextItem.fetch_add( 1 ) )
1165 auto layerPoly = m_layers_poly.find( selected_layer_id[i] );
1167 if( layerPoly != m_layers_poly.end() )
1170 layerPoly->second->ClearArcs();
1171 layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
1181 while( threadsFinished < parallelThreadCount )
1182 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1187 if( aStatusReporter )
1188 aStatusReporter->Report(
_(
"Simplify holes contours" ) );
1192 if( m_layerHoleOdPolys.find( layer ) != m_layerHoleOdPolys.end() )
1198 wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
1200 polyLayer = m_layerHoleIdPolys[layer];
1207 if( aStatusReporter )
1208 aStatusReporter->Report(
_(
"Build BVH for holes and vias" ) );
1210 m_TH_IDs.BuildBVH();
1211 m_TH_ODs.BuildBVH();
1212 m_viaAnnuli.BuildBVH();
1214 if( !m_layerHoleMap.empty() )
1216 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1217 hole.second->BuildBVH();
1223 m_layerMap[
B_Mask]->BuildBVH();
1226 m_layerMap[
F_Mask]->BuildBVH();
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
MAP_CONTAINER_2D_BASE m_layerHoleMap
Holes for each layer.
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
BVH_CONTAINER_2D * m_offboardPadsBack
void createLayers(REPORTER *aStatusReporter)
SHAPE_POLY_SET m_TH_ODPolys
PTH outer diameters.
void createTrackWithMargin(const PCB_TRACK *aTrack, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayer, int aMargin=0)
MAP_POLY m_layerHoleOdPolys
Hole outer diameters (per layer)
SHAPE_POLY_SET * m_frontPlatedCopperPolys
MAP_CONTAINER_2D_BASE m_layerMap
2D elements for each layer.
BVH_CONTAINER_2D m_TH_ODs
List of PTH outer diameters.
SHAPE_POLY_SET * m_frontPlatedPadAndGraphicPolys
unsigned int m_trackCount
float m_averageTrackWidth
std::bitset< LAYER_3D_END > GetVisibleLayers() const
void addFootprintShapes(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId, const std::bitset< LAYER_3D_END > &aVisibilityFlags)
MAP_POLY m_layerHoleIdPolys
Hole inner diameters (per layer)
int GetHolePlatingThickness() const noexcept
Get the hole plating thickness (NB: in BOARD UNITS!).
SHAPE_POLY_SET m_viaAnnuliPolys
Via annular ring outer diameters.
BVH_CONTAINER_2D * m_offboardPadsFront
float m_averageViaHoleDiameter
BVH_CONTAINER_2D m_viaTH_ODs
List of via hole outer diameters.
float m_averageHoleDiameter
SHAPE_POLY_SET m_viaTH_ODPolys
Via hole outer diameters.
void addPads(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads)
BVH_CONTAINER_2D * m_platedPadsBack
void createPadWithHole(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aInflateValue)
MAP_POLY m_layers_poly
Amalgamated polygon contours for various types of items.
SHAPE_POLY_SET * m_backPlatedCopperPolys
EDA_3D_VIEWER_SETTINGS * m_Cfg
void addTable(const PCB_TABLE *aTable, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner)
BVH_CONTAINER_2D m_viaAnnuli
List of via annular rings.
unsigned int m_copperLayersCount
BVH_CONTAINER_2D m_TH_IDs
List of PTH inner diameters.
BVH_CONTAINER_2D * m_platedPadsFront
void addShape(const PCB_SHAPE *aShape, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner, PCB_LAYER_ID aLayer)
SHAPE_POLY_SET m_NPTH_ODPolys
NPTH outer diameters.
SHAPE_POLY_SET * m_backPlatedPadAndGraphicPolys
bool Is3dLayerEnabled(PCB_LAYER_ID aLayer, const std::bitset< LAYER_3D_END > &aVisibilityFlags) const
Check if a layer is enabled.
double m_biuTo3Dunits
Scale factor to convert board internal units to 3D units normalized between -1.0 and 1....
void addText(const EDA_TEXT *aText, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM *aOwner)
int m_SolderMaskExpansion
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
const ZONES & Zones() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
const DRAWINGS & Drawings() const
void Add(OBJECT_2D *aObject)
KICAD_T Type() const
Returns the type of object.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the track shape to a closed polygon.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
bool IsTented(PCB_LAYER_ID aLayer) const override
Checks if the given object is tented (its copper shape is covered by solder mask) on a given side of ...
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
Handle a list of polygons defining a copper zone.
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define DELETE_AND_FREE_MAP(map)
void transformFPShapesToPolySet(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer, int aMaxError, ERROR_LOC aErrorLoc)
void buildPadOutlineAsPolygon(const PAD *aPad, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer, int aWidth, int aMaxError, ERROR_LOC aErrorLoc)
#define DELETE_AND_FREE(ptr)
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
bool IsSolderMaskLayer(int aLayer)
@ LAYER_3D_SOLDERMASK_TOP
@ LAYER_3D_SOLDERMASK_BOTTOM
PCB_LAYER_ID
A quick note on layer IDs:
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
bool opengl_copper_thickness
bool clip_silk_on_via_annuli
bool DifferentiatePlatedCopper()
return true if platted copper aeras and non platted copper areas must be drawn using a different colo...
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension