Comment trouver la courbe moyenne entre deux courbes, qui ne sont pas forcément parallèles.
#DynamoBIM #Revit #Python #Geometry #AutodeskExpertElite #AutodeskCommunity
if this article is not in your language, use the Google Translate
widget ⬈ (bottom of page for Mobile version ⬇)
Trouver la courbe moyenne entre deux courbes qui ne sont pas
parallèles peut sembler complexe. Cependant, en utilisant Dynamo et
Scipy, nous pouvons accomplir cette tâche en plusieurs étapes :
- Étape 1 : Préparation des Courbes
Nous nous assurons que les courbes sont projetées sur un plan commun pour simplifier les calculs.
- Étape 2 : Calcul des Points Moyens
Nous utilisons
uniform_filter1d
du module Python Scipy pour lisser les points obtenus à partir des courbes initiales et créer une courbe moyenne approximative.Note:
Depuis Revit 2024 (Dynamo 2.18+), le package python Scipy est intégré
à Dynamo.
- Étape 3 : Création de la courbe moyenne finale
Ensuite, nous recherchons le long des perpendiculaires de points
équidistants sur les courbes en utilisant des lignes comme des
rayons d'intersection. La direction de ces lignes est calculée à
partir de la courbe précédemment obtenue avec Scipy.
Code
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import numpy as np
from scipy.interpolate import interp1d
from scipy.ndimage import uniform_filter1d
curveA, curveB = IN[0]
plane = Plane.ByOriginNormal(Point.ByCoordinates(0, 0 , 0), Vector.ByCoordinates(0,0,1))
# ensure curves are Z zero
curveA = curveA.PullOntoPlane(plane)
curveB = curveB.PullOntoPlane(plane)
ptCurveA = [curveA.PointAtParameter(n) for n in np.linspace(0, 1, num=500)]
ptCurveB = [curveB.PointAtParameter(n) for n in np.linspace(0, 1, num=500)]
# merge, flatten points and keeping order
pts = [pt for pairPts in zip(ptCurveA,ptCurveB) for pt in pairPts]
data = [[int(p.X), int(p.Y)] for p in pts]
x, y = [i for i in zip(*data)]
# compute the arithmetic average with scipy.ndimage.uniform_filter1d
y_smooth = uniform_filter1d(y,size=5, mode='wrap')
x_smooth = uniform_filter1d(x,size=5, mode='wrap')
rays = []
mid_Pts = []
ray_length = 6000 # example in millimeter
# compute an approximative average curve
pts_uniform = [Point.ByCoordinates(x, y , 0) for x, y in zip(x_smooth, y_smooth)]
pts_uniform_iter = iter(pts_uniform[:])
dsPoints = [Point.ByCoordinates((pta.X + ptb.X) / 2, (pta.Y + ptb.Y) / 2, 0) for pta, ptb in zip(pts_uniform_iter, pts_uniform_iter)]
# remove extra points
dsPoints = dsPoints[1:-1]
aprox_average_curve = PolyCurve.ByPoints(dsPoints, False)
# with this curve compute an new average curve by normal curve intersection (ray) and compute middle points
for n in np.linspace(0, 1, num=100):
normal = aprox_average_curve.NormalAtParameter(n)
pt = aprox_average_curve.PointAtParameter(n)
ray_line = Line.ByStartPointDirectionLength(pt, normal, ray_length)
ray_line = ray_line.Translate(normal.Reverse(), ray_length / 2)
if ray_line.DoesIntersect(curveA) and ray_line.DoesIntersect(curveB):
ptInterA = ray_line.Intersect(curveA)[0]
ptInterB = ray_line.Intersect(curveB)[0]
midpt = Point.ByCoordinates((ptInterA.X + ptInterB.X) / 2, (ptInterA.Y + ptInterB.Y) / 2, 0)
rays.append(ray_line)
mid_Pts.append(midpt)
OUT = rays, PolyCurve.ByPoints(mid_Pts, False)
Vidéo Démonstration
"Il n'y a pas de lignes droites ou d'angles aigus dans la nature.
Par conséquent, les bâtiments ne doivent pas en avoir non plus." -
Antoni Gaudí
0 commentaires:
Enregistrer un commentaire