Mastering The Line Madness (With Python)

Hello Team!

I am trying to create my “Magic” button for which there are many angles of attack.

In short, i am trying standardise the linestyles in my projects whilsts allowing my users to continue to import schematics and details with legacy and incorrect linestyles. And you know… magic button fix.

What i can do (In Python)
-Create linestyle patterns (dash dot etc…)
-Create linestyles (Name, weight, pattern) and name the lines appropriate to color, weight and pattern
-change linestyle colors
-change linestyle patterns
-Find duplicate linesstyles, transfer all the curves in the project from the wrong one to the new one and delete the old one

What i cant do
-Analyse existing line patterns to determine the spacing and lengths of their respectice dash dots and spaces etc… (to determine duplicates to my correct types and replace them)

Does anyone know how to correctly utilise the API to correctly get the linepattern segments and lengths, i have sruggled for a while on this.

As far as i get is this but ive struggled to use it correctly to get a result of any use.
http://disq.us/t/2j6bhda

Ideally, linepattern in… dash [space value], dot [space value], dash, [space value] etc etc… out. I can analyse thr strings after that.

Fingers Crossed

2 Likes

Any chance you can share the code for accessing the line styles, patterns, and the like? Think I can pull the pattern readily, but building the base to get to where you are will take a bit.

Yep, can do in the morning my time.

1 Like

This might not be directly workable in your context, but it will pull most of the information you want from every line style in the project, allowing for comparison of completed patterns using the pattern string value(s).

import clr #import the common language runtime (CLR) so we can access .net libraries in the Python environment
clr.AddReference("RevitNodes") #add the Revit nodes library to the CLR
import Revit #import the Revit library to the python environment
clr.ImportExtensions(Revit.Elements) #add the Revit.Elemetns extention to the Dynamo environment
clr.AddReference("RevitServices") #add the Revit Services library to the CLR
import RevitServices #import the Revit services namespace to the python environment
from RevitServices.Persistence import DocumentManager #import the document manager to the python environment
clr.AddReference("RevitAPI") #add the Revit API to the CLR
import Autodesk #importing the autodesk namepace to the python environment
from Autodesk.Revit.DB import * #importing all of the Revit DB namespace to the python environment so we can be sure we catch what we need in development

doc = DocumentManager.Instance.CurrentDBDocument #the current document
lineStyles = list(doc.Settings.Categories.get_Item(BuiltInCategory.OST_Lines).SubCategories) #line styles are a sub-category of the lines category, so we don't use a filtered element collector to gather them
results = [] #an empty list to hold the results

for lineStyle in lineStyles: #for every linestyle in the list of linestyles
    name = lineStyle.Name #get the name
    color = lineStyle.LineColor #get the line color
    red = color.Red #get the Red value
    green = color.Green #get the green value
    blue = color.Blue #get the blue value
    patternId = lineStyle.GetLinePatternId(GraphicsStyleType.Projection) #get the pattern id 
    pattern = doc.GetElement(patternId) #get the pattern element
    if pattern != None: #if the pattern element is valid, perform the offset items below
        linePattern = LinePatternElement.GetLinePattern(doc, patternId) #get the line pattern from the document using the pattern id
        segments = linePattern.GetSegments() #get the segments from the line pattern
        types = [s.Type for s in segments] #get the segment type from each segment
        segmentTypes = ["Dash","Space","Dot"] #convert the segment types into a more understandable string
        types = [segmentTypes[i] for i in types] #get the understandable string type for each segment
        lengths = [s.Length for s in segments] #get the length of each segment - you might want to round off here at some value
        segmentPatternString = "\r".join([types[i] + " - "+ str(lengths[i]) for i in range(len(types))]) #build a human readible string for the segment types
    else: #if the pattern was not valid, set the values to something human readible and informative
        segmentPattern = None #a null value for the segment pattern element
        segmentPatternString = "Solid" #a string of 'solid' for the segment pattern string
        segments = [] #a empty list for the segments list
    data = {"Line Style": lineStyle, "Line Style ide": lineStyle.Id, "Line Style Name": name, "Color": color, "Color Red Value": red, "Color Green Value": green, "Color Blue Value": blue, "Line Pattern Element": pattern, "Line Pattern Id": patternId, "Line Pattern String": segmentPatternString, "Line Segments": segments} #build the dictionary of line information
    results.append(data) #append the line information dictionary to the resutls list

OUT = results #return the results list to the Dynamo environment

Good luck!

4 Likes

Oooo this is spicey! Thank you!

image

2 Likes

Happy to help!

1 Like

An update here for anyone interested.
I used @jacob.small 's code to only pull the Line Pattern string into what i was working on.
and then following that i converted it to ironPython2 incase i needed to integrate it into anything in that engine.

the two versions are below, i leave for anyone in future as a return gesture for Jacob’s Help :slight_smile:

Code - IronPython2
import clr
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument
lineStyles = list(doc.Settings.Categories.get_Item(BuiltInCategory.OST_Lines).SubCategories)
results = []

for lineStyle in lineStyles:
    patternId = lineStyle.GetLinePatternId(GraphicsStyleType.Projection)
    pattern = doc.GetElement(patternId)

    if pattern is not None:
        linePattern = LinePatternElement.GetLinePattern(doc, patternId)
        segments = linePattern.GetSegments()
        types = [int(s.Type) for s in segments]  # Convert enumeration types to integers
        segmentTypes = ["Dash", "Space", "Dot"]
        types = [segmentTypes[i] for i in types]
        lengths = [s.Length for s in segments]
        segmentPatternString = "\r".join([types[i] + " - " + str(lengths[i]) for i in range(len(types))])
    else:
        segmentPatternString = "Solid"

    data = {"Pattern String": segmentPatternString}
    results.append(data)

OUT = results
Code - cPython3
import clr
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument
lineStyles = list(doc.Settings.Categories.get_Item(BuiltInCategory.OST_Lines).SubCategories)
results = []

for lineStyle in lineStyles:
    patternId = lineStyle.GetLinePatternId(GraphicsStyleType.Projection)
    pattern = doc.GetElement(patternId)

    if pattern is not None:
        linePattern = LinePatternElement.GetLinePattern(doc, patternId)
        segments = linePattern.GetSegments()
        types = [s.Type for s in segments]
        segmentTypes = ["Dash", "Space", "Dot"]
        types = [segmentTypes[i] for i in types]
        lengths = [s.Length for s in segments]
        segmentPatternString = "\r".join([types[i] + " - " + str(lengths[i]) for i in range(len(types))])
    else:
        segmentPatternString = "Solid"

    data = {"Pattern String": segmentPatternString}
    results.append(data)

OUT = results
3 Likes

@jacob.small and @pyXam

Shout out to say THANK-YOU!
This post saved my sanity today!
Spent hours trolling the forums and api docs unable to get this working properly

Your sample code here gave me the piece of the puzzle I was missing!
So happy right now, I just had to post and say thanks for your efforts and for sharing!

Legends!

3 Likes