Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Unit Conversion Question

9 REPLIES 9
Reply
Message 1 of 10
roberts
2317 Views, 9 Replies

Unit Conversion Question

roberts
Explorer
Explorer

Hi.

 

I'm trying to modify an open program written in America for calculating embodied carbon in a project. I'm in the UK and the program uses American units. It's taking the units out of Revit and converting them to Imperial when it runs. I've tried changing the conversion from (for example) DisplayUnityType.DUT_Square_Feet to .DUT_Square_Meters but it was out by a huge margin, I assume Revit is multiplying the original Metric value by the new metric conversion factor.

The line of code i'm trying to change is this : 

revitElement.Volume = elementVolume.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(elementVolume[0].AsDouble(), DisplayUnitType.DUT_SQUARE_METERS) : 0.0;

 

Can anyone help? I'm fairly obviously way over my head (did programming at college 15 years ago....) as most of my work these days is in Grasshopper or Dynamo.

 

Many thanks

 

Rob

0 Likes

Unit Conversion Question

Hi.

 

I'm trying to modify an open program written in America for calculating embodied carbon in a project. I'm in the UK and the program uses American units. It's taking the units out of Revit and converting them to Imperial when it runs. I've tried changing the conversion from (for example) DisplayUnityType.DUT_Square_Feet to .DUT_Square_Meters but it was out by a huge margin, I assume Revit is multiplying the original Metric value by the new metric conversion factor.

The line of code i'm trying to change is this : 

revitElement.Volume = elementVolume.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(elementVolume[0].AsDouble(), DisplayUnitType.DUT_SQUARE_METERS) : 0.0;

 

Can anyone help? I'm fairly obviously way over my head (did programming at college 15 years ago....) as most of my work these days is in Grasshopper or Dynamo.

 

Many thanks

 

Rob

9 REPLIES 9
Message 2 of 10
jeremytammik
in reply to: roberts

jeremytammik
Autodesk
Autodesk

You code snippet looks pretty sensible to me.

 

There seems to be a flaw in your logic, though, at least judging from the variable names; you seem to be retrieving a volume and trying to convert it to square meters. A volume would require cubic meters, though, not square. 

 

Could that be the cause of the problem?

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

You code snippet looks pretty sensible to me.

 

There seems to be a flaw in your logic, though, at least judging from the variable names; you seem to be retrieving a volume and trying to convert it to square meters. A volume would require cubic meters, though, not square. 

 

Could that be the cause of the problem?

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 10
roberts
in reply to: jeremytammik

roberts
Explorer
Explorer

Thanks for the reply @jeremytammik . You are absolutely right that that is an error in that snippet (and a dumb one at that haha) however even after going through and double checking the conversions that aren't related to just the volume they're still out by a huge factor. There's obviously something going on that's more complicated than I'm understanding. 

 

The volume appears to be correct now however the other calculations are all based upon the density and that is waaaay out. It should be 7850kg/m3 (490 PCF)

Modified Code:

 private double GetDensity(Material material)
        {
            double density = 0.0;
            var structuralAsset = a_doc.GetElement(material.StructuralAssetId);
            if (structuralAsset != null)
            {
                var densityParam = structuralAsset.GetParameters("Density");
                density = densityParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(densityParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                
                if (density == 0.0)
                {
                    var unitWeightParam = structuralAsset.GetParameters("Unit weight");
                    density = unitWeightParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(unitWeightParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                }
            }
            return density;
        }


Original:

{
            double density = 0.0;
            var structuralAsset = a_doc.GetElement(material.StructuralAssetId);
            if (structuralAsset != null)
            {
                var densityParam = structuralAsset.GetParameters("Density");
                density = densityParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(densityParam[0].AsDouble(), DisplayUnitType.DUT_POUNDS_MASS_PER_CUBIC_FOOT) : 0.0;
                
                if (density == 0.0)
                {
                    var unitWeightParam = structuralAsset.GetParameters("Unit weight");
                    density = unitWeightParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(unitWeightParam[0].AsDouble(), DisplayUnitType.DUT_POUNDS_FORCE_PER_CUBIC_FOOT) : 0.0;
                }
            }
            return density;
        }


If I'm understanding correctly, it's pulling the material density from the imbedded material data, is it possible that it's taking the material and then multiplying it for the conversion or something like that?

Those two bits of program translate to 252657kg/m3 in the modified metric program and 490PCF (correct) in the imperial one.

Thanks for your time, as I said before I'm well out of my depth but we're pretty desperate for a program to calculate our embodied carbon (it's a big issue over here and something that has a lot of movement behind it) and unfortunately all the other plugins and programs I've looked at are far too complex for the simple calculations a structural engineering company wants and because of that complexity are priced far too high to be feasible.

 

Cheers,
Rob

0 Likes

Thanks for the reply @jeremytammik . You are absolutely right that that is an error in that snippet (and a dumb one at that haha) however even after going through and double checking the conversions that aren't related to just the volume they're still out by a huge factor. There's obviously something going on that's more complicated than I'm understanding. 

 

The volume appears to be correct now however the other calculations are all based upon the density and that is waaaay out. It should be 7850kg/m3 (490 PCF)

Modified Code:

 private double GetDensity(Material material)
        {
            double density = 0.0;
            var structuralAsset = a_doc.GetElement(material.StructuralAssetId);
            if (structuralAsset != null)
            {
                var densityParam = structuralAsset.GetParameters("Density");
                density = densityParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(densityParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                
                if (density == 0.0)
                {
                    var unitWeightParam = structuralAsset.GetParameters("Unit weight");
                    density = unitWeightParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(unitWeightParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                }
            }
            return density;
        }


Original:

{
            double density = 0.0;
            var structuralAsset = a_doc.GetElement(material.StructuralAssetId);
            if (structuralAsset != null)
            {
                var densityParam = structuralAsset.GetParameters("Density");
                density = densityParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(densityParam[0].AsDouble(), DisplayUnitType.DUT_POUNDS_MASS_PER_CUBIC_FOOT) : 0.0;
                
                if (density == 0.0)
                {
                    var unitWeightParam = structuralAsset.GetParameters("Unit weight");
                    density = unitWeightParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(unitWeightParam[0].AsDouble(), DisplayUnitType.DUT_POUNDS_FORCE_PER_CUBIC_FOOT) : 0.0;
                }
            }
            return density;
        }


If I'm understanding correctly, it's pulling the material density from the imbedded material data, is it possible that it's taking the material and then multiplying it for the conversion or something like that?

Those two bits of program translate to 252657kg/m3 in the modified metric program and 490PCF (correct) in the imperial one.

Thanks for your time, as I said before I'm well out of my depth but we're pretty desperate for a program to calculate our embodied carbon (it's a big issue over here and something that has a lot of movement behind it) and unfortunately all the other plugins and programs I've looked at are far too complex for the simple calculations a structural engineering company wants and because of that complexity are priced far too high to be feasible.

 

Cheers,
Rob

Message 4 of 10
jeremytammik
in reply to: roberts

jeremytammik
Autodesk
Autodesk

Before anything else, you need to be clear about what unit is used internally in the Revit database.

  

To do so, set the value to 1.0 display units through the user interface.

  

Then, use RevitLookup to analyse what value actually gets stored.

  

That will give you a conversion factor from display unit to internal database unit.

  

With that in hand, you can start figuring out what is being stored internally:

  

https://thebuildingcoder.typepad.com/blog/2013/03/units-and-revitlookup.html

   

With the internal database unit conversion factor to your preferred display unit, you may not require the built-in Revit unit conversion functionality and ConvertFromInternalUnits at all; you can just do it yourself by multiplying with your conversion factor.

 

Here are more unit related articles:

 

https://thebuildingcoder.typepad.com/blog/units/

  



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Before anything else, you need to be clear about what unit is used internally in the Revit database.

  

To do so, set the value to 1.0 display units through the user interface.

  

Then, use RevitLookup to analyse what value actually gets stored.

  

That will give you a conversion factor from display unit to internal database unit.

  

With that in hand, you can start figuring out what is being stored internally:

  

https://thebuildingcoder.typepad.com/blog/2013/03/units-and-revitlookup.html

   

With the internal database unit conversion factor to your preferred display unit, you may not require the built-in Revit unit conversion functionality and ConvertFromInternalUnits at all; you can just do it yourself by multiplying with your conversion factor.

 

Here are more unit related articles:

 

https://thebuildingcoder.typepad.com/blog/units/

  



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 5 of 10
roberts
in reply to: jeremytammik

roberts
Explorer
Explorer

Thanks @jeremytammik. I assume this is what you meant by setting to 1.0 display units? :

roberts_1-1604348862851.png

When I did that I did as you suggest and found this through dblookup (doesn't tell me what unit it is though?) : 
roberts_0-1604348665487.png

0.028316846592 = 1

Interestingly, when I changed the parameter value back to 7850 it seems to have started reading it correctly in the program...

roberts_2-1604349095385.png

 

*shrug*
All very odd to me. But then I am trying to communicate effectively in a language I pretty much only know how to order a beer in....

 

Cheers
Rob

0 Likes

Thanks @jeremytammik. I assume this is what you meant by setting to 1.0 display units? :

roberts_1-1604348862851.png

When I did that I did as you suggest and found this through dblookup (doesn't tell me what unit it is though?) : 
roberts_0-1604348665487.png

0.028316846592 = 1

Interestingly, when I changed the parameter value back to 7850 it seems to have started reading it correctly in the program...

roberts_2-1604349095385.png

 

*shrug*
All very odd to me. But then I am trying to communicate effectively in a language I pretty much only know how to order a beer in....

 

Cheers
Rob

Message 6 of 10
RPTHOMAS108
in reply to: roberts

RPTHOMAS108
Mentor
Mentor

You don't really need to know the internal units since you just use the methods in UnitUtils to convert to and from internal units.

 

However you might be surprised to learn that the internal units for density are kg/ft^3 (it's a half embrace of the metric system).

i.e. 1/(1000/304.8)^3 = 0.028317

 

https://knowledge.autodesk.com/support/revit-products/learn-explore/caas/CloudHelp/cloudhelp/2014/EN...

 

You don't really need to know the internal units since you just use the methods in UnitUtils to convert to and from internal units.

 

However you might be surprised to learn that the internal units for density are kg/ft^3 (it's a half embrace of the metric system).

i.e. 1/(1000/304.8)^3 = 0.028317

 

https://knowledge.autodesk.com/support/revit-products/learn-explore/caas/CloudHelp/cloudhelp/2014/EN...

 

Message 7 of 10
roberts
in reply to: RPTHOMAS108

roberts
Explorer
Explorer

Thanks for that both. It seems as if the unit conversion is really screwing with the program though. Apologies if this is a loaded question, but what would I need to do to remove the conversion in it's entirety? I don't understand the syntax enough to work it out for myself unfortunately. 
I would assume that I could just delete the part of the code that does the conversion but trial and error has shown that it doesn't seem to be that straight forward. 

Below are two snippets of the code that would need tweaking.

if (pt != null && baseLevel != null && topLevel != null)
            {
                var baseOffset = inst.GetParameters("Base Offset");
                var baseOffsetVal = baseOffset != null && baseOffset.Count > 0 ? UnitUtils.ConvertFromInternalUnits(baseOffset[0].AsDouble(), DisplayUnitType.DUT_MILLIMETERS) : 0.0;

                var topOffset = inst.GetParameters("Top Offset");
                var topOffsetVal = topOffset != null && topOffset.Count > 0 ? UnitUtils.ConvertFromInternalUnits(topOffset[0].AsDouble(), DisplayUnitType.DUT_MILLIMETERS) : 0.0;

                var strPt = new XYZ(pt.X, pt.Y, baseLevel.Elevation + baseOffsetVal);
                var endPt = new XYZ(pt.X, pt.Y, topLevel.Elevation + topOffsetVal);

                double length = strPt.DistanceTo(endPt);

 

 if (structuralAsset != null)
            {
                var densityParam = structuralAsset.GetParameters("Density");
                density = densityParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(densityParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                
                if (density == 0.0)
                {
                    var unitWeightParam = structuralAsset.GetParameters("Unit weight");
                    density = unitWeightParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(unitWeightParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                }
            }

 

It's pretty obvious that this is way above my skill level...

 

Cheers

 

Rob

0 Likes

Thanks for that both. It seems as if the unit conversion is really screwing with the program though. Apologies if this is a loaded question, but what would I need to do to remove the conversion in it's entirety? I don't understand the syntax enough to work it out for myself unfortunately. 
I would assume that I could just delete the part of the code that does the conversion but trial and error has shown that it doesn't seem to be that straight forward. 

Below are two snippets of the code that would need tweaking.

if (pt != null && baseLevel != null && topLevel != null)
            {
                var baseOffset = inst.GetParameters("Base Offset");
                var baseOffsetVal = baseOffset != null && baseOffset.Count > 0 ? UnitUtils.ConvertFromInternalUnits(baseOffset[0].AsDouble(), DisplayUnitType.DUT_MILLIMETERS) : 0.0;

                var topOffset = inst.GetParameters("Top Offset");
                var topOffsetVal = topOffset != null && topOffset.Count > 0 ? UnitUtils.ConvertFromInternalUnits(topOffset[0].AsDouble(), DisplayUnitType.DUT_MILLIMETERS) : 0.0;

                var strPt = new XYZ(pt.X, pt.Y, baseLevel.Elevation + baseOffsetVal);
                var endPt = new XYZ(pt.X, pt.Y, topLevel.Elevation + topOffsetVal);

                double length = strPt.DistanceTo(endPt);

 

 if (structuralAsset != null)
            {
                var densityParam = structuralAsset.GetParameters("Density");
                density = densityParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(densityParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                
                if (density == 0.0)
                {
                    var unitWeightParam = structuralAsset.GetParameters("Unit weight");
                    density = unitWeightParam.Count() > 0 ? UnitUtils.ConvertFromInternalUnits(unitWeightParam[0].AsDouble(), DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER) : 0.0;
                }
            }

 

It's pretty obvious that this is way above my skill level...

 

Cheers

 

Rob

Message 8 of 10
jeremytammik
in reply to: roberts

jeremytammik
Autodesk
Autodesk

I am a total DIY fan.

 

If I were you, and if I do not have to care about other users and their display settings and personal unit preferences, I would do exactly what you are requesting: remove the conversion in its entirety.

 

Just retrieve the required values as real numbers, doubles, directly from the Revit database, using the AsDouble method or whatever else you have at hand, check what factors you need to convert them to your own preferred units, and avoid all the complexity and confusion you seem to be struggling with.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes

I am a total DIY fan.

 

If I were you, and if I do not have to care about other users and their display settings and personal unit preferences, I would do exactly what you are requesting: remove the conversion in its entirety.

 

Just retrieve the required values as real numbers, doubles, directly from the Revit database, using the AsDouble method or whatever else you have at hand, check what factors you need to convert them to your own preferred units, and avoid all the complexity and confusion you seem to be struggling with.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 9 of 10
RPTHOMAS108
in reply to: roberts

RPTHOMAS108
Mentor
Mentor

You have all the information you need on the parameter i.e.

 

We previously used Parameter.DisplayUnitType

We now use Parameter.GetUnitTypeId

 

These above give us the form of how the Parameter is represented in the UI according to UI settings.

 

You then use UnitUtils.ConvertToInternalUnits and UnitUtils.ConvertFromInternalUnits with the objects you get from above to convert to and from internal. Doing it any other way is creating a rod for your back.

 

I tend to leave everything internal and then convert upon interaction with the UI. The main problem I still have is comparing fractions of a ft. I can imagine 0.5mm and 0.1mm but 0.1ft not so easy, so sometimes for comparisons I convert to the units I'm familiar with. Ft is not a decimalised unit and shouldn't really be represented that way (it's base 12 in relation to inches). For small distances people tend to think in fractions of inches within the imperial system so that should have really been the internal length unit ideally. However the legacy is the legacy and if we changed now all the Revit models we have would get 12 times smaller!

 

With the smaller base units you also put larger whole numbers on the LHS of the dot which seems better for Floats but I could be wrong on that.

0 Likes

You have all the information you need on the parameter i.e.

 

We previously used Parameter.DisplayUnitType

We now use Parameter.GetUnitTypeId

 

These above give us the form of how the Parameter is represented in the UI according to UI settings.

 

You then use UnitUtils.ConvertToInternalUnits and UnitUtils.ConvertFromInternalUnits with the objects you get from above to convert to and from internal. Doing it any other way is creating a rod for your back.

 

I tend to leave everything internal and then convert upon interaction with the UI. The main problem I still have is comparing fractions of a ft. I can imagine 0.5mm and 0.1mm but 0.1ft not so easy, so sometimes for comparisons I convert to the units I'm familiar with. Ft is not a decimalised unit and shouldn't really be represented that way (it's base 12 in relation to inches). For small distances people tend to think in fractions of inches within the imperial system so that should have really been the internal length unit ideally. However the legacy is the legacy and if we changed now all the Revit models we have would get 12 times smaller!

 

With the smaller base units you also put larger whole numbers on the LHS of the dot which seems better for Floats but I could be wrong on that.

Message 10 of 10
roberts
in reply to: RPTHOMAS108

roberts
Explorer
Explorer

Just wanted to say a "thanks guys", ended up getting it to work by employing company specific Revit materials - something we should have done a long time ago anyway. Units are all converted properly and now just need to do some tweaks to the reinforcement calculations and we're laughing.

0 Likes

Just wanted to say a "thanks guys", ended up getting it to work by employing company specific Revit materials - something we should have done a long time ago anyway. Units are all converted properly and now just need to do some tweaks to the reinforcement calculations and we're laughing.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report