Announcements
Welcome to the Revit Ideas Board! Before posting, please read the helpful tips here. Thank you for your Ideas!
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Revit API request: EdgeArrayArray should have an Outerloop property

Revit API request: EdgeArrayArray should have an Outerloop property

 

This is an issue creating a headache and unexpected results for Revit API users:

 

Please refer to the following for some background. Mr Jeremy  Tammik jeremy_tammik recommended that an idea be created for this.

 

https://forums.autodesk.com/t5/revit-api-forum/is-the-first-edgeloop-still-the-outer-loop/m-p/130110...

 

What is happening?

 

  • The API ought to implement a new functionality that would be very handy for API users.
  • Right now, API users have to do a lot of work that is uncessessary, and that should be (in my opinion) a core part of the library.

 

I want to be able to do this, for example:

 

EdgeArray edgeArray = edgeArrayArrays.OuterLoop;

 

One single line of code. Instead, I have to implement all of this - and the only reason we have this code is because @stefanome very generously provided it to the community.

 

https://forums.autodesk.com/t5/revit-api-forum/is-the-first-edgeloop-still-the-outer-loop/m-p/102428...

 

public static List<List<CurveLoop>> SortCurveLoops(Face face)
{
var allLoops = face.GetEdgesAsCurveLoops().Select(loop => new CurveLoopUV(loop, face)).ToList();

var outerLoops = allLoops.Where(loop => loop.IsCounterclockwise).ToList();
var innerLoops = allLoops.Where(loop => !outerLoops.Contains(loop)).ToList();

// sort outerLoops putting last the ones that are outside all the preceding loops
bool somethingHasChanged;
do
{
somethingHasChanged = false;
for (var i = 1; i < outerLoops.Count(); i++)
{
var point = outerLoops[i].StartPointUV;
var loop = outerLoops[i - 1];
if (loop.IsPointInside(point) is CurveLoopUV.PointLocation.Inside)
{
var tmp = outerLoops[i];
outerLoops[i] = outerLoops[i - 1];
outerLoops[i - 1] = tmp;

somethingHasChanged = true;
}
}
} while (somethingHasChanged);

var result = new List<List<CurveLoop>>();
foreach (var outerLoop in outerLoops)
{
var list = new List<CurveLoop> {outerLoop.Loop3d};

for (var i = innerLoops.Count - 1; i >= 0; i--)
{
var innerLoop = innerLoops[i];
if (outerLoops.Count() == 1 // skip testing whether the inner loop is inside the outer loop
|| outerLoop.IsPointInside(innerLoop.StartPointUV) == CurveLoopUV.PointLocation.Inside)
{
list.Add(innerLoop.Loop3d);
innerLoops.RemoveAt(i);
}
}

result.Add(list);
}

return result;
}


class CurveLoopUV : IEnumerable<Curve>
{
public enum PointLocation
{
Outside,
OnTheEdge,
Inside,
}

public CurveLoop Loop3d { get; }
private readonly CurveLoop _loop2d;

public readonly double MinX, MaxX, MinY, MaxY;

public CurveLoopUV(CurveLoop curveLoop, Face face)
{
Loop3d = curveLoop;
_loop2d = new CurveLoop();

var points3d = Loop3d.SelectMany(curve => curve.Tessellate().Skip(1));
var pointsUv = points3d.Select(point3d => face.Project(point3d).UVPoint);
var points2d = pointsUv.Select(pointUv => new XYZ(pointUv.U, pointUv.V, 0)).ToList();

MinX = MinY = 1.0e100;
MaxX = MaxY = -1.0e100;
var nPoints = points2d.Count();
for (var i = 0; i < nPoints; i++)
{
var p1 = points2d[i];
var p2 = points2d[(i + 1) % nPoints];
_loop2d.Append(Line.CreateBound(p1, p2));
if (p1.X < MinX) MinX = p1.X;
if (p1.Y < MinY) MinY = p1.Y;
if (p1.X > MaxX) MaxX = p1.X;
if (p1.Y > MaxY) MaxY = p1.Y;
}
}

public PointLocation IsPointInside(XYZ point)
{
if (point.Y + Eps < MinY || point.Y + Eps > MaxY)
return PointLocation.Outside;

if (_loop2d.Any(curve => curve.Distance(point) < Eps))
return PointLocation.OnTheEdge;

var line = Line.CreateBound(point, new XYZ(1.0e100, point.Y, 0));
var nIntersections = _loop2d.Count(edge => edge.Intersect(line) == SetComparisonResult.Overlap);
return nIntersections % 2 == 1 ? PointLocation.Inside : PointLocation.Outside;
}

public bool IsCounterclockwise => _loop2d.IsCounterclockwise(XYZ.BasisZ);

public XYZ StartPointUV => _loop2d.First().GetEndPoint(0);

public IEnumerator<Curve> GetEnumerator() => _loop2d.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

 

 

 

 

 

 

 

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

Submit Idea