Что ж... Сам спросил - сам отвечу =)
В RevitAPI каких-либо методов проекции нет. Однако есть нужная тема у Таммика (http://thebuildingcoder.typepad.com/blog/2014/09/planes-projections-and-picking-points.html). Правда у него там ошибка в методе ProjectOnto - смотрите в комментариях.
Из его поста беру нужные мне методы:
Извините, вам запрещён просмотр содержимого спойлеров.
Теперь в коде плагина, получив нужные мне кривые, я их проецирую на плоскость. Для построения плоскости использую свойство семейства (окна или двери) FacingOrientation:
Plane plane = new Plane(familyInstance.FacingOrientation, new XYZ(0,0,0));
Методы у меня проецируют на плоскость точки. И если для отрезков это не вызовет проблем - там всего две точки (начало и конец), то для дуговых сегментов не подходит. На выручку приходит метод Curve.Tessellate() (http://www.revitapidocs.com/2018.1/f95f3199-3251-c708-c5a3-a0e9ef95ecfa.htm), который дуговые сегменты апроксимирует. Остается только соединить полученные точки в новые отрезки (и только отрезки). Это делается тоже легко:
List<Curve> projectedCurves = new List<Curve>();
foreach (Curve curve in curves)
{
XYZ previosPoint = null;
for (var i = 0; i < curve.Tessellate().Count; i++)
{
XYZ xyzProjected = plane.ProjectOnto(curve.Tessellate()[i]);
if (i == 0)
previosPoint = plane.ProjectOnto(xyzProjected);
else
{
projectedCurves.Add(Line.CreateBound(previosPoint, xyzProjected));
previosPoint = xyzProjected;
}
}
}
В итоге получаю нужный мне контур окна, спроецированный на плоскость:
(https://s17.postimg.org/xv2ke9qkb/Screenshot_16.png) (https://postimg.org/image/xv2ke9qkb/)
Для тех, у кого вдруг возник вопрос "Зачем это нужно?" - дело в том, что дальше я кривые собираю в CurveLoop и используя метод ExporterIFCUtils.ComputeAreaOfCurveLoops() (http://www.revitapidocs.com/2018.1/57f85e13-8ea8-01af-2660-94f1ff5cf7ea.htm) считаю площадь. Однако, в ходе тестов, выяснилось, что метод возвращает 0.0, если CurveLoop не лежит в одной плоскости. В справке этого не написано, к сожалению, хотя это логичное поведение