Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Converting a script from pyrevit to dynamo using wpf

0 REPLIES 0
Reply
Message 1 of 1
REDO10
90 Views, 0 Replies

Converting a script from pyrevit to dynamo using wpf

Hi All, @jeremytammik 

 

I've written a Python script using PyRevit that creates grids with a WPF interface, and it works perfectly. Now, I want to convert it to Dynamo while maintaining the WPF interface. However, I'm struggling to implement the _collect_input_data function, where I'm stuck handling events and exceptions from the UI to ensure the inputs are correct and collecting them in self.data.

 

Here my original code:

 

# -*- coding: UTF-8 -*-
from pyrevit import forms, revit
import wpf, clr

clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")

from System.IO import StringReader
from System.Windows.Markup import XamlReader
from System.Windows import Window
from Autodesk.Revit.DB import *
from string import ascii_uppercase


uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
app = __revit__.Application


class Grids(Window):
    LAYOUT = '''
        <Window 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Grids"
            Height="Auto"
            Width="300"
            SizeToContent ="Height" 
            ResizeMode="NoResize"
            WindowStartupLocation="CenterScreen">
            <StackPanel Margin="10">
                <!--Input LX-->
                <StackPanel Margin="0,0,0,10">
                    <TextBlock Text ="Longueur Total suivant X (m):" Width="170" Height="25" HorizontalAlignment="Left" FontSize="12" FontWeight="Bold" />
                    <DockPanel Width="200" HorizontalAlignment="Left" >
                        <TextBlock Text ="   Lx =" Width="50" Height="25" Margin="0,0,5,0" />
                        <TextBox x:Name="input_Lx" Width="75" Margin="0,0,5,0" />
                        <TextBlock Text="m" Width="25" HorizontalAlignment="Left" />
                    </DockPanel>
                </StackPanel>
                
                <!--Input LY-->
                <StackPanel Margin="0,0,0,10">
                    <TextBlock Text ="Longueur Total suivant Y (m):" Width="170" Height="25" HorizontalAlignment="Left" FontSize="12" FontWeight="Bold" />
                    <DockPanel Width="200" HorizontalAlignment="Left" >
                        <TextBlock Text ="   Ly =" Width="50" Height="25" Margin="0,0,5,0" />
                        <TextBox x:Name="input_Ly" Width="75" Margin="0,0,5,0" />
                        <TextBlock Text="m" Width="25" HorizontalAlignment="Left" />
                    </DockPanel>
                </StackPanel>
                
                <!--Grid Extension -->
                <StackPanel Margin="0,0,0,10">
                    <TextBlock Text ="Extension des Axes X, Y (m):" Width="170" Height="25" HorizontalAlignment="Left" FontSize="12" FontWeight="Bold" />
                    <DockPanel Width="200" HorizontalAlignment="Left" >
                        <TextBlock Text ="   e =" Width="50" Height="25" Margin="0,0,5,0" />
                        <TextBox x:Name="input_extension" Width="75" Margin="0,0,5,0" />
                        <TextBlock Text="m" Width="25" HorizontalAlignment="Left" />
                    </DockPanel>
                </StackPanel>
                
                <!--Spacing along X axis -->
                <StackPanel Margin="0,0,0,10">
                    <TextBlock Text ="Espacement suivant X (m):" Width="170" Height="25" HorizontalAlignment="Left" FontSize="12" FontWeight="Bold" />
                    <DockPanel Width="200" HorizontalAlignment="Left" >
                        <TextBlock Text ="   dx =" Width="50" Height="25" Margin="0,0,5,0" />
                        <TextBox x:Name="input_dx" Width="75" Margin="0,0,5,0" />
                        <TextBlock Text="m" Width="25" HorizontalAlignment="Left" />
                    </DockPanel>
                </StackPanel>
                
                <!--Spacing along Y axis -->
                <StackPanel Margin="0,0,0,10">
                    <TextBlock Text ="Espacement suivant Y (m):" Width="170" Height="25" HorizontalAlignment="Left" FontSize="12" FontWeight="Bold" />
                    <DockPanel Width="200" HorizontalAlignment="Left" >
                        <TextBlock Text ="   dy =" Width="50" Height="25" Margin="0,0,5,0" />
                        <TextBox x:Name="input_dy" Width="75" Margin="0,0,5,0" />
                        <TextBlock Text="m" Width="25" HorizontalAlignment="Left" />
                    </DockPanel>
                </StackPanel>
                
                <!--bubbles symbol -->
                <StackPanel>
                    <TextBlock Text="Choix de symbols pour Lx, Ly:" FontWeight="Bold" Margin="0,0,0,10" />
                    
                    <!-- Symbol Type for Y Axis -->
                    <DockPanel Margin="0,0,0,10" >
                        <TextBlock Text="Type de symbole Sx:" />
                        <ComboBox x:Name="Symbol_x" HorizontalAlignment="Right" SelectionChanged="Symbol_x_SelectionChanged" Width="110">
                            <ComboBoxItem Content="1 2 3 ..." />
                            <ComboBoxItem Content="A B C ..." />
                        </ComboBox>
                    </DockPanel>
                    
                    <!-- Symbol Type for Y Axis -->
                    <DockPanel Margin="0,0,0,10">
                        <TextBlock Text="Type de symbole Sy:" />
                        <TextBox x:Name="Symbol_y" Width="110" HorizontalAlignment="Right"/>
                    </DockPanel>
                </StackPanel>
                
                <!--Separator, OK and Cancel Button-->
                <Separator Margin="0,0,0,10"/>
                <DockPanel HorizontalAlignment="Center">
                    <Button Content="OK" Width="75" Height="25" Margin="0,0,10,0" Click="OK_Clicked" />
                    <Button Content="Cancel" Width="75" Height="25" Click="Cancel_Clicked" />
                </DockPanel>            
            </StackPanel>
        </Window>'''

    def __init__(self):
        wpf.LoadComponent(self, StringReader(Grids.LAYOUT))
        self.data = {}
        self.ShowDialog()

    def Symbol_x_SelectionChanged(self, sender, e):
        selected_item = self.Symbol_x.SelectedItem
        if selected_item.Content == "1 2 3 ...":
            self.Symbol_y.Text = self.Symbol_x.Items[1].Content.ToString()
        else:
            self.Symbol_y.Text = self.Symbol_x.Items[0].Content.ToString()

    def _collect_input_data(self):
        """Collect and convert input data from the UI"""
        # Identify which key has missing or invalid input and alert the user
        if not self.input_Lx.Text:
            forms.alert("Please enter a valid value for : Lx")
        elif not self.input_Ly.Text:
            forms.alert("Please enter a valid value for : Ly")
        elif not self.input_extension.Text:
            forms.alert("Please enter a valid value for : e")
        elif not self.input_dx.Text:
            forms.alert("Please enter a valid value for : dx")
        elif not self.input_dy.Text:
            forms.alert("Please enter a valid value for : dy")
        else:
            try:
                self.data = {
                    "Lx": _input_to_meters(self.input_Lx.Text),
                    "Ly": _input_to_meters(self.input_Ly.Text),
                    "e": _input_to_meters(self.input_extension.Text),
                    "dx": _input_to_meters(self.input_dx.Text),
                    "dy": _input_to_meters(self.input_dy.Text),
                }
            except (ValueError, AttributeError):
                forms.alert("Invalid input or missing selections. Please correct and try again.")

    def symbols_alpha(self, length_x, length_y):
        """Generate Sx and Sy symbols based on lengths of grids"""
        Sx = []
        Sy = []
        if self.Symbol_x.SelectedItem == self.Symbol_x.Items[0]:
            for i in range(length_y):
                if i < len(ascii_uppercase):
                    Sy.append(ascii_uppercase[i])
            Sx = []
        else:
            for i in range(length_x):
                if i < len(ascii_uppercase):
                    Sx.append(ascii_uppercase[i])
            Sy = []
        return Sx, Sy

    def OK_Clicked(self, sender, e):
        self._collect_input_data()
        if not self.data:
            return
        n1 = int(self.data["Lx"] // self.data["dx"])
        if not isclose(self.data["Lx"], n1 * self.data["dx"]):
            length_x = n1 + 2
        else:
            length_x = n1 + 1
        print(length_x)
        n2 = int(self.data["Ly"] // self.data["dy"])
        if not isclose(self.data["Ly"], n2 * self.data["dy"]):
            length_y = n2 + 2
        else:
            length_y = n2 + 1

        # Populate Sx and Sy dynamically based on grid lengths
        self.data["Sx"], self.data["Sy"] = self.symbols_alpha(length_x, length_y)
        print(self.data["Sx"])
        print(self.data["Sy"])
        self.Close()

    def Cancel_Clicked(self, sender, e):
        self.data = {}
        self.Close()


def _input_to_meters(value):
    """Convert a textual value to meters."""
    return UnitUtils.ConvertToInternalUnits(float(value), UnitTypeId.Meters)

def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
    return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)


def create_lines(lx, ly, d, e, y_axis=False):
    """Create lines along X, Y axis """
    if y_axis:
        lx, ly = ly, lx
    n = lx // d
    points_X = []
    i = 0
    while i <= int(n):
        points_X.append(d * i - lx / 2)
        i += 1
    if not isclose(lx, n * d):
        points_X.append(lx / 2)
    points_Y = [-ly / 2 - e, ly / 2 + e]

    if y_axis:
        return [Line.CreateBound(*(XYZ(x, y, 0) for x in points_Y)) for y in points_X]

    return [Line.CreateBound(*(XYZ(x, y, 0) for y in points_Y)) for x in points_X]



def create_grids(lines_x, lines_y, Sx, Sy, doc):
    with Transaction(doc, "Create Grids") as t:
        t.Start()
        grids_X = [Grid.Create(doc, line) for line in lines_x]
        print(len(grids_X))
        grids_Y = [Grid.Create(doc, line) for line in lines_y]
        print(len(grids_Y))
        if Sx:  # If Sx is populated, assign names to grids_X
            print(len(Sx))
            for grid, symbol in zip(grids_X, Sx):
                grid.Name = symbol
            for idx, grid in enumerate(grids_Y):
                grid.Name = str(idx+1)
        if Sy:  # If Sy is populated, assign names to grids_Y
            print(len(Sy))
            for grid, symbol in zip(grids_Y, Sy):
                grid.Name = symbol
            for idx, grid in enumerate(grids_X):
                grid.Name = str(idx+1)
        t.Commit()


def main(doc=None):
    doc = doc or revit.doc
    form = Grids()
    if not form.data:
        return
    data = form.data
    lines_x = create_lines(data["Lx"], data["Ly"], data["dx"], data["e"])
    lines_y = create_lines(data["Lx"], data["Ly"], data["dy"], data["e"], y_axis=True)
    create_grids(lines_x, lines_y, data["Sx"], data["Sy"], doc)


if __name__ == "__main__":
    main()

 

 

Any help would be appreciated

0 REPLIES 0

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report