Découverte de la librairie HelixToolKit avec Dynamo
#DynamoBIM #Revit #Python #HelixToolkit #WPF
#AutodeskExpertElite #AutodeskCommunity
if this article is not in your language, use the Google Translate
widget ⬈ (bottom of page for Mobile version ⬇)
- Introduction
- Il peut être utilisé comme une alternative à
DirectContext3D
(Revit API)
-
Dynamo l'utilise, ce qui la rend accessible dans le
System.AppDomain
courant
Les codes ci-après sont valables avec le moteur IronPython3 et
Dynamo 3.x.
Ils seront mis à jour ultérieurement avec le CPython3 quand PythonNet3 sera implémenté 🤞🤞🤞
Ils seront mis à jour ultérieurement avec le CPython3 quand PythonNet3 sera implémenté 🤞🤞🤞
- Exemple 1 : Visualisation d'une géométrie
Pour afficher une géométrie 3D, la classe
MeshGeometry3D
est utilisée.
Celle-ci est construite à partir d'une liste de triangles définie par des
positions et des indices.
À partir d'un solide en entrée, plusieurs méthodes de tesselation peuvent
être employées pour générer la géométrie.
-
-
Avec le framework .Net 4.x (Dynamo 2.x), il faut utiliser une version un peu différente.
Les classes HelixToolKits à utiliser sont differentes suivant si l'on est avec .Net Core ou avec .Net Framework 4.x
import clr
import sys
import System
clr.AddReference("System.Numerics")
clr.AddReference('HelixToolkit')
clr.AddReference('SharpDX.Mathematics')
clr.AddReference('HelixToolkit.Core.Wpf')
clr.AddReference('HelixToolkit.SharpDX.Core')
clr.AddReference('HelixToolkit.SharpDX.Core.Wpf')
from HelixToolkit import *
from HelixToolkit.Wpf.SharpDX import *
from HelixToolkit.SharpDX.Core import *
from SharpDX import *
import SharpDX
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
clr.AddReference("IronPython.Wpf")
clr.AddReference('System.Core')
clr.AddReference('System.Xml')
clr.AddReference('PresentationCore')
clr.AddReference('PresentationFramework')
clr.AddReferenceByPartialName("WindowsBase")
from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
try:
import wpf
import time
except ImportError:
wpf = None
class MeshViewer(Window):
LAYOUT = '''
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hx="http://helix-toolkit.org/wpf"
Title="..."
Height="700"
Width="600">
<Grid>
<Viewbox Grid.Row="0">
<hx:HelixViewport3D
Height="400"
Width="400"
VerticalAlignment="Bottom"
ZoomExtentsWhenLoaded="True"
CameraRotationMode="Trackball"
IsViewCubeEdgeClicksEnabled="True"
ZoomAroundMouseDownPoint="True"
Margin="5,35,5,2">
<hx:DefaultLights/>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D x:Name="model3D">
<GeometryModel3D.Geometry>
<MeshGeometry3D x:Name="meshMain">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="matDiffuseMain">
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Gray"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
<hx:GridLinesVisual3D Width="8" Length="8" MinorDistance="1" MajorDistance="1" Thickness="0.01"/>
</hx:HelixViewport3D >
</Viewbox>
</Grid>
</Window>
'''
def __init__(self, mesh):
self.ui = wpf.LoadComponent(self, StringReader(MeshViewer.LAYOUT))
self.mesh = mesh
self.Title = "3D Viewer"
indices = System.Windows.Media.Int32Collection([System.Int32(i) for i in mesh.VertexIndicesByTri()])
positions = System.Windows.Media.Media3D.Point3DCollection([System.Windows.Media.Media3D.Point3D(p.X, p.Y, p.Z) for p in mesh.Vertices()])
self.meshMain.TriangleIndices = indices
self.meshMain.Positions = positions
if wpf is not None:
input_mesh = IN[0]
mesh_viewer = MeshViewer(input_mesh)
mesh_viewer.Show()
-
--
- Exemple 2 : Visualisation de l'avancement d'un process 3D
Pour afficher des points, cette fois-ci, nous utilisons la classe
PointsVisual3D
.Cet exemple montre comment visualiser l'avancement d'un processus
3D en générant des points successifs. Chaque point est ajouté à
une scène 3D dans une fenêtre WPF via
HelixViewport3D
.
La classe
HelixPointVisu
encapsule la création et l'affichage des
points 3D Point3DCollection<PointsVisual3D>
avec des propriétés telles que la taille et la
couleur.
-
import clr
import sys
import System
from System.Threading import Thread, ThreadStart, ApartmentState
clr.AddReference('HelixToolkit')
clr.AddReference('SharpDX.Mathematics')
clr.AddReference('HelixToolkit.Core.Wpf')
clr.AddReference('HelixToolkit.SharpDX.Core')
clr.AddReference('HelixToolkit.SharpDX.Core.Wpf')
from HelixToolkit import *
from HelixToolkit.Wpf import *
from HelixToolkit.Wpf.SharpDX import *
from HelixToolkit.SharpDX.Core import *
from SharpDX import *
import SharpDX
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
clr.AddReference("IronPython.Wpf")
clr.AddReference('System.Core')
clr.AddReference('System.Xml')
clr.AddReference('PresentationCore')
clr.AddReference('PresentationFramework')
clr.AddReferenceByPartialName("WindowsBase")
from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
try:
import wpf
import time
except ImportError:
wpf = None
import itertools
import random
class CreateProgressWindow(Window):
LAYOUT = '''
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hx="http://helix-toolkit.org/wpf"
xmlns:hxs="http://helix-toolkit.org/wpf/SharpDX"
Title="..."
Height="700"
Width="600">
<Grid>
<ProgressBar
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="5,30,5,0"
Width="400"
Height="30"
x:Name="pbar" />
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,35,0,0">
<TextBlock.Text>
<MultiBinding StringFormat="{}Process:{0}/{1}">
<Binding Path="Value" ElementName="pbar" />
<Binding Path="Maximum" ElementName="pbar" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<Viewbox Grid.Row="0">
<hx:HelixViewport3D
x:Name="HViewPort"
Height="400"
Width="400"
VerticalAlignment="Bottom"
ZoomExtentsWhenLoaded="True"
CameraRotationMode="Trackball"
IsViewCubeEdgeClicksEnabled="True"
ZoomAroundMouseDownPoint="True"
Margin="5,35,5,2">
<!-- <hx:PointsVisual3D Color="Black" Size="2"/> Points="{Binding dataList}"/>-->
</hx:HelixViewport3D>
</Viewbox>
</Grid>
</Window>
'''
def __init__(self, max, title = ""):
self.ui = wpf.LoadComponent(self, StringReader(CreateProgressWindow.LAYOUT))
self.pbar.Maximum = max
self.Title = title
self.new_value = 0
self.lst = []
def _dispatch_updater(self):
# ask WPF dispatcher for gui update
self.pbar.Dispatcher.Invoke(System.Action(self._update_pbar),
System.Windows.Threading.DispatcherPriority.Background)
def _update_pbar(self):
self.pbar.Value = self.new_value
if self.pbar.Value == self.pbar.Maximum:
self.Close()
def update_progress(self, lst_new_geopts):
self.new_value += 1
curent_idx = len(self.lst) - 1
for objpt in lst_new_geopts:
curent_idx += 1
self.lst.append(objpt)
self.HViewPort.Children.Add(objpt.visuPoint);
self._dispatch_updater()
class HelixPointVisu():
"""
Class for visualizing a point in a 3D space using HelixToolkit.
Args:
x (float): X coordinate of the point.
y (float): Y coordinate of the point.
z (float): Z coordinate of the point.
"""
def __init__(self, x, y, z):
pt = System.Windows.Media.Media3D.Point3D(x, y, z)
if z > 20:
color = System.Windows.Media.Colors.Red
else:
color = System.Windows.Media.Colors.Blue
self.visuPoint = PointsVisual3D()
self.visuPoint.Size = 3
self.visuPoint.Points = System.Windows.Media.Media3D.Point3DCollection([pt])
self.visuPoint.Color = color
def decoThread(func):
"""
Decorator to run a function in a separate thread if the current application is DynamoSandbox.
If not, runs the function normally.
Args:
func: Function to be wrapped.
Returns:
None
"""
def wrapper():
currentAppName = System.AppDomain.CurrentDomain.FriendlyName
if currentAppName == "DynamoSandbox":
thread = Thread(ThreadStart(func))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()
else:
func()
return None
return wrapper
@decoThread
def appThread():
"""
Main function to run the application thread.
Creates points and visualizes them using HelixToolkit.
"""
lst_uv = list(range(800))
pbar = CreateProgressWindow(len(lst_uv), "Points Processing (Qte : {})".format(len(lst_uv)))
pbar.Show()
for idx, i in enumerate(lst_uv):
time.sleep(0.01)
if pbar is not None:
x, y, z = random.randint(-10,30), random.randint(-10,20), random.randint(-10,40)
objpt = HelixPointVisu(x, y, z)
lst_new_geopts = [objpt]
pbar.update_progress(lst_new_geopts)
appThread()
Note Dynamo 2.x:
-
Voici un exemple de visualisation dans Dynamo de l'avancement d'un
"scan 3D" (via ReferenceIntersector + la bibliothèque helixtoolkit
wpf ) dans le but d'obtenir l'enveloppe d'un bâtiment (ici une
maquette liée).
- Ressources
0 commentaires:
Enregistrer un commentaire