27#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
41#ifdef PRINT_STATISTICS_3D_VIEWER
49 int aWidth,
int aMaxError,
ERROR_LOC aErrorLoc )
54 aWidth, aMaxError, aErrorLoc );
61 for(
int ii = 0; ii <
path.PointCount(); ++ii )
79 if( item->GetLayer() == aLayer )
80 item->TransformShapeToPolySet( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
92 if( item->GetLayer() != aLayer )
109 text->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
120 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
139 if( field->GetLayer() == aLayer && field->IsVisible() )
140 field->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
147#define DELETE_AND_FREE( ptr ) \
153#define DELETE_AND_FREE_MAP( map ) \
155 for( auto& [ layer, poly ] : map ) \
197#ifdef PRINT_STATISTICS_3D_VIEWER
200 int64_t start_Time = stats_startCopperLayersTime;
218 std::vector<const PCB_TRACK*> trackList;
235 trackList.push_back( track );
257 std::vector<PCB_LAYER_ID> layer_ids;
266 layer_ids.push_back( layer );
293 if( aStatusReporter )
294 aStatusReporter->
Report(
_(
"Create tracks and vias" ) );
303 for(
const PCB_TRACK* track : trackList )
306 if( !track->IsOnLayer( layer ) )
325 unsigned int nTracks = trackList.size();
327 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
329 const PCB_TRACK *track = trackList[trackIdx];
344 const float thickness =
static_cast<float>( plating / 2.0f );
345 const float hole_inner_radius =
static_cast<float>( holediameter / 2.0f );
346 const float ring_radius =
static_cast<float>( viasize / 2.0f );
351 if( viatype != VIATYPE::THROUGH )
371 hole_inner_radius + thickness,
374 else if( layer == layer_ids[0] )
383 if( hole_inner_radius > 0.0 )
399 const unsigned int nTracks = trackList.size();
401 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
403 const PCB_TRACK *track = trackList[trackIdx];
414 if( viatype != VIATYPE::THROUGH )
444 const int holediameter =
via->GetDrillValue();
453 else if( layer == layer_ids[0] )
455 const int holediameter =
via->GetDrillValue();
457 const int hole_outer_ring_radius =
KiROUND(
via->GetWidth( layer ) / 2.0 );
487 unsigned int nTracks = trackList.size();
489 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
491 const PCB_TRACK *track = trackList[trackIdx];
512 for(
PAD*
pad : footprint->Pads() )
522 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
526 double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
544 for(
PAD*
pad : footprint->Pads() )
554 if(
pad->GetAttribute () != PAD_ATTRIB::NPTH )
582 addPads( footprint, layerContainer, layer );
604 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
620 if( !item->IsOnLayer( layer ) )
623 switch( item->Type() )
650 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
668 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, maxError,
ERROR_INSIDE );
677 item->TransformShapeToPolySet( *copperPolys, layer, 0, maxError,
ERROR_INSIDE );
695 if( !item->IsOnLayer( layer ) )
698 switch( item->Type() )
701 item->TransformShapeToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
717 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
728 cell->TransformTextToPolySet( *layerPoly, 0, maxError,
ERROR_INSIDE );
741 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ),
751 if( aStatusReporter )
752 aStatusReporter->
Report(
_(
"Create zones" ) );
754 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
755 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
761 zones.emplace_back( std::make_pair( zone, layer ) );
762 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
772 std::atomic<size_t> nextZone( 0 );
773 std::atomic<size_t> threadsFinished( 0 );
775 size_t parallelThreadCount = std::min<size_t>( zones.size(),
776 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
778 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
780 std::thread t = std::thread( [&]()
782 for(
size_t areaId = nextZone.fetch_add( 1 );
783 areaId < zones.size();
784 areaId = nextZone.fetch_add( 1 ) )
786 ZONE* zone = zones[areaId].first;
788 if( zone == nullptr )
791 PCB_LAYER_ID layer = zones[areaId].second;
793 if( m_layerMap.contains( layer ) )
794 addSolidAreasShapes( zone, m_layerMap[layer], layer );
796 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
797 && m_layers_poly.contains( layer ) )
799 auto mut_it = layer_lock.find( layer );
801 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
802 zone->TransformSolidAreasShapesToPolygon( layer, *m_layers_poly[layer] );
812 while( threadsFinished < parallelThreadCount )
813 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
818 m_TH_ODPolys.Simplify();
819 m_NPTH_ODPolys.Simplify();
820 m_viaTH_ODPolys.Simplify();
821 m_viaAnnuliPolys.Simplify();
826 if( aStatusReporter )
827 aStatusReporter->Report(
_(
"Build Tech layers" ) );
893 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
895 if( cfg.subtract_mask_from_silk || cfg.DifferentiatePlatedCopper() )
903 if( aStatusReporter )
904 aStatusReporter->Report( wxString::Format(
_(
"Build Tech layer %d" ), (
int) layer ) );
906 if( !Is3dLayerEnabled( layer, enabledFlags ) )
910 m_layerMap[layer] = layerContainer;
913 m_layers_poly[layer] = layerPoly;
915 if( Is3dLayerEnabled( layer, visibilityFlags ) )
920 if( !item->IsOnLayer( layer ) )
923 switch( item->Type() )
926 addShape(
static_cast<PCB_SHAPE*
>( item ), layerContainer, item, layer );
930 addText(
static_cast<PCB_TEXT*
>( item ), layerContainer, item );
934 addShape(
static_cast<PCB_TEXTBOX*
>( item ), layerContainer, item );
938 addTable(
static_cast<PCB_TABLE*
>( item ), layerContainer, item );
957 for(
PCB_TRACK* track : m_board->Tracks() )
959 if( !track->IsOnLayer( layer ) )
969 if( !
via->FlashLayer( copper_layer ) )
974 createTrackWithMargin( track, layerContainer, layer, maskExpansion );
979 for(
FOOTPRINT* footprint : m_board->Footprints() )
983 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
985 for(
PAD*
pad : footprint->Pads() )
987 if( !
pad->IsOnLayer( layer ) )
990 buildPadOutlineAsSegments(
pad, layer, layerContainer, linewidth );
995 addPads( footprint, layerContainer, layer );
998 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
1002 if( cfg.show_zones )
1004 for(
ZONE* zone : m_board->Zones() )
1006 if( zone->IsOnLayer( layer ) )
1007 addSolidAreasShapes( zone, layerContainer, layer );
1015 || ( cfg.DifferentiatePlatedCopper() && ( layer ==
F_Mask || layer ==
B_Mask ) ) )
1018 for(
BOARD_ITEM* item : m_board->Drawings() )
1020 if( !item->IsOnLayer( layer ) )
1023 switch( item->Type() )
1026 item->TransformShapeToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1042 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1053 cell->TransformTextToPolySet( *layerPoly, 0, maxError,
ERROR_INSIDE );
1060 seg.TransformToPolygon( *layerPoly, maxError,
ERROR_INSIDE );
1076 for(
PCB_TRACK* track : m_board->Tracks() )
1082 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, maxError,
ERROR_INSIDE );
1088 for(
FOOTPRINT* footprint : m_board->Footprints() )
1092 int linewidth = m_board->GetDesignSettings().m_LineThickness[
LAYER_CLASS_SILK ];
1094 for(
PAD*
pad : footprint->Pads() )
1096 if(
pad->IsOnLayer( layer ) )
1102 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError,
ERROR_INSIDE );
1109 if( cfg.show_zones || layer ==
F_Mask || layer ==
B_Mask )
1111 for(
ZONE* zone : m_board->Zones() )
1113 if( zone->IsOnLayer( layer ) )
1114 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1126 if( cfg.show_off_board_silk )
1128 BOX2I boardBBox = m_board_poly.BBox();
1130 for(
FOOTPRINT* footprint : m_board->Footprints() )
1132 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1134 if( footprint->IsFlipped() )
1135 addPads( footprint, m_offboardPadsBack,
B_Cu );
1137 addPads( footprint, m_offboardPadsFront,
F_Cu );
1141 m_offboardPadsFront->BuildBVH();
1142 m_offboardPadsBack->BuildBVH();
1147 if( aStatusReporter )
1148 aStatusReporter->Report(
_(
"Simplifying copper layer polygons" ) );
1150 if( cfg.DifferentiatePlatedCopper() )
1152 if( aStatusReporter )
1153 aStatusReporter->Report(
_(
"Calculating plated copper" ) );
1156 if( m_layers_poly.contains(
F_Mask ) )
1157 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
F_Mask ) );
1159 if( m_layers_poly.contains(
B_Mask ))
1160 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at(
B_Mask ) );
1163 if( m_layers_poly.contains(
F_Cu ) )
1164 m_layers_poly[
F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys );
1166 if( m_layers_poly.contains(
B_Cu ) )
1167 m_layers_poly[
B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys );
1171 *m_board->GetItem(
niluuid ) );
1174 *m_board->GetItem(
niluuid ) );
1176 m_platedPadsFront->BuildBVH();
1177 m_platedPadsBack->BuildBVH();
1182 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1183 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1185 if( cfg.DifferentiatePlatedCopper() )
1187 layer_id_without_F_and_B.clear();
1188 layer_id_without_F_and_B.reserve( layer_ids.size() );
1192 if( layer !=
F_Cu && layer !=
B_Cu )
1193 layer_id_without_F_and_B.push_back( layer );
1196 selected_layer_id = layer_id_without_F_and_B;
1199 if( selected_layer_id.size() > 0 )
1201 if( aStatusReporter )
1203 aStatusReporter->Report( wxString::Format(
_(
"Simplifying %d copper layers" ),
1204 (
int) selected_layer_id.size() ) );
1207 std::atomic<size_t> nextItem( 0 );
1208 std::atomic<size_t> threadsFinished( 0 );
1210 size_t parallelThreadCount = std::min<size_t>(
1211 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1212 selected_layer_id.size() );
1214 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1216 std::thread t = std::thread(
1217 [&nextItem, &threadsFinished, &selected_layer_id,
this]()
1219 for(
size_t i = nextItem.fetch_add( 1 );
1220 i < selected_layer_id.size();
1221 i = nextItem.fetch_add( 1 ) )
1223 if( m_layers_poly.contains( selected_layer_id[i] ) )
1226 m_layers_poly[ selected_layer_id[i] ]->ClearArcs();
1227 m_layers_poly[ selected_layer_id[i] ]->Simplify();
1237 while( threadsFinished < parallelThreadCount )
1238 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1243 if( aStatusReporter )
1244 aStatusReporter->Report(
_(
"Simplify holes contours" ) );
1248 if( m_layerHoleOdPolys.contains( layer ) )
1254 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
1256 polyLayer = m_layerHoleIdPolys[layer];
1263 if( aStatusReporter )
1264 aStatusReporter->Report(
_(
"Build BVH for holes and vias" ) );
1266 m_TH_IDs.BuildBVH();
1267 m_TH_ODs.BuildBVH();
1268 m_viaAnnuli.BuildBVH();
1270 if( !m_layerHoleMap.empty() )
1272 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1273 hole.second->BuildBVH();
1279 m_layerMap[
B_Mask]->BuildBVH();
1282 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 addPads(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
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.
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.
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.
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
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
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.
int GetSolderMaskExpansion() const
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()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
Simple container to manage line stroke parameters.
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 transformFPTextToPolySet(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, const std::bitset< LAYER_3D_END > &aFlags, 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
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
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