-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: Issues with material quantities solved #2715
Conversation
Hey @connorivy, thanks for the quick feedback. This PR extends the work started in #2655. As this PR is more complex and may require further discussion, it'd be great if we could handle #2655 independently. |
private bool RequiresGeometryComputation(DB.Element element) | ||
{ | ||
if (element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Windows || | ||
element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Doors || | ||
element is DB.Architecture.Railing|| | ||
element is DB.Architecture.TopRail) return true; | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain a bit why you are using these specific clauses to determine if an object needs geometry computation? Were these just the elements you ran into that needed it? If so, how did you know these elements needed it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @connorivy
thanks for the feedback. I am using this specific categories to start with. I am quite sure that there are others but in this way they can be easily added. I introduced the issue previously that the Revit API handles the computation of the areas differently. While for walls, the default computation returns the area of the largest surface (or the area along the LocationCurve multiplied with the height), for other categories, the default method returns the sum of all surfaces.
For now, I chose Windows, doors railing and top rail as those are the ones where we noticed the inconsistency. I am working on a robust testing method where I am comparing the computed quantities to the expected quantities. This should give an overview.
I know that these categories are inconsisten as we are testing the quantities for our use cases.
if(element is DB.MEPCurve ) | ||
{ | ||
// Area and Volume are computed based on geometry elements | ||
GetGeometry(element, out List<DB.Mesh> meshes, out List<DB.Solid> solids); | ||
volume = solids.Sum(s => s.Volume); | ||
area = solids.Select(s => s.Faces.Cast<DB.Face>().Select(face => face.Area).Max()).Sum(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here it looks like you aren't filtering the solids to see if the MaterialElementId == materialId. Could this result in sending incorrect data? Assuming that the material is something that it isn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the very good question. I need to double-check this. I am not completely sure but I don’t see a problem as MEPCurves can only have 1 material. Also, I think that the MEPCurves do not have the material assigned on the solids. But I will verify this once more.
Hey @ks-cph I wanted to say thanks for teaching me a bit about MEP systems in Revit and for making these PRs. I merged in the first one because it added some good functionality. I'm okay with your answers to my above questions and I have one hangup that is preventing me from merging this PR.
The non-MEP elements such as the railing are a bit more intriguing because theoretically this would work if the mesh is acurate, right? One additional question that I have about these types of elements is how we'd be able to separate parent materials from child materials. For example, looking at the materialQuantities of this railing, how do we make sure that there isn't any overlap between the parent's material quantities, and the child's (the topRail property of the railing) materialQunatities. They both share the same material, so I'm not sure if that material is being double counted or not. You've made several PRs dealing with materialQuantities so I am very curious what you think of my comments above. Also maybe fill me in a little more on what you're using materialQuantities for and that may help me understand the data that people actually want to see regarding these quantities. |
Thanks for the excellent feedback. I am working on the material quantities for Real-Time LCA. Let me start with the second comment. With the new implementation, the quantities are computed based on all solids belonging to an element. The TopRail is a different element with its own geometry, so the quantities are not double-counted despite sharing the same material. In regards to the Ducts: The quantities can only be as accurate as the underlying data. So the current implementation is correct. The only option I see for tackling this issue is to expect the user to provide such a property. We can add a thickness property to |
Hi @connorivy, Do you have more input on this? We'd highly appreciate this being included in the next release. |
Hey @ks-cph, jumping in here, thanks again for your PR!
|
Hey @teocomi,
|
Hey @ks-cph let's have a quick chat about this: https://calendly.com/d/4bv-cpb-99q/15-min-chat |
Hey @ks-cph checking in to see if this is still an issue? |
I have changed the code. Now, only Pipes and flex pipes return a volume and area. To point out that the quantities are not correctly calculated, the values are NaN instead of 0. |
Hi' @connorivy and @teocomi @ks-cph committed a new solution to this PR last week addressing the previously discussed issues. Thanks :) |
Hey Martin, we'll get back to you on this next week! Sorry, we were at our retreat. |
Hello @ks-cph and @martinromby , We've discussed it and have decided that we're okay with sending incorrect material quantity values if that is what lives in Revit. However, you've made some recent changes that we don't want to accept. The main change that I'm referring to is narrowing the scope of the legit api calls to only be called for "HostObjects". Now the default materialQuantity retrieval method is to use the "from mesh" version that is more expensive and potentially incorrect. Also, I'm not sure if you are aware that MEPCurve element inherits from HostObject, so the next clause where you are checking if an element is a pipe is unreachable code. In an attempt to make things a bit more performant, I took a stab at implementing the functionality that you are looking for here. Take a look at this branch and let me know if this does what you are looking for. https://github.com/specklesystems/speckle-sharp/tree/revit/connor/material-quantites-add-by-mesh |
Hi Connor, The implemented solution on the branch mentioned would solve parts of our problems. However, it would not solve one of our primary concerns: So we would need more exceptions. As mentioned before, we added the exception for doors, windows, and railings for this reason. |
I was looking into this issue this morning and ran into the post that you made on the autodesk forum https://forums.autodesk.com/t5/revit-api-forum/method-getmaterialarea-appears-to-use-different-formulas-for/td-p/11988215. The response from the developers is quite helpful, and I now see what you have been going for this whole time. Hearing directly from the development team about which elements return the area of a single face versus the area of all sides makes this functionality feel much more solid and less like a shot in the dark. I made some addition adjustments to this branch and I think it is about what you are looking for https://github.com/specklesystems/speckle-sharp/tree/revit/connor/material-quantites-add-by-mesh. It is basically just your PR except I split up the methods in a way that helped me understand better what was going on. Let me know if we are on the same page like I think we are, or not. Pay special attention to the very last method in the ConvertMaterialQuantities file, "MaterialAreaAPICallWillReportSingleFace". Hopefully what this method does is clear because of the name. Let me know if there are any other cases that need to be added |
Hi @connorivy, Lines 51 to 56 in 7b3040c
Could we call |
Hi @connorivy Looks like this is a very promising solution and with the small additions from @ks-cph, regarding Pipe and Duct Insulation, it satisfies the current needs and closes the remaining issues. |
Ah okay, my assumption (and the assumption that this code makes) was that anything that was part of an MEP system would use the material of the MEP system. Can you think of other cases when this is not true. The code addition that you proposed looks fine. One question is that you're using |
Hi @connorivy, I checked this for all classes that inherit from MEPCurve (see the table below). Most classes do not define the MEPSystem. Retrieving them from the Solid works for all but not for Linings and Wires (they don't have a Solid). If you think that this is computationally too expensive, I can try to find another way of finding the material for these categories. I cannot think of any element where there should be multiple solids in one element. But it would be correct to return a collection in case there are more.
|
Hey @ks-cph Check thanks very much for looking into that, that info is very helpful. Check out the branch now. I just added another function "MaterialIsAttachedToMEPSystem" which just controls the route for which elements will have their materials extracted from the mep system. This will fix the issue with insulation because it will no longer use the MEP route. Let me know if this looks good |
Hey @connorivy , Thanks again for your updates. This implementation should now fix the last issues. |
Description & motivation
Solves issue #2117 and improves the calculation of material quantities.
There are some problems with obtaining quantities in Revit:
Changes:
Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs
get the revit material from MEP elementsObjects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs
get materials forMEPCurves
and compute the quantities based on the geometryObjects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs
compute the quantities based on the geometry instead of the Revit API default methods. This is currently only implemented for windows, doors, and railings, but other categories may follow.Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs
compute the length of railings using the path lengthObjects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs
the new method GetGeometry is based on existing codehttps://github.com/specklesystems/speckle-sharp/blob/15f0a8c516b19ae86a6777bd68fcafb2a9ebf29a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial%20Classes/ConvertMeshUtils.cs#L41-78
Validation of changes:
The changes have been tested extensively with the default Revit model.
MEPCurves
: Pipse, ductsChecklist: