Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
811 changes: 811 additions & 0 deletions extensions/SwichDesign.extension/lib/autodimswichdesign/geometry.py

Large diffs are not rendered by default.

886 changes: 886 additions & 0 deletions extensions/SwichDesign.extension/lib/autodimswichdesign/revit_io.py

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions extensions/SwichDesign.extension/lib/autodimswichdesign/standards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
"""US CD dimensioning constants for the Automatic Dimensions rules.

SOURCES: values taken from the user-supplied reference document
("United States CAD and Architectural Dimensioning Standards"), which
summarizes NCS/ANSI conventions. They have NOT been verified against a
licensed primary NCS copy (paywalled). Treat as project defaults, not
certified standard values.

UNITS: Revit's internal length unit is always decimal FEET - every
constant here is feet.

PAPER vs MODEL SPACE: these are PAPER (printed sheet) distances.
For model-space placement multiply by the view scale (View.Scale):
3/8" on paper at 1/8"=1'-0" (scale 96) is 3.0 ft in the model.

IronPython 2.7 note: 1/16 is INTEGER division = 0 there, which would
silently zero these constants - hence the __future__ import and float
literals. Keep both.
"""
from __future__ import division

INCH = 1.0 / 12.0

# Gap between the object and the start of the extension line.
EXTENSION_LINE_GAP_FT = (1.0 / 16.0) * INCH # 1/16"

# Spacing between stacked/parallel dimension tiers, and minimum
# distance from the object outline to the first dimension line.
TIER_SPACING_FT = (3.0 / 8.0) * INCH # 3/8"

# --- exterior first-string offset (user-configurable, paper inches) ---
#
# Drafting convention (secondary sources; NCS primary text is paywalled,
# see PROJECT_BRIEF section 1): the FIRST dimension line sits ~1/2" off
# the object, SUBSEQUENT tiers 3/8" apart. The old code used 3/8" for
# both, which put the first string too close to the wall (live report).
# Both values are PAPER inches; multiply by View.Scale for model feet.

TIER_SPACING_DEFAULT_IN = 0.375 # 3/8" between stacked tiers
FIRST_OFFSET_DEFAULT_IN = 0.75 # fallback when scale is unlisted

# "Auto" preset: constant paper offset reads cramped at large scales and
# wasteful at small ones, so the preset tapers with the view scale.
SCALE_FIRST_OFFSET_IN = {
12: 1.0, # 1" = 1'-0"
16: 1.0, # 3/4" = 1'-0"
24: 0.75, # 1/2" = 1'-0"
32: 0.75, # 3/8" = 1'-0"
48: 0.75, # 1/4" = 1'-0"
64: 0.625, # 3/16" = 1'-0"
96: 0.5, # 1/8" = 1'-0"
}


def first_offset_for_scale(scale):
"""Preset first-string offset (paper inches) for a view scale.
Exact table hit, else the nearest listed scale, else the default."""
if scale in SCALE_FIRST_OFFSET_IN:
return SCALE_FIRST_OFFSET_IN[scale]
best = None
best_d = None
for key in SCALE_FIRST_OFFSET_IN:
d = abs(key - scale)
if best_d is None or d < best_d:
best_d = d
best = key
if best is None:
return FIRST_OFFSET_DEFAULT_IN
return SCALE_FIRST_OFFSET_IN[best]


def parse_paper_inches(text):
"""User-typed paper distance -> float inches, or None.

Accepts '0.75', '3/4', '3/4"', '1 1/2"', '1-1/2'. Anything else
(including the 'Auto (by view scale)' combo entry) returns None -
the caller decides what None means."""
if text is None:
return None
s = str(text).strip().replace('"', '').replace("''", '')
if not s:
return None
s = s.replace('-', ' ')
parts = s.split()
total = 0.0
seen = False
for part in parts:
if '/' in part:
top_bot = part.split('/')
if len(top_bot) != 2:
return None
try:
total += float(top_bot[0]) / float(top_bot[1])
seen = True
except (ValueError, ZeroDivisionError):
return None
else:
try:
total += float(part)
seen = True
except ValueError:
return None
return total if seen else None

# Minimum overall extension line length.
MIN_EXTENSION_LINE_FT = (9.0 / 16.0) * INCH # 9/16"

# Minimum plotted text height for dimensions/annotation.
MIN_TEXT_HEIGHT_FT = (3.0 / 32.0) * INCH # 3/32"

# Exterior dimensioning targets: structural stud faces at run ends,
# centerlines of door/window openings. (Informational - enforced by
# which references revit_io functions return.)
EXTERIOR_TARGET = "stud_face_to_opening_centerline"

# Terminator per US architectural practice is the oblique tick, but the
# actual terminator comes from the DimensionType the user has active -
# not enforced in code.
TERMINATOR = "tick"

# Opening dimensioning modes (user-selectable per run of the tool):
# 'center' - dimension to the opening centerline (classic exterior practice)
# 'ro' - dimension to both sides of the opening via the family's
# Left/Right references (rough-opening style; the exact plane
# depends on how the family's width references were built)
OPENING_MODE_CENTER = "center"
OPENING_MODE_RO = "ro"


def format_ft_in(value_ft):
"""Decimal feet -> readable feet-inches string.

Normalizes the inches component so 34.9967 ft renders as 35'-0.0",
never 34'-12.0" (live-observed rounding bug).
"""
sign = "-" if value_ft < 0 else ""
total_in = abs(value_ft) * 12.0
feet = int(total_in // 12)
inches = total_in - feet * 12
if inches >= 11.95:
feet += 1
inches = 0.0
return "{0}{1}'-{2:.1f}\"".format(sign, feet, inches)
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Automatic Dimensions"
Width="520" SizeToContent="Height"
ResizeMode="NoResize"
ShowInTaskbar="False"
WindowStartupLocation="CenterScreen">

<Window.Resources>
<Style TargetType="TextBlock" x:Key="RowLabel">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,0,12,0"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style TargetType="RadioButton">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,0,18,0"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style TargetType="TextBlock" x:Key="Hint">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#888888"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Margin" Value="0,2,0,0"/>
</Style>
</Window.Resources>

<Grid Margin="16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!-- what to dimension -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="Dimension:"
Style="{StaticResource RowLabel}"/>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<RadioButton x:Name="mode_ext_rb" GroupName="Mode"
Content="Exterior" Checked="mode_changed"/>
<RadioButton x:Name="mode_int_rb" GroupName="Mode"
Content="Interior" Checked="mode_changed"/>
</StackPanel>

<TextBlock x:Name="mode_hint_tb" Grid.Row="1" Grid.Column="1"
Style="{StaticResource Hint}" Margin="0,2,0,10"/>

<!-- measure to -->
<TextBlock Grid.Row="2" Grid.Column="0" Text="Measure walls to:"
Style="{StaticResource RowLabel}"/>
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal">
<RadioButton x:Name="face_finish_rb" GroupName="Face"
Content="Face of finish"/>
<RadioButton x:Name="face_core_rb" GroupName="Face"
Content="Face of core (stud)"/>
</StackPanel>
<TextBlock Grid.Row="3" Grid.Column="1"
Text="Core faces are calibrated per wall at placement; any wall that cannot be calibrated falls back to its finish face and is named in the notes."
Style="{StaticResource Hint}" Margin="0,2,0,10"/>

<!-- openings -->
<TextBlock Grid.Row="4" Grid.Column="0" Text="Openings:"
Style="{StaticResource RowLabel}"/>
<StackPanel Grid.Row="4" Grid.Column="1" Orientation="Horizontal">
<RadioButton x:Name="open_cl_rb" GroupName="Openings"
Content="Centreline"/>
<RadioButton x:Name="open_ro_rb" GroupName="Openings"
Content="Rough opening (jambs)"/>
</StackPanel>
<TextBlock Grid.Row="5" Grid.Column="1"
Text="Applies to both exterior and interior strings."
Style="{StaticResource Hint}" Margin="0,2,0,10"/>

<!-- exterior offsets -->
<TextBlock Grid.Row="6" Grid.Column="0" Text="Exterior strings:"
Style="{StaticResource RowLabel}"/>
<StackPanel Grid.Row="6" Grid.Column="1" Orientation="Horizontal">
<TextBlock Text="First offset" Style="{StaticResource RowLabel}"
Margin="0,0,6,0"/>
<ComboBox x:Name="first_offset_cb" IsEditable="True"
Width="140" FontSize="12" VerticalAlignment="Center"/>
<TextBlock Text="Spacing" Style="{StaticResource RowLabel}"
Margin="14,0,6,0"/>
<ComboBox x:Name="spacing_cb" IsEditable="True"
Width="70" FontSize="12" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Grid.Row="7" Grid.Column="1"
Text="Paper distances, multiplied by the view scale. Auto picks a per-scale preset (1/2&quot; at 1/8&quot; scale, 3/4&quot; at 1/4&quot; scale). Exterior strings only."
Style="{StaticResource Hint}" Margin="0,2,0,10"/>

<!-- side splitting -->
<TextBlock Grid.Row="8" Grid.Column="0" Text="Split sides:"
Style="{StaticResource RowLabel}"/>
<StackPanel Grid.Row="8" Grid.Column="1" Orientation="Horizontal">
<TextBox x:Name="split_tb" Width="60" FontSize="12"
VerticalAlignment="Center"/>
<TextBlock Text="ft (0 = automatic, by wall-crossing rule)"
Style="{StaticResource RowLabel}" Margin="8,0,0,0"/>
</StackPanel>
<TextBlock Grid.Row="9" Grid.Column="1"
Text="A wall joins a farther string only when its witness lines would not cross another selected wall. Enter a distance in feet to also split anything dragged farther than that."
Style="{StaticResource Hint}" Margin="0,2,0,10"/>

<!-- dry run -->
<TextBlock Grid.Row="10" Grid.Column="0" Text="Run as:"
Style="{StaticResource RowLabel}"/>
<StackPanel Grid.Row="10" Grid.Column="1">
<CheckBox x:Name="dry_cb" Content="Dry run - report only, no model changes"
FontSize="12" VerticalAlignment="Center"/>
<CheckBox x:Name="audit_cb" Content="Report which wall face each dimension picked"
FontSize="12" Margin="0,6,0,0"/>
</StackPanel>

<!-- footer -->
<Grid Grid.Row="11" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,18,0,0">
<TextBlock x:Name="status_tb" VerticalAlignment="Center"
FontSize="11" Foreground="#666666" FontStyle="Italic"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Cancel" Width="86" Height="28" Margin="0,0,8,0"
IsCancel="True" Click="cancel_clicked"/>
<Button Content="Dimension" Width="96" Height="28"
IsDefault="True" Click="dimension_clicked"/>
</StackPanel>
</Grid>
</Grid>
</Window>
Loading