Dès lors que l'on analyse des géométries en programmation, les opérations de vecteurs deviennent vite incontournable, parmi elles le produit vectoriel et le produit scalaire.
Voici quelques particularités de ces 2 opérations avec des vecteurs unitaires
Note: vecteur unitaire = vecteur à longueur 1, appeler aussi vecteur Normalisé
- Produit scalaire de 2 vecteurs normalisés :
Soit le scalaire n résultant de l'opération sur un plan XY, suivant les résultats on peut en déduire que :
si n égale à -1 → les 2 vecteurs sont alignés dans le sens opposé (angle 180°)
si n égale à 1 → les 2 vecteurs sont alignés dans le même sens (angle 0°)
si n égale à 0 → les 2 vecteurs sont perpendiculaires (angle 90°)
Note:
v1 et v2 étant normaux le résultat varie entre -1 et 1:
- Produit vectoriel de 2 vecteurs (normalisés ou non) :
Soit le vecteur résultant de l'opération sur un plan XY, suivant les résultats de la base directe, on peut en déduire que :
si la composante Z du vecteur> 0 → l'angle formé entre u et vers v est positif
si la composante Z du vecteur< 0 → l'angle formé entre u et vers v est négatif
si la longueur du vecteur= 0 → u et v sont parallèles (colinéaires)
Quelques exemples d'applications
-
Avec le produit scalaire (dot Product) :
-
obtenir la distance entre 2 faces parallèles
-
obtenir la distance entre 2 faces parallèles
def compute_distance_planarfaces(faceA, faceB):
bbxUVa = faceA.GetBoundingBox()
pta = faceA.Evaluate((bbxUVa.Min + bbxUVa.Max) / 2.0)
normalA = faceA.FaceNormal #or faceA.ComputeNormal((bbxUVa.Min + bbxUVa.Max) / 2.0)
#
bbxUVb = faceB.GetBoundingBox()
ptb = faceB.Evaluate((bbxUVb.Min + bbxUVb.Max) / 2.0)
if pta.DistanceTo(ptb) < 0.001:
return 0.0
vector_between_faces = ptb - pta
# Project this vector onto the normal to get the distance
distance = vector_between_faces.DotProduct(normalA.Normalize())
return abs(distance)
- vérifier si 2 vecteurs sont perpendiculaires
def isPerpendicular(v1, v2):
#with Revit API
return v1.DotProduct(v2) == 0
- Ordonner une liste de points suivant un vecteur
La similarité cosinus donne la similarité de deux vecteurs à n dimensions en déterminant le cosinus de leur angle.
def cosine_similarity(point, vector):
dot_prod = point.DotProduct(vector)
mag_point = point.GetLength()
mag_vector = vector.GetLength()
# avoid division by zero if the magnitude is zero
if mag_point == 0 or mag_vector == 0:
return 0
return dot_prod / (mag_point * mag_vector)
import random
import numpy as np
# generate 2D array of shape (30, 2) with random integers
random_2D = np.random.randint(0, 30, (30,2))
lst_points = [XYZ(x, y, 0) for x, y in random_2D]
#
vector_direction = XYZ(2, 5, 0)
sorted_points = sorted(lst_points, key=lambda p: cosine_similarity(p, vector_direction))
- trouver l'orientation d'une face par rapport aux points cardinaux
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
def getOrientation(vecTrueNorth, vecTrueEast, solidFace):
#with Revit API
faceNorm = solidFace.FaceNormal
dotP_N = faceNorm.DotProduct(vecTrueNorth)
dotP_E = faceNorm.DotProduct(vecTrueEast)
#0.7 = Pi / 4 or (45°)
if dotP_N > 0.7 and abs(dotP_E) <= 0.7:
return "North"
elif dotP_N < -0.7 and abs(dotP_E) <= 0.7:
return "South"
elif dotP_E > 0.7 and abs(dotP_N) <= 0.7:
return "East"
elif dotP_E < -0.7 and abs(dotP_N) <= 0.7:
return "West"
else:
return None
room = UnwrapElement(IN[0])
currentLocation = doc.ActiveProjectLocation
origin = XYZ(0, 0, 0)
projectPosition = currentLocation.GetProjectPosition(origin)
angleToNorth = projectPosition.Angle
vecNorth = XYZ.BasisY
vecEast = XYZ.BasisX
rotTransf = Transform.CreateRotation(XYZ.BasisZ, - angleToNorth)
vecTrueNorth = rotTransf.OfVector(vecNorth)
vecTrueEast = rotTransf.OfVector(vecEast)
calculator = SpatialElementGeometryCalculator(doc)
resultOrient = list()
if calculator.CanCalculateGeometry(room):
results = calculator.CalculateSpatialElementGeometry(room)
roomSolid = results.GetGeometry()
roomMaterial = list()
for face in roomSolid.Faces:
for subface in results.GetBoundaryFaceInfo(face):
if subface.SubfaceType == SubfaceType.Side:
boundingElement = subface.GetBoundingElementFace()
lnkelemId = subface.SpatialBoundaryElement
materialId = boundingElement.MaterialElementId
elem = doc.GetElement(lnkelemId.HostElementId )
surfaceDs = face.ToProtoType()
nameOrient = getOrientation(vecTrueNorth, vecTrueEast, face)
resultOrient.append([surfaceDs[0], elem, nameOrient])
OUT = resultOrient
-
Avec le produit vectoriel (cross product)
- vérifier si 2 vecteurs sont parallèles
def isParallel(v1, v2):
return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))
- vérifier si un arc est dans le sens horaire
def isClockwise(arc):
#with Dynamo API
pStart = arc.StartPoint
pCenter = arc.CenterPoint
pEnd = arc.EndPoint
vecta = Vector.ByTwoPoints(pCenter, pStart)
vectb = Vector.ByTwoPoints(pCenter, pEnd)
cp = vecta.Cross(vectb)
return cp.Z < 0
- ou encore pour vérifier si un point est situé dans un polygone
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
polygon = IN[0]
pointCheck = IN[1]
def isInsidePolyg(polygon, pointCheck):
#with Dynamo API
lstangle =[]
pointPolyg = polygon.Points
for idx, pt in enumerate(pointPolyg):
if idx > 0:
vecta = Vector.ByTwoPoints(pointCheck, pointPolyg[idx -1])
vectb = Vector.ByTwoPoints(pointCheck, pt)
cross = vecta.Cross(vectb).Normalized()
angle = vecta.AngleWithVector(vectb)
vecta.Dispose()
vectb.Dispose()
cross.Dispose()
lstangle.append(angle * cross.Z)
return abs(sum(lstangle)) > 180
OUT = isInsidePolyg(polygon, pointCheck)
0 commentaires:
Enregistrer un commentaire