Cyrillic Lookup, Moving Grids and Combining Edges

Let's start this week with the following topics from freecodecamp and the Revit API discussion forum:

SVG, Internet Privacy and Research on Pointless Meetings

Here are a couple of recent articles I found interesting, pointed out in the freecodecamp newsletter:

"To err is human. But to really foul things up, you need a computer." – Paul Ehrlich

Back to the Revit API and some useful solutions discussed in the Revit API discussion forum:

Cyrillic Characters in Lookup Tables

There seem to be some issues handling Cyrillic characters in lookup tables, as pointed out in the thread on Russian letters doesn't export in lookup tables. Happily, however, at least a partial solution can be found:

... it works. Now, when he switches to the Russian keyboard, he can insert a CSV to a family with Cyrillic text with no loss.

Moving a Grid

Matt Taylor very kindly pointed out the solution to another old thread on moving a grid:

I would guess that the grid cannot be moved because it doesn't have a leader. Use the AddLeader method to add a leader first. You'll also probably need to do a document.Regenerate afterwards, before you set the leader points.

I found the old blog post that contains the code. Seeing the code, I can confirm that my guess was correct.

Combining Edges

To wrap it up, Lucas Moreira shared a more complex solution to combine connected edge segments into one continuous line:

Question: I am fetching the edge loops of a face.

When I do so, depending on the original geometry that created the solids, these loop segments can be composed of 2 or more subsegments to form an edge, cf., the orange and red semi-segments below:

Two semi segments forming an edge

Two semi segments forming an edge

How can I identify and retrieve a continuous line for each edge?

Is there a way I can do that recursively regardless of the number of segments forming the edge?

I am coding for Revit 2019 and retrieving the segments using the Face.EdgeLoops property.

Answer: Two steps:

Here are hints from StackOverflow for the first:

The Building Coder provides some older thoughts on sorting and orienting curves to form a contiguous loop:

One method that does part of the work that you should definitely be aware of is the Edge.AsCurveFollowingFace method that returns a curve corresponding to the edge oriented in its topological direction on the specified face. That is the simplest option and a good place to start.

Response: That helped me a lot and I am really close to a solution.

My scenario is slightly different as I am only using horizontally aligned edges of the exterior face of the geometry. I think it actually makes it easier, because I don't have to sort the edges, but sort only the segments that would compose one straight edge.

I used the Python node on Dynamo to prototype what I need – the visual 3d space there helps me with debugging.

What I am doing is getting a list with all the Edges.AsCurveLoops, separating the horizontally aligned ones. The algorithm evaluates that list and groups the curves to be joined into sublists, because I was already making sure that all the curves are oriented in the same direction. I just need to pair the curve start points with their matching endpoints and use the unmatched points to form my 'new' undivided edge curve. I will use the logic in sorting vertices of a polygon in CCW or CW direction for that.

I know that this code can be optimized, but I will post it here for the sake of completion. It might help someone:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
import Autodesk
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
#from Revit import GeometryConversion as gp

import math

curves = IN[0]
#The next 2 methods will assume that the directions is known.
#The start point of a curve
def startPoint(curve):
    return curve.GetEndPoint(0)

#The end point of a curve
def endPoint(curve):
    return curve.GetEndPoint(1)
#Groups lines to be joined in sublists with the curves that have to be joined    
def joinCurves(list):
  comp=[]
  re=[]
  unjoined = []
  for c in curves:
    c = c.ToRevitType()
    match = False
    for co in comp:
      if startPoint(c).IsAlmostEqualTo(startPoint(co)) and endPoint(c).IsAlmostEqualTo(endPoint(co)):
        match = True
    if match:
      continue
    else:
      comp.append(c)      
      joined = []
      for c2 in curves:

        match = False
        c2 = c2.ToRevitType()
        for co in comp:
          if startPoint(c2).IsAlmostEqualTo(startPoint(co)) and endPoint(c2).IsAlmostEqualTo(endPoint(co)):
            match = True
        if match:
          continue
        else:
          if c2.Intersect(c) == SetComparisonResult.Disjoint:
            continue
          elif c2.Intersect(c) ==  SetComparisonResult.Equal:
            continue
          elif c2.Intersect(c) == SetComparisonResult.Subset:
            comp.append(c2)
            joined.append(c2.ToProtoType())
    joined.append(c.ToProtoType())
    re.append(joined)

  return re

result = joinCurves(curves)
OUT = result

Many thanks to Lucas for raising and solving this interesting task.