36#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
57#ifdef PRINT_STATISTICS_3D_VIEWER
73 aMaxError, aErrorLoc );
80 for(
int ii = 0; ii <
path.PointCount(); ++ii )
98 if( item->GetLayer() == aLayer )
99 item->TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
107#define DELETE_AND_FREE( ptr ) \
113#define DELETE_AND_FREE_MAP( map ) \
115 for( auto& [ layer, poly ] : map ) \
159#ifdef PRINT_STATISTICS_3D_VIEWER
162 int64_t start_Time = stats_startCopperLayersTime;
183 std::vector<const PCB_TRACK*> trackList;
196 trackList.push_back( track );
219 std::vector<PCB_LAYER_ID> layer_ids;
223 for(
unsigned i = 0; i <
arrayDim( cu_seq ); ++i )
231 layer_ids.push_back( layer );
260 if( aStatusReporter )
261 aStatusReporter->
Report(
_(
"Create tracks and vias" ) );
270 for(
const PCB_TRACK* track : trackList )
273 if( !track->IsOnLayer( layer ) )
292 unsigned int nTracks = trackList.size();
294 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
296 const PCB_TRACK *track = trackList[trackIdx];
311 const float thickness =
static_cast<float>( plating / 2.0f );
312 const float hole_inner_radius =
static_cast<float>( holediameter / 2.0f );
313 const float ring_radius =
static_cast<float>( viasize / 2.0f );
318 if( viatype != VIATYPE::THROUGH )
338 hole_inner_radius + thickness,
341 else if( layer == layer_ids[0] )
352 if( hole_inner_radius > 0.0 )
374 const unsigned int nTracks = trackList.size();
376 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
378 const PCB_TRACK *track = trackList[trackIdx];
389 if( viatype != VIATYPE::THROUGH )
419 const int holediameter =
via->GetDrillValue();
428 else if( layer == layer_ids[0] )
430 const int holediameter =
via->GetDrillValue();
432 const int hole_outer_ring_radius =
KiROUND(
via->GetWidth() / 2.0 );
462 unsigned int nTracks = trackList.size();
464 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
466 const PCB_TRACK *track = trackList[trackIdx];
487 for(
PAD*
pad : footprint->Pads() )
497 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
501 double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
519 for(
PAD*
pad : footprint->Pads() )
529 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
578 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE,
609 if( !item->IsOnLayer( layer ) )
612 switch( item->Type() )
639 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
650 else if( layer ==
B_Cu )
669 if( !item->IsOnLayer( layer ) )
672 switch( item->Type() )
675 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
699 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
709 if( aStatusReporter )
710 aStatusReporter->
Report(
_(
"Create zones" ) );
712 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
713 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
719 zones.emplace_back( std::make_pair( zone, layer ) );
720 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
736 std::atomic<size_t> nextZone( 0 );
737 std::atomic<size_t> threadsFinished( 0 );
739 size_t parallelThreadCount = std::min<size_t>( zones.size(),
740 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
742 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
744 std::thread t = std::thread( [&]()
746 for(
size_t areaId = nextZone.fetch_add( 1 );
747 areaId < zones.size();
748 areaId = nextZone.fetch_add( 1 ) )
750 ZONE* zone = zones[areaId].first;
752 if( zone == nullptr )
755 PCB_LAYER_ID layer = zones[areaId].second;
757 auto layerContainer = m_layerMap.find( layer );
758 auto layerPolyContainer = m_layers_poly.find( layer );
760 if( layerContainer != m_layerMap.end() )
761 addSolidAreasShapes( zone, layerContainer->second, layer );
763 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
764 && layerPolyContainer != m_layers_poly.end() )
766 auto mut_it = layer_lock.find( layer );
768 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
769 zone->TransformSolidAreasShapesToPolygon( layer, *layerPolyContainer->second );
779 while( threadsFinished < parallelThreadCount )
780 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
793 if( aStatusReporter )
794 aStatusReporter->Report(
_(
"Build Tech layers" ) );
815 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
817 if( cfg.subtract_mask_from_silk || cfg.DifferentiatePlatedCopper() )
825 if( aStatusReporter )
826 aStatusReporter->Report( wxString::Format(
_(
"Build Tech layer %d" ), (
int) layer ) );
828 if( !Is3dLayerEnabled( layer, enabledFlags ) )
832 m_layerMap[layer] = layerContainer;
835 m_layers_poly[layer] = layerPoly;
837 if( Is3dLayerEnabled( layer, visibilityFlags ) )
842 if( !item->IsOnLayer( layer ) )
845 switch( item->Type() )
848 addShape(
static_cast<PCB_SHAPE*
>( item ), layerContainer, item );
852 addText(
static_cast<PCB_TEXT*
>( item ), layerContainer, item );
856 addShape(
static_cast<PCB_TEXTBOX*
>( item ), layerContainer, item );
881 for(
PCB_TRACK* track : m_board->Tracks() )
887 createViaWithMargin( track, layerContainer, maskExpansion );
893 for(
FOOTPRINT* footprint : m_board->Footprints() )
897 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
899 for(
PAD*
pad : footprint->Pads() )
901 if( !
pad->IsOnLayer( layer ) )
904 buildPadOutlineAsSegments(
pad, layerContainer, linewidth );
909 addPads( footprint, layerContainer, layer,
false,
false );
912 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
918 for(
ZONE* zone : m_board->Zones() )
920 if( zone->IsOnLayer( layer ) )
921 addSolidAreasShapes( zone, layerContainer, layer );
929 || ( cfg.DifferentiatePlatedCopper() && ( layer ==
F_Mask || layer ==
B_Mask ) ) )
934 if( !item->IsOnLayer( layer ) )
937 switch( item->Type() )
940 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
973 for(
PCB_TRACK* track : m_board->Tracks() )
979 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, maxError,
986 for(
FOOTPRINT* footprint : m_board->Footprints() )
990 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
992 for(
PAD*
pad : footprint->Pads() )
994 if(
pad->IsOnLayer( layer ) )
1003 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1007 footprint->TransformFPTextToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1013 if( cfg.show_zones || layer ==
F_Mask || layer ==
B_Mask )
1015 for(
ZONE* zone : m_board->Zones() )
1017 if( zone->IsOnLayer( layer ) )
1018 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1030 if( cfg.show_off_board_silk )
1032 BOX2I boardBBox = m_board_poly.BBox();
1034 for(
FOOTPRINT* footprint : m_board->Footprints() )
1036 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1038 if( footprint->IsFlipped() )
1039 addPads( footprint, m_offboardPadsBack,
B_Cu,
false,
false );
1041 addPads( footprint, m_offboardPadsFront,
F_Cu,
false,
false );
1045 m_offboardPadsFront->BuildBVH();
1046 m_offboardPadsBack->BuildBVH();
1051 if( aStatusReporter )
1052 aStatusReporter->Report(
_(
"Simplifying copper layer polygons" ) );
1054 if( cfg.DifferentiatePlatedCopper() )
1056 if( aStatusReporter )
1057 aStatusReporter->Report(
_(
"Calculating plated copper" ) );
1060 if( m_layers_poly.find(
F_Mask ) != m_layers_poly.end() )
1062 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
F_Mask ),
1066 if( m_layers_poly.find(
B_Mask ) != m_layers_poly.end() )
1068 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
B_Mask ),
1073 bool hasF_Cu =
false;
1074 bool hasB_Cu =
false;
1076 if( m_layers_poly.find(
F_Cu ) != m_layers_poly.end() )
1083 if( m_layers_poly.find(
B_Cu ) != m_layers_poly.end() )
1091 if( hasF_Cu && m_frontPlatedCopperPolys->OutlineCount() )
1092 m_frontPlatedPadAndGraphicPolys->Append( *m_frontPlatedCopperPolys );
1094 if( hasB_Cu && m_backPlatedCopperPolys->OutlineCount() )
1095 m_backPlatedPadAndGraphicPolys->Append( *m_backPlatedCopperPolys );
1103 for(
FOOTPRINT* footprint : m_board->Footprints() )
1105 addPads( footprint, m_platedPadsFront,
F_Cu,
false,
true );
1106 addPads( footprint, m_platedPadsBack,
B_Cu,
false,
true );
1111 *m_board->GetItem(
niluuid ) );
1114 *m_board->GetItem(
niluuid ) );
1116 m_platedPadsFront->BuildBVH();
1117 m_platedPadsBack->BuildBVH();
1122 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1123 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1125 if( cfg.DifferentiatePlatedCopper() )
1127 layer_id_without_F_and_B.clear();
1128 layer_id_without_F_and_B.reserve( layer_ids.size() );
1132 if( layer !=
F_Cu && layer !=
B_Cu )
1133 layer_id_without_F_and_B.push_back( layer );
1136 selected_layer_id = layer_id_without_F_and_B;
1139 if( selected_layer_id.size() > 0 )
1141 if( aStatusReporter )
1143 aStatusReporter->Report( wxString::Format(
_(
"Simplifying %d copper layers" ),
1144 (
int) selected_layer_id.size() ) );
1147 std::atomic<size_t> nextItem( 0 );
1148 std::atomic<size_t> threadsFinished( 0 );
1150 size_t parallelThreadCount = std::min<size_t>(
1151 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1152 selected_layer_id.size() );
1154 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1156 std::thread t = std::thread(
1157 [&nextItem, &threadsFinished, &selected_layer_id,
this]()
1159 for(
size_t i = nextItem.fetch_add( 1 );
1160 i < selected_layer_id.size();
1161 i = nextItem.fetch_add( 1 ) )
1163 auto layerPoly = m_layers_poly.find( selected_layer_id[i] );
1165 if( layerPoly != m_layers_poly.end() )
1168 layerPoly->second->ClearArcs();
1169 layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
1179 while( threadsFinished < parallelThreadCount )
1180 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1185 if( aStatusReporter )
1186 aStatusReporter->Report(
_(
"Simplify holes contours" ) );
1190 if( m_layerHoleOdPolys.find( layer ) != m_layerHoleOdPolys.end() )
1196 wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
1198 polyLayer = m_layerHoleIdPolys[layer];
1205 if( aStatusReporter )
1206 aStatusReporter->Report(
_(
"Build BVH for holes and vias" ) );
1208 m_TH_IDs.BuildBVH();
1209 m_TH_ODs.BuildBVH();
1210 m_viaAnnuli.BuildBVH();
1212 if( !m_layerHoleMap.empty() )
1214 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1215 hole.second->BuildBVH();
1221 m_layerMap[
B_Mask]->BuildBVH();
1224 m_layerMap[
F_Mask]->BuildBVH();
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
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.
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)
void addShape(const PCB_SHAPE *aShape, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner)
void createTrack(const PCB_TRACK *aTrack, CONTAINER_2D_BASE *aDstContainer)
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
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...
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
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.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
VECTOR2I ShapePos() const
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
PAD_SHAPE GetShape() const
const VECTOR2I & GetSize() 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 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.
void buildPadOutlineAsPolygon(const PAD *aPad, SHAPE_POLY_SET &aBuffer, int aWidth, int aMaxError, ERROR_LOC aErrorLoc)
#define DELETE_AND_FREE_MAP(map)
void transformFPShapesToPolySet(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer, int aMaxError, ERROR_LOC aErrorLoc)
#define DELETE_AND_FREE(ptr)
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
@ LAYER_3D_SOLDERMASK_TOP
@ LAYER_3D_SOLDERMASK_BOTTOM
PCB_LAYER_ID
A quick note on layer IDs:
PCB_LAYER_ID ToLAYER_ID(int aLayer)
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
constexpr ret_type KiROUND(fp_type v, bool aQuiet=false)
Round a floating point number to an integer using "round halfway cases away from zero".