Map lines from viewport space to sheet space

Map lines from viewport space to sheet space

DanielKP2Z9V
Advocate Advocate
293 Views
2 Replies
Message 1 of 3

Map lines from viewport space to sheet space

DanielKP2Z9V
Advocate
Advocate

Does anyone know how to map elements from viewport space to sheet space on which viewport is placed? I've had initial success with this code, it worked on a simple plan, but when running it on a rotated plan or on an elevation it either placed lines incorrectly (rotated) or threw an exception altogether (elevation).

 

If anyone knows a good example to follow that would be much appreciated.

 

 

 

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.Attributes;
using System.Collections.Generic;
using System.Linq;

[Transaction(TransactionMode.Manual)]
public class MapLinesToSheet : IExternalCommand
{
    public Result Execute(
        ExternalCommandData commandData,
        ref string message,
        ElementSet elements)
    {
        UIDocument uidoc = commandData.Application.ActiveUIDocument;
        Document doc = uidoc.Document;
        View activeView = uidoc.ActiveView;

        // Find the viewport that contains this active view
        Viewport viewport = GetViewportForActiveView(doc, activeView);
        if (viewport == null)
        {
            message = "No viewport found for the active view.";
            return Result.Failed;
        }

        // Get the sheet that contains the viewport
        ViewSheet sheet = doc.GetElement(viewport.SheetId) as ViewSheet;
        if (sheet == null)
        {
            message = "No sheet found for the active view.";
            return Result.Failed;
        }

        // Use the existing selection
        ICollection<ElementId> selectedIds = uidoc.Selection.GetElementIds();
        if (selectedIds.Count == 0)
        {
            message = "No elements selected. Please select some lines first.";
            return Result.Failed;
        }

        // Get the scale of the viewport
        double viewportScale = activeView.Scale;

        // Begin transaction
        using (Transaction trans = new Transaction(doc, "Map Lines to Sheet Space"))
        {
            trans.Start();

            foreach (ElementId id in selectedIds)
            {
                Element element = doc.GetElement(id);
                if (element is CurveElement curveElement)
                {
                    Curve curve = curveElement.GeometryCurve;

                    // Get the transformation from the viewport to the sheet
                    Transform transform = viewport.GetProjectionToSheetTransform();

                    // Scale the curve manually by dividing its coordinates by the viewport scale
                    Curve scaledCurve = ScaleCurve(curve, 1 / viewportScale);

                    // Apply the transform to the scaled curve
                    Curve transformedCurve = scaledCurve.CreateTransformed(transform);

                    // Project the transformed curve to the sheet plane
                    Curve projectedCurve = ProjectCurveToSheetPlane(transformedCurve);

                    // Create the new curve on the sheet
                    if (projectedCurve != null)
                    {
                        doc.Create.NewDetailCurve(sheet, projectedCurve);
                    }
                    else
                    {
                        message = "Failed to project curve to sheet plane.";
                        return Result.Failed;
                    }
                }
            }

            trans.Commit();
        }

        return Result.Succeeded;
    }

    private Viewport GetViewportForActiveView(Document doc, View activeView)
    {
        // Find the viewport that displays the active view
        FilteredElementCollector collector = new FilteredElementCollector(doc).OfClass(typeof(Viewport));
        foreach (Viewport vp in collector.Cast<Viewport>())
        {
            if (vp.ViewId == activeView.Id)
            {
                return vp;
            }
        }

        return null; // No matching viewport found
    }

    private Curve ScaleCurve(Curve curve, double scaleFactor)
    {
        // Scale each point in the curve by multiplying the coordinates by the scaleFactor
        Transform scaleTransform = Transform.Identity.ScaleBasis(scaleFactor);
        return curve.CreateTransformed(scaleTransform);
    }

    private Curve ProjectCurveToSheetPlane(Curve curve)
    {
        // Define the XY plane of the sheet (Z = 0)
        Plane sheetPlane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero);

        // Project each point of the curve onto the sheet plane
        XYZ start = ProjectPointToPlane(curve.GetEndPoint(0), sheetPlane);
        XYZ end = ProjectPointToPlane(curve.GetEndPoint(1), sheetPlane);

        // Return a new line or arc based on the projected points
        if (curve is Line)
        {
            return Line.CreateBound(start, end);
        }
        else if (curve is Arc arc)
        {
            XYZ mid = ProjectPointToPlane(arc.Evaluate(0.5, true), sheetPlane);
            return Arc.Create(start, end, mid);
        }

        return null; // If the curve type is not supported
    }

    private XYZ ProjectPointToPlane(XYZ point, Plane plane)
    {
        // Project a point onto a plane
        XYZ originToPt = point - plane.Origin;
        double distance = originToPt.DotProduct(plane.Normal);
        XYZ projection = point - distance * plane.Normal;

        return projection;
    }
}

 

 

294 Views
2 Replies
Replies (2)
Message 2 of 3

FrankHolidaytoiling
Advocate
Advocate

i found your rotation was returning 0 radians, so i wrote this and used it in my Transform. The only problem is the rotation centre is not correct, it is slightly offset. I think maybe again we need to use the views centre? well i will try this when i get time.....

private static double GetViewRotation(View view)
{
XYZ upDirection = view.UpDirection;
XYZ rightDirection = view.RightDirection;

double angle = rightDirection.AngleTo(XYZ.BasisX);

if (upDirection.CrossProduct(rightDirection).Z < 0)
{
angle = -angle;
}

return angle;
}

0 Likes
Message 3 of 3

baleti3266
Advocate
Advocate

thank you @FrankHolidaytoiling for looking into it, this has been solved in a follow up thread:
Solved: Re: Has anyone implemented revision clouds around selected elements on the sheet? - Autodesk...
turned out Viewport.GetProjectionToSheetTransform was needed to solve it

0 Likes