Last week we had the visit from our ADN Senior Director Jim Quanci (@jimquanci), Tech Evangelist Shiya Lou (@shiyalou) and ADN Manager Natalia Polikarpova (@nataliapolikar1), Since we were hosting 3 meetups in the NYC area for the Web development community. We had the chance to share the View and Data API, a WebGL and three.js API that we are promoting, which allows you to add 3D content to your web application, but is not only a pretty picture, it also allows you to obtain the metadata from any 3D design model you have, and the best part about it is that it will support up to 50+ different file formats including non-Autodesk files. Don’t believe me? try it yourself here.
On Tuesday the 21st, we hosted the meetup to the NYC WebGL group at Code & Design Academy, where Jim Quanci and Shiya Lou, talked about our API and how attractive is to have 3D content in your web now at days. We had many knowledgeable guys in WebGL, and knowing that this is not an easy technology to master, we got great positive feedback on how the API works now, You want to check it out? head over to LMV rocks, a URL created by our engineering team that tends to have continues changes since this is what the development team uses to show off what the viewer is capable of doing, pretty cool website.
On Wednesday the 22nd (Happy belated Earth Day btw) we hosted at our Autodesk Office located near Flatiron building, the AngularJS meetup group, where together with Tech Evangelist, Shiya Lou we ran a small workshop on how to get started with the View and Data API using AngularJS. If you missed it, don’t worry, you can still go over the small workshop we put together for you to try it, here is the link for you to try it.
After a busy week we got until Thursday, where we hosted a full house at our NYC office again, this time we had over the group of Swabbies from the #weekofcode event hosted by Code Crew. This time Jim Quanci and yours truly had the opportunity of sharing how to add 3D content to your web application. Showing how attractive this topic is, for not only developers, but for Designers and eCommerce as well. Great connections were made, new friendships with the attendees and the start of a good relationship with the attendees of the meetups to start many collaborations with the NYC web developers community definitely got a good start.
-------------------------------------------------------------
Back to Revit API. This week I had the chance to work on an interesting case of developer from Russia. He is using the FindInserts method in order to find family Instances in his Hosted Object. In his case, wants to identify the Id’s of the doors that are part of what walls. But currently he is having the difficulty that when the length of the wall is close to the size of the door, the FindInsters method (which gets the ids of the instances inserted into the host object) is returning the Id’s of the neighbor’s walls.
Question: I've found strange behavior of HostObject.FindInserts method in some cases in Revit 2015 UR7. I don't know exactly, if it is a bug or just my misunderstanding of this method conception.
The addin command illustrate the problem, that wall.FindInserts method finds the door with id = 211299 for three different walls in Revit project.
using System.Collections.Generic;
using System.Text;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Linq;
namespace FindInsertsMisunderstandingOrBugSample
{
[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand
{
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
var uiapp = commandData.Application;
var uidoc = uiapp.ActiveUIDocument;
var doc = uidoc.Document;
var collector = new FilteredElementCollector(doc);
var walls = collector
.OfClass(typeof (Wall))
.OfType<Wall>();
var wallsIdsByInsertIds = new Dictionary<ElementId,
IList<ElementId>>();
foreach (var wall in walls)
{
foreach (var insId in
wall.FindInserts(false, false, false, false))
{
IList<ElementId> wallsIdsList;
if (!wallsIdsByInsertIds.TryGetValue
(insId, out wallsIdsList))
{
wallsIdsList = new List<ElementId>();
wallsIdsByInsertIds.Add(insId, wallsIdsList);
}
wallsIdsList.Add(wall.Id);
}
}
var sb = new StringBuilder();
foreach (var insert in wallsIdsByInsertIds)
{
sb.AppendLine(string.Format
("inserted element with id={0} founded in walls:"
, insert.Key));
foreach (var wallId in insert.Value)
sb.AppendLine(string.Format(" - {0}", wallId));
}
TaskDialog.Show("inserts", sb.ToString());
return Result.Succeeded;
}
}
}
So, please let me know, if it is a bug (and if it is not represented in 2016, I can't test it in Revit 2016 right now) or a feature (please enlighten me in this case))
Answer:Thank you for your query. I tried your project with the model you provided. I'm able to reproduce what you mentioned, but then after I tried doing a model myself, and I get back only the Id of the host object that contains the door. This raises the question, are you doing anything specific to your walls? is there some kind of openings in the walls? and that being the reason you get back the Id of the three nearby walls. Maybe you could explain a bit more how are you drawing these walls.
I found a couple of posts by our Revit API Evangelist - Jeremy Tammik, where he goes through the use of FindInserts, and in one part of the post, I found something that might give you a better idea on how this works. Here is the link and a reference to what I mentioned:
"works great on walls with hosted families but not with walls that had structure separated with lining walls, e.g., three walls making up one wall with the linings walls joined the structural wall."
Because based on the comments in there it seems like the behavior you are getting, should be the correct one. Since this method will get the ids of openings when you provide it with a wall. Also I'm attaching the result that I got when trying your command with my model and yours next to it.
Also I tried your plug-in in Revit 2016, there needs to be a change in the code since it seems that .OfType() got removed from the API, but after that the functionality keeps being the same.
Here is how it looks now.
var walls = collector
.OfClass(typeof(Wall));
var wallsIdsByInsertIds = new Dictionary<ElementId,
IList<ElementId>>();
foreach (HostObject wall in walls)
Let me know what you think.
Response:Thank you for your answer. I know Jeremy Tammik and his blog, thank you, and practically the happy combination of the http://thebuildingcoder.typepad.com/blog/2015/03/findinserts-retrieves-all-openings-in-all-wall-types.html blog post and some programming tasks led me to explore FindInserts method and its usage.
After several attempts, I've reproduced the case.First of all, you need a short wall, it length should be a little more, than door width, secondly with "wall joins" tool change wall joins as shown in the attached "reproduced.png" file
Also, if the wall with a door length is a little more, the case is not reproduced (please, see attached "notreproduced.png" file).
Answer 2: After further investigation, we have found that currently your walls overlap with the door, being this a good cause on why you are getting the Id's of the host object neighbor's walls. Also when the walls are placed orthogonally, it does not happen. Also, when I modify the style of the door temporarily and put it back to its original value (such as trim width), then it does not happen.
I will suggest to keep using your workaround to be able to continue with you development, That for each Id, returned by wall.FindInserts method get the element and check if it’s Host.Id equals Wall.Id
Here is how it looks now.
using System.Collections.Generic;
using System.Text;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Linq;
namespace FindInsertsMisunderstandingOrBugSample
{
[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand
{
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
var uiapp = commandData.Application;
var uidoc = uiapp.ActiveUIDocument;
var doc = uidoc.Document;
var collector = new FilteredElementCollector(doc);
var walls = collector
.OfClass(typeof (Wall))
.OfType<Wall>();
var wallsIdsByInsertIds = new Dictionary<ElementId,
IList<ElementId>>();
foreach (var wall in walls)
{
foreach (var insId in
wall.FindInserts(false, false, false, false))
{
IList<ElementId> wallsIdsList;
if (!wallsIdsByInsertIds.TryGetValue
(insId, out wallsIdsList))
{
wallsIdsList = new List<ElementId>();
wallsIdsByInsertIds.Add(insId, wallsIdsList);
}
// workaround check for Host Id
FamilyInstance fi = doc.GetElement(insId) as FamilyInstance;
if (fi.Host.Id == wall.Id)
wallsIdsList.Add(wall.Id);
}
}
var sb = new StringBuilder();
foreach (var insert in wallsIdsByInsertIds)
{
sb.AppendLine(string.Format
("inserted element with id={0} founded in walls:"
, insert.Key));
foreach (var wallId in insert.Value)
sb.AppendLine(string.Format(" - {0}", wallId));
}
TaskDialog.Show("inserts", sb.ToString());
return Result.Succeeded;
}
}
}
Thank you very much for all your patience and collaboration.
Thanks for reading, until next time.