TextNote with horizontal leader

Hi,

Can somebody explain why the potato comes wrong and how to fix it? :sweat_smile:

import clr

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

def u(e):
	return UnwrapElement(e)

def toNormal(p):
	return XYZ(p.X/304.8, p.Y/304.8, p.Z/304.8)

def type(name):
	fil = FilteredElementCollector(doc).OfClass(TextNoteType).WhereElementIsElementType().ToElements()
	o = []
	for i in fil:
		n = i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
		if n == name:
			o.append(i)
	return o[0].Id
	
doc = DocumentManager.Instance.CurrentDBDocument

text = u(IN[0])
type = type(u(IN[1]))
vector = toNormal(u(IN[3]))
offset = IN[4]/304.8

pt1 = toNormal(u(IN[2]))
pt2 = XYZ(pt1.X+vector.X,pt1.Y+vector.Y,0)
pt3 = XYZ(pt2.X+offset,pt2.Y,0)

TransactionManager.Instance.EnsureInTransaction(doc)

textNote = TextNote.Create(doc, doc.ActiveView.Id, pt3, text, type)

leader = textNote.AddLeader(TextNoteLeaderTypes.TNLT_STRAIGHT_R)
leader.End = pt1
leader.Elbow = pt2

TransactionManager.Instance.TransactionTaskDone()

OUT = pt1, pt2, pt3

Comes wrong?

Yeah, I need that elbow part, or whatever does it called, to be horizontal. I seems to be doing something wrong with adding offset to a vector.

Update:
It seems that script working correctly, it just the insertion point of the TextNote is at the top of it. So to get a horizontal elbow I need to add offset in the Y direction that equals to half of the height of the TextNote box. Now how can I get the size of it? :sweat_smile:

Maybe this helps?

def type(name):
	fil = FilteredElementCollector(doc).OfClass(TextNoteType).WhereElementIsElementType().ToElements()
	o = []
	for i in fil:
		n = i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
		if n == name:
			o.append(i)
	return o[0].Id, o[0]

 
	
doc = DocumentManager.Instance.CurrentDBDocument

text = u(IN[0])
typeIn = type(u(IN[1]))[0]
typeHeight = type(u(IN[1]))[1].GetParameters('Text Size')[0].AsDouble()*304.8
1 Like

Thanks that helps, but it gives me only the value of the text size… nontheless it is useful!
With a bit experimenting I’ve determine that for ever mm of text size Revit multiplies it with 1.85 and the scale value. The rest of the bounding box is extra space that equals to 3.345 times scale. So the bounding box is 1.85 * text height * scale + 3.345 * scale. I’m though not getting te desired displacement at Y axis.

import clr

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

def u(e):
	return UnwrapElement(e)

def toNormal(p):
	return XYZ(p.X/304.8, p.Y/304.8, p.Z/304.8)

def type(name):
	fil = FilteredElementCollector(doc).OfClass(TextNoteType).WhereElementIsElementType().ToElements()
	o = []
	for i in fil:
		n = i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
		if n == name:
			o.append(i)
	return o[0].Id, o[0]
	
doc = DocumentManager.Instance.CurrentDBDocument

text = u(IN[0])
typeIn = type(u(IN[1]))[0]
typeHeight = type(u(IN[1]))[1].GetParameters('Text Size')[0].AsDouble()*304.8
scale = doc.ActiveView.Scale
vector = toNormal(u(IN[3]))
offsetX = IN[4]/304.8
tH = 1.85
eX = 3.345
offsetY = ((typeHeight*tH*scale)+(eX*scale))/2
offy = offsetY/304.8
#offy = 0

pt1 = toNormal(u(IN[2]))
pt2 = XYZ(pt1.X+vector.X,pt1.Y+vector.Y,0)
pt3 = XYZ(pt2.X+offsetX,pt2.Y+offy,0)

TransactionManager.Instance.EnsureInTransaction(doc)

textNote = TextNote.Create(doc, doc.ActiveView.Id, pt3, text, typeIn)

leader = textNote.AddLeader(TextNoteLeaderTypes.TNLT_STRAIGHT_R)
leader.End = pt1
leader.Elbow = pt2

TransactionManager.Instance.TransactionTaskDone()

OUT = pt2.Y*304.8, pt3.Y*304.8
1 Like

Hey, so I get something a bit odd…

Very basic maths, shift the point down by half the height of the font…

It is wonky, but if i shift my view scales around, it goes flat and stays there!

pt4 = XYZ(pt3.X-10, (pt3.Y-typeHeight/2), 0)

TransactionManager.Instance.EnsureInTransaction(doc)

textNote = TextNote.Create(doc, doc.ActiveView.Id, pt3, text, typeIn)

leader = textNote.AddLeader(TextNoteLeaderTypes.TNLT_STRAIGHT_R)
leader.End = pt1
leader.Elbow = pt4

Hmmm…!

It’s making it with the wrong placing and when you change the scale Revit changes the points positions in the way that the elbow levels out. It’s not what I’m after… The goal is to place like a thousand of notes on hundreds views at once.

Different workaround… I’ll let you re-write for lists.

import clr

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

def u(e):
	return UnwrapElement(e)

def toNormal(p):
	return XYZ(p.X/304.8, p.Y/304.8, p.Z/304.8)

def type(name):
	fil = FilteredElementCollector(doc).OfClass(TextNoteType).WhereElementIsElementType().ToElements()
	o = []
	for i in fil:
		n = i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
		if n == name:
			o.append(i)
	return o[0].Id, o[0]
	
doc = DocumentManager.Instance.CurrentDBDocument

text = u(IN[0])
typeIn = type(u(IN[1]))[0]
typeHeight = type(u(IN[1]))[1].GetParameters('Text Size')[0].AsDouble()*304.8
scale = doc.ActiveView.Scale
vector = toNormal(u(IN[3]))
offsetX = IN[4]/304.8
tH = 1.85
eX = 3.345
offsetY = ((typeHeight*tH*scale)+(eX*scale))/2
offy = offsetY/304.8
#offy = 0

pt1 = toNormal(u(IN[2]))
pt2 = XYZ(pt1.X+vector.X,pt1.Y+vector.Y,0)
pt3 = XYZ(pt2.X+offsetX,pt2.Y+offy,0)

TransactionManager.Instance.EnsureInTransaction(doc)

textNote = TextNote.Create(doc, doc.ActiveView.Id, pt3, text, typeIn)

leader = textNote.AddLeader(TextNoteLeaderTypes.TNLT_STRAIGHT_R)
leader.Elbow = XYZ(pt2.X, leader.Elbow.Y, pt2.Z )
leader.End = pt1

TransactionManager.Instance.TransactionTaskDone()

OUT = pt2.Y*304.8, pt3.Y*304.8
2 Likes

It’s alive! :smiley:

I’m not good with python, so for anyone if you need for the script to work in other view than active or with leader at different position or arc; feel free to modify the script to your needs. And maybe share. Because sharing is caring. :+1:

Ok, unfortunately I’ve run out of time, but here’s a version working with lists, I’ve kept everything simple so you can see the principle… you’ll need to feed a list of views, a list of lists of text & points… then run a For loop to go over the ‘zip’ in here… Have a go and post back :slight_smile:

import clr

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

def u(e):
	return UnwrapElement(e)

def toNormal(p):
    return XYZ(p.X/304.8, p.Y/304.8, p.Z/304.8)

def type(name):
	fil = FilteredElementCollector(doc).OfClass(TextNoteType).WhereElementIsElementType().ToElements()
	o = []
	for i in fil:
		n = i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
		if n == name:
			o.append(i)
	return o[0].Id
	
doc = DocumentManager.Instance.CurrentDBDocument

text = u(IN[0])
typeIn = type(u(IN[1]))
pointsIn = u(IN[2])
vector = toNormal(u(IN[3]))
offsetX = IN[4]/304.8

#pt1 = [toNormal(point1) for point1 in pointsIn]
pt1 = []
for point1 in pointsIn:
    pt1.append(toNormal(point1))

pt2 = []
for point1 in pt1:
    pt2.append(XYZ(point1.X+vector.X,point1.Y+vector.Y,0))

pt3 = []
for point2 in pt2:
    pt3.append(XYZ(point2.X+offsetX,point2.Y,0))

TransactionManager.Instance.EnsureInTransaction(doc)

output = []
for point3, point2, point1, t in zip(pt3, pt2, pt1, text):
    textNote = TextNote.Create(doc, doc.ActiveView.Id, point3, t, typeIn)

    leader = textNote.AddLeader(TextNoteLeaderTypes.TNLT_STRAIGHT_R)
    leader.Elbow = XYZ(point2.X, leader.Elbow.Y, point2.Z )
    leader.End = point1
    output.append(textNote)

TransactionManager.Instance.TransactionTaskDone()

OUT = output
2 Likes

Thanks for the list management!

If I understand correctly this part loops on it self, right? Because what is exactly the value of Y? I’m not getting it… :sweat_smile:

That is the default value of the leader, thanks to Jeremy Tammik :slight_smile:

So no looping required, Woop!

Ah soooo… sneaky