Transform.CreateTranslation(_offset); // 2014
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Application app = uiapp.Application;
Document doc = uidoc.Document;
Options opt = app.Create.NewGeometryOptions();
XyzEqualityComparer comparer
= new XyzEqualityComparer(1e-6);
#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
Creator creator = new Creator(doc);
Transaction t = new Transaction(doc);
t.Start("Create model curve copies of top face edges");
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
IList <Face> topFaces = new List <Face>();
int n;
int nWalls = 0;
//foreach( Element e in uidoc.Selection.Elements ) // 2014
foreach (ElementId id in uidoc.Selection.GetElementIds()) // 2015
{
Element e = doc.GetElement(id);
Wall wall = e as Wall;
if (null == wall)
{
Debug.Print("Skipped "
+ Util.ElementDescription(e));
continue;
}
// Get the side faces
IList <Reference> sideFaces
= HostObjectUtils.GetSideFaces(wall,
ShellLayerType.Exterior);
// Access the first side face
Element e2 = doc.GetElement(sideFaces[0]);
Debug.Assert(e2.Id.Equals(e.Id),
"expected side face element to be the wall itself");
Face face = e2.GetGeometryObjectFromReference(
sideFaces[0]) as Face;
if (null == face)
{
Debug.Print("No side face found for "
+ Util.ElementDescription(e));
continue;
}
// When there are opening such as doors or
// windows in the wall, we need to find the
// outer loop.
// For one possible approach to extract the
// outermost loop, please refer to
// http://thebuildingcoder.typepad.com/blog/2008/12/2d-polygon-areas-and-outer-loop.html
// Determine the outer loop of the side face
// by finding the polygon with the largest area
XYZ normal;
double area, dist, maxArea = 0;
EdgeArray outerLoop = null;
foreach (EdgeArray ea in face.EdgeLoops)
{
if (CmdWallProfileArea.GetPolygonPlane(
ea.GetPolygon(), out normal, out dist, out area) &&
Math.Abs(area) > Math.Abs(maxArea))
{
maxArea = area;
outerLoop = ea;
}
}
n = 0;
#if GET_FACES_FROM_OUTER_LOOP
// With the outermost loop, calculate the top faces
foreach (Edge edge in outerLoop)
{
// For each edge, get the neighbouring
// face and check its normal
for (int i = 0; i < 2; ++i)
{
PlanarFace pf = edge.get_Face(i)
as PlanarFace;
if (null == pf)
{
Debug.Print("Skipped non-planar face on "
+ Util.ElementDescription(e));
continue;
}
if (Util.PointsUpwards(pf.Normal, 0.9))
{
if (topFaces.Contains(pf))
{
Debug.Print("Duplicate face on "
+ Util.ElementDescription(e));
}
else
{
topFaces.Add(pf);
++n;
}
}
}
}
#endif // GET_FACES_FROM_OUTER_LOOP
List <XYZ> sideVertices = outerLoop.GetPolygon();
// Go over all the faces of the wall and
// determine which ones fulfill the following
// two criteria: (i) planar face pointing
// upwards, and (ii) neighbour of the side
// face outer loop.
Solid solid = wall.get_Geometry(opt)
.OfType <Solid>()
.First <Solid>(sol => null != sol);
foreach (Face f in solid.Faces)
{
if (IsTopFace(f))
{
IList <XYZ> faceVertices
= f.Triangulate().Vertices;
//if( sideVertices.Exists( v
// => faceVertices.Contains<XYZ>( v, comparer ) ) )
//{
// topFaces.Add( f );
// ++n;
//}
foreach (XYZ v in faceVertices)
{
if (sideVertices.Contains <XYZ>(
v, comparer))
{
topFaces.Add(f);
++n;
#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
// Display face for debugging purposes
foreach (EdgeArray ea in f.EdgeLoops)
{
IEnumerable <Curve> curves
= ea.Cast <Edge>()
.Select <Edge, Curve>(
x => x.AsCurve());
foreach (Curve curve in curves)
{
//creator.CreateModelCurve( curve.get_Transformed( _t ) ); // 2013
creator.CreateModelCurve(curve.CreateTransformed(_t)); // 2014
}
}
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
break;
}
}
}
}
Debug.Print(string.Format(
"{0} top face{1} found on {2} ({3})",
n, Util.PluralSuffix(n),
Util.ElementDescription(e)),
nWalls++);
}
#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
t.Commit();
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
string s = string.Format(
"{0} wall{1} successfully processed",
nWalls, Util.PluralSuffix(nWalls));
n = topFaces.Count;
TaskDialog.Show("Wall Top Faces",
string.Format(
"{0} with {1} top face{2}.",
s, n, Util.PluralSuffix(n)));
return(Result.Succeeded);
}