32#include <unordered_set>
43static std::optional<int>
getInPcbUnits(
const nlohmann::json& aObj,
const std::string& aKey,
44 std::optional<int> aDefault = std::optional<int>() )
46 if( aObj.contains( aKey ) && aObj[aKey].is_number() )
53static std::optional<int>
getInSchUnits(
const nlohmann::json& aObj,
const std::string& aKey,
54 std::optional<int> aDefault = std::optional<int>() )
56 if( aObj.contains( aKey ) && aObj[aKey].is_number() )
71 []( nlohmann::json& json_array,
const std::shared_ptr<NETCLASS>& nc )
75 nlohmann::json nc_json = { {
"name", nc->GetName().ToUTF8() },
76 {
"priority", nc->GetPriority() },
77 {
"schematic_color", nc->GetSchematicColor(
true ) },
78 {
"pcb_color", nc->GetPcbColor(
true ) },
79 {
"tuning_profile", nc->GetDelayProfile() } };
82 []( nlohmann::json&
json,
const std::string& aKey,
int aValue )
87 if( nc->HasWireWidth() )
91 if( nc->HasBusWidth() )
94 if( nc->HasLineStyle() )
95 nc_json.push_back( {
"line_style", nc->GetLineStyle() } );
97 if( nc->HasClearance() )
98 saveInPcbUnits( nc_json,
"clearance", nc->GetClearance() );
100 if( nc->HasTrackWidth() )
101 saveInPcbUnits( nc_json,
"track_width", nc->GetTrackWidth() );
103 if( nc->HasViaDiameter() )
104 saveInPcbUnits( nc_json,
"via_diameter", nc->GetViaDiameter() );
106 if( nc->HasViaDrill() )
107 saveInPcbUnits( nc_json,
"via_drill", nc->GetViaDrill() );
109 if( nc->HasuViaDiameter() )
110 saveInPcbUnits( nc_json,
"microvia_diameter", nc->GetuViaDiameter() );
112 if( nc->HasuViaDrill() )
113 saveInPcbUnits( nc_json,
"microvia_drill", nc->GetuViaDrill() );
115 if( nc->HasDiffPairWidth() )
116 saveInPcbUnits( nc_json,
"diff_pair_width", nc->GetDiffPairWidth() );
118 if( nc->HasDiffPairGap() )
119 saveInPcbUnits( nc_json,
"diff_pair_gap", nc->GetDiffPairGap() );
121 if( nc->HasDiffPairViaGap() )
122 saveInPcbUnits( nc_json,
"diff_pair_via_gap", nc->GetDiffPairViaGap() );
124 json_array.push_back( nc_json );
128 [](
const nlohmann::json& entry )
130 wxString
name = entry[
"name"];
132 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>(
name,
false );
134 int priority = entry[
"priority"];
135 nc->SetPriority( priority );
137 nc->SetDelayProfile( entry[
"tuning_profile"] );
140 nc->SetClearance( *value );
143 nc->SetTrackWidth( *value );
146 nc->SetViaDiameter( *value );
149 nc->SetViaDrill( *value );
151 if(
auto value =
getInPcbUnits( entry,
"microvia_diameter" ) )
152 nc->SetuViaDiameter( *value );
155 nc->SetuViaDrill( *value );
158 nc->SetDiffPairWidth( *value );
161 nc->SetDiffPairGap( *value );
163 if(
auto value =
getInPcbUnits( entry,
"diff_pair_via_gap" ) )
164 nc->SetDiffPairViaGap( *value );
167 nc->SetWireWidth( *value );
170 nc->SetBusWidth( *value );
172 if( entry.contains(
"line_style" ) && entry[
"line_style"].is_number() )
173 nc->SetLineStyle( entry[
"line_style"].get<int>() );
175 if( entry.contains(
"pcb_color" ) && entry[
"pcb_color"].is_string() )
176 nc->SetPcbColor( entry[
"pcb_color"].get<KIGFX::COLOR4D>() );
178 if( entry.contains(
"schematic_color" )
179 && entry[
"schematic_color"].is_string() )
181 nc->SetSchematicColor( entry[
"schematic_color"].get<KIGFX::COLOR4D>() );
188 [&]() -> nlohmann::json
190 nlohmann::json ret = nlohmann::json::array();
192 if( m_defaultNetClass )
193 saveNetclass( ret, m_defaultNetClass );
195 for(
const auto& [
name, netclass] : m_netClasses )
196 saveNetclass( ret, netclass );
200 [&](
const nlohmann::json& aJson )
202 if( !aJson.is_array() )
205 m_netClasses.clear();
207 for(
const nlohmann::json& entry : aJson )
209 if( !entry.is_object() || !entry.contains(
"name" ) )
212 std::shared_ptr<NETCLASS> nc = readNetClass( entry );
214 if( nc->IsDefault() )
215 m_defaultNetClass = nc;
217 m_netClasses[nc->GetName()] = nc;
223 [&]() -> nlohmann::json
225 nlohmann::json ret = {};
227 for(
const auto& [netname,
color] : m_netColorAssignments )
229 std::string key( netname.ToUTF8() );
230 ret[ std::move( key ) ] =
color;
235 [&](
const nlohmann::json& aJson )
237 if( !aJson.is_object() )
240 m_netColorAssignments.clear();
242 for(
const auto& pair : aJson.items() )
244 wxString key( pair.key().c_str(), wxConvUTF8 );
245 m_netColorAssignments[std::move( key )] = pair.value().get<
KIGFX::COLOR4D>();
251 [&]() -> nlohmann::json
253 nlohmann::json ret = {};
255 for(
const auto& [netname, netclassNames] : m_netClassLabelAssignments )
257 nlohmann::json netclassesJson = nlohmann::json::array();
259 for(
const auto& netclass : netclassNames )
261 std::string netclassStr( netclass.ToUTF8() );
262 netclassesJson.push_back( std::move( netclassStr ) );
265 std::string key( netname.ToUTF8() );
266 ret[std::move( key )] = netclassesJson;
271 [&](
const nlohmann::json& aJson )
273 if( !aJson.is_object() )
276 m_netClassLabelAssignments.clear();
278 for(
const auto& pair : aJson.items() )
280 wxString key( pair.key().c_str(), wxConvUTF8 );
282 for(
const auto& netclassName : pair.value() )
283 m_netClassLabelAssignments[key].insert( netclassName.get<wxString>() );
289 [&]() -> nlohmann::json
291 nlohmann::json ret = nlohmann::json::array();
293 for(
const auto& [matcher, netclassName] : m_netClassPatternAssignments )
295 nlohmann::json pattern_json = {
296 {
"pattern", matcher->GetPattern().ToUTF8() },
297 {
"netclass", netclassName.ToUTF8() }
300 ret.push_back( std::move( pattern_json ) );
305 [&](
const nlohmann::json& aJson )
307 if( !aJson.is_array() )
310 m_netClassPatternAssignments.clear();
312 for(
const nlohmann::json& entry : aJson )
314 if( !entry.is_object() )
317 if( entry.contains(
"pattern" ) && entry[
"pattern"].is_string()
318 && entry.contains(
"netclass" ) && entry[
"netclass"].is_string() )
320 wxString pattern = entry[
"pattern"].get<wxString>();
321 wxString netclass = entry[
"netclass"].get<wxString>();
323 m_netClassPatternAssignments.push_back(
324 { std::make_unique<EDA_COMBINED_MATCHER>( pattern,
CTX_NETCLASS ),
379 for(
auto& netClass :
m_internals->At(
"classes" ).items() )
381 if( netClass.value().contains(
"nets" ) && netClass.value()[
"nets"].is_array() )
383 nlohmann::json migrated = nlohmann::json::array();
385 for(
auto& net : netClass.value()[
"nets"].items() )
388 netClass.value()[
"nets"] = migrated;
407 nlohmann::json patterns = nlohmann::json::array();
409 for(
auto& netClass :
m_internals->At(
"classes" ).items() )
411 if( netClass.value().contains(
"name" )
412 && netClass.value().contains(
"nets" )
413 && netClass.value()[
"nets"].is_array() )
415 wxString netClassName = netClass.value()[
"name"].get<wxString>();
417 for(
auto& net : netClass.value()[
"nets"].items() )
419 nlohmann::json pattern_json = {
420 {
"pattern", net.value().get<wxString>() },
421 {
"netclass", netClassName }
424 patterns.push_back( pattern_json );
429 m_internals->SetFromString(
"netclass_patterns", patterns );
443 for(
auto& netClass :
m_internals->At(
"classes" ).items() )
446 netClass.value()[
"priority"] = std::numeric_limits<int>::max();
448 netClass.value()[
"priority"] = priority++;
453 if(
m_internals->contains(
"netclass_assignments" )
454 &&
m_internals->At(
"netclass_assignments" ).is_object() )
456 nlohmann::json migrated = {};
458 for(
const auto& pair :
m_internals->At(
"netclass_assignments" ).items() )
460 nlohmann::json netclassesJson = nlohmann::json::array();
462 if( pair.value().get<wxString>() != wxEmptyString )
463 netclassesJson.push_back( pair.value() );
465 migrated[pair.key()] = netclassesJson;
468 m_internals->SetFromString(
"netclass_assignments", migrated );
480 const wxString emptyStr =
"";
482 for(
auto& netClass :
m_internals->At(
"classes" ).items() )
483 netClass.value()[
"tuning_profile"] = emptyStr.ToUTF8();
560 const std::set<wxString>& netclasses )
567 const std::set<wxString>& netclasses )
584 if( assignment.first->GetPattern() == pattern )
586 assignment.second = netclass;
594 { std::make_unique<EDA_COMBINED_MATCHER>( pattern,
CTX_NETCLASS ), netclass } );
601 std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&& netclassPatterns )
608std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&
672 auto getExplicitNetclass = [
this](
const wxString& netclass ) -> std::shared_ptr<NETCLASS>
688 auto getOrAddImplicitNetcless = [
this](
const wxString& netclass ) -> std::shared_ptr<NETCLASS>
694 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( netclass,
false );
695 nc->SetPriority( std::numeric_limits<int>::max() - 1 );
706 if( aNetName.IsEmpty() )
713 return cacheItr->second;
716 std::unordered_set<std::shared_ptr<NETCLASS>> resolvedNetclasses;
723 for(
const wxString& netclassName : it->second )
725 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
729 resolvedNetclasses.insert( std::move( netclass ) );
733 resolvedNetclasses.insert( getOrAddImplicitNetcless( netclassName ) );
741 if( matcher->StartsWith( aNetName ) )
743 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
747 resolvedNetclasses.insert( std::move( netclass ) );
751 resolvedNetclasses.insert( getOrAddImplicitNetcless( netclassName ) );
757 if( resolvedNetclasses.size() == 0 )
767 std::vector<NETCLASS*> netclassPtrs;
769 for(
const std::shared_ptr<NETCLASS>& nc : resolvedNetclasses )
770 netclassPtrs.push_back( nc.get() );
773 name.Printf(
"Effective for net: %s", aNetName );
774 std::shared_ptr<NETCLASS> effectiveNetclass = std::make_shared<NETCLASS>(
name,
false );
777 if( netclassPtrs.size() == 1 )
781 return *resolvedNetclasses.begin();
785 effectiveNetclass->SetConstituentNetclasses( std::move( netclassPtrs ) );
790 return effectiveNetclass;
800 std::vector<NETCLASS*> constituents = nc->GetConstituentNetclasses();
802 wxASSERT( constituents.size() > 0 );
807 constituents.pop_back();
811 nc->ResetParameters();
813 nc->SetConstituentNetclasses( std::move( constituents ) );
819 std::vector<NETCLASS*>& constituentNetclasses )
const
823 std::sort( constituentNetclasses.begin(), constituentNetclasses.end(),
826 int p1 = nc1->GetPriority();
827 int p2 = nc2->GetPriority();
833 return nc1->GetName().Cmp( nc2->GetName() ) < 0;
839 for(
auto itr = constituentNetclasses.rbegin(); itr != constituentNetclasses.rend(); ++itr )
846 effectiveNetclass->SetClearanceParent( nc );
852 effectiveNetclass->SetTrackWidthParent( nc );
858 effectiveNetclass->SetViaDiameterParent( nc );
863 effectiveNetclass->SetViaDrill( nc->
GetViaDrill() );
864 effectiveNetclass->SetViaDrillParent( nc );
870 effectiveNetclass->SetuViaDiameterParent( nc );
876 effectiveNetclass->SetuViaDrillParent( nc );
882 effectiveNetclass->SetDiffPairWidthParent( nc );
888 effectiveNetclass->SetDiffPairGapParent( nc );
894 effectiveNetclass->SetDiffPairViaGapParent( nc );
900 effectiveNetclass->SetWireWidthParent( nc );
905 effectiveNetclass->SetBusWidth( nc->
GetBusWidth() );
906 effectiveNetclass->SetBusWidthParent( nc );
912 effectiveNetclass->SetLineStyleParent( nc );
917 if( pcbColor != COLOR4D::UNSPECIFIED )
919 effectiveNetclass->SetPcbColor( pcbColor );
920 effectiveNetclass->SetPcbColorParent( nc );
925 if( schColor != COLOR4D::UNSPECIFIED )
927 effectiveNetclass->SetSchematicColor( schColor );
928 effectiveNetclass->SetSchematicColorParent( nc );
934 effectiveNetclass->SetDelayProfileParent( nc );
946 bool addedDefault =
false;
1014 addedDefault =
true;
1021 addedDefault =
true;
1029 addedDefault =
true;
1034 return addedDefault;
1051 return c ==
'_' || c ==
'^' || c ==
'~';
1056 std::vector<wxString>* aMemberList )
1060 static wxString digits( wxT(
"0123456789" ) );
1061 return digits.Contains( c );
1064 size_t busLen = aBus.length();
1071 int braceNesting = 0;
1073 prefix.reserve( busLen );
1077 for( ; i < busLen; ++i )
1079 if( aBus[i] ==
'{' )
1086 else if( aBus[i] ==
'}' )
1091 if( aBus[i] ==
' ' || aBus[i] ==
']' )
1094 if( aBus[i] ==
'[' )
1107 for( ; i < busLen; ++i )
1109 if( aBus[i] ==
'.' && i + 1 < busLen && aBus[i+1] ==
'.' )
1111 tmp.ToLong( &begin );
1124 tmp = wxEmptyString;
1129 for( ; i < busLen; ++i )
1131 if( aBus[i] ==
']' )
1146 for( ; i < busLen; ++i )
1148 if( aBus[i] ==
'}' )
1159 if( braceNesting != 0 )
1164 else if( begin >
end )
1165 std::swap( begin,
end );
1172 for(
long idx = begin; idx <=
end; ++idx )
1174 wxString str = prefix;
1178 aMemberList->emplace_back( str );
1187 std::vector<wxString>* aMemberList )
1189 size_t groupLen = aGroup.length();
1193 int braceNesting = 0;
1195 prefix.reserve( groupLen );
1199 for( ; i < groupLen; ++i )
1201 if( aGroup[i] ==
'{' )
1208 else if( aGroup[i] ==
'}' )
1213 if( aGroup[i] ==
' ' || aGroup[i] ==
'[' || aGroup[i] ==
']' )
1216 prefix += aGroup[i];
1219 if( braceNesting != 0 )
1232 for( ; i < groupLen; ++i )
1234 if( aGroup[i] ==
'{' )
1241 else if( aGroup[i] ==
'}' )
1249 if( aMemberList && !tmp.IsEmpty() )
1257 if( aGroup[i] ==
' ' || aGroup[i] ==
',' )
1259 if( aMemberList && !tmp.IsEmpty() )
constexpr EDA_IU_SCALE schIUScale
constexpr EDA_IU_SCALE pcbIUScale
void ReleaseNestedSettings(NESTED_SETTINGS *aSettings)
Saves and frees a nested settings object, if it exists within this one.
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
A color representation with 4 components: red, green, blue, alpha.
NESTED_SETTINGS is a JSON_SETTINGS that lives inside a JSON_SETTINGS.
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
A collection of nets and the parameters used to route or test these nets.
void SetViaDiameter(int aDia)
void SetViaDrill(int aSize)
bool HasLineStyle() const
void SetDelayProfileParent(NETCLASS *aParent)
int GetViaDiameter() const
void SetWireWidthParent(NETCLASS *parent)
static const char Default[]
the name of the default NETCLASS
void SetuViaDrillParent(NETCLASS *parent)
bool HasDelayProfile() const
bool HasuViaDrill() const
void SetDiffPairWidthParent(NETCLASS *parent)
void SetuViaDiameter(int aSize)
void SetDiffPairWidth(int aSize)
int GetDiffPairViaGap() const
void SetViaDrillParent(NETCLASS *parent)
void SetDiffPairGapParent(NETCLASS *parent)
int GetDiffPairGap() const
bool HasViaDiameter() const
bool HasDiffPairWidth() const
bool HasuViaDiameter() const
void SetTrackWidthParent(NETCLASS *parent)
int GetuViaDiameter() const
bool HasTrackWidth() const
void SetViaDiameterParent(NETCLASS *parent)
int GetDiffPairWidth() const
void SetuViaDrill(int aSize)
void SetDelayProfile(const wxString &aDelayProfile)
void SetDiffPairGap(int aSize)
void SetBusWidthParent(NETCLASS *parent)
void SetClearance(int aClearance)
COLOR4D GetPcbColor(bool aIsForSave=false) const
bool HasDiffPairGap() const
COLOR4D GetSchematicColor(bool aIsForSave=false) const
void SetBusWidth(int aWidth)
wxString GetDelayProfile() const
void SetClearanceParent(NETCLASS *parent)
int GetTrackWidth() const
void SetWireWidth(int aWidth)
bool HasWireWidth() const
void SetuViaDiameterParent(NETCLASS *parent)
void SetTrackWidth(int aWidth)
bool HasDiffPairViaGap() const
bool HasClearance() const
NET_SETTINGS stores various net-related settings in a project context.
void ClearAllCaches()
Clears the effective netclass cache for all nets.
std::map< wxString, std::shared_ptr< NETCLASS > > m_compositeNetClasses
Map of netclass names to netclass definitions for.
bool addMissingDefaults(NETCLASS *nc) const
Adds any missing fields to the given netclass from the default netclass.
void ClearNetColorAssignments()
Clears all net name to color assignments Calling user is responsible for resetting the effective netc...
bool operator==(const NET_SETTINGS &aOther) const
void ClearCacheForNet(const wxString &netName)
Clears effective netclass cache for the given net.
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const wxString &aNetName)
Fetches the effective (may be aggregate) netclass for the given net name.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
void ClearNetclassLabelAssignments()
Clears all net name to netclasses assignments Calling user is responsible for resetting the effective...
void ClearNetclassLabelAssignment(const wxString &netName)
Clears a specific net name to netclass assignment Calling user is responsible for resetting the effec...
void ClearNetclassPatternAssignments()
Clears all netclass pattern assignments.
std::map< wxString, KIGFX::COLOR4D > m_netColorAssignments
A map of fully-qualified net names to colors used in the board context.
void SetNetclasses(const std::map< wxString, std::shared_ptr< NETCLASS > > &netclasses)
Sets all netclass Calling this method will reset the effective netclass calculation caches.
bool HasNetclassLabelAssignment(const wxString &netName) const
Determines if a given net name has netclasses assigned.
void SetNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Sets a net name to netclasses assignment Calling user is responsible for resetting the effective netc...
std::shared_ptr< NETCLASS > m_defaultNetClass
The default netclass.
static bool ParseBusGroup(const wxString &aGroup, wxString *name, std::vector< wxString > *aMemberList)
Parse a bus group label into the name and a list of components.
void ClearNetclasses()
Clears all netclasses Calling this method will reset the effective netclass calculation caches.
std::map< wxString, std::shared_ptr< NETCLASS > > m_impicitNetClasses
Map of netclass names to netclass definitions for implicit netclasses.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetCompositeNetclasses() const
Gets all composite (multiple assignment / missing defaults) netclasses.
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > m_netClassPatternAssignments
List of net class pattern assignments.
std::map< wxString, std::shared_ptr< NETCLASS > > m_effectiveNetclassCache
Cache of nets to pattern-matched netclasses.
void SetNetclassPatternAssignments(std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > &&netclassPatterns)
Sets all netclass pattern assignments Calling user is responsible for resetting the effective netclas...
void SetNetclassPatternAssignment(const wxString &pattern, const wxString &netclass)
Sets a netclass pattern assignment Calling this method will reset the effective netclass calculation ...
std::map< wxString, std::shared_ptr< NETCLASS > > m_netClasses
Map of netclass names to netclass definitions.
const std::map< wxString, std::set< wxString > > & GetNetclassLabelAssignments() const
Gets all current net name to netclasses assignments.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetNetclasses() const
Gets all netclasses.
std::shared_ptr< NETCLASS > GetDefaultNetclass()
Gets the default netclass for the project.
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parse a bus vector (e.g.
const std::map< wxString, KIGFX::COLOR4D > & GetNetColorAssignments() const
Gets all net name to color assignments.
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > & GetNetclassPatternAssignments()
Gets the netclass pattern assignments.
void RecomputeEffectiveNetclasses()
Recomputes the internal values of all aggregate effective netclasses Called when a value of a user-de...
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
std::map< wxString, std::set< wxString > > m_netClassLabelAssignments
Map of net names to resolved netclasses.
void SetNetclass(const wxString &netclassName, std::shared_ptr< NETCLASS > &netclass)
Sets the given netclass Calling user is responsible for resetting the effective netclass calculation ...
void makeEffectiveNetclass(std::shared_ptr< NETCLASS > &effectiveNetclass, std::vector< NETCLASS * > &netclasses) const
Creates an effective aggregate netclass from the given constituent netclasses.
void AppendNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Apppends to a net name to netclasses assignment Calling user is responsible for resetting the effecti...
void SetDefaultNetclass(std::shared_ptr< NETCLASS > netclass)
Sets the default netclass for the project Calling user is responsible for resetting the effective net...
std::shared_ptr< NETCLASS > GetNetClassByName(const wxString &aNetName) const
Get a NETCLASS object from a given Netclass name string.
void SetNetColorAssignment(const wxString &netName, const KIGFX::COLOR4D &color)
Sets a net to color assignment Calling user is responsible for resetting the effective netclass calcu...
NET_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
bool HasNetclass(const wxString &netclassName) const
Determines if the given netclass exists.
Like a normal param, but with custom getter and setter functions.
static bool isSuperSubOverbar(wxChar c)
const int netSettingsSchemaVersion
static std::optional< int > getInSchUnits(const nlohmann::json &aObj, const std::string &aKey, std::optional< int > aDefault=std::optional< int >())
static std::optional< int > getInPcbUnits(const nlohmann::json &aObj, const std::string &aKey, std::optional< int > aDefault=std::optional< int >())
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
constexpr double IUTomm(int iu) const
constexpr int IUToMils(int iu) const
constexpr int MilsToIU(int mils) const
constexpr int mmToIU(double mm) const