Family Bounding Box and AEC Hackathon Munich

I briefly mentioned the AEC Hackathon in Munich yesterday.

Here is some more information on that, highlighting the exciting speaker line-up and target topics, plus a solution for determining the bounding box of an entire family and a suggestion to implement a continuous integration service for RevitLookup:

AEC Hackathon Munich Topics and Speakers

The AEC Hackathon is coming to Germany, March 31 - April 2, at the Technical University in Munich, Germany.

I am unable to attend, unfortunately, and will miss it sorely.

It brings a weekend of geeking at its finest. It gives those designing, building and maintaining our built environment, the opportunity to engage, collaborate and interact on multiple aspects of the building industry. Not all built environment professionals have to code or have much background with tech. Just come with your knowledge, an open mind, collaborative spirit, and willingness to solve Mon-Fri problems leveraging various kinds of technology.

We've shaped an exhilarating Program on Robotics, Generative Design, IOT, AR/VR and web services for you!

Check out some of our Speakers:

Why you should not miss this Event:

Did we get you excited? If you like to learn more about the Event have a look at our website:

www.aechackathon-germany.de

How can you Engage in the Event?

  1. Come on by Join us for the weekend, observe, and offer your industry expertise to teams as needed. Encourage others in your company to join you as this is a great way to get exposed to new technologies and meet other innovators in top AEC firms. รจ Register

  2. Team up and solve an Industry Problems:
    Bring a problem you want to solve or company/industry challenge. The Friday Night Lightning Rounds are open to all that want to propose an idea and form a team around improving some element of the design, build, operational process. Past teams have created high-tech solutions for tracking tools, high End BIM Solutions, using virtual reality for jobsite safety training, and much more. Visit our YouTube channel to watch past team presentation.

  3. Learn how to develop on Innovative Software Platforms: If you are an IT affinitive User or a Software Developer and you always wanted to learn how to develop on FORGE, Dynamo Studio, KUKA Robot, Microsoft Mixed Reality, IoT Hub, Azure Functions and Cognitive Services come and join our free Developer Workshops in the afternoon before the Event.

Take a look at our Prep Workshops.

If you have any Questions, please have a look at the Frequently asked Questions.

AEC Hackathon at TU Munich

Family Bounding Box

Kevin @kelau1993 Lau shared a solution to determine the bounding box of a family in the family document environment in the Revit API discussion forum thread on family bounding box in family document.

It looks very cool indeed to me, so I went ahead and created a complete Visual Studio project and FamilyBoundingBox GitHub repository for it to make it more accessible.

Here is Kevin's code, taken from the FamilyBoundingBox Command.cs module:

/// <summary>
/// Computes the effective 'BoundingBoxXYZ' of the 
/// whole family, including all combined and 
/// individual forms.
/// </summary>
/// <param name="document">The Revit document that 
/// contains the family.</param>
/// <returns>The effective 'BoundingBoxXYZ' of the 
/// whole family.</returns>
private static BoundingBoxXYZ ComputeFamilyBoundingBoxXyz(
  Document document )
{
  BoundingBoxXYZ familyBoundingBoxXyz = null;

  HashSet<ElementId> genericFormExclusionSet
    = new HashSet<ElementId>();

  familyBoundingBoxXyz
    = MergeGeomCombinationBoundingBoxXyz( document, 
      familyBoundingBoxXyz, 
      genericFormExclusionSet );

  familyBoundingBoxXyz
    = MergeSolidBoundingBoxXyz( document, 
      familyBoundingBoxXyz, 
      genericFormExclusionSet );

  return familyBoundingBoxXyz;
}

/// <summary>
/// Merge <paramref name="boundingBoxXyz"/> with the 
/// 'BoundingBoxXYZ's of all 'GeomCombination's in 
/// <paramref name="document"/> into a new 'BoundingBoxXYZ'. 
/// Collect all members of the 'GeomCombination's
/// found into <paramref name="geomCombinationMembers"/>.
/// </summary>
/// <param name="document">The Revit 'Document' to search 
/// for all 'GeomCombination's.</param>
/// <param name="boundingBoxXyz">The 'BoundingBoxXYZ' to merge with.</param>
/// <param name="geomCombinationMembers">A 'HashSet' to collect all of the
/// 'GeomCombination' members that form the 'GeomCombination'.</param>
/// <returns>The new merged 'BoundingBoxXYZ' of
/// <paramref name="boundingBoxXyz"/> and all 'GeomCombination's
/// in <paramref name="document"/></returns>
private static BoundingBoxXYZ MergeGeomCombinationBoundingBoxXyz(
  Document document,
  BoundingBoxXYZ boundingBoxXyz,
  HashSet<ElementId> geomCombinationMembers )
{
  BoundingBoxXYZ mergedResult = boundingBoxXyz;

  FilteredElementCollector geomCombinationCollector
    = new FilteredElementCollector( document )
      .OfClass( typeofGeomCombination ) );

  foreachGeomCombination geomCombination in geomCombinationCollector )
  {
    if( geomCombinationMembers != null )
    {
      foreachGenericForm genericForm in geomCombination.AllMembers )
      {
        geomCombinationMembers.Add( genericForm.Id );
      }
    }

    BoundingBoxXYZ geomCombinationBoundingBox 
      = geomCombination.get_BoundingBox( null );

    if( mergedResult == null )
    {
      mergedResult = new BoundingBoxXYZ();
      mergedResult.Min = geomCombinationBoundingBox.Min;
      mergedResult.Max = geomCombinationBoundingBox.Max;
      continue;
    }

    mergedResult = MergeBoundingBoxXyz(
      mergedResult, geomCombinationBoundingBox );
  }

  return mergedResult;
}

/// <summary>
/// Merge <paramref name="boundingBoxXyz"/> with the 'BoundingBoxXYZ's of
/// all 'GenericForm's in <paramref name="document"/> that are solid into
/// a new 'BoundingBoxXYZ'.
/// Exclude all 'GenericForm's in
/// <paramref name="genericFormExclusionSet"/> from being found in
/// <paramref name="document"/>.
/// </summary>
/// <param name="document">The Revit 'Document' to search for all
/// 'GenericForm's excluding the ones in
/// <paramref name="genericFormExclusionSet"/>.</param>
/// <param name="boundingBoxXyz">The 'BoundingBoxXYZ' to merge with.</param>
/// <param name="genericFormExclusionSet">A 'HashSet' of all the
/// 'GenericForm's to exclude from being merged with in
/// <paramref name="document"/>.</param>
/// <returns>The new merged 'BoundingBoxXYZ' of
/// <paramref name="boundingBoxXyz"/> and all 'GenericForm's excluding
/// the ones in <paramref name="genericFormExclusionSet"/>
/// in <paramref name="document"/></returns>
private static BoundingBoxXYZ MergeSolidBoundingBoxXyz(
  Document document,
  BoundingBoxXYZ boundingBoxXyz,
  HashSet<ElementId> genericFormExclusionSet )
{
  BoundingBoxXYZ mergedResult = boundingBoxXyz;

  FilteredElementCollector genericFormCollector
    = new FilteredElementCollector( document )
      .OfClass( typeofGenericForm ) );

  if( genericFormExclusionSet != null
    && genericFormExclusionSet.Any() )
  {
    genericFormCollector.Excluding(
      genericFormExclusionSet );
  }

  foreachGenericForm solid in
    genericFormCollector
      .Cast<GenericForm>()
      .Where( genericForm => genericForm.IsSolid ) )
  {
    BoundingBoxXYZ solidBoundingBox
      = solid.get_BoundingBox( null );

    if( mergedResult == null )
    {
      mergedResult = new BoundingBoxXYZ();
      mergedResult.Min = solidBoundingBox.Min;
      mergedResult.Max = solidBoundingBox.Max;
      continue;
    }

    mergedResult = MergeBoundingBoxXyz(
      mergedResult, solidBoundingBox );
  }

  return mergedResult;
}

/// <summary>
/// Merge <paramref name="boundingBoxXyz0"/> and
/// <paramref name="boundingBoxXyz1"/> into a new 'BoundingBoxXYZ'.
/// </summary>
/// <param name="boundingBoxXyz0">A 'BoundingBoxXYZ' to merge</param>
/// <param name="boundingBoxXyz1">A 'BoundingBoxXYZ' to merge</param>
/// <returns>The new merged 'BoundingBoxXYZ'.</returns>
static BoundingBoxXYZ MergeBoundingBoxXyz(
  BoundingBoxXYZ boundingBoxXyz0,
  BoundingBoxXYZ boundingBoxXyz1 )
{
  BoundingBoxXYZ mergedResult = new BoundingBoxXYZ();

  mergedResult.Min = new XYZ(
    Math.Min( boundingBoxXyz0.Min.X, boundingBoxXyz1.Min.X ),
    Math.Min( boundingBoxXyz0.Min.Y, boundingBoxXyz1.Min.Y ),
    Math.Min( boundingBoxXyz0.Min.Z, boundingBoxXyz1.Min.Z ) );

  mergedResult.Max = new XYZ(
    Math.Max( boundingBoxXyz0.Max.X, boundingBoxXyz1.Max.X ),
    Math.Max( boundingBoxXyz0.Max.Y, boundingBoxXyz1.Max.Y ),
    Math.Max( boundingBoxXyz0.Max.Z, boundingBoxXyz1.Max.Z ) );

  return mergedResult;
}

Continuous integration for RevitLookup?

Peter Hirn of Build Informed GmbH very kindly offered to implement a continuous integration service for RevitLookup, similar to the daily builds provided for Dynamo at dynamobuilds.com.

He raised the Revit API discussion forum thread on CI for RevitLookup to discuss the issue.

We're considering to set up a public CI for RevitLookup.

The output could be something like the Dynamo builds.

I'm thinking Travis or Jenkins for the builds.

We would provide the infrastructure and maintenance for this service.

I'd love to get your feedback on this idea.

If you have any thought or suggestion on this, please participate in the CI for RevitLookup discussion and let us know.

Thank you!