Model Line - Move/Trim Extents to round corner

Hello Dynamo Friends :slight_smile:

I made a little dynamo tool that connects model lines and another one that rounds the corner.

How can I manipulate the extents of the model line to trim it to the arc so I don´t have to do it manually?

I don´t want to create a new mode line, the extents of the existing one should be modified.

modellines

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

clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')

import System

from System.Windows.Forms import Form, Label, TextBox, Button
from System.Drawing import Size

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

import math
import traceback

class InputForm(Form):
    def __init__(self):
        self.InitializeComponent()

    def InitializeComponent(self):
        self.Text = 'Enter Number'
        self.Size = Size(400,400)

        self.label = Label()
        self.label.Text = 'Enter a number:'
        self.label.Location = System.Drawing.Point(10, 20)
        self.label.Size = Size(180, 20)
        self.Controls.Add(self.label)

        self.textBox = TextBox()
        self.textBox.Location = System.Drawing.Point(10, 50)
        self.textBox.Size = Size(180, 20)
        # Set a default value for the textBox here
        self.textBox.Text = '1'
        self.Controls.Add(self.textBox)

        self.button = Button()
        self.button.Text = 'OK'
        self.button.Location = System.Drawing.Point(60, 80)
        self.button.Click += self.button_click
        self.Controls.Add(self.button)

    def button_click(self, sender, e):
        self.DialogResult = System.Windows.Forms.DialogResult.OK
        self.Close()

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

# Function to get the line style of a Revit model curve
def get_line_style(curve_element):
    try:
        # Adjust this method according to your Revit API version and element type
        line_style_id = curve_element.LineStyle.Id
        return doc.GetElement(line_style_id)
    except Exception as e:
        raise Exception(f"Error in get_line_style: {e}\n{traceback.format_exc()}")

# Function to apply a line style to a Revit model curve
def apply_line_style(dynamo_model_curve, graphics_style):
    try:
        if dynamo_model_curve and graphics_style:
            # Retrieve the underlying Revit element
            revit_model_curve = dynamo_model_curve.InternalElement

            # Start a transaction
            TransactionManager.Instance.EnsureInTransaction(doc)

            # Access and set the line style parameter using the ElementId of the GraphicsStyle
            line_style_parameter = revit_model_curve.LookupParameter("Line Style")  # Revit parameter name
            if line_style_parameter and not line_style_parameter.IsReadOnly:
                # Use the ElementId of the GraphicsStyle object
                line_style_parameter.Set(graphics_style.Id)
            else:
                raise Exception("Line style parameter is not available or read-only.")

            TransactionManager.Instance.TransactionTaskDone()
        else:
            raise Exception("Model curve or graphics style is None")
    except Exception as e:
        raise Exception(f"Error in apply_line_style: {e}\n{traceback.format_exc()}")





# Function to find the common endpoint and distinct endpoints of two lines
def find_endpoints(line1, line2):
    try:
        endpoints1 = [line1.StartPoint, line1.EndPoint]
        endpoints2 = [line2.StartPoint, line2.EndPoint]

        for pt1 in endpoints1:
            for pt2 in endpoints2:
                if pt1.IsAlmostEqualTo(pt2):
                    distinct1 = line1.StartPoint if pt1.IsAlmostEqualTo(line1.EndPoint) else line1.EndPoint
                    distinct2 = line2.StartPoint if pt2.IsAlmostEqualTo(line2.EndPoint) else line2.EndPoint
                    return (pt1, distinct1, distinct2)

        raise Exception("No common endpoint found")
    except Exception as e:
        raise Exception(f"Error in find_endpoints: {e}\n{traceback.format_exc()}")

# Function to calculate the bisector of two vectors
def calculate_bisector(vec1, vec2):
    try:
        vec1 = vec1.Normalized()
        vec2 = vec2.Normalized()
        return vec1.Add(vec2).Normalized()
    except Exception as e:
        raise Exception(f"Error in calculate_bisector: {e}\n{traceback.format_exc()}")

# Function to find endpoints and calculate bisector and target point
def process_lines(line1, line2, radius):
    try:
        common, distinct1, distinct2 = find_endpoints(line1, line2)
        vector1 = Vector.ByTwoPoints(common, distinct1)
        vector2 = Vector.ByTwoPoints(common, distinct2)
        bisector = calculate_bisector(vector1, vector2)
        angle_between_curves = vector1.AngleWithVector(vector2)
        angle_rad = math.radians((180 - angle_between_curves) / 2)
        target_distance = radius / math.cos(angle_rad)
        target_point = common.Translate(bisector.Scale(target_distance))
        return common, distinct1, distinct2, target_point
    except Exception as e:
        raise Exception(f"Error in process_lines: {e}\n{traceback.format_exc()}")

# Function to create an arc from two lines and a radius
def create_arc_from_lines(line1, line2, radius, center):
    try:
        tangent1 = line1.PointAtParameter(line1.ParameterAtPoint(center))
        tangent2 = line2.PointAtParameter(line2.ParameterAtPoint(center))

        direction1 = Vector.ByTwoPoints(center, tangent1)
        direction2 = Vector.ByTwoPoints(center, tangent2)
        cross_product = direction1.Cross(direction2)

        if cross_product.Z < 0:  # Assuming Z-up orientation
            tangent1, tangent2 = tangent2, tangent1

        return Arc.ByCenterPointStartPointEndPoint(center, tangent1, tangent2)
    except Exception as e:
        raise Exception(f"Error in create_arc_from_lines: {e}\n{traceback.format_exc()}")

def get_model_curves():
    try:
        selection_ids = uidoc.Selection.GetElementIds()
        selection = []
        for id in selection_ids:
            element = doc.GetElement(id)
            selection.append(element)
        if selection:
            return selection
        else:
            return 'No elements selected'
    except Exception as e:
        return f"Error in get_model_curves: {e}\n{traceback.format_exc()}"

# Get the input model curves and radius
model_curves = get_model_curves()

if isinstance(model_curves, str):
    OUT = model_curves
else:
    try:
        curve1 = model_curves[0].GeometryCurve.ToProtoType()
        curve2 = model_curves[1].GeometryCurve.ToProtoType()
        
        # Get the line style of the first selected curve
        first_curve_element = model_curves[0]
        line_style = get_line_style(first_curve_element)

        form = InputForm()
        if form.ShowDialog() == System.Windows.Forms.DialogResult.OK:
            input_number = form.textBox.Text
        else:
            input_number = None

        if input_number:
            radius = float(input_number)
            common, distinct1, distinct2, arc_center = process_lines(curve1, curve2, radius)
            arc = create_arc_from_lines(curve1, curve2, radius, arc_center)

            TransactionManager.Instance.EnsureInTransaction(doc)
            model_curve = Revit.Elements.ModelCurve.ByCurve(arc)
            apply_line_style(model_curve, line_style)
            TransactionManager.Instance.TransactionTaskDone()

            OUT = model_curve
        else:
            OUT = "No input number provided"
    except Exception as e:
        OUT = f"Error during processing: {e}\n{traceback.format_exc()}"

# Output the result or the error message
OUT
1 Like

Hey,

Nice work… Perhaps this post helps?

Kind regards,

Mark

1 Like

Thanks, I got it workin with SetGeometryCurve

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

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

# Function to halve a model curve
def halve_model_curve(model_curve):
    try:
        # Convert the model curve to a Dynamo line
        dynamo_line = model_curve.GeometryCurve.ToProtoType()

        # Find the midpoint
        midpoint = dynamo_line.PointAtParameter(0.5)

        # Create a new line from start to midpoint
        new_line = Line.ByStartPointEndPoint(dynamo_line.StartPoint, midpoint)

        # Convert back to a Revit line
        revit_line = new_line.ToRevitType()

        return revit_line
    except Exception as e:
        return f"Error in halving model curve: {e}"

# Retrieve the input model curve
input_model_curve = UnwrapElement(IN[0])

TransactionManager.Instance.EnsureInTransaction(doc)

# Halve the model curve
halved_curve = halve_model_curve(input_model_curve)

# Update the model curve in Revit
input_model_curve.SetGeometryCurve(halved_curve, False)

TransactionManager.Instance.TransactionTaskDone()

# Output the modified curve
OUT = input_model_curve