Convex Hull and Volume Computation

Max raised an interesting question in a comment on the discussion on the

calculation of 2D polygon areas
:

Question:
If I have an array of 3d points, how can I do to get volume information?

Answer:
The answer is maybe not quite as easy as you expected.
To calculate that volume, you have to solve two tasks:

Both of these steps are non-trivial.
A number of different

convex hull algorithms

exist both for the two-dimensional and for higher dimensional cases.
Several open source libraries for solid modelling or computational geometry implement these.
One of the best known and most reliable tools which is specifically targeted at these two issues is

Qhull
.
Here is the blurb from its home page:

Qhull computes the convex hull, Delaunay triangulation, Voronoi diagram, halfspace intersection about a point, furthest-site Delaunay triangulation, and furthest-site Voronoi diagram.
The source code runs in 2-d, 3-d, 4-d, and higher dimensions.
Qhull implements the Quickhull algorithm for computing the convex hull.
It handles roundoff errors from floating point arithmetic.
It computes volumes, surface areas, and approximations to the convex hull.

I downloaded the current version of Qhull to explore exactly what you might be able to use for your purposes.
The Qhull distribution includes a list of sample programs.
One of these is qconvex, and one of its output options is FA to compute total area and volume of the input points, which is pretty exactly what you want.

Now how can you make use of this inside the Revit API?

Qhull is implemented in standard C, the Revit API is a .NET environment.
The easiest way to make use of C source code from .NET is to compile a DLL and call it from .NET.
In this case you would need to analyse the source code for the qconvex program, which is contained in the file qconvex.c, and package the required functionality in a DLL that you make accessible from .NET.

The relevant lines of code from qconvex.c are:


qh_checkflags (qh qhull_command, hidden_options);
qh_initflags (qh qhull_command);
points= qh_readpoints (&numpoints, &dim, &ismalloc);
qh_init_B (points, numpoints, dim, ismalloc);
qh_qhull();
qh_check_output();
qh_produce_output();

This program reads its input from a file or the console standard input stream, performs its calculations, and produces its output into a file or the standard output stream.
You would need to adapt this to pass the information from and to the .NET calling application.

Another alternative, possible much simpler, but obviously less efficient, would be to set up the .NET application to write and read files in the expected Qhull input and output formats and then execute the unchanged qconvex executable provided by the Qhull package.

Reply from Max:
Very good this library, but we need a wrapper for .NET, and how can I encapsulate this library in a C# project?

What do you think about this alternative solution for

polyhedra volume calculation
?

Answer:
The polyhedra volume calculation article looks interesting, it seems like a simple approach for solving the second part of the problem, the volume calculation.
It still needs to be ported from Java to .NET, though.
It also does nothing to help you with the first part of the problem, the determination of the convex hull.

Revit will not automatically provide a convex hull for a room or any element’s faces and edges.
Imagine an L-shaped room: its convex hull does not include some of the vertices of the walls in the inner corner.
Imagine any shape at all that is not already convex. You need to eliminate all ‘inner’ vertices to obtain the convex hull.

Regarding access to Qhull from .NET, I explained two methods for making use of the library from a .NET client above:

  • Create a DLL from the C code, and implement a C function that can be called from .NET, read the input from .NET, and return the output to .NET.
  • Create a .NET application that writes and reads files in the expected Qhull input and output formats, and then execute the unchanged qconvex executable provided by the Qhull package as an external process using the files to communicate.
    Maybe you can use pipes instead of physical files on the disk.

Comments

10 responses to “Convex Hull and Volume Computation”

  1. Hi Jeremy!
    Could you please tell me how I can force pinning of a Rvt Link in code?… I have a filter set up to select them, but the .pinned property is a read only boolean.

  2. Hi Jeremy.
    Thx again for this post.
    Have you ever eard about a solution to see if an element is visible into a view?
    Cheers!

  3. Dear Jim,
    Yes, the Pinned property on the Element class is read-only, just as you say. The remarks say that an element which is pinned may not be moved, and warnings will be issued when an attempt is made to delete it. The same property on the ImportInstance offers a set method as well, so it is read-write. No, sorry, I do not know how you might work around this to set the property through the API.
    Cheers, Jeremy.

  4. Dear Pierre,
    Glad you liked it!
    How about the property View.Elements? For a given view, it returns a set of all elements that will be drawn in the view. Elements that belong to this set have graphics that may be visible in this view. Some elements may still be hidden because they are obscured by other elements.
    Cheers, Jeremy.

  5. Jim Bish Avatar
    Jim Bish

    Jeremy,
    If I use a filter on OST_RvtLinks, two items are returned. One is the Autodesk.Revit.Symbol -&- the other is Autodesk.Revit.Instance. “Supposedly”, the Instance has a property .pinned that is editable. Is that true, and if so, How do we access it?

  6. Dear Jim,
    Hmm, I am afraid the Instance you have got hold of is not an ImportInstance element.
    An example of recursively iterating through all import instances is given in the discussion in
    http://thebuildingcoder.typepad.com/blog/2009/05/imports-in-families.html
    I massaged the code presented there slightly as follows to read and modify the Pinned property:
    foreach ( ImportInstance i in imports )
    {
    string s = i.Pinned ? “” : “not “;
    Debug.Print( indent
    + ” ‘{0}’ {1}pinned”,
    i.ObjectType.Name, s );
    i.Pinned = !i.Pinned;
    }
    Cheers, Jeremy.

  7. Jim Bish Avatar
    Jim Bish

    No, this is not an ImportInstance. It is a native .rvt file with 100% native geometry linked into the project… more specifically, the site plan (100% Revit). Here’s a snip of the selection set filter.
    Public Function Execute(ByVal commandData As Autodesk.Revit.ExternalCommandData, _
    ByRef message As String, ByVal elements As Autodesk.Revit.ElementSet) As _
    Autodesk.Revit.IExternalCommand.Result Implements Autodesk.Revit.IExternalCommand.Execute
    Dim rvtApp As Autodesk.Revit.Application = commandData.Application
    Dim doc As Autodesk.Revit.Document = rvtApp.ActiveDocument
    Dim element As Autodesk.Revit.Element = Nothing
    Dim CatFilter As Autodesk.Revit.Filter
    CatFilter = rvtApp.Create.Filter.NewCategoryFilter(Autodesk.Revit.BuiltInCategory.OST_RvtLinks)
    Dim result As New List(Of Autodesk.Revit.Element)
    Dim NumLinks As String = rvtApp.ActiveDocument.Elements(CatFilter, result)
    For Each element In result
    If TypeOf (element) Is Autodesk.Revit.Elements.Instance Then
    If element.Pinned = False Then
    MessageBox.Show(“Hello!… ” & element.Name & ” is not pinned!… Please pin it.”)
    End If
    End If
    Next

  8. Dear Jim,
    Thank you very much for the sample code, that always helps clarify things a lot. Unfortunately, I do not believe this is currently possible. I guess that pinning objects involves so many constraints in the background that it has not been exposed as read-write through the API yet.
    Cheers, Jeremy.

  9. Hi Jeremy,
    I need to get intersection point from a volume define by a list of points and a line outside Revit (not with revit api), or determine whether a point is contained in a volume; is there any library in c/c# that I can use?
    Cheers
    Max

  10. Dear Max,
    I would guess that there are tens of thousands of solutions for that out there.
    Start off by looking at wikipedia, of course:
    http://en.wikipedia.org/wiki/Line-plane_intersection
    When you say your volume is defined by a list of points, that leaves a lot of possibilities. Are you dealing with the convex hull of the points?
    http://en.wikipedia.org/wiki/Convex_hull
    If so, you are lucky and everything is well defined and easy.
    I talked a bit about convex hulls and volume computation way back, and point to a powerful open source library for that:
    http://thebuildingcoder.typepad.com/blog/2009/06/convex-hull-and-volume-computation.html
    Oh, I see now, that is the article you were looking at :-)
    If you do not have a convex hull, which I strongly assume, you are dealing with a polytope, or a polyhedron in 3D:
    http://en.wikipedia.org/wiki/Polytope
    Looking at that article, I see the following link which describes an algorithm answering your question:
    http://en.wikipedia.org/wiki/Intersection_of_a_polyhedron_with_a_line
    That in turn points to some pseudo code for an implementation:
    http://adrianboeing.blogspot.com/2010/02/intersection-of-convex-hull-with-line.html
    Oops, that is for a convex hull again.
    Actually, googling for “C# .net line plane intersection” returns tons of hits, e.g.
    http://stackoverflow.com/questions/30080/how-to-know-if-a-line-intersects-a-plane-in-c-basic-2d-geometry
    There you go.
    As you can see, you will have to do some research on your own.
    That wasn’t so hard, was it?
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading