I can't get a solid from a directshape created based on 4 points.

I can't get a solid from a directshape created based on 4 points.

AndrewButenko
Advocate Advocate
1,182 Views
11 Replies
Message 1 of 12

I can't get a solid from a directshape created based on 4 points.

AndrewButenko
Advocate
Advocate

Hello!

I need to get a solid based on four points. I am using TessellatedShapeBuilder.
I render a directshape and it looks like this:

зображення_2022-10-07_162341988.png

 

When I try to get solid out of it. That solid does not exist.
I drew the meshes and it looks like this:
зображення_2022-10-07_162548517.png

 

If you look closely, I see unconnected dots in the corners:

зображення_2022-10-07_162751272.png

Does anyone know how to get a solid in this case?

 

0 Likes
Accepted solutions (1)
1,183 Views
11 Replies
Replies (11)
Message 2 of 12

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @AndrewButenko ,

 

One suggestion is to analyze the direct shape element using the RevitLookup tool.

Could you please try to get/access solid of direct shape via the RevitLookup tool?

 

RevitLookup Links:https://github.com/jeremytammik/RevitLookup 

 

Also please take a look at the below link

https://forums.autodesk.com/t5/revit-api-forum/convert-directshape-to-solid/m-p/11429871#M66027 


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 3 of 12

mhannonQ65N2
Collaborator
Collaborator

A TessellatedShapeBuilder can sometimes build a mesh instead of a solid. If you need it to create a solid, set its Target property to TessellatedShapeBuilderTarget.Solid and its Fallback property to TessellatedShapeBuilderFallback.Abort so it will either create a solid or fail.

0 Likes
Message 4 of 12

RPTHOMAS108
Mentor
Mentor

Hard to solve a problem without being able to understand what exactly you are trying to do or how. Perhaps providing a code sample is the most efficient way of getting an answer here. 

 

If you are using tessellated shape builder, then as @mhannonQ65N2 notes it will have a fall back if your geometry fails to create a solid. Looking at your images you seem to have gaps in your geometry that could lead to a mesh rather than solid. Calling GetBuildResult will indicate the type of geometry being created.

0 Likes
Message 5 of 12

AndrewButenko
Advocate
Advocate

Thanks to all who responded. I have set the options:

 

builder.Target = TessellatedShapeBuilderTarget.Solid;
builder.Fallback = TessellatedShapeBuilderFallback.Abort;

 

And now I'm getting an error:
TessellatedShapeBuilder failed to build the requested geometry

Here is my code which i am using :

 

private static DirectShape CreatePrizmeDirectShape(Document doc, List<XYZ> lft, List<XYZ> rght, double Height)
{
List<List<XYZ>> pntss = new List<List<XYZ>>();

List<XYZ> pnts = new List<XYZ>();

pnts.Add(lft.FirstElem());
pnts.Add(lft.LastElem());
pnts.Add(rght.LastElem());
pnts.Add(rght.FirstElem());
pntss.Add(pnts.Clone());


pnts.Clear();
pnts.Add(lft.FirstElem());
pnts.Add(rght.FirstElem());
pnts.Add(rght.FirstElem().ZUpp(Height));
pnts.Add(lft.FirstElem().ZUpp(Height));
pntss.Add(pnts.Clone());


pnts.Clear();
pnts.Add(lft.FirstElem().ZUpp(Height));
pnts.Add(lft.LastElem().ZUpp(Height));
pnts.Add(lft.LastElem());
pnts.Add(lft.FirstElem());
pntss.Add(pnts.Clone());


pnts.Clear();
pnts.Add(lft.LastElem().ZUpp(Height));
pnts.Add(lft.LastElem());
pnts.Add(rght.LastElem());
pnts.Add(rght.LastElem().ZUpp(Height));
pntss.Add(pnts.Clone());


pnts.Clear();
pnts.Add(rght.FirstElem().ZUpp(Height));
pnts.Add(rght.LastElem().ZUpp(Height));
pnts.Add(rght.LastElem());
pnts.Add(rght.FirstElem());
pntss.Add(pnts.Clone());


pnts.Clear();
pnts.Add(lft.FirstElem().ZUpp(Height));
pnts.Add(lft.LastElem().ZUpp(Height));
pnts.Add(rght.LastElem().ZUpp(Height));
pnts.Add(rght.FirstElem().ZUpp(Height));
pntss.Add(pnts.Clone());

 

return CreateTessellatedShape(doc, pntss);
}

 

private static DirectShape CreateTessellatedShape(Document doc, List<List<XYZ>> lloopverics)
{


FilteredElementCollector collector = new FilteredElementCollector(doc).OfClass(typeof(Material));
IEnumerable<Material> materialsEnum = collector.ToElements().Cast<Material>();

var materialReturn1 = from materialElement in materialsEnum
where materialElement.Name == "Default"
select materialElement;

ElementId materialId = materialReturn1.First().Id;



TessellatedShapeBuilder builder = new TessellatedShapeBuilder();

builder.Target = TessellatedShapeBuilderTarget.Solid;

builder.Fallback = TessellatedShapeBuilderFallback.Abort;
//builder.Fallback = TessellatedShapeBuilderFallback.Salvage ;

builder.OpenConnectedFaceSet(true);

for (int i = 0; i < lloopverics.Count; i++)
{
builder.AddFace(new TessellatedFace(lloopverics[i], materialId));
}


builder.CloseConnectedFaceSet();
builder.Build();

TessellatedShapeBuilderResult TessellatedShapeBuilderObject = builder.GetBuildResult();

 

Transaction t = new Transaction(doc, "Create direct shape");
t.Start();
DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
ds.SetShape(TessellatedShapeBuilderObject.GetGeometricalObjects());
t.Commit();

return ds;

}



 

Here is the input:

  Name Value Type

lft.FirstElem(){(42.513861810, 364.342648187, 4.188446398)}Autodesk.Revit.DB.XYZ
lft.LastElem(){(43.986909346, 386.113916267, 4.466224178)}Autodesk.Revit.DB.XYZ
rght.FirstElem(){(40.279565212, 365.119862152, 4.188446398)}Autodesk.Revit.DB.XYZ
rght.LastElem(){(41.668282718, 385.644753829, 4.466224178)}Autodesk.Revit.DB.XYZ
rght.FirstElem().ZUpp(Height){(40.279565212, 365.119862152, 7.132890844)}Autodesk.Revit.DB.XYZ
rght.LastElem().ZUpp(Height){(41.668282718, 385.644753829, 7.132890844)}Autodesk.Revit.DB.XYZ
lft.FirstElem().ZUpp(Height){(42.513861810, 364.342648187, 7.132890844)}Autodesk.Revit.DB.XYZ
lft.LastElem().ZUpp(Height){(43.986909346, 386.113916267, 7.132890844)}Autodesk.Revit.DB.XYZ



0 Likes
Message 6 of 12

jeremy_tammik
Alumni
Alumni

Yes. Well, you will have to implement something to eliminate slightly offset duplicates of existing points. One method that I often like to use is to create a dictionary of all the vertices with a variable precision comparison operator, using vertices as dictionary keys. Every new point encountered is compared with the existing keys. If it is almost the same, the existing key is used instead. Look for GetVertices in The Building Coder samples, in CmdNestedInstanceGeo.cs:

  

https://github.com/jeremytammik/the_building_coder_samples

  

I have explained this in other recent forum threads also, so you can search this forum for CmdNestedInstanceGeo to discover similar solutions.

  

 

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 7 of 12

AndrewButenko
Advocate
Advocate

Thanks for the answer !
Did I understand correctly that I should try to build a solid and if it is not built, then take points from the mesh to "clean" them using a function that will remove those points that lie nearby. And then from the received points again get a solid?

0 Likes
Message 8 of 12

jeremy_tammik
Alumni
Alumni

Yes, that is my suggestion.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 9 of 12

AndrewButenko
Advocate
Advocate

Unfortunately this doesn't help. I get 12 points for input and 12 for output. They are not close to each other.

0 Likes
Message 10 of 12

jeremy_tammik
Alumni
Alumni

Depending on your shape, you might be able to simply generate the convex hull of all your points.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 11 of 12

RPTHOMAS108
Mentor
Mentor
Accepted solution

Your first face added is non-planar I didn't check the others.

 

The shape builder TessellatedFace class does say the following:

"...Face data is always set, even if the input data are invalid (e.g., describes a wildly non-planar face). A TessellatedShepeBuilder's function is used to check the data and heal them if possible."

 

This shape builder also says:

"All faces are planar and have polyline boundaries, defined as sequences of 3d coordinates."

 

I take it to mean that it will not create more exotic types of faces e.g. ruled faces if you add non-planer face definitions.

 

There must also be a point at which it is guessing how to 'heal' the face or perhaps it can't heal two connected faces because there is not a solution where they could both be planar with the target points provided. If you want to input a shape like this, then triangulate it to ensure all input faces are planar. Split the rectangle 1,2,3,4 into 1,2,3 & 1,3,4 no great hardship in that apart from the visible crease line perhaps.

 

You can't predict how it will try to heal something so I would be instead deciding that process myself in terms of the input.

 

 

 

Message 12 of 12

AndrewButenko
Advocate
Advocate

Thanks a lot! Triangulation helped and now everything works. Unfortunately, there are still many problems ahead with cutting the created geometry from the wall, which works or does not work completely randomly...

0 Likes