36#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
54#ifdef PRINT_STATISTICS_3D_VIEWER
70 aMaxError, aErrorLoc );
77 for(
int ii = 0; ii <
path.PointCount(); ++ii )
95 if( item->GetLayer() == aLayer )
96 item->TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
104#define DELETE_AND_FREE( ptr ) \
110#define DELETE_AND_FREE_MAP( map ) \
112 for( auto& [ layer, poly ] : map ) \
156#ifdef PRINT_STATISTICS_3D_VIEWER
159 unsigned start_Time = stats_startCopperLayersTime;
180 std::vector<const PCB_TRACK*> trackList;
193 trackList.push_back( track );
216 std::vector<PCB_LAYER_ID> layer_ids;
220 for(
unsigned i = 0; i <
arrayDim( cu_seq ); ++i )
230 layer_ids.push_back( layer );
259 if( aStatusReporter )
260 aStatusReporter->
Report(
_(
"Create tracks and vias" ) );
269 for(
const PCB_TRACK* track : trackList )
272 if( !track->IsOnLayer( layer ) )
291 unsigned int nTracks = trackList.size();
293 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
295 const PCB_TRACK *track = trackList[trackIdx];
310 const float thickness =
static_cast<float>( plating / 2.0f );
311 const float hole_inner_radius =
static_cast<float>( holediameter / 2.0f );
312 const float ring_radius =
static_cast<float>( viasize / 2.0f );
317 if( viatype != VIATYPE::THROUGH )
337 hole_inner_radius + thickness,
340 else if( layer == layer_ids[0] )
351 if( hole_inner_radius > 0.0 )
373 const unsigned int nTracks = trackList.size();
375 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
377 const PCB_TRACK *track = trackList[trackIdx];
388 if( viatype != VIATYPE::THROUGH )
418 const int holediameter =
via->GetDrillValue();
427 else if( layer == layer_ids[0] )
429 const int holediameter =
via->GetDrillValue();
431 const int hole_outer_ring_radius =
KiROUND(
via->GetWidth() / 2.0 );
461 unsigned int nTracks = trackList.size();
463 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
465 const PCB_TRACK *track = trackList[trackIdx];
486 for(
PAD*
pad : footprint->Pads() )
496 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
500 double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
518 for(
PAD*
pad : footprint->Pads() )
528 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
577 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE,
608 if( !item->IsOnLayer( layer ) )
611 switch( item->Type() )
634 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
653 if( !item->IsOnLayer( layer ) )
656 switch( item->Type() )
659 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
679 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
689 if( aStatusReporter )
690 aStatusReporter->
Report(
_(
"Create zones" ) );
692 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
693 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
699 zones.emplace_back( std::make_pair( zone, layer ) );
700 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
716 std::atomic<size_t> nextZone( 0 );
717 std::atomic<size_t> threadsFinished( 0 );
719 size_t parallelThreadCount = std::min<size_t>( zones.size(),
720 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
722 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
724 std::thread t = std::thread( [&]()
726 for(
size_t areaId = nextZone.fetch_add( 1 );
727 areaId < zones.size();
728 areaId = nextZone.fetch_add( 1 ) )
730 ZONE* zone = zones[areaId].first;
732 if( zone == nullptr )
735 PCB_LAYER_ID layer = zones[areaId].second;
737 auto layerContainer = m_layerMap.find( layer );
738 auto layerPolyContainer = m_layers_poly.find( layer );
740 if( layerContainer != m_layerMap.end() )
741 addSolidAreasShapes( zone, layerContainer->second, layer );
743 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
744 && layerPolyContainer != m_layers_poly.end() )
746 auto mut_it = layer_lock.find( layer );
748 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
749 zone->TransformSolidAreasShapesToPolygon( layer, *layerPolyContainer->second );
759 while( threadsFinished < parallelThreadCount )
760 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
773 if( aStatusReporter )
774 aStatusReporter->Report(
_(
"Build Tech layers" ) );
795 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
797 if( cfg.subtract_mask_from_silk || cfg.differentiate_plated_copper )
805 if( aStatusReporter )
806 aStatusReporter->Report( wxString::Format(
_(
"Build Tech layer %d" ), (
int) layer ) );
808 if( !Is3dLayerEnabled( layer, enabledFlags ) )
812 m_layerMap[layer] = layerContainer;
815 m_layers_poly[layer] = layerPoly;
817 if( Is3dLayerEnabled( layer, visibilityFlags ) )
822 if( !item->IsOnLayer( layer ) )
825 switch( item->Type() )
828 addShape(
static_cast<PCB_SHAPE*
>( item ), layerContainer, item );
832 addText(
static_cast<PCB_TEXT*
>( item ), layerContainer, item );
836 addShape(
static_cast<PCB_TEXTBOX*
>( item ), layerContainer, item );
853 if( ( layer ==
F_Mask || layer ==
B_Mask ) && !m_board->GetTentVias() )
857 for(
PCB_TRACK* track : m_board->Tracks() )
862 createViaWithMargin( track, layerContainer, maskExpansion );
868 for(
FOOTPRINT* footprint : m_board->Footprints() )
872 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
874 for(
PAD*
pad : footprint->Pads() )
876 if( !
pad->IsOnLayer( layer ) )
879 buildPadOutlineAsSegments(
pad, layerContainer, linewidth );
884 addPads( footprint, layerContainer, layer,
false,
false );
887 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
893 for(
ZONE* zone : m_board->Zones() )
895 if( zone->IsOnLayer( layer ) )
896 addSolidAreasShapes( zone, layerContainer, layer );
904 || ( cfg.differentiate_plated_copper && ( layer ==
F_Mask || layer ==
B_Mask ) ) )
909 if( !item->IsOnLayer( layer ) )
912 switch( item->Type() )
915 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
940 if( ( layer ==
F_Mask || layer ==
B_Mask ) && !m_board->GetTentVias() )
944 for(
PCB_TRACK* track : m_board->Tracks() )
949 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, maxError,
956 for(
FOOTPRINT* footprint : m_board->Footprints() )
960 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
962 for(
PAD*
pad : footprint->Pads() )
964 if(
pad->IsOnLayer( layer ) )
973 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
977 footprint->TransformFPTextToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
983 if( cfg.show_zones || layer ==
F_Mask || layer ==
B_Mask )
985 for(
ZONE* zone : m_board->Zones() )
987 if( zone->IsOnLayer( layer ) )
988 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1000 if( cfg.show_off_board_silk )
1002 BOX2I boardBBox = m_board_poly.BBox();
1004 for(
FOOTPRINT* footprint : m_board->Footprints() )
1006 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1008 if( footprint->IsFlipped() )
1009 addPads( footprint, m_offboardPadsBack,
B_Cu,
false,
false );
1011 addPads( footprint, m_offboardPadsFront,
F_Cu,
false,
false );
1015 m_offboardPadsFront->BuildBVH();
1016 m_offboardPadsBack->BuildBVH();
1021 if( aStatusReporter )
1022 aStatusReporter->Report(
_(
"Simplifying copper layer polygons" ) );
1024 if( cfg.differentiate_plated_copper )
1026 if( aStatusReporter )
1027 aStatusReporter->Report(
_(
"Calculating plated copper" ) );
1030 if( m_layers_poly.find(
F_Mask ) != m_layers_poly.end() )
1032 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
F_Mask ),
1036 if( m_layers_poly.find(
B_Mask ) != m_layers_poly.end() )
1038 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
B_Mask ),
1043 if( m_layers_poly.find(
F_Cu ) != m_layers_poly.end() )
1049 if( m_layers_poly.find(
B_Cu ) != m_layers_poly.end() )
1061 for(
FOOTPRINT* footprint : m_board->Footprints() )
1063 addPads( footprint, m_platedPadsFront,
F_Cu,
false,
true );
1064 addPads( footprint, m_platedPadsBack,
B_Cu,
false,
true );
1069 *m_board->GetItem(
niluuid ) );
1072 *m_board->GetItem(
niluuid ) );
1074 m_platedPadsFront->BuildBVH();
1075 m_platedPadsBack->BuildBVH();
1080 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1081 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1083 if( cfg.differentiate_plated_copper )
1085 layer_id_without_F_and_B.clear();
1086 layer_id_without_F_and_B.reserve( layer_ids.size() );
1090 if( layer !=
F_Cu && layer !=
B_Cu )
1091 layer_id_without_F_and_B.push_back( layer );
1094 selected_layer_id = layer_id_without_F_and_B;
1097 if( selected_layer_id.size() > 0 )
1099 if( aStatusReporter )
1101 aStatusReporter->Report( wxString::Format(
_(
"Simplifying %d copper layers" ),
1102 (
int) selected_layer_id.size() ) );
1105 std::atomic<size_t> nextItem( 0 );
1106 std::atomic<size_t> threadsFinished( 0 );
1108 size_t parallelThreadCount = std::min<size_t>(
1109 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1110 selected_layer_id.size() );
1112 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1114 std::thread t = std::thread(
1115 [&nextItem, &threadsFinished, &selected_layer_id,
this]()
1117 for(
size_t i = nextItem.fetch_add( 1 );
1118 i < selected_layer_id.size();
1119 i = nextItem.fetch_add( 1 ) )
1121 auto layerPoly = m_layers_poly.find( selected_layer_id[i] );
1123 if( layerPoly != m_layers_poly.end() )
1126 layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
1136 while( threadsFinished < parallelThreadCount )
1137 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1142 if( aStatusReporter )
1143 aStatusReporter->Report(
_(
"Simplify holes contours" ) );
1147 if( m_layerHoleOdPolys.find( layer ) != m_layerHoleOdPolys.end() )
1153 wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
1155 polyLayer = m_layerHoleIdPolys[layer];
1162 if( aStatusReporter )
1163 aStatusReporter->Report(
_(
"Build BVH for holes and vias" ) );
1165 m_TH_IDs.BuildBVH();
1166 m_TH_ODs.BuildBVH();
1167 m_viaAnnuli.BuildBVH();
1169 if( !m_layerHoleMap.empty() )
1171 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1172 hole.second->BuildBVH();
1178 m_layerMap[
B_Mask]->BuildBVH();
1181 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.
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
SHAPE_POLY_SET * m_backPlatedPadPolys
EDA_3D_VIEWER_SETTINGS * m_Cfg
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.
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....
SHAPE_POLY_SET * m_frontPlatedPadPolys
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.
FOOTPRINTS & Footprints()
BOARD_DESIGN_SETTINGS & GetDesignSettings() 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.
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 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)
unsigned 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 differentiate_plated_copper
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_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".