Anuncios
Welcome to the Revit Ideas Board! Before posting, please read the helpful tips here. Thank you for your Ideas!
cancelar
Mostrando los resultados de 
Mostrar  solo  | Buscar en lugar de 
Quiere decir: 

ConnectTo Revit API method to behave similar to the Revit UI connection of mechanical elements.

ConnectTo Revit API method to behave similar to the Revit UI connection of mechanical elements.

Below the confirmation from the Revit Autodesk Developers that ConnectTo Revit API method is not enough to connect mechanical elements 

 

ABertzouanis9F98Y_0-1624900685210.png

https://forums.autodesk.com/t5/revit-api-forum/connecting-duct-fitting-to-duct-the-fitting-does-not-...

8 Comentarios
richard.laroche
Contributor

Yeah, just spent a while dealing with this issue.
I spawn a plumbing fixture on a pipe face using that method: doc.Create.NewFamilyInstance(pipeface,pipefacecenter,XYZ(0,0,0),fixturefamilysymbol)

 

the fixturefamilysymbol is a simple cylinder with a connector set to "global".

richardlaroche_1-1679512800317.png

 

The family has a "Nominal Diameter" family parameter set to instance and the connector diameter is referenced to it.

richardlaroche_0-1679512730639.png

 

Then I try to connect the  NewFamilyInstance's connector to the reference pipe connector using connecfrom = list(newfamilyinstance.MEPModel.ConnectorManager.UnusedConnectors)[0].ConnectTo( list(referencepipe.ConnectorManager.UnusedConnectors)[0])

(I did all the necessary filtering before to keep elements with only one UnusedConnector)

Sometime it does work. Sometimes not. Here is an example:



Here is my code (please forgive my brutal style and overkill boilerplate):

 

 

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *
from System.Collections.Generic import *
from Autodesk.Revit.Attributes import*


import clr
clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

from System.Collections.Generic import *

# Import Revit Nodes
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import python library
import sys
pyt_path =  r"C:\Program Files\Autodesk\Revit 2022\AddIns\DynamoForRevit"
sys.path.append(pyt_path)
import os

import subprocess

import System
from System import *

doc = DocumentManager.Instance.CurrentDBDocument
# The inputs to this node will be stored as a list in the IN variables.


def getParamValue(element,param):
    
    try:
       DB = element.GetOrderedParameters()
       for i in DB:
           if i.Definition.Name == param:
               if i.StorageType == 2:
                   value = (i.AsDouble())
               elif i.StorageType == 1:
                   value = (i.AsInteger())
               elif i.StorageType == 3:
                   value = (i.AsString())
               else: value = (i.AsElementId())
    except:
        value = ("Aucune valeur trouvée")
    return value

def getParamObj(element,param):
    valueout = 0
    try:
        DB = element.GetOrderedParameters()
        for i in DB:
          if i.Definition.Name == param:
              valueout = i
            
    except:
        pass
    return valueout

def getpipefaceformagicconnector(wpipe):
    pipe = UnwrapElement(wpipe)
    cons = list(pipe.ConnectorManager.UnusedConnectors)
    if len(cons) >0:
        geomenum = pipe.get_Geometry(opt)
        pipecurve = pipe.Location.Curve
        solids = []
        pipefaces = []
        for geobj in geomenum:
            solids.append(geobj)
        for solid in solids:
            flist = solid.Faces
            for fc in flist:
                if "PlanarFace" in fc.GetType().ToString():
                    pipefaces.append(fc)
                   
        for con in cons:
            for pipeface in pipefaces:
                if pipecurve.GetEndPoint(0).DistanceTo(con.Origin)==0 and pipeface.Origin.DistanceTo(con.Origin) - getParamValue(pipe,"Outside Diameter")/2 < 0.01:
                    return pipeface
                elif pipecurve.GetEndPoint(1).DistanceTo(con.Origin)==0 and pipeface.Origin.DistanceTo(con.Origin)- getParamValue(pipe,"Outside Diameter")/2 < 0.01:
                    return pipeface
                    
    return ["Error",UnwrapElement(wpipe)]

def getpipefacecenterformagicconnector(wpipe):
    pipe = UnwrapElement(wpipe)
    cons = list(pipe.ConnectorManager.UnusedConnectors)
    if len(cons) >0:
        geomenum = pipe.get_Geometry(opt)
        pipecurve = pipe.Location.Curve
        solids = []
        pipefaces = []
        for geobj in geomenum:
            solids.append(geobj)
        for solid in solids:
            flist = solid.Faces
            for fc in flist:
                if "PlanarFace" in fc.GetType().ToString():
                    pipefaces.append(fc)
                   
        for con in cons:
            for pipeface in pipefaces:
                if pipecurve.GetEndPoint(0).DistanceTo(con.Origin)==0 and pipeface.Origin.DistanceTo(con.Origin) - getParamValue(pipe,"Outside Diameter")/2 < 0.01:
                    return pipecurve.GetEndPoint(0)
                elif pipecurve.GetEndPoint(1).DistanceTo(con.Origin)==0 and pipeface.Origin.DistanceTo(con.Origin)- getParamValue(pipe,"Outside Diameter")/2 < 0.01:
                    return pipecurve.GetEndPoint(1)
                    
    return listout.append(["Error",UnwrapElement(wpipe)])

def getpipeconnectorformagicconnector(wpipe):
    pipe = UnwrapElement(wpipe)
    cons = list(pipe.ConnectorManager.UnusedConnectors)
    if len(cons) >0:
        geomenum = pipe.get_Geometry(opt)
        pipecurve = pipe.Location.Curve
        solids = []
        pipefaces = []
        for geobj in geomenum:
            solids.append(geobj)
        for solid in solids:
            flist = solid.Faces
            for fc in flist:
                if "PlanarFace" in fc.GetType().ToString():
                    pipefaces.append(fc)
                   
        for con in cons:
            for pipeface in pipefaces:
                if pipecurve.GetEndPoint(0).DistanceTo(con.Origin)==0 and pipeface.Origin.DistanceTo(con.Origin) - getParamValue(pipe,"Outside Diameter")/2 < 0.01:
                    return con
                elif pipecurve.GetEndPoint(1).DistanceTo(con.Origin)==0 and pipeface.Origin.DistanceTo(con.Origin)- getParamValue(pipe,"Outside Diameter")/2 < 0.01:
                    return con
                    
    return ["Error",UnwrapElement(wpipe)]

def getMagicConnectorFamTyp(document):

    allPlumbingfixturesTypesInProject = FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_PlumbingFixtures).WhereElementIsElementType().ToElements()
    
    pftinsert = []
    
    for pbft in allPlumbingfixturesTypesInProject:
        pbftType = pbft.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM)
        if "Magic" in pbftType.AsString():
            pftinsert.append(pbft)
            TransactionManager.Instance.EnsureInTransaction(doc)
            pbft.Activate()
            TransactionManager.Instance.TransactionTaskDone()
            return pbft
    return None
        



TransactionManager.Instance.EnsureInTransaction(doc)

Connecto = []
RefFace = []
RefLines = []
listout = []
opt = Options()
opt.ComputeReferences = True
mcft = getMagicConnectorFamTyp(doc)
wpipe = doc.GetElement(ElementId(4869586))


pipeface = getpipefaceformagicconnector(wpipe)
pipefacecenter = getpipefacecenterformagicconnector(wpipe)
#faceNormals.append(pipeface.FaceNormal)
#pipecurve = UnwrapElement(wpipe).Location.Curve
Connecto = getpipeconnectorformagicconnector(wpipe)


MagicConnector = doc.Create.NewFamilyInstance(pipeface,pipefacecenter,XYZ(0,0,0),mcft)
listout.append([MagicConnector,wpipe,pipeface,pipefacecenter])
level = UnwrapElement(wpipe).LevelId
phase = UnwrapElement(wpipe).get_Parameter(BuiltInParameter.PHASE_CREATED).AsElementId()
DiamAssign = getParamValue(UnwrapElement(wpipe),"Diameter")
listout.append(DiamAssign)
MagicConnDiameter = getParamObj(MagicConnector,"Nominal Diameter")
MagicConnDiameter.Set(DiamAssign)
#MagicConnOffsetfromHost = getParamObj(MagicConnector,"Offset from Host")
#MagicConnOffsetfromHost.Set(8/304.8)
MagicConnector.get_Parameter(BuiltInParameter.PHASE_CREATED).Set(phase)
MagicConnHWFU = getParamObj(doc.GetElement(MagicConnector.GetTypeId()),"CWFU")
MagicConnHWFU.Set(10)
MagicConnHWFU = getParamObj(doc.GetElement(MagicConnector.GetTypeId()),"HWFU")
MagicConnHWFU.Set(0)
MagicConnHWFU = getParamObj(doc.GetElement(MagicConnector.GetTypeId()),"WFU")
MagicConnHWFU.Set(0)

try
    connecfrom = list(MagicConnector.MEPModel.ConnectorManager.UnusedConnectors)
    connecfrom[0].ConnectTo(Connecto)
    listout.append([MagicConnector,"connect OK",Connecto,connecfrom[0]])
    
except
    connecfrom = list(MagicConnector.MEPModel.ConnectorManager.UnusedConnectors)
    listout.append([MagicConnector,"connect fail",Connecto,connecfrom[0]])

    
                    
          



TransactionManager.Instance.TransactionTaskDone()
# Assign your output to the OUT variable.
OUT = listout

ABertzouanis9F98Y
Enthusiast

@richard.laroche

Many thanks for your message and sharing videos and code.

 

This Idea is about Revit API functionality which is not  same to the Revit UI. "ConnectTo" Method works fine to connect elements only when the connection points are at exact same position between the elements and when no other modification in geometry size or other parameter is necessary for the connection to work.

 

Question:

Could you please confirm if in your first video that the pipe and fitting element are at the correct location having their connection points at exact same position?

 

To verify that the "connectTo" method works:

1. Connect the vertical pipe to the fitting using the Revit UI.

2. Disconnect the Pipe from the Fitting using the Revit UI.

(Now that your elements are in the position having connection points at exact same location and elements do not need adjustment in their geometry and size and other parameters)

3. Try to use the "connectTo" method to connect pipe to fitting.

(This should work)

richard.laroche
Contributor

@ABertzouanis9F98Y 

 

Thank you for checking out my issue.

 

I changed the XYZ used in the NewFamilyInstance to use the connector origin instead of the pipe face center but they have the exact same XYZ:

pipefacecenterXYZ = list(UnwrapElement(wpipe).ConnectorManager.UnusedConnectors)[0].Origin

pipeconnectorXYZ = list(pipe.ConnectorManager.UnusedConnectors)[0]

 

verifying pipefacecenterXYZ.DistanceTo(pipeconnectorXYZ) I get 0. So I know that the pipe connector is really at the face center.

 

But then I verify my plumbing fixture connector and the distance to the pipe connector, I get something weird for the pipe I showed in my forst video:
(list(MagicConnector.MEPModel.ConnectorManager.UnusedConnectors)[0].Origin).DistanceTo(pipeconnectorXYZ)/304.8 = 2.0588462975328

 

So I tried this test with another pipe where the script actually works without an error (as in my second video) and I got that:

(list(MagicConnector.MEPModel.ConnectorManager.UnusedConnectors)[0].Origin).DistanceTo(pipeconnectorXYZ)/304.8 = 2.1817385470803

But everything still works. So I will assume that this distance isn't the source of the problem.

 

 

Also checked the family to make sure that the connector was created on the plumbing fixture's origin:

richardlaroche_0-1679577297662.pngrichardlaroche_1-1679577346820.pngrichardlaroche_2-1679577396976.png

 

 

My last assumption is that the problem would be caused by the vertical orientation of the pipes. I only get an error for pipes that have disconnected ends in the vertical position.

richard.laroche
Contributor
 
richard.laroche
Contributor

@ABertzouanis9F98Y 

 

Just to be precise with the question you asked, yes I did try to:

1. Connect the vertical pipe to the fitting using the Revit UI.

2. Disconnect the Pipe from the Fitting using the Revit UI.

3. Try to use the "connectTo" method to connect pipe to fitting.

 

It does work. Only problem is that it implies that I have to connect my plumbing fixture manually using the UI, which is exactly what I am trying to automate.

 

I will try to make other experiments with NewFamilyInstance methods using different arguments.

 
 
jeremy_tammik
Autodesk

Thank you for the explanation and samples. I asked the development team for their opinion and suggestions.

richard.laroche
Contributor

@jeremy_tammik 

Thank you for looking at this problem.
To help any person investigating into this, here is what I mentionned to you on another page:

 

I tinkered something that works even though I dont't actually know why it does work.
I noticed that the FamilyInstance that I spawn always had doc.GetElement(MagicConnector.Id).Location.Point = XYZ(0,0,0)
All the time, even if I clearly see the object on the face of the pipe in the model.
So i just added a line of code before the "ConnectTo" and a 1mm "Offset from Host" to the familyinstance:
MagicConnOffsetfromHost = getParamObj(MagicConnector,"Offset from Host")
MagicConnOffsetfromHost.Set(1/304.8)
doc.GetElement(MagicConnector.Id).Location.Move(XYZ(0,0,0))
connecfrom = list(MagicConnector.MEPModel.ConnectorManager.UnusedConnectors)
connecfrom[0].ConnectTo(Connecto)

TaDam!
Now it works with vertical pipes.

I can send you the complete python code if needed.

Thanks for the quick reply!

jeremy_tammik
Autodesk

Many thanks to all for your valuable input and patience with this.

 

The development team replied:

 

The ConnectTo API was the barebone connection only. It does not have the rich capability of the UI. It has been a known issue for a long time. We will take this as an API feature request to be prioritized.

 

Checking the forum discussion, it seems the customer found some workaround to move forward; not sure how that impacts the priority. The underlying issue is real, valid and requires a fair amount of effort. Ideally, we like the UI and API user calling into the same method. Unfortunately, that is not the case of ConnectTo at this point.

 

We may explore the possibility of putting a wrapper and validation around the internal method RbsEditorUtils::RbsConnectionElementPickEditorSolution to expose that to the API. We logged a development ticket REVIT-205160 for this under MEP Mechanical Routing Solutions.

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

Enviar idea  

Autodesk Design & Make Report