Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

GeometryCreationUtilities.CreateSweptGeome fails when sweeping along closed path

13 REPLIES 13
SOLVED
Reply
Message 1 of 14
dirk.neethling
1075 Views, 13 Replies

GeometryCreationUtilities.CreateSweptGeome fails when sweeping along closed path

Hello,

I am sweeping along a closed path, consisting of two arcs connected at each of their ends with straight lines.

When I only sweep along the straight lines and one arc between them, it works. I can exchange arcs, and it also works.

But in the closed loop configuration, i.e. both arcs and the connecting straight lines, it fails with the following message:

exc = {"createSweptSolid failed when creating the Swept solid."}

 

Below the code for the arcs and the methods used.

What am I doing wrong?

Regards, DIrk

 

            var segment = "HT_STL_G_COMPONENT BORED TUNNEL STANDARD TYPE 1";
            double OUTER_SEAL_RADIUS = Length.MetersToFeet(5.500 / 2.0) - Length.MetersToFeet(0.04);
            double startAngle = -Angle.DegreeToRadiant(11.25);
            double endAngle = Angle.DegreeToRadiant(56.25);

            Arc arc_top = Arc.Create(planeTop, OUTER_SEAL_RADIUS, startAngle, endAngle);
            ModelArc upperArc = CreateModelCurve(doc, planeTop, arc_top);

            Arc arc_bottom = Arc.Create(planeBottom, OUTER_SEAL_RADIUS, startAngle, endAngle);
            ModelArc lowerArc = CreateModelCurve(doc, planeBottom, arc_bottom);
            var lowerArcReversed = lowerArc.GeometryCurve.CreateReversed();

            //vertical connectors
            var upperStart = upperArc.GeometryCurve.GetEndPoint(0);
            var lowerFin = lowerArcReversed.GetEndPoint(1);
            var startLine = Creator.CreateModelLine(doc, lowerFin, upperStart);

            var upperFin = upperArc.GeometryCurve.GetEndPoint(1);
            var lowerStart = lowerArcReversed.GetEndPoint(0);
            var finLine = Creator.CreateModelLine(doc, upperFin, lowerStart);

            Debug.WriteLine("startLine: {0};{1}", startLine.GetCurve().GetEndPoint(0), startLine.GetCurve().GetEndPoint(1));
            Debug.WriteLine("upperArc: {0};{1}", upperArc.GetCurve().GetEndPoint(0), upperArc.GetCurve().GetEndPoint(1));
            Debug.WriteLine("finLine: {0};{1}", finLine.GetCurve().GetEndPoint(0), finLine.GetCurve().GetEndPoint(1));
            Debug.WriteLine("lowerArcReversed: {0};{1}", lowerArcReversed.GetEndPoint(0), lowerArcReversed.GetEndPoint(1));

            CurveLoop sweepes = new CurveLoop();
            sweepes.Append(startLine.GeometryCurve);
            sweepes.Append(upperArc.GeometryCurve);
            sweepes.Append(finLine.GeometryCurve);
            sweepes.Append(lowerArcReversed);

            Solid seal = sealProfile(doc, segment, pnt, width, sweepes);
   Solid sealProfile(Document doc, string segment, XYZ center, double width, CurveLoop sweeps)
    {
        CurveLoop profileLoop = null;
        Solid solid = null;
        Line initV = null;
        ElementId categoryId = new ElementId(BuiltInCategory.OST_GenericModel);
        DirectShape ds = null;
        List<GeometryObject> solids = null;
        XYZ vt = new XYZ(0, 0, width);
        XYZ origin_top = center - vt;
        XYZ origin_bottom = center + vt;

        try
        {
            //get the sweep, get plane per to first sweep vector, 
            //then you instantiate the cross-section in that plane to get it normal to the first sweep vector
            double param = sweeps.First().GetEndParameter(0);
            Curve firstCurve = sweeps.First();
            XYZ xyz = firstCurve.GetEndPoint(0);
            Transform tr = firstCurve.ComputeDerivatives(0, true);
            var v = XYZ.BasisZ;
            var v_normaltostartofarc = tr.OfVector(v);

            //tilt this profile into the sweep path
            XYZ endPoint1 = (sweeps.First() as Curve).Tessellate().ElementAt(0);
            XYZ endPoint2 = (sweeps.First() as Curve).Tessellate().ElementAt(1);
            initV = Line.CreateBound(endPoint1, endPoint2);
            var tangent = initV.Direction.CrossProduct(XYZ.BasisZ);

            //Plane LoopPlane = new Plane(initV.Direction, endPoint1);
            Plane LoopPlane = new Plane(tr.BasisX.Normalize(), tr.Origin);

            var _profilepoints = new List<XYZ>() { 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-10,0)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-11.36,-7.7)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-14.15,-10.49)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-13,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-11,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-10.27,-13.78)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-9.41,-12.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-7.95,-12)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-6.49,-12.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-5.63,-13.78)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-4.91,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-2.91,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-2.18,-13.78)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-1.4,-12.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(0,-12)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(1.4,-12.5 )), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(2.18,-13.78)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(2.91,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(4.91,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(5.63,-13.78)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(6.49,-12.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(7.95,-12)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(9.41,-12.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(10.27,-13.78)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(11,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(13,-16.5)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(14.15,-10.49)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(11.36,-7.7)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(10,0)), 
                FAIR_Space.Extensions.MmToFootPlanePoint(LoopPlane,new UV(-10,0))
            };

            profileLoop = new CurveLoop();

            for (int i = 0; i < (_profilepoints.Count - 1); i++)
            {
                Line line = Line.CreateBound(_profilepoints[i], _profilepoints[i + 1]);
                profileLoop.Append(line);
            }

            //rotate profileLoop on plane into position
            //ray from centroid to point of insertion
            var ray = origin_bottom - endPoint1;
            var angle = ray.AngleOnPlaneTo(XYZ.BasisX, LoopPlane.Normal);
            Debug.WriteLine("Segment [{0}]: {1}°", segment, Angle.RadiantToDegree(angle));
            //var angle = Math.PI / 2 + Angle.DegreeToRadiant(33.75);
            var transform = Transform.CreateRotationAtPoint(LoopPlane.Normal, angle, endPoint1);
            profileLoop.Transform(transform);
            IList<CurveLoop> profileLoops = new List<CurveLoop>();
            profileLoops.Add(profileLoop);

            SolidOptions solOptions = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId);
            solid = GeometryCreationUtilities.CreateSweptGeometry(sweeps /*sweepPath*/, 0, param, profileLoops, solOptions);

            categoryId = new ElementId(BuiltInCategory.OST_GenericModel);
            ds = DirectShape.CreateElement(doc, categoryId, Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
            solids = new List<GeometryObject>() { solid };
            ds.SetShape(solids);
            ds.Name = "ExtrusionTest3";
            //SolidSolidCutUtils 
        }
        catch (Exception exc)
        {
            Debug.WriteLine(exc);
        }

        return solid;
    }

    public static XYZ MmToFootPlanePoint(Plane plane, UV pt)
    {
        return plane.Origin + plane.XVec.Multiply(pt.U / 304.8) + plane.YVec.Multiply(pt.V / 304.8);
    }

 

13 REPLIES 13
Message 2 of 14
FAIR59
in reply to: dirk.neethling

You're not doing anything wrong. I'm afraid this is a Revit "thing" , too much going on in the corner, start face and end face.

A closed path (rectangular) in a plane works fine!!

 

Solution :

 

split your first Curve/Line in 2 halves. That way the direction at the start of the path is the same as the direction at the end.Knipsel.PNG

pathLoop.Append( end halve);    // line 1 in picture

pathLoop.Append( curve);           // line 2 in picture

...

pathLoop.Append( start halve);   // line 5 in picture

Message 3 of 14
dirk.neethling
in reply to: FAIR59

Thanks, I tried your suggestion. I split the left vertical line.

When I add the upper part of the left vertical line, the two Arcs and the right vertical line to the

CurveLoop Array, CreateSweptGeometry works fine, see pic. However, when I add the last line Segment (the lower half of the left vertical line), in order to close the path, the method call cracks with:

 

+  exc {"createSweptSolid failed when creating the Swept solid."} System.Exception {Autodesk.Revit.Exceptions.InternalException}

 

 

 

split_segment1.png

Message 4 of 14

I think I found a reason why this does not work, even though it should work anyway, since the start and finish coincide.

The upper and lower arcs are drawn on planes which are slightly offset to each other. The reason being that the tunnel lining ring, composed of the segments, as a slightly conical shape if seen from the side. This is done so that rings can be turned in the axial direction so that the Tunnel Boring Machine can change direction.

If the lower plane is slightly offset w.r.t. the upper plane, then the lower arc will be slightly shorter compared to the upper one, if projected into the same plane as the upper arc. Is it possible to draw the lower arc in the same plane as the upper one, and then transform it into the offset plane, so that it automatically becomes longer?

 

-		planeTop	{Autodesk.Revit.DB.Plane}	Autodesk.Revit.DB.Plane
+		base	{Autodesk.Revit.DB.Plane}	Autodesk.Revit.DB.Surface {Autodesk.Revit.DB.Plane}
+		Normal	{(0.000000000, 0.000000000, 1.000000000)}	Autodesk.Revit.DB.XYZ
+		Origin	{(0.000000000, 0.000000000, -7.536093855)}	Autodesk.Revit.DB.XYZ
+		XVec	{(1.000000000, 0.000000000, 0.000000000)}	Autodesk.Revit.DB.XYZ
+		YVec	{(0.000000000, 1.000000000, 0.000000000)}	Autodesk.Revit.DB.XYZ
-		planeBottom	{Autodesk.Revit.DB.Plane}	Autodesk.Revit.DB.Plane
+		base	{Autodesk.Revit.DB.Plane}	Autodesk.Revit.DB.Surface {Autodesk.Revit.DB.Plane}
+		Normal	{(0.000000000, 0.008181544, 0.999966531)}	Autodesk.Revit.DB.XYZ
+		Origin	{(0.000000000, 0.000000000, -12.148945515)}	Autodesk.Revit.DB.XYZ
+		XVec	{(1.000000000, 0.000000000, 0.000000000)}	Autodesk.Revit.DB.XYZ
+		YVec	{(0.000000000, 0.999966531, -0.008181544)}	Autodesk.Revit.DB.XYZ
Message 5 of 14
FAIR59
in reply to: dirk.neethling

When you say slight offset, do you mean a different position of the centerpoint?, or a different Radius?

Also I notice that the planeBottom is not vertical. Is that intentional? 

 

If nothing else works you could combine 2 U shaped solids in the DirectShape.

Message 6 of 14
dirk.neethling
in reply to: FAIR59

No I mean the planes are not exactly parallel to each other. The upper plane is horizontal, and the lower one tilts slightly downwards. I solved that part by projecting 3 vertical rays down from the upper Arc, at each end and in the middle.

Then I used the method below to determine the intersection Points on the plane below, which is at a slight angle to the horizontal.

Those 3 Points I then use to construct a new Arc, which is a projection of the upper arc on the lower plane.

I checked the x and y values of each projected Point, and they are exactly the same, as one would expect from a proper projection. So that part is OK.

However, when I then try to Close the path with the last remaining line Segment, the method again Fails.

So I am going to embark on another solution:

 

  1. call CreateSweptGeometry along a single line Segment at a time
  2. that way I can also control the Rotation of the Profile.
  3. create Corner elements which properly mimic the turning of the Profile around the Corner. Then place each one individually.

 

It seems there is no other solution, is that correct?

 

Message 7 of 14
FAIR59
in reply to: dirk.neethling

The curve in the tilted plane isn't an Arc anymore, but an Ellipse.

 

Knipsel.PNG

If the seal is in the outer curved plane, I would find the method used so far to be good enough, 

The alternative method of creating corners will probably give you the same problems with regards to direction/placement of profile. 

Message 8 of 14
dirk.neethling
in reply to: FAIR59

Hello FAIR59,

 

thanks for answering. Of course you're right about the ellipse, I only noticed now. Generally the solution is good. However,

the Problem at the edges is that the Profile does not properly turn the corner, resulting in the profile being imprintend on the longitudinal section:

Regards, DIrk

profile_edge.png

 

Message 9 of 14
dirk.neethling
in reply to: FAIR59

Hello FAIR59,

can any of this be avoided by running the corresponding sweep command in a Family Document, and then doing a FamilyInstance in the project document?

Regards, Dirk

Message 10 of 14
dirk.neethling
in reply to: FAIR59

Hello FAIR59,

 

I have 2 more questions:

  1. can I convert the swept Profile, which is of type solid, into an Element, so that I can do boolean operations with the Segment, which is a FamilyInstance?
  2. How can I colour the Profile black? Through SolidOptions? If so, I could not find any sample code.

Regards, Dirk

 

Message 11 of 14
FAIR59
in reply to: dirk.neethling

I think you have the same kind of creation methods in the Family Editor, so the same kind of problems.

 

We're trying to connect the square with the curved lines (see picture), so Revit has to make some adjustments.

 

Capture.JPG

In modelling I sometimes first make  something bigger and then cut it back with a Void

 

CutWithVoid.JPG

Regards Frank

 

Message 12 of 14
dirk.neethling
in reply to: FAIR59

Hello FAIR59,

 

thanks for the advice. I am accepting this as a solution, but I have 3 questions:

1. How can I transform a Solid? I tried applying the transform (below) to the solid which I obtain from the sweep, but the solid does not react to it.

Transform.CreateRotationAtPoint 
or
Transform.CreateTranslation


2. Is there a way to convert a Solid into an Element?

 

3. Is there an Extrusion/Sweep method which yields an Element?

Regards, Dirk

Message 13 of 14
FAIR59
in reply to: dirk.neethling

Hello Dirk

 

  1. As far as I can see, transformations need be applied before the creation of the solid
  2. No, the DirectShape is an Element.
  3. All GeometryCreationUtilities methods  results in solids and do not exist in the 3D model.

Maybe you'd have to go to the FamilyEditor afterall, then the result is an FamilyInstance

 

answer to ealier question, (maybe you've already found the answer):

 

material for the solid:

 

SolidOptions solOptions = new SolidOptions(_material.Id, ElementId.InvalidElementId);

 

Regards Frank

 

Message 14 of 14
dirk.neethling
in reply to: FAIR59

Hello Frank,

thanks for the pointers.

I figured having to do transformations beforehand. I got partial results, but conisidering the effort, I am reconsidering FamilyDocument. Transforming a FamilyInstance would be easier than doing it for each plane seperately on which a seal is swept.

If I sweep the seals in a FamilyDocument, and then instantiate that via FamilyInstance, will they react to a Transformation as a unit?

Regards, Dirk

Btw: where do I obtain material?

Regards, DIrk

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community