Creating a mirrored project location

Creating a mirrored project location

Betsalel
Participant Participant
774 Views
9 Replies
Message 1 of 10

Creating a mirrored project location

Betsalel
Participant
Participant

I’m trying to create a Python script that transfers all Project locations from a source model to a target model. The documented way for setting a new ProjectLocation’s position is using the SetProjectPosition() method, which works for unmirrored link locations.
However, a ProjectPosition only contains X, Y, Z, and angle - and not reflection, so it igrnores mirroring of some locations(for mirrored linking).

ProjectLocation does have a GetTransform() method but no SetTransform() method.

I’m trying to use ElementTransformUtils.MirrorElement(), but it seems to have no effect.

whats the best way to achieve this?

 

import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from Autodesk.Revit.DB import *
from pyrevit import forms


uiapp = __revit__.Application
uidoc = __revit__.ActiveUIDocument


def getTargetLocation(sourceLocation):
    for t in target_doc.ProjectLocations:
        if t.Name == sourceLocation.Name:
            return t
        
def PositionString(pp):
    x="X(E/W): {}".format(UnitUtils.ConvertFromInternalUnits(pp.EastWest, UnitTypeId.Meters))
    y="Y(N/S): {}".format(UnitUtils.ConvertFromInternalUnits(pp.NorthSouth, UnitTypeId.Meters))
    angle="angle: {}".format(UnitUtils.ConvertFromInternalUnits(pp.Angle, UnitTypeId.Degrees))
    elevation="Elevation: {}".format(UnitUtils.ConvertFromInternalUnits(pp.Elevation, UnitTypeId.Meters))
    return "{}\n{}\n{}\n{}".format(x,y,angle,elevation)

def TransformString(t):
    return "{}, {}, {}".format(t.BasisX.ToString(), t.BasisY.ToString(), t.BasisZ.ToString())

source_doc = uidoc.Document
target_doc = forms.select_open_docs(title='Select Destination Documents', multiple=False)

print(source_doc)

if not target_doc:
    print("Error: Target document not found. Please ensure both documents are open.")
    exit()

# Access the project location from the source model
source_project_location = source_doc.ActiveProjectLocation

project_locations = source_doc.ProjectLocations
for l in project_locations:
    position=l.GetProjectPosition(XYZ(0, 0, 0))
    print("\nName: {}".format(l.Name))
    print(PositionString(position))

    locationTransform=l.GetTransform()
    print(TransformString(locationTransform))
    
    existingTargetLocation=getTargetLocation(l)
    if existingTargetLocation:
        print("{} exists in model {}".format(existingTargetLocation.Name, target_doc.Title))
        print(PositionString(existingTargetLocation.GetProjectPosition(XYZ(0,0,0))))

        existingTargetLocationTransform=existingTargetLocation.GetTransform()
        print(TransformString(existingTargetLocationTransform))
    else:
        print('creating location {} in model {}'.format(l.Name,target_doc.Title))
        t = Transaction(target_doc, 'create location {}'.format(l.Name))
        t.Start()
        newTargetLocation = ProjectLocation.Create(target_doc, target_doc.SiteLocation.Id, l.Name)
        #print new ProjectLocation position and transform
        print(PositionString(newTargetLocation.GetProjectPosition(XYZ(0, 0, 0))))
        print(TransformString(newTargetLocation.GetTransform()))

        mirrorPlane=Plane.CreateByNormalAndOrigin(XYZ(1,0,0), XYZ(10,10,10))
        #print new ProjectLocation position and transform after transforming
        ElementTransformUtils.MirrorElement(target_doc, newTargetLocation.Id, mirrorPlane)
        ElementTransformUtils.MoveElement(target_doc, newTargetLocation.Id, locationTransform.BasisX)
        newTargetLocation.SetProjectPosition(XYZ(0, 0, 0), position)
        t.Commit()
        print("success")
        
        print(PositionString(newTargetLocation.GetProjectPosition(XYZ(0, 0, 0))))
        print(TransformString(newTargetLocation.GetTransform()))
    

    print("-------------")

 

 

0 Likes
Accepted solutions (1)
775 Views
9 Replies
Replies (9)
Message 2 of 10

jeremy_tammik
Alumni
Alumni

What is the optimal approach and best practice to achieve this manually in the end user interface?

   

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

Betsalel
Participant
Participant
Its a script for local use - not an app. So UI isnt the issue.
Im asking about the implementation of setting a reflection to a ProjectLocatio/Position
0 Likes
Message 4 of 10

jeremy_tammik
Alumni
Alumni

Well, the optimal workflow and best practices are actually always an issue when working with BIM, and an important one at that, maybe the most important of all. Before addressing a task programmatically via the Revit API, it is of greatr importance to establish that (a) what you are trying to do is possible at all in the UI, and (b) that the approach you are taking follows the established optimal workflow and best practices in the UI. Otherwise, with the Revit API, you can easily end up fighting and struggling to defeat the system instead of making good use of the existing built-in functionality.

   

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

jeremy_tammik
Alumni
Alumni

So, in short, I do not know the best approach to achieve this. Do you know how to do it in the UI? Regardless of either, I have meanwhile also asked the development team for advice for you.

  

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

Betsalel
Participant
Participant

Thanks Jeremy,

Sorry, I misunderstood your previous post. It is possible with the UI:

  • Creating a mirrored project location can be done via ‘Publish Coordinates’.
  • Transferring all locations between models can be done via ‘Transfer Project Standards’ > ‘Project Information’.

However, ‘Project Information’ also transfers and overrides other project settings.

The scenario I’m talking about is that an architectural model (A-BldgTypeX.rvt) is scattered around an architectural site model (A-Site). An engineer, such as a plumbing engineer, has analogous models: P-BldgTypeX and P-Site.

So, after publishing all the locations from A-Site to A-BldgTypeX link instances, I want to transfer (and later update) all these locations to P-BldgTypeX.

 

0 Likes
Message 7 of 10

mircea_kleps
Autodesk
Autodesk

Can you please be more specific about the first step? How exactly is the mirrored location obtained? I'm trying to understand how this works in UI to see if it can be done by API.


Mircea Kleps
Revit Software Engineer
0 Likes
Message 8 of 10

Betsalel
Participant
Participant

@mircea_kleps wrote:

Can you please be more specific about the first step? How exactly is the mirrored location obtained? 


  1. Starting with a host file containing a link
  2. Click 'Publish Coordinates' (just like described in the docs)
  3. Select a mirrored instance of the link
  4. Save the model. When promped - allow revit to modify the link file

now the link file has a mirrored project location:

Betsalel_0-1726731528412.png

 

0 Likes
Message 9 of 10

mircea_kleps
Autodesk
Autodesk
Accepted solution

Ok, MirrorElement on the ProjectLocation actually performs a mirror, but, as per its documentation, it works on a copy of the object, not on the one that it is passed.

You can use instead MirrorElements, which can be passed an argument to specify whether to mirror copies or the passed elements.


Mircea Kleps
Revit Software Engineer
0 Likes
Message 10 of 10

Betsalel
Participant
Participant

@mircea_kleps @jeremy_tammik , thanks! that did the job.

BTW, for some reson, in a reflected ProjectLocation - the angle from the source location position needs to be multiplied by -1.  The working definition:

def matchLocation(sourceLocation,targetLocation): #return True only if model was modified
    modelChanged = False
    sourceTransform = sourceLocation.GetTransform()
    targetTransform = targetLocation.GetTransform()
    sourcePosition = sourceLocation.GetProjectPosition(XYZ(0, 0, 0))
    
    if targetTransform.AlmostEqual(sourceTransform):
        print("locations match")
    elif sourceTransform.HasReflection == targetTransform.HasReflection:
        targetLocation.SetProjectPosition(XYZ(0, 0, 0), sourcePosition)
        print("location modified")
        modelChanged = True
    else:
        mirrorPlane=Plane.CreateByNormalAndOrigin(XYZ(1,0,0), XYZ(0,0,0))
        element_ids = List[ElementId]()
        element_ids.Add(targetLocation.Id)
        ElementTransformUtils.MirrorElements(targetLocation.Document, element_ids, mirrorPlane, False)
        mirroredPosition=ProjectPosition(sourcePosition.EastWest, sourcePosition.NorthSouth, sourcePosition.Elevation, -sourcePosition.Angle)
        targetLocation.SetProjectPosition(XYZ(0, 0, 0), mirroredPosition)
        print("location modified(with reflection)")
        modelChanged = True
    return modelChanged

 

0 Likes