public static DirectShape CreateDirectShape( Document doc, Solid transientSolid, string dsName) { ElementId catId = new ElementId( BuiltInCategory.OST_GenericModel); AddInId addInId = doc.Application.ActiveAddInId; DirectShape ds = DirectShape.CreateElement(doc, catId, addInId.GetGUID().ToString(), ""); if (ds.IsValidGeometry(transientSolid)) { ds.SetShape(new GeometryObject[] { transientSolid }); } else { TessellatedShapeBuilderResult result = GetTessellatedSolid(doc, transientSolid); ds.SetShape(result.GetGeometricalObjects()); } ds.Name = dsName; return(ds); }
/// <summary> /// Create a geometry object(s) described by stored face sets, if possible. /// Usually a single-element IList conatining either Solid or Mesh is returned. /// A two-elemant IList containing a Solid as the 1st element and a Mesh as /// the 2nd is returned if while building multiple face sets, a fallback /// was used for some but not all sets. /// </summary> /// <returns>The IList created, or null. The IList can contain a Solid and/or a Mesh. /// If Solid is present, it always the 1st element.</returns> private IList <GeometryObject> CreateGeometryObjects(string guid, out bool hasInvalidData, out TessellatedShapeBuilderOutcome outcome) { try { m_TessellatedShapeBuilder.CloseConnectedFaceSet(); // The OwnerInfo is currently unused; the value doesn't really matter. m_TessellatedShapeBuilder.LogString = IFCImportFile.TheFileName; m_TessellatedShapeBuilder.LogInteger = IFCImportFile.TheBrepCounter; m_TessellatedShapeBuilder.OwnerInfo = guid != null ? guid : "Temporary Element"; TessellatedShapeBuilderResult result = m_TessellatedShapeBuilder.Build(TargetGeometry, FallbackGeometry, GraphicsStyleId); // It is important that we clear the TSB after we build above, otherwise we will "collect" geometries // in the DirectShape and create huge files with redundant data. ClearTessellatedShapeBuilder(); hasInvalidData = result.HasInvalidData; outcome = result.Outcome; return(result.GetGeometricalObjects()); } catch (Exception ex) { Importer.TheLog.LogError(CreatorId(), ex.Message, false); ClearTessellatedShapeBuilder(); hasInvalidData = true; outcome = TessellatedShapeBuilderOutcome.Nothing; return(null); } }
/// <summary> /// Creates a solid from a list of points. Intented to create single face solids for solid operations. /// </summary> /// <param name="vertices">A list of XYZ vertices of the face.</param> /// <returns>A solid consisting of one face.</returns> public static Solid CreateSolid(IList <XYZ> vertices) { TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); //http://thebuildingcoder.typepad.com/blog/2014/05/directshape-performance-and-minimum-size.html builder.OpenConnectedFaceSet(false); builder.AddFace(new TessellatedFace(vertices, ElementId.InvalidElementId)); builder.CloseConnectedFaceSet(); builder.Build(); TessellatedShapeBuilderResult result = builder.GetBuildResult(); return(result.GetGeometricalObjects()[0] as Solid); }
private void ImportSTLDocument( STLDocument stlDocument, Document doc, string stlDocumentName) { StlImportProperties properties = StlImportProperties.GetProperties(); using (Transaction t = new Transaction(doc, "Import STL")) { t.Start(); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); int i = 0; foreach (Facet facet in stlDocument.Facets) { builder.AddFace(FromFacet(facet)); i++; } builder.CloseConnectedFaceSet(); TessellatedShapeBuilderResult result = builder.Build(properties.Target, properties.Fallback, properties.GraphicsStyleId); // Pre-release code from DevDays //DirectShape ds = DirectShape.CreateElement( // doc, result.GetGeometricalObjects(), "A", "B"); //ds.SetCategoryId(new ElementId( // BuiltInCategory.OST_GenericModel)); // Code updated for Revit UR1 ElementId categoryId = new ElementId(BuiltInCategory.OST_GenericModel); DirectShape ds = DirectShape.CreateElement(doc, categoryId, "A", "B"); ds.SetShape(result.GetGeometricalObjects()); ds.Name = stlDocumentName; t.Commit(); } }
public List <PlanarFace> GetMeshedFaces() { Mesh mesh = GetMesh(); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); List <XYZ> args = new List <XYZ>(3); XYZ[] triangleCorners = new XYZ[3]; for (int i = 0; i < mesh.NumTriangles; ++i) { MeshTriangle triangle = mesh.get_Triangle(i); triangleCorners[0] = triangle.get_Vertex(0); triangleCorners[1] = triangle.get_Vertex(1); triangleCorners[2] = triangle.get_Vertex(2); TessellatedFace tesseFace = new TessellatedFace(triangleCorners, ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices( tesseFace)) { builder.AddFace(tesseFace); } } builder.CloseConnectedFaceSet(); TessellatedShapeBuilderResult result = builder.Build( TessellatedShapeBuilderTarget.AnyGeometry, TessellatedShapeBuilderFallback.Mesh, ElementId.InvalidElementId); var geo = result.GetGeometricalObjects(); var solids = GeoHelper.GetSolidsInModel(geo, GeoHelper.SolidVolumnConstraint.Any); var faces = GeoHelper.GetSurfaces(solids.Keys); return(faces.OfType <PlanarFace>().ToList()); }
private void Execute(IEnumerable <List <XYZ> > triangles) { void Run(Document doc) { TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); foreach (List <XYZ> triangle in triangles) { TessellatedFace tessellatedFace = new TessellatedFace(triangle, ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices(tessellatedFace)) { builder.AddFace(tessellatedFace); } } builder.CloseConnectedFaceSet(); builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; builder.Fallback = TessellatedShapeBuilderFallback.Mesh; builder.Build(); TessellatedShapeBuilderResult result = builder.GetBuildResult(); //var ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel)); //ds.ApplicationId = Assembly.GetExecutingAssembly().GetType().GUID.ToString(); //ds.ApplicationDataId = Guid.NewGuid().ToString(); //ds.Name = "NavisWorksShape"; //DirectShapeOptions dsOptions = ds.GetOptions(); //dsOptions.ReferencingOption = DirectShapeReferencingOption.Referenceable; //ds.SetOptions(dsOptions); //ds.SetShape(result.GetGeometricalObjects()); CreateDirectShape(doc, result.GetGeometricalObjects()); } _eventHandler.Action = Run; _eventHandler.TransactionName = "Importing navisWorks elements"; _externalEvent.Raise(); }
public static void Execute( ExternalCommandData commandData) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; Selection choices = uidoc.Selection; try { Reference reference = choices.PickObject( ObjectType.Face); Element el = doc.GetElement( reference.ElementId); Face face = el.GetGeometryObjectFromReference( reference) as Face; Mesh mesh = face.Triangulate(); var familyInstance = el as FamilyInstance; if (null != familyInstance) { var t = familyInstance .GetTotalTransform(); mesh = mesh.get_Transformed(t); } using (Transaction trans = new Transaction(doc)) { trans.Start("Create DirectShape from Face"); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); List <XYZ> args = new List <XYZ>(3); XYZ[] triangleCorners = new XYZ[3]; for (int i = 0; i < mesh.NumTriangles; ++i) { MeshTriangle triangle = mesh.get_Triangle(i); triangleCorners[0] = triangle.get_Vertex(0); triangleCorners[1] = triangle.get_Vertex(1); triangleCorners[2] = triangle.get_Vertex(2); TessellatedFace tesseFace = new TessellatedFace(triangleCorners, ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices( tesseFace)) { builder.AddFace(tesseFace); } } builder.CloseConnectedFaceSet(); //TessellatedShapeBuilderResult result // = builder.Build( // TessellatedShapeBuilderTarget.AnyGeometry, // TessellatedShapeBuilderFallback.Mesh, // ElementId.InvalidElementId ); // 2016 builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; // 2018 builder.Fallback = TessellatedShapeBuilderFallback.Mesh; // 2018 builder.Build(); // 2018 TessellatedShapeBuilderResult result = builder.GetBuildResult(); // 2018 ElementId categoryId = new ElementId( BuiltInCategory.OST_GenericModel); //DirectShape ds = DirectShape.CreateElement( // doc, categoryId, // Assembly.GetExecutingAssembly().GetType() // .GUID.ToString(), Guid.NewGuid().ToString() ); // 2016 DirectShape ds = DirectShape.CreateElement( doc, categoryId); // 2018 ds.ApplicationId = Assembly.GetExecutingAssembly() .GetType().GUID.ToString(); // 2018 ds.ApplicationDataId = Guid.NewGuid().ToString(); // 2018 ds.SetShape(result.GetGeometricalObjects()); ds.Name = "MyShape"; trans.Commit(); } } catch (Exception ex) { Debug.Print(ex.Message); } }
/// <summary> /// Create a new list of geometry objects from the /// given input. As input, we supply the result of /// Room.GetClosedShell. The output is the exact /// same solid lacking whatever flaws are present /// in the input solid. /// </summary> static IList <GeometryObject> CopyGeometry( GeometryElement geo, ElementId materialId, List <IntPoint3d> coords, List <TriangleIndices> indices) { TessellatedShapeBuilderResult result = null; TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); // Need to include the key in the value, otherwise // no way to access it later, cf. // https://stackoverflow.com/questions/1619090/getting-a-keyvaluepair-directly-from-a-dictionary Dictionary <XYZ, KeyValuePair <XYZ, int> > pts = new Dictionary <XYZ, KeyValuePair <XYZ, int> >( new XyzEqualityComparer()); int nSolids = 0; //int nFaces = 0; int nTriangles = 0; //int nVertices = 0; List <XYZ> vertices = new List <XYZ>(3); foreach (GeometryObject obj in geo) { Solid solid = obj as Solid; if (null != solid) { if (0 < solid.Volume) { ++nSolids; builder.OpenConnectedFaceSet(false); #region Create a new solid based on tessellation of the invalid room closed shell solid #if CREATE_NEW_SOLID_USING_TESSELATION Debug.Assert( SolidUtils.IsValidForTessellation(solid), "expected a valid solid for room closed shell"); SolidOrShellTessellationControls controls = new SolidOrShellTessellationControls() { // // Summary: // A positive real number specifying how accurately a triangulation should approximate // a solid or shell. // // Exceptions: // T:Autodesk.Revit.Exceptions.ArgumentOutOfRangeException: // When setting this property: The given value for accuracy must be greater than // 0 and no more than 30000 feet. // This statement is not true. I set Accuracy = 0.003 and an exception was thrown. // Setting it to 0.006 was acceptable. 0.03 is a bit over 9 mm. // // Remarks: // The maximum distance from a point on the triangulation to the nearest point on // the solid or shell should be no greater than the specified accuracy. This constraint // may be approximately enforced. Accuracy = 0.03, // // Summary: // An number between 0 and 1 (inclusive) specifying the level of detail for the // triangulation of a solid or shell. // // Exceptions: // T:Autodesk.Revit.Exceptions.ArgumentOutOfRangeException: // When setting this property: The given value for levelOfDetail must lie between // 0 and 1 (inclusive). // // Remarks: // Smaller values yield coarser triangulations (fewer triangles), while larger values // yield finer triangulations (more triangles). LevelOfDetail = 0.1, // // Summary: // A non-negative real number specifying the minimum allowed angle for any triangle // in the triangulation, in radians. // // Exceptions: // T:Autodesk.Revit.Exceptions.ArgumentOutOfRangeException: // When setting this property: The given value for minAngleInTriangle must be at // least 0 and less than 60 degrees, expressed in radians. The value 0 means to // ignore the minimum angle constraint. // // Remarks: // A small value can be useful when triangulating long, thin objects, in order to // keep the number of triangles small, but it can result in long, thin triangles, // which are not acceptable for all applications. If the value is too large, this // constraint may not be satisfiable, causing the triangulation to fail. This constraint // may be approximately enforced. A value of 0 means to ignore the minimum angle // constraint. MinAngleInTriangle = 3 * Math.PI / 180.0, // // Summary: // A positive real number specifying the minimum allowed value for the external // angle between two adjacent triangles, in radians. // // Exceptions: // T:Autodesk.Revit.Exceptions.ArgumentOutOfRangeException: // When setting this property: The given value for minExternalAngleBetweenTriangles // must be greater than 0 and no more than 30000 feet. // // Remarks: // A small value yields more smoothly curved triangulated surfaces, usually at the // expense of an increase in the number of triangles. Note that this setting has // no effect for planar surfaces. This constraint may be approximately enforced. MinExternalAngleBetweenTriangles = 0.2 * Math.PI }; TriangulatedSolidOrShell shell = SolidUtils.TessellateSolidOrShell(solid, controls); int n = shell.ShellComponentCount; Debug.Assert(1 == n, "expected just one shell component in room closed shell"); TriangulatedShellComponent component = shell.GetShellComponent(0); int coordsBase = coords.Count; int indicesBase = indices.Count; n = component.VertexCount; for (int i = 0; i < n; ++i) { XYZ v = component.GetVertex(i); coords.Add(new IntPoint3d(v)); } n = component.TriangleCount; for (int i = 0; i < n; ++i) { TriangleInShellComponent t = component.GetTriangle(i); vertices.Clear(); vertices.Add(component.GetVertex(t.VertexIndex0)); vertices.Add(component.GetVertex(t.VertexIndex1)); vertices.Add(component.GetVertex(t.VertexIndex2)); indices.Add(new TriangleIndices( coordsBase + t.VertexIndex0, coordsBase + t.VertexIndex1, coordsBase + t.VertexIndex2)); TessellatedFace tf = new TessellatedFace( vertices, materialId); if (builder.DoesFaceHaveEnoughLoopsAndVertices(tf)) { builder.AddFace(tf); ++nTriangles; } } #else // Iterate over the individual solid faces foreach (Face f in solid.Faces) { vertices.Clear(); #region Use face triangulation #if USE_FACE_TRIANGULATION Mesh mesh = f.Triangulate(); int n = mesh.NumTriangles; for (int i = 0; i < n; ++i) { MeshTriangle triangle = mesh.get_Triangle(i); XYZ p1 = triangle.get_Vertex(0); XYZ p2 = triangle.get_Vertex(1); XYZ p3 = triangle.get_Vertex(2); vertices.Clear(); vertices.Add(p1); vertices.Add(p2); vertices.Add(p3); TessellatedFace tf = new TessellatedFace( vertices, materialId); if (builder.DoesFaceHaveEnoughLoopsAndVertices(tf)) { builder.AddFace(tf); ++nTriangles; } } #endif // USE_FACE_TRIANGULATION #endregion // Use face triangulation #region Use original solid and its EdgeLoops #if USE_EDGELOOPS // This returns arbitrarily ordered and // oriented edges, so no solid can be // generated. foreach (EdgeArray loop in f.EdgeLoops) { foreach (Edge e in loop) { XYZ p = e.AsCurve().GetEndPoint(0); XYZ q = p; if (pts.ContainsKey(p)) { KeyValuePair <XYZ, int> kv = pts[p]; q = kv.Key; int n = kv.Value; pts[p] = new KeyValuePair <XYZ, int>( q, ++n); Debug.Print("Ignoring vertex at {0} " + "with distance {1} to existing " + "vertex {2}", p, p.DistanceTo(q), q); } else { pts[p] = new KeyValuePair <XYZ, int>( p, 1); } vertices.Add(q); ++nVertices; } } #endif // USE_EDGELOOPS #endregion // Use original solid and its EdgeLoops #region Use original solid and GetEdgesAsCurveLoops #if USE_AS_CURVE_LOOPS // The solids generated by this have some weird // normals, so they do not render correctly in // the Forge viewer. Revert to triangles again. IList <CurveLoop> loops = f.GetEdgesAsCurveLoops(); foreach (CurveLoop loop in loops) { foreach (Curve c in loop) { XYZ p = c.GetEndPoint(0); XYZ q = p; if (pts.ContainsKey(p)) { KeyValuePair <XYZ, int> kv = pts[p]; q = kv.Key; int n = kv.Value; pts[p] = new KeyValuePair <XYZ, int>( q, ++n); Debug.Print("Ignoring vertex at {0} " + "with distance {1} to existing " + "vertex {2}", p, p.DistanceTo(q), q); } else { pts[p] = new KeyValuePair <XYZ, int>( p, 1); } vertices.Add(q); ++nVertices; } } #endif // USE_AS_CURVE_LOOPS #endregion // Use original solid and GetEdgesAsCurveLoops builder.AddFace(new TessellatedFace( vertices, materialId)); ++nFaces; } #endif // CREATE_NEW_SOLID_USING_TESSELATION #endregion // Create a new solid based on tessellation of the invalid room closed shell solid builder.CloseConnectedFaceSet(); builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; // Solid failed builder.Fallback = TessellatedShapeBuilderFallback.Mesh; // use Abort if target is Solid builder.Build(); result = builder.GetBuildResult(); // Debug printout log of current solid's glTF facet data n = coords.Count - coordsBase; Debug.Print("{0} glTF vertex coordinates " + "in millimetres:", n); Debug.Print(string.Join(" ", coords .TakeWhile <IntPoint3d>((p, i) => coordsBase <= i) .Select <IntPoint3d, string>(p => p.ToString()))); n = indices.Count - indicesBase; Debug.Print("{0} glTF triangles:", n); Debug.Print(string.Join(" ", indices .TakeWhile <TriangleIndices>((ti, i) => indicesBase <= i) .Select <TriangleIndices, string>(ti => ti.ToString()))); } } } return(result.GetGeometricalObjects()); }
private static IList <GeometryObject> GetGeometryObjectsFromFace(Face face) { IList <GeometryObject> shapeGeometries = null; try { List <CurveLoop> profiles = new List <CurveLoop>(); XYZ normal = face.ComputeNormal(new UV(0, 0)); IList <CurveLoop> curveLoops = face.GetEdgesAsCurveLoops(); IList <IList <CurveLoop> > sortedCurveLoops = ExporterIFCUtils.SortCurveLoops(curveLoops); foreach (IList <CurveLoop> curveLoopList in sortedCurveLoops) { foreach (CurveLoop curveLoop in curveLoopList) { if (curveLoop.IsCounterclockwise(normal)) { profiles.Insert(0, curveLoop); } else { profiles.Add(curveLoop); } } } List <List <XYZ> > allLoopVertices = new List <List <XYZ> >(); for (int i = 0; i < profiles.Count; i++) { List <XYZ> vertices = new List <XYZ>(); CurveLoop curveLoop = profiles[i]; foreach (Curve curve in curveLoop) { IList <XYZ> tessellatedVertices = curve.Tessellate(); tessellatedVertices.RemoveAt(tessellatedVertices.Count - 1); vertices.AddRange(tessellatedVertices); } allLoopVertices.Add(vertices); } TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); TessellatedFace tesseFace = new TessellatedFace(allLoopVertices.ToArray(), ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices(tesseFace)) { builder.AddFace(tesseFace); } builder.CloseConnectedFaceSet(); #if RELEASE2015 || RELEASE2016 TessellatedShapeBuilderResult result = builder.Build(TessellatedShapeBuilderTarget.AnyGeometry, TessellatedShapeBuilderFallback.Mesh, ElementId.InvalidElementId); #else builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; builder.Fallback = TessellatedShapeBuilderFallback.Mesh; builder.Build(); TessellatedShapeBuilderResult result = builder.GetBuildResult(); #endif shapeGeometries = result.GetGeometricalObjects(); } catch (Exception ex) { MessageBox.Show("Failed to get geometry objects from a face.\n" + ex.Message, "Get Geometry Objects", MessageBoxButtons.OK, MessageBoxIcon.Warning); } return(shapeGeometries); }
// Create a pyramid-shaped DirectShape using given material for the faces static public void CreateTessellatedShape(Document doc, ElementId materialId) { List <XYZ> loopVertices = new List <XYZ>(4); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(true); // create a pyramid with a square base 4' x 4' and 5' high double length = 4.0; double height = 5.0; XYZ basePt1 = XYZ.Zero; XYZ basePt2 = new XYZ(length, 0, 0); XYZ basePt3 = new XYZ(length, length, 0); XYZ basePt4 = new XYZ(0, length, 0); XYZ apex = new XYZ(length / 2, length / 2, height); loopVertices.Add(basePt1); loopVertices.Add(basePt2); loopVertices.Add(basePt3); loopVertices.Add(basePt4); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(basePt1); loopVertices.Add(apex); loopVertices.Add(basePt2); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(basePt2); loopVertices.Add(apex); loopVertices.Add(basePt3); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(basePt3); loopVertices.Add(apex); loopVertices.Add(basePt4); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(basePt4); loopVertices.Add(apex); loopVertices.Add(basePt1); builder.AddFace(new TessellatedFace(loopVertices, materialId)); builder.CloseConnectedFaceSet(); builder.Target = TessellatedShapeBuilderTarget.Solid; builder.Fallback = TessellatedShapeBuilderFallback.Abort; builder.Build(); TessellatedShapeBuilderResult result = builder.GetBuildResult(); using (Transaction t = new Transaction(doc, "Create tessellated direct shape")) { t.Start(); DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel)); ds.ApplicationId = "Application id"; ds.ApplicationDataId = "Geometry object id"; ds.SetShape(result.GetGeometricalObjects()); t.Commit(); } }
public static void CreateCube(Document doc, XYZ min, XYZ max, string name) { List <XYZ> loopVertices = new List <XYZ>(4); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(true); XYZ topLeftBack = new XYZ(min.X, max.Y, min.Z); XYZ topRightBack = new XYZ(max.X, max.Y, min.Z); XYZ bottomLeftBack = new XYZ(min.X, min.Y, min.Z); //min XYZ bottomRightBack = new XYZ(max.X, min.Y, min.Z); XYZ topLeftFront = new XYZ(min.X, max.Y, max.Z); XYZ topRightFront = new XYZ(max.X, max.Y, max.Z); //max XYZ bottomLeftFront = new XYZ(min.X, min.Y, max.Z); XYZ bottomRightFront = new XYZ(max.X, min.Y, max.Z); //Create the material ElementId materialId = ElementId.InvalidElementId; loopVertices.Add(topLeftBack); loopVertices.Add(topRightBack); loopVertices.Add(topRightFront); loopVertices.Add(topLeftFront); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(bottomLeftBack); loopVertices.Add(bottomRightBack); loopVertices.Add(bottomRightFront); loopVertices.Add(bottomLeftFront); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(topLeftBack); loopVertices.Add(topLeftFront); loopVertices.Add(bottomLeftFront); loopVertices.Add(bottomLeftBack); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(topLeftBack); loopVertices.Add(topLeftFront); loopVertices.Add(bottomRightFront); loopVertices.Add(bottomRightBack); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(topLeftBack); loopVertices.Add(topRightBack); loopVertices.Add(bottomRightBack); loopVertices.Add(bottomLeftBack); builder.AddFace(new TessellatedFace(loopVertices, materialId)); loopVertices.Clear(); loopVertices.Add(topLeftFront); loopVertices.Add(topRightFront); loopVertices.Add(bottomRightFront); loopVertices.Add(bottomLeftFront); builder.AddFace(new TessellatedFace(loopVertices, materialId)); builder.CloseConnectedFaceSet(); builder.Build(); TessellatedShapeBuilderResult result = builder.GetBuildResult(); using (Transaction t = new Transaction(doc, "Create tessellated direct shape")) { t.Start(); DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel)); ds.Name = name; ds.SetShape(result.GetGeometricalObjects()); t.Commit(); } }
public static void Execute1( ExternalCommandData commandData) { Transaction trans = null; UIDocument uidoc = commandData.Application .ActiveUIDocument; Document doc = uidoc.Document; try { Selection choices = uidoc.Selection; Reference reference = choices.PickObject( ObjectType.Face); Element el = doc.GetElement( reference.ElementId); trans = new Transaction(doc, "Create elements"); trans.Start(); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); Face face = el.GetGeometryObjectFromReference( reference) as Face; Mesh mesh = face.Triangulate(); List <XYZ> args = new List <XYZ>(3); XYZ offset = new XYZ(); if (el.Location is LocationPoint) { LocationPoint locationPoint = el.Location as LocationPoint; offset = locationPoint.Point; } for (int i = 0; i < mesh.NumTriangles; i++) { MeshTriangle triangle = mesh.get_Triangle( i); XYZ p1 = triangle.get_Vertex(0); XYZ p2 = triangle.get_Vertex(1); XYZ p3 = triangle.get_Vertex(2); p1 = p1.Add(offset); p2 = p2.Add(offset); p3 = p3.Add(offset); args.Clear(); args.Add(p1); args.Add(p2); args.Add(p3); TessellatedFace tesseFace = new TessellatedFace(args, ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices( tesseFace)) { builder.AddFace(tesseFace); } } builder.CloseConnectedFaceSet(); //TessellatedShapeBuilderResult result // = builder.Build( // TessellatedShapeBuilderTarget.AnyGeometry, // TessellatedShapeBuilderFallback.Mesh, // ElementId.InvalidElementId ); // 2016 builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; // 2018 builder.Fallback = TessellatedShapeBuilderFallback.Mesh; // 2018 builder.Build(); // 2018 TessellatedShapeBuilderResult result = builder.GetBuildResult(); // 2018 ElementId categoryId = new ElementId( BuiltInCategory.OST_GenericModel); //DirectShape ds = DirectShape.CreateElement( // doc, categoryId, // Assembly.GetExecutingAssembly().GetType() // .GUID.ToString(), Guid.NewGuid().ToString() ); // 2016 DirectShape ds = DirectShape.CreateElement( doc, categoryId); // 2018 ds.ApplicationId = Assembly.GetExecutingAssembly() .GetType().GUID.ToString(); // 2018 ds.ApplicationDataId = Guid.NewGuid().ToString(); // 2018 ds.SetShape(result.GetGeometricalObjects()); ds.Name = "MyShape"; trans.Commit(); } catch (Exception ex) { if (trans != null) { trans.RollBack(); } Debug.Print(ex.Message); } }
static internal IEnumerable <GeometryObject> Convert(IEnumerable <Rhino.Geometry.Mesh> meshes) { List <XYZ> faceVertices = new List <XYZ>(4); var builder = new TessellatedShapeBuilder(); builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; builder.Fallback = TessellatedShapeBuilderFallback.Mesh; foreach (var mesh in meshes) { Rhino.Geometry.Mesh[] pieces = mesh.DisjointMeshCount > 1 ? mesh.SplitDisjointPieces() : new Rhino.Geometry.Mesh[] { mesh }; foreach (var piece in pieces) { // Meshes with edges smaller than AbsoluteRevitTolerance (1/16 inch) are not welcome in Revit while (piece.CollapseFacesByEdgeLength(false, ModelAbsoluteTolerance) > 0) { ; } piece.Faces.ConvertNonPlanarQuadsToTriangles(RhinoMath.ZeroTolerance, RhinoMath.UnsetValue, 5); bool isOriented = false; bool hasBoundary = false; bool isSolid = piece.IsClosed && piece.IsManifold(true, out isOriented, out hasBoundary) && isOriented; var vertices = piece.Vertices; builder.OpenConnectedFaceSet(isSolid); foreach (var face in piece.Faces) { faceVertices.Add(Convert(vertices[face.A])); faceVertices.Add(Convert(vertices[face.B])); faceVertices.Add(Convert(vertices[face.C])); if (face.IsQuad) { faceVertices.Add(Convert(vertices[face.D])); } builder.AddFace(new TessellatedFace(faceVertices, ElementId.InvalidElementId)); faceVertices.Clear(); } builder.CloseConnectedFaceSet(); } } try { builder.Build(); } catch (Autodesk.Revit.Exceptions.ApplicationException e) { Debug.Fail(e.Source, e.Message); return(null); } TessellatedShapeBuilderResult result = builder.GetBuildResult(); return(result.GetGeometricalObjects()); }
/// <summary> /// Create a new DirectShape element from given /// list of faces and return the number of faces /// processed. /// Return -1 if a face vertex index exceeds the /// total number of available vertices, /// representing a fatal error. /// </summary> public static DirectShape NewDirectShape( //List<XYZ> vertices, Autodesk.DesignScript.Geometry.Mesh mesh, //FaceCollection faces, //UIDocument UIdoc, //ElementId graphicsStyleId, //string appGuid, string shapeName) { int nFaces = 0; int nFacesFailed = 0; Document doc = DocumentManager.Instance.CurrentDBDocument; string appGuid = doc.Application.ActiveAddInId.GetGUID().ToString(); // Retrieve "<Sketch>" graphics style, // if it exists. FilteredElementCollector collector = new FilteredElementCollector(doc) .OfClass(typeof(GraphicsStyle)); GraphicsStyle style = collector.Cast <GraphicsStyle>() .FirstOrDefault <GraphicsStyle>(gs => gs.Name.Equals("<Sketch>")); ElementId graphicsStyleId = null; if (style != null) { graphicsStyleId = style.Id; } TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.LogString = shapeName; List <Autodesk.DesignScript.Geometry.Point> corners = new List <Autodesk.DesignScript.Geometry.Point>(4); List <XYZ> XYZcorners = new List <XYZ>(4); builder.OpenConnectedFaceSet(false); // foreach (Face f in faces) //{ builder.LogInteger = nFaces; if (corners.Capacity < mesh.FaceIndices.Length) { corners = new List <Autodesk.DesignScript.Geometry.Point>(mesh.FaceIndices.Length); XYZcorners = new List <XYZ>(mesh.FaceIndices.Length); } corners.Clear(); XYZcorners.Clear(); foreach (IndexGroup i in mesh.FaceIndices) { //Debug.Assert(vertices.Count > i.vertex, // "how can the face vertex index be larger " // + "than the total number of vertices?"); corners.Add(mesh.VertexPositions[i.A]); XYZcorners.Add(new XYZ(mesh.VertexPositions[(int)i.A].X, mesh.VertexPositions[(int)i.A].Y, mesh.VertexPositions[(int)i.A].Z)); corners.Add(mesh.VertexPositions[(int)i.B]); XYZcorners.Add(new XYZ(mesh.VertexPositions[(int)i.B].X, mesh.VertexPositions[(int)i.B].Y, mesh.VertexPositions[(int)i.B].Z)); corners.Add(mesh.VertexPositions[(int)i.C]); XYZcorners.Add(new XYZ(mesh.VertexPositions[(int)i.C].X, mesh.VertexPositions[(int)i.C].Y, mesh.VertexPositions[(int)i.C].Z)); if (i.Count > 3) { corners.Add(mesh.VertexPositions[(int)i.D]); XYZcorners.Add(new XYZ(mesh.VertexPositions[(int)i.D].X, mesh.VertexPositions[(int)i.D].Y, mesh.VertexPositions[(int)i.D].Z)); } } try { builder.AddFace(new TessellatedFace(XYZcorners, ElementId.InvalidElementId)); ++nFaces; } catch (Autodesk.Revit.Exceptions.ArgumentException ex) { // Remember something went wrong here. ++nFacesFailed; Debug.Print( "Revit API argument exception {0}\r\n" + "Failed to add face with {1} corners: {2}", ex.Message, corners.Count, string.Join(", ", XYZcorners.Select <XYZ, string>( p => Util.PointString(p)))); } //} builder.CloseConnectedFaceSet(); // Refer to StlImport sample for more clever // handling of target and fallback and the // possible combinations. TessellatedShapeBuilderResult r = builder.Build( TessellatedShapeBuilderTarget.Mesh, TessellatedShapeBuilderFallback.Salvage, graphicsStyleId); ConversionLog myLog = new ConversionLog("c:\\conversionLogFileName.txt"); DataConversionMonitorScope myLoggingScope = new DataConversionMonitorScope(myLog); TessellatedShapeBuilderOutcome testOutcome = r.Outcome; IList <GeometryObject> test = r.GetGeometricalObjects(); try { TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument); DirectShape ds = DirectShape.CreateElement( doc, _categoryId, appGuid, shapeName); ds.SetShape(r.GetGeometricalObjects()); ds.Name = shapeName; Debug.Print( "Shape '{0}': added {1} face{2}, {3} face{4} failed.", shapeName, nFaces, Util.PluralSuffix(nFaces), nFacesFailed, Util.PluralSuffix(nFacesFailed)); TransactionManager.Instance.TransactionTaskDone(); return(ds); } catch (Exception ex) { Debug.Print( "Problem with adding DirectShape: " + ex.Message.ToString()); return(null); } }
public static void Execute( ExternalCommandData commandData) { Transaction trans = null; UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; try { Selection choices = uidoc.Selection; Reference faceref = choices.PickObject( ObjectType.Face); string rep = faceref .ConvertToStableRepresentation(doc); Debug.Assert(rep.EndsWith(":SURFACE"), "expected stable representation to end with SURFACE"); Debug.Print("Face reference picked: " + rep); Element el = doc.GetElement( faceref.ElementId); using (trans = new Transaction(doc)) { trans.Start("Create elements"); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); // This may return a face in the family // symbol definition with no family instance // transform applied. Use the GeometryElement // GetTransformed method to retrieve the face // with the instance transformation applied. Face face = el.GetGeometryObjectFromReference( faceref) as Face; Debug.Print("Face reference property: " + ((null == face.Reference) ? "<nil>" : face.Reference.ConvertToStableRepresentation(doc))); Transform t = null; FamilyInstance fi = el as FamilyInstance; if (null != fi) { // Will this handle a face selected // in a nested family instance? // Some, yes, but not all. //t = fi.GetTransform(); // This also works for some instances // but not all. //Transform t1 = fi.GetTotalTransform(); Options opt = new Options(); opt.ComputeReferences = true; GeometryElement geo = el.get_Geometry(opt); GeometryElement geo2 = geo.GetTransformed( Transform.Identity); Stack <Transform> tstack = new Stack <Transform>(); if (GetTransformStackForObject(tstack, geo, doc, rep) && 0 < tstack.Count) { Debug.Print("GetTransformStackForObject " + "returned true with tstack count {0}", tstack.Count); t = Transform.Identity; while (0 < tstack.Count) { t *= tstack.Pop(); } } } Mesh mesh = face.Triangulate(); if (null != t) { mesh = mesh.get_Transformed(t); } XYZ[] triangleCorners = new XYZ[3]; for (int i = 0; i < mesh.NumTriangles; i++) { MeshTriangle triangle = mesh.get_Triangle(i); triangleCorners[0] = triangle.get_Vertex(0); triangleCorners[1] = triangle.get_Vertex(1); triangleCorners[2] = triangle.get_Vertex(2); XYZ normal = GetNormal(triangleCorners); SketchPlane sketchPlane = GetSketchPlane( doc, triangleCorners[0], normal); DrawModelLineLoop(sketchPlane, triangleCorners); TessellatedFace tesseFace = new TessellatedFace(triangleCorners, ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices( tesseFace)) { builder.AddFace(tesseFace); } } builder.CloseConnectedFaceSet(); //TessellatedShapeBuilderResult result // = builder.Build( // TessellatedShapeBuilderTarget.AnyGeometry, // TessellatedShapeBuilderFallback.Mesh, // ElementId.InvalidElementId ); // 2016 builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; // 2018 builder.Fallback = TessellatedShapeBuilderFallback.Mesh; // 2018 builder.Build(); // 2018 TessellatedShapeBuilderResult result = builder.GetBuildResult(); // 2018 ElementId categoryId = new ElementId( BuiltInCategory.OST_GenericModel); //DirectShape ds = DirectShape.CreateElement( // doc, categoryId, // Assembly.GetExecutingAssembly().GetType().GUID.ToString(), // Guid.NewGuid().ToString() ); // 2016 DirectShape ds = DirectShape.CreateElement( doc, categoryId); // 2018 ds.ApplicationId = Assembly.GetExecutingAssembly() .GetType().GUID.ToString(); // 2018 ds.ApplicationDataId = Guid.NewGuid().ToString(); // 2018 ds.SetShape(result.GetGeometricalObjects()); ds.Name = "MyShape"; trans.Commit(); } } catch (Exception ex) { TaskDialog.Show("Error", ex.Message); } }