18 avr. 2025

[Dynamo+=Python] Regroupement de Lignes parallèles




Quelques solutions pour regrouper efficacement des lignes parallèles dans Dynamo avec Python 


#DynamoBIM #Python #LINQ #RevitAPI  #PythonNet3 #IronPython #AutodeskExpertElite #AutodeskCommunity 

if this article is not in your language, use the Google Translate widget ⬈ (bottom of page for Mobile version )


Après un premier article sur le sujet, je vous propose ici deux autres approches complémentaires – plus performantes et plus élégantes – pour regrouper des lignes parallèles dans Dynamo.
L'une s'appuie sur une fonction récursive, l'autre exploite la puissance de LINQ via PythonNet3 ou IronPython.


  • Solution par fonction récursive et produit vectoriel

Je vous renvoie également quelques articles précédents concernant les opérations vectorielles.

https://voltadynabim.blogspot.com/2021/02/dynamo-python-operationvecteurs.html

https://voltadynabim.blogspot.com/2024/12/dynamo-python-la-similarite-cosinus.html

code (compatible avec tous les moteurs Python)


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


def group_parallal_lines(lines, n=0):
    """
    group parallal curves 
    """
    if len(lines) == 0 or n > 900:
        return []
    group = [lines.pop(0)]
    idx_group = []
    vectA = group[0].Direction.Normalized()
    for idx, line in enumerate(lines):
        vectB = line.Direction.Normalized()
        if abs(vectA.Cross(vectB).Length) < 0.01 :
            group.append(line)
            idx_group.append(idx)
    rest = [l for idx, l in enumerate(lines) if idx not in idx_group]
    
    return [group] + group_parallal_lines(rest, n+1)
    
ds_lines = IN[0]
final_group = []
t1 = time.time()
groups =  group_parallal_lines(ds_lines)
elapse_time = time.time() - t1

OUT =  f"{elapse_time=:.2f}s", groups






  • Solution avec LINQ et sérialisation de l'orientation des lignes
On utilise ici la méthode GroupBy (LINQ) avec comme clé une représentation bi-vectorielle représentant la direction des lignes (sérialisation de la direction/orientation).

Le code contient une portion pour la vérification visuelle du résultat (couleur par groupe).

code (compatible seulement avec IronPython3 et PythonNet3)


import sys
import clr
import System
from System import Array
from System.Collections.Generic import List, IList, Dictionary

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

clr.AddReference('System.Drawing')
import System.Drawing

clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)

clr.AddReference('GeometryColor')
from Modifiers import GeometryColor
clr.AddReference('DSCoreNodes') 
import DSCore
from DSCore import Color as DSColor

import time

def bi_direction_representation(line):
    v1 = line.Direction.Normalized()
    v2 = v1.Reverse()
    lst_vect = sorted([v1, v2], key = lambda v : (v.X, v.Y, v.Z))
    vect_repr = "|".join([f"Vect({v.X:.2f},{v.Y:.2f},{v.Z:.2f})" for v in lst_vect])
    return vect_repr.replace("-0.00", "0.00")
    
ds_lines = List[DS.Curve](IN[0])
check_lines_color = []
# colors for check result
color_values  = System.Enum.GetValues[System.Drawing.KnownColor]()
color_values = [c for idx, c in enumerate(color_values) if 0.45 < System.Drawing.Color.FromKnownColor(c).GetBrightness() < 0.65]
color_values.reverse()

t1 = time.time()
groups = ds_lines.GroupBy[DS.Curve, System.String](System.Func[DS.Curve, System.String](
                                    lambda c : bi_direction_representation(c)))\
                            .Select(System.Func[System.Object, System.Object](lambda x : x.ToList()))\
                            .ToList()
                                    
elapse_time = time.time() - t1
#
# check the results adding colors
for group_curves, color_value in zip(groups, color_values):
    color_to_apply = System.Drawing.Color.FromKnownColor(color_value) 
    ds_color = DSColor.ByARGB(color_to_apply.R, 
                            color_to_apply.G, 
                            color_to_apply.B, 
                            0)
    for line in group_curves:
        check_lines_color.append(GeometryColor.ByGeometryColor(line, ds_color))

OUT =  f"{elapse_time=:.2f}s", groups, check_lines_color




  • Résultats

Méthode Temps d'exécution Nombre d'éléments traités
Recursive Function 6.22 s 26 400 lignes
LINQ + bi-representation 0.98 s 26 400 lignes



« Les gens faibles se vengent. Les gens forts pardonnent. Les gens intelligents ignorent. »
Albert Einstein


0 commentaires:

Enregistrer un commentaire