Revit.Line intersects Revit.Plane and creates point?

@Vladimir ,

finally someone helped me in a forum, with this masterpiece.


import clr 
import math
from pyrevit import revit,forms,script

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

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


doc = __revit__.ActiveUIDocument.Document
view = doc.ActiveView
uidoc = __revit__.ActiveUIDocument
app = __revit__.Application
DB = Autodesk.Revit.DB
output = script.get_output()
unit = doc.GetUnits()
selection = uidoc.Selection
#-------------------------------------------------------------------------------
class SelectionFilter(ISelectionFilter):
    def __init__(self, categories):
        self.categories = categories

    def AllowElement(self, element):
        if element.Category.Name in self.categories:
            return True
        return False

    def AllowReference(self, reference, point):
        return False
        
def ToLst(ele):
    if isinstance(ele,list):
        return ele
    else:
        return [ele]

def Flatten_lv3 (lst):
    return [i for sub_lst in lst for i in sub_lst]

def AllElementsOfCategoryInView(categories):
	categories = ToLst(categories)
	allcates = doc.Settings.Categories
	valid_cate = []
	alleles = []
	for cate in allcates:
		for category in categories:
			if cate.Name == category:
				valid_cate.append(cate)

	for cate in valid_cate:
		alleles.append(FilteredElementCollector(doc,view.Id).OfCategoryId(cate.Id).WhereElementIsNotElementType().ToElements())

	return Flatten_lv3(alleles)

def IntersectionPlaneAndLine(plane,line):
    planePoint = plane.Origin
    planeNormal = plane.Normal
    lineStart = line.GetEndPoint(0)
    lineEnd = line.GetEndPoint(1)
    lineDirection = (lineEnd - lineStart).Normalize()

    # Check if the line is parallel to the plane
    # If yes, return None
    if planeNormal.DotProduct(lineDirection) == 0:
        return None
    
    lineParameter = (planeNormal.DotProduct(planePoint) - planeNormal.DotProduct(lineStart)) / planeNormal.DotProduct(lineDirection)

    return lineStart + lineParameter * lineDirection

def IsPointOnLine(point,line):
    # If a point C is on a line, it will be between start point(A) and end point(B) of a line
    # AB = AC + CB
    lineStart = line.GetEndPoint(0)
    lineEnd = line.GetEndPoint(1)
    lineLength = lineStart.DistanceTo(lineEnd)
    startToPoint = lineStart.DistanceTo(point)
    pointToEnd = point.DistanceTo(lineEnd)

    if lineLength == startToPoint + pointToEnd:
        return True
    else:
        return False

def GetZCoordinate(point):
    return point.Z

def SortPointByElevation(points):
    return sorted(points, key=GetZCoordinate)

def SortPointByLineDirection(line,lstPoint):
    direction = line.Direction
    vectorZ = direction.Z
    sortedPoints = SortPointByElevation(lstPoint)
    if vectorZ > 0:
        return sortedPoints
    else:
        return list(reversed(sortedPoints))

def SplitPipeByPoint(pipe,pts):
    ele = []
    with Transaction(doc,'Break Curve') as t:
        t.Start()
        result = []
        for pt in pts:
            try:
                ele.append(DB.Plumbing.PlumbingUtils.BreakCurve(doc,pipe.Id,pt))
            except Exception as er:
                result.append(er)
        ele.append(pipe.Id)
        result = [doc.GetElement(Id) for Id in ele]
        t.Commit()
    return result

def SplitDuctByPoint(duct,pts):
    ele = []
    result = []
    with Transaction(doc,'Break Curve') as t:
        t.Start()
        for pt in pts:
            try:
                ele.append(DB.Mechanical.MechanicalUtils.BreakCurve(doc,duct.Id,pt))
            except Exception as er:
                result.append(er)
        ele.append(duct.Id)
        result = [doc.GetElement(Id) for Id in ele]
        t.Commit()
    return result

def ClosestConnectors(ele1, ele2):
	conn1 = ele1.ConnectorManager.Connectors
	conn2 = ele2.ConnectorManager.Connectors
	
	dist = 100000000
	connset = None
	for c in conn1:
		for d in conn2:
			conndist = c.Origin.DistanceTo(d.Origin)
			if conndist < dist:
				dist = conndist
				connset = [c,d]
	return connset

def CreateUnionFitting(ele1,ele2):
    connectors = ClosestConnectors(ele1,ele2)
    result = []
    with Transaction(doc,'Create Union Fitting') as t:
        t.Start()
        try:
            result.append(doc.Create.NewUnionFitting(connectors[0],connectors[1]))
        except Exception as er:
            result.append(er)
        t.Commit()
    return result

#----------------------------Main Logic-----------------------------------------
# Select duct and pipe
filterEle = SelectionFilter(["Ducts","Pipes"])
refEle = selection.PickObjects(ObjectType.Element, filterEle, "Select Model Elements")
selectedEle = []
for sublst in refEle:
    selectedEle.append(doc.GetElement(sublst))


eleLine = []
for ele in selectedEle:
    line = ele.Location.Curve
    eleLine.append(line)

# Get all levels in view
allLevels = AllElementsOfCategoryInView("Levels")
levelElevations = [level.Elevation for level in allLevels]

# Create planes from levels
planeLst = []
z_axis = XYZ(0,0,1)
for elevation in levelElevations:
    plane = Plane.CreateByNormalAndOrigin(z_axis,XYZ(0,0,elevation))
    planeLst.append(plane)

# Get intersection points between line and plane
intersectionPoint = []
for line in eleLine:
    sublst = []
    for plane in planeLst:
        point = IntersectionPlaneAndLine(plane,line)
        if IsPointOnLine(point,line):
            sublst.append(point)
    intersectionPoint.append(SortPointByLineDirection(line,sublst))


#----------------------------------Split Vertical Segment-----------------------------------------------------------------
with TransactionGroup(doc,'Split Vertical Segment') as tg:
    tg.Start()

    newEles = []
    newEles2 = []
    for ele,sub_lst in zip(selectedEle,intersectionPoint):
        if isinstance(ele,Autodesk.Revit.DB.Plumbing.Pipe):
            newEles = SplitPipeByPoint(ele,sub_lst)
            newEles2 = newEles[1:]
        else:
            newEles = SplitDuctByPoint(ele,sub_lst)
            newEles2 = newEles[1:]

        for ele1,ele2 in zip(newEles,newEles2):
            CreateUnionFitting(ele1,ele2)

    tg.Assimilate()

(some module settings and it should also work in dynamo)

1 Like