├── AlignTag.v11.suo
├── AlignTag
├── Resources
│ ├── alignTags.gif
│ ├── AlignAppIcon.png
│ ├── align-top-large.png
│ ├── align-top-small.png
│ ├── arrange-large.png
│ ├── arrange-small.png
│ ├── align-icon-large.png
│ ├── align-icon-small.png
│ ├── align-left-large.png
│ ├── align-left-small.png
│ ├── align-right-large.png
│ ├── align-right-small.png
│ ├── AlignBottomSmall (1).png
│ ├── AlignLeftLarge (1).png
│ ├── align-bottom-large.png
│ ├── align-bottom-small.png
│ ├── align-center-large.png
│ ├── align-center-small.png
│ ├── align-middle-large.png
│ ├── align-middle-small.png
│ ├── untangle-vertically-large.png
│ ├── untangle-vertically-small.png
│ ├── align-icon-grey-background.png
│ ├── distribute-vertically-large.png
│ ├── distribute-vertically-small.png
│ ├── untangle-horizontally-large.png
│ ├── untangle-horizontally-small.png
│ ├── DistributeVerticallyLarge (1).png
│ ├── distribute-horizontally-large.png
│ └── distribute-horizontally-small.png
├── CopyToRevitAddinFolder.bat
├── AlignTag.addin
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ └── Resources.Designer (1).cs
├── PostBuild.ps1
├── AlignExecute.cs
├── App.cs
├── Tools.cs
├── AlignTag.csproj
├── AnnotationElement.cs
├── Align.cs
└── Arrange.cs
├── LICENSE
├── Align.Test
├── Align - Backup.Test.csproj
├── Align.Test.csproj
└── AlignTest.cs
├── README.md
├── .gitignore
└── AlignTag.sln
/AlignTag.v11.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag.v11.suo
--------------------------------------------------------------------------------
/AlignTag/Resources/alignTags.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/alignTags.gif
--------------------------------------------------------------------------------
/AlignTag/Resources/AlignAppIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/AlignAppIcon.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-top-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-top-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-top-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-top-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/arrange-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/arrange-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/arrange-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/arrange-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-icon-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-icon-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-icon-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-left-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-left-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-left-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-left-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-right-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-right-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-right-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-right-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/AlignBottomSmall (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/AlignBottomSmall (1).png
--------------------------------------------------------------------------------
/AlignTag/Resources/AlignLeftLarge (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/AlignLeftLarge (1).png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-bottom-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-bottom-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-bottom-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-bottom-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-center-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-center-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-center-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-center-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-middle-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-middle-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-middle-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-middle-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/untangle-vertically-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/untangle-vertically-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/untangle-vertically-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/untangle-vertically-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/align-icon-grey-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/align-icon-grey-background.png
--------------------------------------------------------------------------------
/AlignTag/Resources/distribute-vertically-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/distribute-vertically-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/distribute-vertically-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/distribute-vertically-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/untangle-horizontally-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/untangle-horizontally-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/untangle-horizontally-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/untangle-horizontally-small.png
--------------------------------------------------------------------------------
/AlignTag/Resources/DistributeVerticallyLarge (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/DistributeVerticallyLarge (1).png
--------------------------------------------------------------------------------
/AlignTag/Resources/distribute-horizontally-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/distribute-horizontally-large.png
--------------------------------------------------------------------------------
/AlignTag/Resources/distribute-horizontally-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonmoreau/align-tag/HEAD/AlignTag/Resources/distribute-horizontally-small.png
--------------------------------------------------------------------------------
/AlignTag/CopyToRevitAddinFolder.bat:
--------------------------------------------------------------------------------
1 | copy "AlignTag.addin" "%AppData%\Autodesk\REVIT\Addins\2019"
2 | copy "bin\debug\AlignTag.dll" "%AppData%\Autodesk\REVIT\Addins\2019"
3 | pause
--------------------------------------------------------------------------------
/AlignTag/AlignTag.addin:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Application AlignTag
5 | AlignTag\AlignTag.dll
6 | AlignTag.App
7 | 5a9e8c41-09d6-4cdf-8556-38f8119137a4
8 | BM42
9 | BIM 42, http://bim42.com
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Simon Moreau
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/AlignTag/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("AlignTag")]
9 | [assembly: AssemblyDescription("Align Tags in Revit")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("BIM 42")]
12 | [assembly: AssemblyProduct("Revit Add-In AlignTag")]
13 | [assembly: AssemblyCopyright("")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("321044f7-b0b2-4b1c-af18-e71a19252be0")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.1.0.0")]
36 | [assembly: AssemblyFileVersion("1.1.0.0")]
37 |
--------------------------------------------------------------------------------
/AlignTag/PostBuild.ps1:
--------------------------------------------------------------------------------
1 | param ($Configuration, $TargetName, $ProjectDir, $TargetPath, $TargetDir)
2 | write-host $Configuration
3 | write-host $TargetName
4 | write-host $ProjectDir
5 | write-host $TargetPath
6 | write-host $TargetDir
7 |
8 | # sign the dll
9 | $thumbPrint = "e729567d4e9be8ffca04179e3375b7669bccf272"
10 | $cert=Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert | Where { $_.Thumbprint -eq $thumbPrint}
11 |
12 | Set-AuthenticodeSignature -FilePath $TargetPath -Certificate $cert -IncludeChain All -TimestampServer "http://timestamp.comodoca.com/authenticode"
13 |
14 | function CopyToFolder($revitVersion, $addinFolder) {
15 |
16 | if (Test-Path $addinFolder) {
17 | try {
18 | # Remove previous versions
19 | if (Test-Path ($addinFolder + "\" + $TargetName + ".addin")) { Remove-Item ($addinFolder + "\" + $TargetName + ".addin") }
20 | if (Test-Path ($addinFolder + "\" + $TargetName)) { Remove-Item ($addinFolder + "\" + $TargetName) -Recurse }
21 |
22 | # create the folder
23 | New-Item -ItemType Directory -Path ($addinFolder + "\" + $TargetName) -Force
24 |
25 | # Copy the addin file
26 | xcopy /Y ($ProjectDir + $TargetName + ".addin") ($addinFolder)
27 | xcopy /Y ($TargetDir + "\*.dll*") ($addinFolder + "\" + $TargetName)
28 | }
29 | catch {
30 | Write-Host "Something went wrong"
31 | }
32 | }
33 | }
34 |
35 | $revitVersion = $Configuration.replace('Debug','').replace('Release','')
36 |
37 | # Copy to Addin folder for debug
38 | $addinFolder = ($env:APPDATA + "\Autodesk\REVIT\Addins\" + $revitVersion)
39 | CopyToFolder $revitVersion $addinFolder
40 |
41 | # Copy to release folder for building the package
42 | $ReleasePath="G:\My Drive\05 - Travail\Revit Dev\AlignTag\Releases"
43 | $releaseFolder = ($ReleasePath + "\BIM 42 Align.bundle\Contents\" + $revitVersion + "\")
44 | CopyToFolder $revitVersion $releaseFolder
45 |
46 |
47 | ## Zip the package
48 |
49 | $BundleFolder = ($ReleasePath + "\BIM 42 Align.bundle")
50 |
51 | $ReleaseZip = ($ReleasePath + "\" + $TargetName + ".zip")
52 | if (Test-Path $ReleaseZip) { Remove-Item $ReleaseZip }
53 |
54 | if ( Test-Path -Path $ReleasePath ) {
55 | 7z a -tzip $ReleaseZip ($BundleFolder)
56 | }
--------------------------------------------------------------------------------
/AlignTag/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace AlignTag.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AlignTag.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Align.Test/Align - Backup.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net48
5 |
6 | false
7 |
8 | 2022Debug;2022Release;2021Debug;2020Debug;2019Debug;2023Debug;2023Release;2021Release;2020Release;2019Release
9 |
10 |
11 |
12 |
13 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\RevitAPI.dll
14 | False
15 |
16 |
17 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\RevitAPIUI.dll
18 | False
19 |
20 |
21 |
22 | $(PROGRAMFILES)\Autodesk\Revit 2023\RevitAPI.dll
23 | False
24 |
25 |
26 | $(PROGRAMFILES)\Autodesk\Revit 2023\RevitAPIUI.dll
27 | False
28 |
29 |
30 |
31 | $(PROGRAMFILES)\Autodesk\Revit 2022\RevitAPI.dll
32 | False
33 |
34 |
35 | $(PROGRAMFILES)\Autodesk\Revit 2022\RevitAPIUI.dll
36 | False
37 |
38 |
39 |
40 | $(PROGRAMFILES)\Autodesk\Revit 2021\RevitAPI.dll
41 | False
42 |
43 |
44 | $(PROGRAMFILES)\Autodesk\Revit 2021\RevitAPIUI.dll
45 | False
46 |
47 |
48 |
49 | $(PROGRAMFILES)\Autodesk\Revit 2020\RevitAPI.dll
50 | False
51 |
52 |
53 | $(PROGRAMFILES)\Autodesk\Revit 2020\RevitAPIUI.dll
54 | False
55 |
56 |
57 |
58 | $(PROGRAMFILES)\Autodesk\Revit 2019\RevitAPI.dll
59 | False
60 |
61 |
62 | $(PROGRAMFILES)\Autodesk\Revit 2019\RevitAPIUI.dll
63 | False
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Align.Test/Align.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net48
5 |
6 | false
7 |
8 | 2022Debug;2022Release;2021Debug;2020Debug;2019Debug;2023Debug;2023Release;2021Release;2020Release;2019Release;2024Debug;2024Release
9 |
10 |
11 |
12 |
13 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\RevitAPI.dll
14 | False
15 |
16 |
17 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\RevitAPIUI.dll
18 | False
19 |
20 |
21 |
22 | $(PROGRAMFILES)\Autodesk\Revit 2023\RevitAPI.dll
23 | False
24 |
25 |
26 | $(PROGRAMFILES)\Autodesk\Revit 2023\RevitAPIUI.dll
27 | False
28 |
29 |
30 |
31 | $(PROGRAMFILES)\Autodesk\Revit 2022\RevitAPI.dll
32 | False
33 |
34 |
35 | $(PROGRAMFILES)\Autodesk\Revit 2022\RevitAPIUI.dll
36 | False
37 |
38 |
39 |
40 | $(PROGRAMFILES)\Autodesk\Revit 2021\RevitAPI.dll
41 | False
42 |
43 |
44 | $(PROGRAMFILES)\Autodesk\Revit 2021\RevitAPIUI.dll
45 | False
46 |
47 |
48 |
49 | $(PROGRAMFILES)\Autodesk\Revit 2020\RevitAPI.dll
50 | False
51 |
52 |
53 | $(PROGRAMFILES)\Autodesk\Revit 2020\RevitAPIUI.dll
54 | False
55 |
56 |
57 |
58 | $(PROGRAMFILES)\Autodesk\Revit 2019\RevitAPI.dll
59 | False
60 |
61 |
62 | $(PROGRAMFILES)\Autodesk\Revit 2019\RevitAPIUI.dll
63 | False
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/AlignTag/AlignExecute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections.Generic;
4 | using Autodesk.Revit.Attributes;
5 | using Autodesk.Revit.DB;
6 | using Autodesk.Revit.UI;
7 | using Autodesk.Revit.UI.Selection;
8 | using Autodesk.Revit.DB.Architecture;
9 | using System.Globalization;
10 | using System.Resources;
11 |
12 | namespace AlignTag
13 | {
14 | [Transaction(TransactionMode.Manual)]
15 | class AlignLeft : IExternalCommand
16 | {
17 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
18 | {
19 | Align align = new Align();
20 |
21 | return align.AlignElements(commandData, ref message, AlignType.Left);
22 | }
23 | }
24 |
25 | [Transaction(TransactionMode.Manual)]
26 | class AlignRight : IExternalCommand
27 | {
28 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
29 | {
30 | Align align = new Align();
31 |
32 | return align.AlignElements(commandData, ref message, AlignType.Right);
33 | }
34 | }
35 |
36 | [Transaction(TransactionMode.Manual)]
37 | class AlignTop : IExternalCommand
38 | {
39 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
40 | {
41 | Align align = new Align();
42 |
43 | return align.AlignElements(commandData, ref message, AlignType.Up);
44 | }
45 | }
46 |
47 | [Transaction(TransactionMode.Manual)]
48 | class AlignBottom : IExternalCommand
49 | {
50 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
51 | {
52 | Align align = new Align();
53 |
54 | return align.AlignElements(commandData, ref message, AlignType.Down);
55 | }
56 | }
57 |
58 | [Transaction(TransactionMode.Manual)]
59 | class AlignCenter : IExternalCommand
60 | {
61 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
62 | {
63 | Align align = new Align();
64 |
65 | return align.AlignElements(commandData, ref message, AlignType.Center);
66 | }
67 | }
68 |
69 | [Transaction(TransactionMode.Manual)]
70 | class AlignMiddle : IExternalCommand
71 | {
72 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
73 | {
74 | Align align = new Align();
75 |
76 | return align.AlignElements(commandData, ref message, AlignType.Middle);
77 | }
78 | }
79 |
80 | [Transaction(TransactionMode.Manual)]
81 | class DistributeHorizontally : IExternalCommand
82 | {
83 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
84 | {
85 | Align align = new Align();
86 |
87 | return align.AlignElements(commandData, ref message, AlignType.Horizontally);
88 | }
89 | }
90 |
91 | [Transaction(TransactionMode.Manual)]
92 | class DistributeVertically : IExternalCommand
93 | {
94 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
95 | {
96 | Align align = new Align();
97 |
98 | return align.AlignElements(commandData, ref message, AlignType.Vertically);
99 | }
100 | }
101 |
102 | [Transaction(TransactionMode.Manual)]
103 | class UntangleVertically : IExternalCommand
104 | {
105 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
106 | {
107 | Align align = new Align();
108 |
109 | return align.AlignElements(commandData, ref message, AlignType.UntangleVertically);
110 | }
111 | }
112 |
113 | [Transaction(TransactionMode.Manual)]
114 | class UntangleHorizontally : IExternalCommand
115 | {
116 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
117 | {
118 | Align align = new Align();
119 |
120 | return align.AlignElements(commandData, ref message, AlignType.UntangleHorizontally);
121 | }
122 | }
123 |
124 | //[Transaction(TransactionMode.Manual)]
125 | //class Arrange : IExternalCommand
126 | //{
127 | // public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
128 | // {
129 | // Arrange arrange = new Arrange();
130 |
131 | // return arrange.ArrangeElements(commandData, ref message);
132 | // }
133 | //}
134 | }
135 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

2 |
3 | Align
4 |
5 |
6 | Align everything in Revit
7 |
8 | # Overview
9 |
10 | The Align tool allows you to align, distribute or organize selected elements, annotations, tags and text along the axis you specify. Furthermore, the Arrange feature will automatically neatly place your tags around the current view.
11 |
12 | The Align plug-in for Autodesk® Revit® can help to save time while producing complex drawings with large sets of annotation.
13 |
14 | Just select a few elements and the Align tool will sort them for you.
15 |
16 | 
17 |
18 | # Getting Started
19 |
20 | Edit _AlignTag.csproj_, and make sure that the following lines a correctly pointing to your Revit installation folder:
21 | * Line 27: $(ProgramW6432)\Autodesk\Revit Preview Release\Revit.exe
22 | * Line 37: $(ProgramW6432)\Autodesk\Revit Preview Release\Revit.exe
23 | * Line 42: $(ProgramW6432)\Autodesk\Revit Preview Release\RevitAPI.dll
24 | * Line 46: $(ProgramW6432)\Autodesk\Revit Preview Release\RevitAPIUI.dll
25 | * Line 140 to 143: ...
26 |
27 | Open the solution in Visual Studio 2017, buid it, and hit "Start" to run Revit in debug mode.
28 |
29 | ## Installation
30 |
31 | There is two ways to install this plugin in Revit:
32 |
33 | ### The easy way
34 |
35 | Download the installer on the [Autodesk App Exchange](https://apps.autodesk.com/RVT/en/Detail/Index?id=2903508825431715905&appLang=en&os=Win32_64)
36 |
37 | ### The (not so) easy way
38 |
39 | You install Align just [like any other Revit add-in](http://help.autodesk.com/view/RVT/2018/ENU/?guid=GUID-4FFDB03E-6936-417C-9772-8FC258A261F7), by copying the add-in manifest (_"AlignTag.addin"_), the assembly DLL (_"AlignTag.dll"_) and the associated help file (_"AlignHelp.chm"_) to the Revit Add-Ins folder (%APPDATA%\Autodesk\Revit\Addins\2018).
40 |
41 | If you specify the full DLL pathname in the add-in manifest, it can also be located elsewhere. However, this DLL, its dependanties and help files must be locted in the same folder.
42 |
43 | Futhermore, the Visual Studio solution contain all the necessary post-build scripts to copy these files into appropriates folders.
44 |
45 | ## Built With
46 |
47 | * .NET Framework 4.7 and [Visual Studio Community](https://www.visualstudio.com/vs/community/)
48 | * The Visual Studio Revit C# and VB add-in templates from [The Building Coder](http://thebuildingcoder.typepad.com/blog/2017/04/revit-2018-visual-studio-c-and-vb-net-add-in-wizards.html)
49 |
50 | # Development
51 |
52 | Want to contribute? Great, I would be happy to integrate your improvements!
53 |
54 | To fix a bug or enhance an existing module, follow these steps:
55 |
56 | * Fork the repo
57 | * Create a new branch (`git checkout -b improve-feature`)
58 | * Make the appropriate changes in the files
59 | * Add changes to reflect the changes made
60 | * Commit your changes (`git commit -am 'Improve feature'`)
61 | * Push to the branch (`git push origin improve-feature`)
62 | * Create a Pull Request
63 |
64 | # Bug / Feature Request
65 |
66 | If you find a bug (connection issue, error while uploading, ...), kindly open an issue [here](https://github.com/simonmoreau/align-tag/issues/new) by including a screenshot of your problem and the expected result.
67 |
68 | If you'd like to request a new function, feel free to do so by opening an issue [here](https://github.com/simonmoreau/align-tag/issues/new). Please include workflows samples and their corresponding results.
69 |
70 | # License
71 |
72 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE) file for details
73 |
74 | # Contact information
75 |
76 | This software is an open-source project mostly maintained by myself, Simon Moreau. If you have any questions or request, feel free to contact me at [simon@bim42.com](mailto:simon@bim42.com) or on Twitter [@bim42](https://twitter.com/bim42?lang=en).
77 |
78 | # Revision list
79 |
80 | | **Version Number** | **Version Description** |
81 | | :-------------: |:-------------|
82 | 1.3.0|Add support for every Revit element. Align every element according to its bounding box. Bug fix. Support for Autodesk® Revit® 2018 Version.
83 | 1.2.0|Add support for Text, Keynote Tag, Room and Space Tags. Align every tag according to its bounding box. Add Align Center and Align Middle. Support for Autodesk® Revit® 2017 Version.
84 | 1.1.0|Support for Autodesk® Revit® 2016 Version. Add the Arrange Tags feature.
85 | 1.0.0|First Release
86 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 | Files/
13 |
14 | # Build results
15 | [Dd]ebug/
16 | [Dd]ebugPublic/
17 | [Rr]elease/
18 | [Rr]eleases/
19 | x64/
20 | x86/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 | [Ll]og/
25 |
26 | # Visual Studio 2015 cache/options directory
27 | .vs/
28 | # Uncomment if you have tasks that create the project's static files in wwwroot
29 | #wwwroot/
30 |
31 | # MSTest test Results
32 | [Tt]est[Rr]esult*/
33 | [Bb]uild[Ll]og.*
34 |
35 | # NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # Build Results of an ATL Project
40 | [Dd]ebugPS/
41 | [Rr]eleasePS/
42 | dlldata.c
43 |
44 | # DNX
45 | project.lock.json
46 | project.fragment.lock.json
47 | artifacts/
48 |
49 | *_i.c
50 | *_p.c
51 | *_i.h
52 | *.ilk
53 | *.meta
54 | *.obj
55 | *.pch
56 | *.pdb
57 | *.pgc
58 | *.pgd
59 | *.rsp
60 | *.sbr
61 | *.tlb
62 | *.tli
63 | *.tlh
64 | *.tmp
65 | *.tmp_proj
66 | *.log
67 | *.vspscc
68 | *.vssscc
69 | .builds
70 | *.pidb
71 | *.svclog
72 | *.scc
73 |
74 | # Chutzpah Test files
75 | _Chutzpah*
76 |
77 | # Visual C++ cache files
78 | ipch/
79 | *.aps
80 | *.ncb
81 | *.opendb
82 | *.opensdf
83 | *.sdf
84 | *.cachefile
85 | *.VC.db
86 | *.VC.VC.opendb
87 |
88 | # Visual Studio profiler
89 | *.psess
90 | *.vsp
91 | *.vspx
92 | *.sap
93 |
94 | # TFS 2012 Local Workspace
95 | $tf/
96 |
97 | # Guidance Automation Toolkit
98 | *.gpState
99 |
100 | # ReSharper is a .NET coding add-in
101 | _ReSharper*/
102 | *.[Rr]e[Ss]harper
103 | *.DotSettings.user
104 |
105 | # JustCode is a .NET coding add-in
106 | .JustCode
107 |
108 | # TeamCity is a build add-in
109 | _TeamCity*
110 |
111 | # DotCover is a Code Coverage Tool
112 | *.dotCover
113 |
114 | # NCrunch
115 | _NCrunch_*
116 | .*crunch*.local.xml
117 | nCrunchTemp_*
118 |
119 | # MightyMoose
120 | *.mm.*
121 | AutoTest.Net/
122 |
123 | # Web workbench (sass)
124 | .sass-cache/
125 |
126 | # Installshield output folder
127 | [Ee]xpress/
128 |
129 | # DocProject is a documentation generator add-in
130 | DocProject/buildhelp/
131 | DocProject/Help/*.HxT
132 | DocProject/Help/*.HxC
133 | DocProject/Help/*.hhc
134 | DocProject/Help/*.hhk
135 | DocProject/Help/*.hhp
136 | DocProject/Help/Html2
137 | DocProject/Help/html
138 |
139 | # Click-Once directory
140 | publish/
141 |
142 | # Publish Web Output
143 | *.[Pp]ublish.xml
144 | *.azurePubxml
145 | # TODO: Comment the next line if you want to checkin your web deploy settings
146 | # but database connection strings (with potential passwords) will be unencrypted
147 | #*.pubxml
148 | *.publishproj
149 |
150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
151 | # checkin your Azure Web App publish settings, but sensitive information contained
152 | # in these scripts will be unencrypted
153 | PublishScripts/
154 |
155 | # NuGet Packages
156 | *.nupkg
157 | # The packages folder can be ignored because of Package Restore
158 | **/packages/*
159 | # except build/, which is used as an MSBuild target.
160 | !**/packages/build/
161 | # Uncomment if necessary however generally it will be regenerated when needed
162 | #!**/packages/repositories.config
163 | # NuGet v3's project.json files produces more ignoreable files
164 | *.nuget.props
165 | *.nuget.targets
166 |
167 | # Microsoft Azure Build Output
168 | csx/
169 | *.build.csdef
170 |
171 | # Microsoft Azure Emulator
172 | ecf/
173 | rcf/
174 |
175 | # Windows Store app package directories and files
176 | AppPackages/
177 | BundleArtifacts/
178 | Package.StoreAssociation.xml
179 | _pkginfo.txt
180 |
181 | # Visual Studio cache files
182 | # files ending in .cache can be ignored
183 | *.[Cc]ache
184 | # but keep track of directories ending in .cache
185 | !*.[Cc]ache/
186 |
187 | # Others
188 | ClientBin/
189 | ~$*
190 | *~
191 | *.dbmdl
192 | *.dbproj.schemaview
193 | *.jfm
194 | *.pfx
195 | *.publishsettings
196 | node_modules/
197 | orleans.codegen.cs
198 |
199 | # Since there are multiple workflows, uncomment next line to ignore bower_components
200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
201 | #bower_components/
202 |
203 | # RIA/Silverlight projects
204 | Generated_Code/
205 |
206 | # Backup & report files from converting an old project file
207 | # to a newer Visual Studio version. Backup files are not needed,
208 | # because we have git ;-)
209 | _UpgradeReport_Files/
210 | Backup*/
211 | UpgradeLog*.XML
212 | UpgradeLog*.htm
213 |
214 | # SQL Server files
215 | *.mdf
216 | *.ldf
217 |
218 | # Business Intelligence projects
219 | *.rdl.data
220 | *.bim.layout
221 | *.bim_*.settings
222 |
223 | # Microsoft Fakes
224 | FakesAssemblies/
225 |
226 | # GhostDoc plugin setting file
227 | *.GhostDoc.xml
228 |
229 | # Node.js Tools for Visual Studio
230 | .ntvs_analysis.dat
231 |
232 | # Visual Studio 6 build log
233 | *.plg
234 |
235 | # Visual Studio 6 workspace options file
236 | *.opt
237 |
238 | # Visual Studio LightSwitch build output
239 | **/*.HTMLClient/GeneratedArtifacts
240 | **/*.DesktopClient/GeneratedArtifacts
241 | **/*.DesktopClient/ModelManifest.xml
242 | **/*.Server/GeneratedArtifacts
243 | **/*.Server/ModelManifest.xml
244 | _Pvt_Extensions
245 |
246 | # Paket dependency manager
247 | .paket/paket.exe
248 | paket-files/
249 |
250 | # FAKE - F# Make
251 | .fake/
252 |
253 | # JetBrains Rider
254 | .idea/
255 | *.sln.iml
256 |
257 | # CodeRush
258 | .cr/
259 |
260 | # Python Tools for Visual Studio (PTVS)
261 | __pycache__/
262 | *.pyc
--------------------------------------------------------------------------------
/AlignTag.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32421.90
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlignTag", "AlignTag\AlignTag.csproj", "{AB14DB7D-855A-4952-8BD5-752DDDD05D7E}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Align.Test", "Align.Test\Align.Test.csproj", "{840BAA3B-473D-4F82-B42A-85F63CFF68AF}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | 2019Debug|Any CPU = 2019Debug|Any CPU
13 | 2019Release|Any CPU = 2019Release|Any CPU
14 | 2020Debug|Any CPU = 2020Debug|Any CPU
15 | 2020Release|Any CPU = 2020Release|Any CPU
16 | 2021Debug|Any CPU = 2021Debug|Any CPU
17 | 2021Release|Any CPU = 2021Release|Any CPU
18 | 2022Debug|Any CPU = 2022Debug|Any CPU
19 | 2022Release|Any CPU = 2022Release|Any CPU
20 | 2023Debug|Any CPU = 2023Debug|Any CPU
21 | 2023Release|Any CPU = 2023Release|Any CPU
22 | 2024Debug|Any CPU = 2024Debug|Any CPU
23 | 2024Release|Any CPU = 2024Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2019Debug|Any CPU.ActiveCfg = 2019Debug|Any CPU
27 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2019Debug|Any CPU.Build.0 = 2019Debug|Any CPU
28 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2019Release|Any CPU.ActiveCfg = 2019Release|Any CPU
29 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2019Release|Any CPU.Build.0 = 2019Release|Any CPU
30 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2020Debug|Any CPU.ActiveCfg = 2020Debug|Any CPU
31 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2020Debug|Any CPU.Build.0 = 2020Debug|Any CPU
32 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2020Release|Any CPU.ActiveCfg = 2020Release|Any CPU
33 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2020Release|Any CPU.Build.0 = 2020Release|Any CPU
34 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2021Debug|Any CPU.ActiveCfg = 2021Debug|Any CPU
35 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2021Debug|Any CPU.Build.0 = 2021Debug|Any CPU
36 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2021Release|Any CPU.ActiveCfg = 2021Release|Any CPU
37 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2021Release|Any CPU.Build.0 = 2021Release|Any CPU
38 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2022Debug|Any CPU.ActiveCfg = 2022Debug|Any CPU
39 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2022Debug|Any CPU.Build.0 = 2022Debug|Any CPU
40 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2022Release|Any CPU.ActiveCfg = 2022Release|Any CPU
41 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2022Release|Any CPU.Build.0 = 2022Release|Any CPU
42 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2023Debug|Any CPU.ActiveCfg = 2023Debug|Any CPU
43 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2023Debug|Any CPU.Build.0 = 2023Debug|Any CPU
44 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2023Release|Any CPU.ActiveCfg = 2023Release|Any CPU
45 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2023Release|Any CPU.Build.0 = 2023Release|Any CPU
46 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2024Debug|Any CPU.ActiveCfg = 2024Debug|Any CPU
47 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2024Debug|Any CPU.Build.0 = 2024Debug|Any CPU
48 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2024Release|Any CPU.ActiveCfg = 2024Release|Any CPU
49 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}.2024Release|Any CPU.Build.0 = 2024Release|Any CPU
50 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2019Debug|Any CPU.ActiveCfg = 2019Debug|Any CPU
51 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2019Debug|Any CPU.Build.0 = 2019Debug|Any CPU
52 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2019Release|Any CPU.ActiveCfg = 2019Release|Any CPU
53 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2019Release|Any CPU.Build.0 = 2019Release|Any CPU
54 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2020Debug|Any CPU.ActiveCfg = 2020Debug|Any CPU
55 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2020Debug|Any CPU.Build.0 = 2020Debug|Any CPU
56 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2020Release|Any CPU.ActiveCfg = 2020Release|Any CPU
57 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2020Release|Any CPU.Build.0 = 2020Release|Any CPU
58 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2021Debug|Any CPU.ActiveCfg = 2021Debug|Any CPU
59 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2021Debug|Any CPU.Build.0 = 2021Debug|Any CPU
60 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2021Release|Any CPU.ActiveCfg = 2021Release|Any CPU
61 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2021Release|Any CPU.Build.0 = 2021Release|Any CPU
62 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2022Debug|Any CPU.ActiveCfg = 2022Debug|Any CPU
63 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2022Debug|Any CPU.Build.0 = 2022Debug|Any CPU
64 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2022Release|Any CPU.ActiveCfg = 2022Release|Any CPU
65 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2022Release|Any CPU.Build.0 = 2022Release|Any CPU
66 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2023Debug|Any CPU.ActiveCfg = 2023Debug|Any CPU
67 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2023Debug|Any CPU.Build.0 = 2023Debug|Any CPU
68 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2023Release|Any CPU.ActiveCfg = 2023Release|Any CPU
69 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2023Release|Any CPU.Build.0 = 2023Release|Any CPU
70 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2024Debug|Any CPU.ActiveCfg = 2024Debug|Any CPU
71 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2024Debug|Any CPU.Build.0 = 2024Debug|Any CPU
72 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2024Release|Any CPU.ActiveCfg = 2024Release|Any CPU
73 | {840BAA3B-473D-4F82-B42A-85F63CFF68AF}.2024Release|Any CPU.Build.0 = 2024Release|Any CPU
74 | EndGlobalSection
75 | GlobalSection(SolutionProperties) = preSolution
76 | HideSolutionNode = FALSE
77 | EndGlobalSection
78 | GlobalSection(ExtensibilityGlobals) = postSolution
79 | SolutionGuid = {FEE85557-E92A-4887-8A3E-9C7E02DC9C66}
80 | EndGlobalSection
81 | EndGlobal
82 |
--------------------------------------------------------------------------------
/AlignTag/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/Align.Test/AlignTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Autodesk.Revit.UI;
9 | using Autodesk.Revit.DB;
10 | using Autodesk.Revit.ApplicationServices;
11 |
12 | namespace Align.Test
13 | {
14 | [TestFixture]
15 | public class AlignTest
16 | {
17 | private Document document;
18 | [SetUp]
19 | public void RunBeforeTest(UIApplication uiApplication)
20 | {
21 | string versionName = uiApplication.Application.VersionName.Replace("Autodesk Revit ", "");
22 |
23 | string path = $"G:\\My Drive\\05 - Travail\\Revit Dev\\AlignTag\\Test Models\\AlignTestModel_{versionName}.rvt";
24 | UIDocument uIDocument = uiApplication.OpenAndActivateDocument(path);
25 | document = uIDocument.Document;
26 | Console.WriteLine($"Run 'SetUp' in {GetType().Name}");
27 | Console.WriteLine($"Open the AlignTestModel_{versionName} model.");
28 | }
29 |
30 | [TearDown]
31 | public void RunAfterTest()
32 | {
33 | Console.WriteLine($"Run 'TearDown' in {GetType().Name}");
34 | }
35 |
36 | [Test]
37 | public void AlignTagLeft()
38 | {
39 | int[] ids = new int[] { 201324, 201325, 201326, 201327 };
40 | AlignTestFunction(ids, AlignTag.AlignType.Left);
41 | }
42 |
43 | [Test]
44 | public void AlignTagRight()
45 | {
46 | int[] ids = new int[] { 201379, 201380, 201381, 201382 };
47 | AlignTestFunction(ids, AlignTag.AlignType.Right);
48 | }
49 |
50 | [Test]
51 | public void AlignTagCenter()
52 | {
53 | int[] ids = new int[] { 201439, 201440, 201441, 201442 };
54 | AlignTestFunction(ids, AlignTag.AlignType.Center);
55 | }
56 |
57 | [Test]
58 | public void AlignTagUp()
59 | {
60 | int[] ids = new int[] { 201483, 201484, 201485, 201486 };
61 | AlignTestFunction(ids, AlignTag.AlignType.Up);
62 | }
63 |
64 | [Test]
65 | public void AlignTagDown()
66 | {
67 | int[] ids = new int[] { 201556, 201557, 201558, 201559 };
68 | AlignTestFunction(ids, AlignTag.AlignType.Down);
69 | }
70 |
71 | [Test]
72 | public void AlignTagMiddle()
73 | {
74 | int[] ids = new int[] { 201600, 201601, 201602, 201603 };
75 | AlignTestFunction(ids, AlignTag.AlignType.Middle);
76 | }
77 |
78 | [Test]
79 | public void DistributeTagHorizontaly()
80 | {
81 | int[] ids = new int[] { 201956, 201957, 201958, 201959 };
82 | AlignTestFunction(ids, AlignTag.AlignType.Horizontally);
83 | }
84 |
85 | [Test]
86 | public void DistributeTagVerticaly()
87 | {
88 | int[] ids = new int[] { 202057, 202058, 202059, 202060 };
89 | AlignTestFunction(ids, AlignTag.AlignType.Vertically);
90 | }
91 |
92 | [Test]
93 | public void AlignWallLeft()
94 | {
95 | int[] ids = new int[] { 202240, 202272, 202307, 202356 };
96 | AlignTestFunction(ids, AlignTag.AlignType.Left);
97 | }
98 |
99 | [Test]
100 | public void AlignWallLeftWithPinned()
101 | {
102 | int[] ids = new int[] { 205004, 205005, 205006, 205007 };
103 | AlignTestFunction(ids, AlignTag.AlignType.Left);
104 | }
105 |
106 | [Test]
107 | public void AlignWallRight()
108 | {
109 | int[] ids = new int[] { 202393, 202394, 202395, 202396 };
110 | AlignTestFunction(ids, AlignTag.AlignType.Right);
111 | }
112 |
113 | [Test]
114 | public void AlignWallCenter()
115 | {
116 | int[] ids = new int[] { 202412, 202413, 202414, 202415 };
117 | AlignTestFunction(ids, AlignTag.AlignType.Center);
118 | }
119 |
120 | [Test]
121 | public void AlignWallUp()
122 | {
123 | int[] ids = new int[] { 202423, 202424, 202425, 202426 };
124 | AlignTestFunction(ids, AlignTag.AlignType.Up);
125 | }
126 |
127 | [Test]
128 | public void AlignWallDown()
129 | {
130 | int[] ids = new int[] { 202450, 202451, 202452, 202453 };
131 | AlignTestFunction(ids, AlignTag.AlignType.Down);
132 | }
133 |
134 | [Test]
135 | public void AlignWallMiddle()
136 | {
137 | int[] ids = new int[] { 202459, 202460, 202461, 202462 };
138 | AlignTestFunction(ids, AlignTag.AlignType.Middle);
139 | }
140 |
141 | [Test]
142 | public void DistributeWallHorizontaly()
143 | {
144 | int[] ids = new int[] { 202532, 202533, 202534, 202535 };
145 | AlignTestFunction(ids, AlignTag.AlignType.Horizontally);
146 | }
147 |
148 | [Test]
149 | public void DistributeWallVerticaly()
150 | {
151 | int[] ids = new int[] { 202470, 202471, 202472, 202473 };
152 | AlignTestFunction(ids, AlignTag.AlignType.Vertically);
153 | }
154 |
155 | [Test]
156 | public void AlignRoomTagTop()
157 | {
158 | int[] ids = new int[] { 205282, 205285 };
159 | AlignTestFunction(ids, AlignTag.AlignType.Up);
160 | }
161 |
162 | [Test]
163 | public void AlignRoomTagBottom()
164 | {
165 | int[] ids = new int[] { 205288, 205291, 205294 };
166 | AlignTestFunction(ids, AlignTag.AlignType.Down);
167 | }
168 |
169 | [Test]
170 | public void AlignSpaceTagTop()
171 | {
172 | int[] ids = new int[] { 205654, 205655 };
173 | AlignTestFunction(ids, AlignTag.AlignType.Up);
174 | }
175 |
176 | [Test]
177 | public void AlignSpaceTagBottom()
178 | {
179 | int[] ids = new int[] { 205656, 205657, 205658 };
180 | AlignTestFunction(ids, AlignTag.AlignType.Down);
181 | }
182 |
183 | [Test]
184 | public void AlignTextNoteRight()
185 | {
186 | int[] ids = new int[] { 205777, 205811, 205819 };
187 | AlignTestFunction(ids, AlignTag.AlignType.Right);
188 | }
189 |
190 | [Test]
191 | public void AlignTextNoteVerticaly()
192 | {
193 | int[] ids = new int[] { 205832, 205838, 205839 };
194 | AlignTestFunction(ids, AlignTag.AlignType.Vertically);
195 | }
196 |
197 | private void AlignTestFunction(int[] ids, AlignTag.AlignType alignType)
198 | {
199 | AlignTag.Align align = new AlignTag.Align();
200 |
201 | ICollection selectedIds = ids.Select(id => new ElementId(id)).ToList();
202 |
203 | using (TransactionGroup txg = new TransactionGroup(document))
204 | {
205 | align.AlignTag(alignType, txg, selectedIds, document);
206 | }
207 | }
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/AlignTag/App.cs:
--------------------------------------------------------------------------------
1 | #region Namespaces
2 | using System;
3 | using System.Collections.Generic;
4 | using Autodesk.Revit.ApplicationServices;
5 | using Autodesk.Revit.Attributes;
6 | using Autodesk.Revit.DB;
7 | using Autodesk.Revit.UI;
8 | using System.Windows.Media;
9 | using System.Windows.Media.Imaging;
10 | using System.Reflection;
11 | using System.IO;
12 | #endregion
13 |
14 | namespace AlignTag
15 | {
16 | class App : IExternalApplication
17 | {
18 | public Result OnStartup(UIControlledApplication a)
19 | {
20 |
21 | //Create the panel for BIM42 Tools
22 | RibbonPanel AlignPanel = a.CreateRibbonPanel("Align");
23 |
24 | //Create icons in this panel
25 | Icons.CreateIcons(AlignPanel);
26 |
27 | return Result.Succeeded;
28 | }
29 |
30 | public Result OnShutdown(UIControlledApplication a)
31 | {
32 | return Result.Succeeded;
33 | }
34 | }
35 |
36 | class Icons
37 | {
38 | public static void CreateIcons(RibbonPanel bim42Panel)
39 | {
40 | //Retrive dll path
41 | string DllPath = Assembly.GetExecutingAssembly().Location;
42 |
43 | //Create contextual help
44 | string helpPath = "https://witty-river-01a861010.2.azurestaticapps.net/Align/Align.html";
45 | ContextualHelp help = new ContextualHelp(ContextualHelpType.Url, helpPath);
46 |
47 |
48 | //Add Align Left Button
49 | PushButtonData alignLeftButton = new PushButtonData("alignLeftButton", "Align Left", DllPath, "AlignTag.AlignLeft");
50 | alignLeftButton.ToolTip = "Align Tags or Elements Left";
51 | alignLeftButton.LargeImage = RetriveImage("AlignTag.Resources.align-left-large.png");
52 | alignLeftButton.Image = RetriveImage("AlignTag.Resources.align-left-small.png");
53 | alignLeftButton.SetContextualHelp(help);
54 |
55 | //Add Align Right Button
56 | PushButtonData alignRightButton = new PushButtonData("alignRightButton", "Align Right", DllPath, "AlignTag.AlignRight");
57 | alignRightButton.ToolTip = "Align Tags or Elements Right";
58 | alignRightButton.LargeImage = RetriveImage("AlignTag.Resources.align-right-large.png");
59 | alignRightButton.Image = RetriveImage("AlignTag.Resources.align-right-small.png");
60 | alignRightButton.SetContextualHelp(help);
61 |
62 | //Add Align TOp Button
63 | PushButtonData alignTopButton = new PushButtonData("alignTopButton", "Align Top", DllPath, "AlignTag.AlignTop");
64 | alignTopButton.ToolTip = "Align Tags or Elements Top";
65 | alignTopButton.LargeImage = RetriveImage("AlignTag.Resources.align-top-large.png");
66 | alignTopButton.Image = RetriveImage("AlignTag.Resources.align-top-small.png");
67 | alignTopButton.SetContextualHelp(help);
68 |
69 | //Add Align bottom Button
70 | PushButtonData alignBottomButton = new PushButtonData("alignBottomButton", "Align Bottom", DllPath, "AlignTag.AlignBottom");
71 | alignBottomButton.ToolTip = "Align Tags or Elements Bottom";
72 | alignBottomButton.LargeImage = RetriveImage("AlignTag.Resources.align-bottom-large.png");
73 | alignBottomButton.Image = RetriveImage("AlignTag.Resources.align-bottom-small.png");
74 | alignBottomButton.SetContextualHelp(help);
75 |
76 | //Add Align Center Button
77 | PushButtonData alignCenterButton = new PushButtonData("alignCenterButton", "Align Center", DllPath, "AlignTag.AlignCenter");
78 | alignCenterButton.ToolTip = "Align Tags or Elements Center";
79 | alignCenterButton.LargeImage = RetriveImage("AlignTag.Resources.align-center-large.png");
80 | alignCenterButton.Image = RetriveImage("AlignTag.Resources.align-center-small.png");
81 | alignCenterButton.SetContextualHelp(help);
82 |
83 | //Add Align Middle Button
84 | PushButtonData alignMiddleButton = new PushButtonData("alignMiddleButton", "Align Middle", DllPath, "AlignTag.AlignMiddle");
85 | alignMiddleButton.ToolTip = "Align Tags or Elements Middle";
86 | alignMiddleButton.LargeImage = RetriveImage("AlignTag.Resources.align-middle-large.png");
87 | alignMiddleButton.Image = RetriveImage("AlignTag.Resources.align-middle-small.png");
88 | alignMiddleButton.SetContextualHelp(help);
89 |
90 | //Add Distribute horizontally Button
91 | PushButtonData distributeHorizontallyButton = new PushButtonData("distributeHorizontallyButton", "Distribute\nHorizontally", DllPath, "AlignTag.DistributeHorizontally");
92 | distributeHorizontallyButton.ToolTip = "Distribute Tags or Elements Horizontally";
93 | distributeHorizontallyButton.LargeImage = RetriveImage("AlignTag.Resources.distribute-horizontally-large.png");
94 | distributeHorizontallyButton.Image = RetriveImage("AlignTag.Resources.distribute-horizontally-small.png");
95 | distributeHorizontallyButton.SetContextualHelp(help);
96 |
97 | //Add Distribute vertically Button
98 | PushButtonData distributeVerticallyButton = new PushButtonData("distributeVerticallyButton", "Distribute\nVertically", DllPath, "AlignTag.DistributeVertically");
99 | distributeVerticallyButton.ToolTip = "Distribute Tags or Elements Vertically";
100 | distributeVerticallyButton.LargeImage = RetriveImage("AlignTag.Resources.distribute-vertically-large.png");
101 | distributeVerticallyButton.Image = RetriveImage("AlignTag.Resources.distribute-vertically-small.png");
102 | distributeVerticallyButton.SetContextualHelp(help);
103 |
104 | //Add Arrange Button
105 | PushButtonData arrangeButton = new PushButtonData("ArrangeButton", "Arrange\nTags", DllPath, "AlignTag.Arrange");
106 | arrangeButton.ToolTip = "Arrange Tags around the view";
107 | arrangeButton.LargeImage = RetriveImage("AlignTag.Resources.arrange-large.png");
108 | arrangeButton.Image = RetriveImage("AlignTag.Resources.arrange-small.png");
109 | arrangeButton.SetContextualHelp(help);
110 |
111 | //Add Untangle Vertically Button
112 | PushButtonData untangleVerticallyButton = new PushButtonData("UntangleVerticallyButton", "Untangle\nVertically", DllPath, "AlignTag.UntangleVertically");
113 | untangleVerticallyButton.ToolTip = "Untangle Vertically Tags or Elements ";
114 | untangleVerticallyButton.LargeImage = RetriveImage("AlignTag.Resources.untangle-vertically-large.png");
115 | untangleVerticallyButton.Image = RetriveImage("AlignTag.Resources.untangle-vertically-small.png");
116 | untangleVerticallyButton.SetContextualHelp(help);
117 |
118 | //Add Untangle Horizontally Button
119 | PushButtonData untangleHorizontallyButton = new PushButtonData("UntangleHorizontallyButton", "Untangle\nHorizontally", DllPath, "AlignTag.UntangleHorizontally");
120 | untangleHorizontallyButton.ToolTip = "Untangle Horizontally Tags or Elements ";
121 | untangleHorizontallyButton.LargeImage = RetriveImage("AlignTag.Resources.untangle-horizontally-large.png");
122 | untangleHorizontallyButton.Image = RetriveImage("AlignTag.Resources.untangle-horizontally-small.png");
123 | untangleHorizontallyButton.SetContextualHelp(help);
124 |
125 | bim42Panel.AddStackedItems(alignLeftButton, alignCenterButton, alignRightButton);
126 | bim42Panel.AddStackedItems(alignTopButton, alignMiddleButton, alignBottomButton);
127 | bim42Panel.AddStackedItems(distributeHorizontallyButton, distributeVerticallyButton, arrangeButton);
128 | bim42Panel.AddStackedItems(untangleVerticallyButton, untangleHorizontallyButton);
129 |
130 | }
131 |
132 | private static ImageSource RetriveImage(string imagePath)
133 | {
134 | Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(imagePath);
135 |
136 | switch (imagePath.Substring(imagePath.Length - 3))
137 | {
138 | case "jpg":
139 | var jpgDecoder = new System.Windows.Media.Imaging.JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
140 | return jpgDecoder.Frames[0];
141 | case "bmp":
142 | var bmpDecoder = new System.Windows.Media.Imaging.BmpBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
143 | return bmpDecoder.Frames[0];
144 | case "png":
145 | var pngDecoder = new System.Windows.Media.Imaging.PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
146 | return pngDecoder.Frames[0];
147 | case "ico":
148 | var icoDecoder = new System.Windows.Media.Imaging.IconBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
149 | return icoDecoder.Frames[0];
150 | default:
151 | return null;
152 | }
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/AlignTag/Properties/Resources.Designer (1).cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34014
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace AlignTag.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AlignTag.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap AlignBottomLarge {
67 | get {
68 | object obj = ResourceManager.GetObject("AlignBottomLarge", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap AlignBottomSmall {
77 | get {
78 | object obj = ResourceManager.GetObject("AlignBottomSmall", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized resource of type System.Byte[].
85 | ///
86 | internal static byte[] AlignHelp {
87 | get {
88 | object obj = ResourceManager.GetObject("AlignHelp", resourceCulture);
89 | return ((byte[])(obj));
90 | }
91 | }
92 |
93 | ///
94 | /// Looks up a localized resource of type System.Drawing.Bitmap.
95 | ///
96 | internal static System.Drawing.Bitmap AlignLeftLarge {
97 | get {
98 | object obj = ResourceManager.GetObject("AlignLeftLarge", resourceCulture);
99 | return ((System.Drawing.Bitmap)(obj));
100 | }
101 | }
102 |
103 | ///
104 | /// Looks up a localized resource of type System.Drawing.Bitmap.
105 | ///
106 | internal static System.Drawing.Bitmap AlignLeftSmall {
107 | get {
108 | object obj = ResourceManager.GetObject("AlignLeftSmall", resourceCulture);
109 | return ((System.Drawing.Bitmap)(obj));
110 | }
111 | }
112 |
113 | ///
114 | /// Looks up a localized resource of type System.Drawing.Bitmap.
115 | ///
116 | internal static System.Drawing.Bitmap AlignRightLarge {
117 | get {
118 | object obj = ResourceManager.GetObject("AlignRightLarge", resourceCulture);
119 | return ((System.Drawing.Bitmap)(obj));
120 | }
121 | }
122 |
123 | ///
124 | /// Looks up a localized resource of type System.Drawing.Bitmap.
125 | ///
126 | internal static System.Drawing.Bitmap AlignRightSmall {
127 | get {
128 | object obj = ResourceManager.GetObject("AlignRightSmall", resourceCulture);
129 | return ((System.Drawing.Bitmap)(obj));
130 | }
131 | }
132 |
133 | ///
134 | /// Looks up a localized resource of type System.Drawing.Bitmap.
135 | ///
136 | internal static System.Drawing.Bitmap AlignTopLarge {
137 | get {
138 | object obj = ResourceManager.GetObject("AlignTopLarge", resourceCulture);
139 | return ((System.Drawing.Bitmap)(obj));
140 | }
141 | }
142 |
143 | ///
144 | /// Looks up a localized resource of type System.Drawing.Bitmap.
145 | ///
146 | internal static System.Drawing.Bitmap AlignTopSmall {
147 | get {
148 | object obj = ResourceManager.GetObject("AlignTopSmall", resourceCulture);
149 | return ((System.Drawing.Bitmap)(obj));
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized resource of type System.Drawing.Bitmap.
155 | ///
156 | internal static System.Drawing.Bitmap ArrangeLarge {
157 | get {
158 | object obj = ResourceManager.GetObject("ArrangeLarge", resourceCulture);
159 | return ((System.Drawing.Bitmap)(obj));
160 | }
161 | }
162 |
163 | ///
164 | /// Looks up a localized resource of type System.Drawing.Bitmap.
165 | ///
166 | internal static System.Drawing.Bitmap ArrangeSmall {
167 | get {
168 | object obj = ResourceManager.GetObject("ArrangeSmall", resourceCulture);
169 | return ((System.Drawing.Bitmap)(obj));
170 | }
171 | }
172 |
173 | ///
174 | /// Looks up a localized resource of type System.Drawing.Bitmap.
175 | ///
176 | internal static System.Drawing.Bitmap DistributeHorizontallyLarge {
177 | get {
178 | object obj = ResourceManager.GetObject("DistributeHorizontallyLarge", resourceCulture);
179 | return ((System.Drawing.Bitmap)(obj));
180 | }
181 | }
182 |
183 | ///
184 | /// Looks up a localized resource of type System.Drawing.Bitmap.
185 | ///
186 | internal static System.Drawing.Bitmap DistributeHorizontallySmall {
187 | get {
188 | object obj = ResourceManager.GetObject("DistributeHorizontallySmall", resourceCulture);
189 | return ((System.Drawing.Bitmap)(obj));
190 | }
191 | }
192 |
193 | ///
194 | /// Looks up a localized resource of type System.Drawing.Bitmap.
195 | ///
196 | internal static System.Drawing.Bitmap DistributeVerticallyLarge {
197 | get {
198 | object obj = ResourceManager.GetObject("DistributeVerticallyLarge", resourceCulture);
199 | return ((System.Drawing.Bitmap)(obj));
200 | }
201 | }
202 |
203 | ///
204 | /// Looks up a localized resource of type System.Drawing.Bitmap.
205 | ///
206 | internal static System.Drawing.Bitmap DistributeVerticallySmall {
207 | get {
208 | object obj = ResourceManager.GetObject("DistributeVerticallySmall", resourceCulture);
209 | return ((System.Drawing.Bitmap)(obj));
210 | }
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/AlignTag/Tools.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Resources;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using Autodesk.Revit.DB;
8 | using System.IO;
9 |
10 | namespace AlignTag
11 | {
12 | class Tools
13 | {
14 | //Define cultureInfo
15 | public static ResourceManager LangResMan; // declare Resource manager to access to specific cultureinfo
16 | public static CultureInfo Cult; // declare culture info
17 |
18 | public static void GetLocalisationValues()
19 | {
20 | //Create the culture for english
21 | Tools.Cult = CultureInfo.CreateSpecificCulture("en");
22 | Tools.LangResMan = new System.Resources.ResourceManager("BIM42.Revit2015.Resources.en", System.Reflection.Assembly.GetExecutingAssembly());
23 | }
24 |
25 | public static double? GetValueFromString(string text)
26 | {
27 | //Check the string value
28 | string heightValueString;
29 | double lenght;
30 |
31 |
32 | if (text.Contains(" mm"))
33 | {
34 | heightValueString = text.Replace(" mm", "");
35 | }
36 | else if (text.Contains("mm"))
37 | {
38 | heightValueString = text.Replace("mm", "");
39 | }
40 | else
41 | {
42 | heightValueString = text;
43 | }
44 |
45 | if (double.TryParse(heightValueString, out lenght))
46 | {
47 | return lenght;
48 | }
49 | else
50 | {
51 | return null;
52 | }
53 |
54 | }
55 |
56 | public static void ExtractRessource(string resourceName, string path)
57 | {
58 | using (Stream input = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
59 | using (Stream output = File.Create(path))
60 | {
61 |
62 | // Insert null checking here for production
63 | byte[] buffer = new byte[8192];
64 |
65 | int bytesRead;
66 | while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
67 | {
68 | output.Write(buffer, 0, bytesRead);
69 | }
70 |
71 | }
72 | }
73 |
74 | internal static ICollection RevitReferencesToElementIds(Document doc, IList selectedReferences)
75 | {
76 | return selectedReferences.Select(x => doc.GetElement(x).Id).ToList();
77 | }
78 |
79 | public static void CreateDebuggingSphere(Document doc, XYZ point, string value, Color color)
80 | {
81 |
82 | using (Transaction tx = new Transaction(doc))
83 | {
84 |
85 | tx.Start("Create Direct Shapes Spheres");
86 |
87 | Solid solid = CreateSphereAt(point, 0.5);
88 |
89 | CreateDirectShape(doc, solid, color, value + "{" + point.X + "," + point.Y + "," + point.Z + "}");
90 |
91 | tx.Commit();
92 | }
93 | }
94 |
95 | public static void DrawInView(Document doc, View view, XYZ point)
96 | {
97 |
98 | // Create a geometry plane
99 |
100 | XYZ origin = view.CropBox.Transform.Inverse.OfPoint(point);
101 | XYZ normal = view.ViewDirection;
102 |
103 | Plane geomPlane = Plane.CreateByNormalAndOrigin(normal, origin);
104 |
105 | //Create a circle
106 | Arc geomCircle = Arc.Create(origin, 10, 0, 2.0 * Math.PI, geomPlane.XVec, geomPlane.YVec);
107 |
108 |
109 | // Create a sketch plane in current document
110 |
111 | SketchPlane.Create(doc, geomPlane);
112 |
113 | // Create a DetailLine element using the
114 | // newly created geometry line and sketch plane
115 |
116 | DetailLine line = doc.Create.NewDetailCurve(view, geomCircle) as DetailLine;
117 |
118 |
119 | }
120 |
121 | public void DrawInViewCoordinates(Document doc)
122 | {
123 | View view = doc.ActiveView;
124 |
125 | //0 of the view
126 | XYZ origin = new XYZ(0, 0, 0);
127 | //In the model reference
128 | XYZ viewOriginInodel = view.CropBox.Transform.OfPoint(origin);
129 | Solid originSolid = CreateSphereAt(viewOriginInodel, 0.1);
130 | CreateDirectShape(doc, originSolid, new Color(0, 255, 0), "View Origin");
131 |
132 |
133 | origin = new XYZ(1, 0, 0);
134 | //In the model reference
135 | viewOriginInodel = view.CropBox.Transform.OfPoint(origin);
136 | originSolid = CreateSphereAt(viewOriginInodel, 0.1);
137 | CreateDirectShape(doc, originSolid, new Color(0, 255, 0), "View X");
138 |
139 | origin = new XYZ(0, 1, 0);
140 | //In the model reference
141 | viewOriginInodel = view.CropBox.Transform.OfPoint(origin);
142 | originSolid = CreateSphereAt(viewOriginInodel, 0.1);
143 | CreateDirectShape(doc, originSolid, new Color(0, 255, 0), "View Y");
144 |
145 | origin = new XYZ(0, 0, 1);
146 | //In the model reference
147 | viewOriginInodel = view.CropBox.Transform.OfPoint(origin);
148 | originSolid = CreateSphereAt(viewOriginInodel, 0.1);
149 | CreateDirectShape(doc, originSolid, new Color(0, 255, 0), "View Z");
150 |
151 | }
152 |
153 |
154 |
155 | private static void CreateDirectShape(Document doc, Solid solid, Color color, string paramValue)
156 | {
157 | OverrideGraphicSettings ogs = new OverrideGraphicSettings();
158 | //ogs.SetProjectionFillColor(color); //new Color(0,255,0)
159 | //ogs.SetProjectionFillPatternId(new ElementId(4));
160 | //ogs.SetProjectionFillPatternVisible(true);
161 |
162 | // create direct shape and assign the sphere shape
163 | DirectShape dsmax = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
164 |
165 | dsmax.ApplicationId = "ApplicationID";
166 | dsmax.ApplicationDataId = "ApplicationDataId";
167 |
168 | dsmax.SetShape(new GeometryObject[] { solid });
169 | doc.ActiveView.SetElementOverrides(dsmax.Id, ogs);
170 |
171 | Parameter parameter = dsmax.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
172 | parameter.Set(paramValue);
173 | }
174 |
175 | ///
176 | /// Create and return a solid sphere with
177 | /// a given radius and centre point.
178 | ///
179 | private static Solid CreateSphereAt(XYZ centre, double radius)
180 | {
181 | // Use the standard global coordinate system
182 | // as a frame, translated to the sphere centre.
183 |
184 | Frame frame = new Frame(centre, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ);
185 |
186 | // Create a vertical half-circle loop;
187 | // this must be in the frame location.
188 |
189 | Arc arc = Arc.Create(centre - radius * XYZ.BasisZ, centre + radius * XYZ.BasisZ, centre + radius * XYZ.BasisX);
190 |
191 | Line line = Line.CreateBound(arc.GetEndPoint(1), arc.GetEndPoint(0));
192 |
193 | CurveLoop halfCircle = new CurveLoop(); halfCircle.Append(arc); halfCircle.Append(line);
194 |
195 | List loops = new List(1);
196 |
197 | loops.Add(halfCircle);
198 |
199 | return GeometryCreationUtilities.CreateRevolvedGeometry(frame, loops, 0, 2 * Math.PI);
200 | }
201 |
202 | }
203 |
204 | ///
205 | /// Retrive the error message for displaying it in the Revit interface
206 | ///
207 | public class ErrorMessageException : ApplicationException
208 | {
209 | ///
210 | /// constructor entirely using baseclass'
211 | ///
212 | public ErrorMessageException()
213 | : base()
214 | {
215 | }
216 |
217 | ///
218 | /// constructor entirely using baseclass'
219 | ///
220 | /// error message
221 | public ErrorMessageException(String message)
222 | : base(message)
223 | {
224 | }
225 | }
226 |
227 |
228 | ///
229 | /// Manage Warning in the Revit interface
230 | ///
231 | public class TemporaryCommitPreprocessor : IFailuresPreprocessor
232 | {
233 | public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
234 | {
235 | IList failList = new List();
236 | // Inside event handler, get all warnings
237 | failList = failuresAccessor.GetFailureMessages();
238 | foreach (FailureMessageAccessor failure in failList)
239 | {
240 | // check FailureDefinitionIds against ones that you want to dismiss,
241 | FailureDefinitionId failID = failure.GetFailureDefinitionId();
242 | // prevent Revit from showing Unenclosed room warnings
243 | if (failID == BuiltInFailures.RoomFailures.RoomTagNotInRoom ||
244 | failID == BuiltInFailures.RoomFailures.RoomTagNotInRoomToArea ||
245 | failID == BuiltInFailures.RoomFailures.RoomTagNotInRoomToRoom ||
246 | failID == BuiltInFailures.RoomFailures.RoomTagNotInRoomToSpace)
247 | {
248 | failuresAccessor.DeleteWarning(failure);
249 | }
250 | }
251 |
252 | return FailureProcessingResult.Continue;
253 | }
254 | }
255 |
256 | }
257 |
--------------------------------------------------------------------------------
/AlignTag/AlignTag.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 |
7 |
8 |
9 |
10 | {AB14DB7D-855A-4952-8BD5-752DDDD05D7E}
11 | Library
12 | Properties
13 | AlignTag
14 | v4.8
15 | 512
16 |
17 |
18 |
19 | true
20 | bin\2024Debug\
21 | DEBUG;TRACE;Version2024
22 | full
23 | x64
24 | 7.3
25 | prompt
26 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\Revit.exe
27 | Program
28 |
29 |
30 | bin\2024Release\
31 | TRACE;Version2024
32 | true
33 | pdbonly
34 | x64
35 | 7.3
36 | prompt
37 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\Revit.exe
38 | Program
39 |
40 |
41 | true
42 | bin\2023Debug\
43 | DEBUG;TRACE;Version2023
44 | full
45 | x64
46 | 7.3
47 | prompt
48 | $(PROGRAMFILES)\Autodesk\Revit 2023\Revit.exe
49 | Program
50 |
51 |
52 | bin\2023Release\
53 | TRACE;Version2023
54 | true
55 | pdbonly
56 | x64
57 | 7.3
58 | prompt
59 | $(PROGRAMFILES)\Autodesk\Revit 2023\Revit.exe
60 | Program
61 |
62 |
63 | true
64 | bin\2022Debug\
65 | DEBUG;TRACE;Version2022
66 | full
67 | x64
68 | 7.3
69 | prompt
70 | $(PROGRAMFILES)\Autodesk\Revit 2022\Revit.exe
71 | Program
72 |
73 |
74 | bin\2022Release\
75 | TRACE;Version2022
76 | true
77 | pdbonly
78 | x64
79 | 7.3
80 | prompt
81 | $(PROGRAMFILES)\Autodesk\Revit 2022\Revit.exe
82 | Program
83 |
84 |
85 | true
86 | bin\2021Debug\
87 | DEBUG;TRACE;Version2021
88 | full
89 | x64
90 | 7.3
91 | prompt
92 | $(PROGRAMFILES)\Autodesk\Revit 2021\Revit.exe
93 | Program
94 |
95 |
96 | bin\2021Release\
97 | TRACE;Version2021
98 | true
99 | pdbonly
100 | x64
101 | 7.3
102 | prompt
103 | $(PROGRAMFILES)\Autodesk\Revit 2021\Revit.exe
104 | Program
105 |
106 |
107 | true
108 | bin\2020Debug\
109 | DEBUG;TRACE;Version2020
110 | full
111 | x64
112 | 7.3
113 | prompt
114 | $(PROGRAMFILES)\Autodesk\Revit 2020\Revit.exe
115 | Program
116 |
117 |
118 | bin\2020Release\
119 | TRACE;Version2020
120 | true
121 | pdbonly
122 | x64
123 | 7.3
124 | prompt
125 | $(PROGRAMFILES)\Autodesk\Revit 2020\Revit.exe
126 | Program
127 |
128 |
129 | true
130 | bin\2019Debug\
131 | DEBUG;TRACE;Version2019
132 | full
133 | x64
134 | 7.3
135 | prompt
136 | $(PROGRAMFILES)\Autodesk\Revit 2019\Revit.exe
137 | Program
138 |
139 |
140 | bin\2019Release\
141 | TRACE;Version2019
142 | true
143 | pdbonly
144 | x64
145 | 7.3
146 | prompt
147 | $(PROGRAMFILES)\Autodesk\Revit 2019\Revit.exe
148 | Program
149 |
150 |
151 |
152 |
153 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\RevitAPI.dll
154 | False
155 |
156 |
157 | $(PROGRAMFILES)\Autodesk\Revit Preview Release\RevitAPIUI.dll
158 | False
159 |
160 |
161 |
162 | $(PROGRAMFILES)\Autodesk\Revit 2023\RevitAPI.dll
163 | False
164 |
165 |
166 | $(PROGRAMFILES)\Autodesk\Revit 2023\RevitAPIUI.dll
167 | False
168 |
169 |
170 |
171 | $(PROGRAMFILES)\Autodesk\Revit 2022\RevitAPI.dll
172 | False
173 |
174 |
175 | $(PROGRAMFILES)\Autodesk\Revit 2022\RevitAPIUI.dll
176 | False
177 |
178 |
179 |
180 | $(PROGRAMFILES)\Autodesk\Revit 2021\RevitAPI.dll
181 | False
182 |
183 |
184 | $(PROGRAMFILES)\Autodesk\Revit 2021\RevitAPIUI.dll
185 | False
186 |
187 |
188 |
189 | $(PROGRAMFILES)\Autodesk\Revit 2020\RevitAPI.dll
190 | False
191 |
192 |
193 | $(PROGRAMFILES)\Autodesk\Revit 2020\RevitAPIUI.dll
194 | False
195 |
196 |
197 |
198 | $(PROGRAMFILES)\Autodesk\Revit 2019\RevitAPI.dll
199 | False
200 |
201 |
202 | $(PROGRAMFILES)\Autodesk\Revit 2019\RevitAPIUI.dll
203 | False
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | True
228 | True
229 | Resources.resx
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 | ResXFileCodeGenerator
240 | Resources.Designer.cs
241 | Designer
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 | powershell -ExecutionPolicy Unrestricted $(ProjectDir)PostBuild.ps1 -Configuration $(Configuration) -TargetName $(TargetName) -ProjectDir $(ProjectDir) -TargetPath $(TargetPath) -TargetDir $(TargetDir)
278 |
279 |
--------------------------------------------------------------------------------
/AlignTag/AnnotationElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Autodesk.Revit.DB;
7 | using Autodesk.Revit.UI;
8 | using Autodesk.Revit.DB.Architecture;
9 | using Autodesk.Revit.DB.Mechanical;
10 |
11 | namespace AlignTag
12 | {
13 | class AnnotationElement
14 | {
15 | public XYZ Center { get; set; }
16 |
17 | public XYZ UpLeft { get; set; }
18 |
19 | public XYZ UpRight { get; set; }
20 |
21 | public XYZ DownLeft { get; set; }
22 |
23 | public XYZ DownRight { get; set; }
24 |
25 | public Element Parent { get; set; }
26 |
27 | private Document _doc;
28 | private View _ownerView;
29 |
30 | public AnnotationElement(PreparationElement preparationElement)
31 | {
32 | Element e = preparationElement.Element;
33 | Parent = e;
34 | _doc = e.Document;
35 |
36 |
37 | if (_doc.GetElement(e.OwnerViewId) != null)
38 | {
39 | _ownerView = _doc.GetElement(e.OwnerViewId) as View;
40 | }
41 | else
42 | {
43 | _ownerView = _doc.ActiveView;
44 | }
45 |
46 |
47 | //Create the view plan
48 | Plane viewPlane = Plane.CreateByNormalAndOrigin(_ownerView.ViewDirection, _ownerView.Origin);
49 |
50 | BoundingBoxXYZ elementBBox = e.get_BoundingBox(_ownerView);
51 |
52 | XYZ globalMax = elementBBox.Max;
53 | XYZ globalMin = elementBBox.Min;
54 |
55 | if (preparationElement.DisplacementVector != null)
56 | {
57 | globalMax = elementBBox.Max - preparationElement.DisplacementVector;
58 | globalMin = elementBBox.Min - preparationElement.DisplacementVector;
59 | }
60 |
61 | double distanceProjected = ProjectedDistance(viewPlane, globalMax, globalMin);
62 |
63 | XYZ alternateMax = new XYZ(globalMax.X, globalMin.Y, globalMax.Z);
64 | XYZ alternateMin = new XYZ(globalMin.X, globalMax.Y, globalMin.Z);
65 | double alternateDistanceProjected = ProjectedDistance(viewPlane, alternateMax, alternateMin);
66 |
67 | if (alternateDistanceProjected > distanceProjected)
68 | {
69 | globalMax = alternateMax;
70 | globalMin = alternateMin;
71 | }
72 |
73 | Transform ownerViewTransform = _ownerView.CropBox.Transform;
74 | XYZ max = ownerViewTransform.Inverse.OfPoint(globalMax); //Max in the coordinate space of the view
75 | XYZ min = ownerViewTransform.Inverse.OfPoint(globalMin); //Min in the coordinate space of the view
76 |
77 | UpLeft = new XYZ(GetMin(min.X, max.X), GetMax(max.Y, min.Y), 0);
78 | UpRight = new XYZ(GetMax(min.X, max.X), GetMax(max.Y, min.Y), 0);
79 | DownLeft = new XYZ(GetMin(min.X, max.X), GetMin(max.Y, min.Y), 0);
80 | DownRight = new XYZ(GetMax(min.X, max.X), GetMin(max.Y, min.Y), 0);
81 |
82 | Center = (UpRight + DownLeft) / 2;
83 |
84 | }
85 |
86 | public override string ToString()
87 | {
88 | string[] Valueparams = new string[] {Parent.Id.ToString(),
89 | UpLeft.X.ToString(), UpLeft.Y.ToString(), UpLeft.Z.ToString(),
90 | UpRight.X.ToString(), UpRight.Y.ToString(), UpRight.Z.ToString(),
91 | DownLeft.X.ToString(), DownLeft.Y.ToString(), DownLeft.Z.ToString(),
92 | DownRight.X.ToString(), DownRight.Y.ToString(), DownRight.Z.ToString(),
93 | Center.X.ToString(), Center.Y.ToString(), Center.Z.ToString() };
94 |
95 | return String.Join(",", Valueparams);
96 | }
97 |
98 | private double ProjectedDistance(Plane plane, XYZ pointA, XYZ pointB)
99 | {
100 | //To be tested
101 | XYZ UVA = ProjectionOnPlane(pointA, plane);
102 | XYZ UVB = ProjectionOnPlane(pointB, plane);
103 |
104 | return UVA.DistanceTo(UVB);
105 | }
106 |
107 | private XYZ ProjectionOnPlane(XYZ q, Plane plane)
108 | {
109 | //The projection of a point q = (x, y, z) onto a plane given by a point p = (a, b, c) and a normal n = (d, e, f) is
110 | // q_proj = q - dot(q - p, n) * n
111 |
112 | XYZ p = plane.Origin;
113 | XYZ n = plane.Normal.Normalize();
114 | XYZ q_proj = q - n.Multiply(n.DotProduct(q - p));
115 |
116 | return q_proj;
117 | }
118 |
119 | private double GetMax(double value1, double value2)
120 | {
121 | if (value1 >= value2)
122 | {
123 | return value1;
124 | }
125 | else
126 | {
127 | return value2;
128 | }
129 | }
130 |
131 | private double GetMin(double value1, double value2)
132 | {
133 | if (value1 >= value2)
134 | {
135 | return value2;
136 | }
137 | else
138 | {
139 | return value1;
140 | }
141 | }
142 |
143 | public XYZ GetLeaderEnd()
144 | {
145 | XYZ LeaderEnd = this.Center;
146 | Element e = this.Parent;
147 | //Find the leader end, if any
148 | if (e.GetType() == typeof(IndependentTag))
149 | {
150 | IndependentTag tag = e as IndependentTag;
151 | if (tag.HasLeader)
152 | {
153 | if (tag.LeaderEndCondition == LeaderEndCondition.Free)
154 | {
155 | #if Version2022 || Version2023 || Version2024
156 | Reference referencedElement = tag.GetTaggedReferences().FirstOrDefault();
157 | if (referencedElement != null) LeaderEnd = tag.GetLeaderEnd(referencedElement);
158 | #elif Version2019 || Version2020 || Version2021
159 | LeaderEnd = tag.LeaderEnd;
160 | #endif
161 | }
162 | else
163 | {
164 | Element taggedElement = TagLeader.GetTaggedElement(_doc, tag);
165 | LeaderEnd = TagLeader.GetLeaderEnd(taggedElement, _ownerView);
166 | }
167 | }
168 | }
169 | else if (e.GetType() == typeof(TextNote))
170 | {
171 | TextNote note = e as TextNote;
172 | if (note.LeaderCount != 0)
173 | {
174 | LeaderEnd = note.GetLeaders().FirstOrDefault().End;
175 | }
176 |
177 | }
178 | else if (e.GetType().IsSubclassOf(typeof(SpatialElementTag)))
179 | {
180 | SpatialElementTag tag = e as SpatialElementTag;
181 |
182 | if (tag.HasLeader)
183 | {
184 | LeaderEnd = tag.LeaderEnd;
185 | }
186 | }
187 | else
188 | {
189 | LeaderEnd = Center;
190 | }
191 |
192 | return LeaderEnd;
193 | }
194 |
195 | public void MoveTo(XYZ point, AlignType alignType)
196 | {
197 | if (!Parent.Pinned)
198 | {
199 | XYZ displacementVector = new XYZ();
200 |
201 | switch (alignType)
202 | {
203 | case AlignType.Left:
204 | displacementVector = point - UpLeft;
205 | break;
206 | case AlignType.Right:
207 | displacementVector = point - UpRight;
208 | break;
209 | case AlignType.Up:
210 | displacementVector = point - UpRight;
211 | break;
212 | case AlignType.Down:
213 | displacementVector = point - DownRight;
214 | break;
215 | case AlignType.Center:
216 | displacementVector = point - Center;
217 | break;
218 | case AlignType.Middle:
219 | displacementVector = point - Center;
220 | break;
221 | case AlignType.Vertically:
222 | displacementVector = point - Center;
223 | break;
224 | case AlignType.Horizontally:
225 | displacementVector = point - Center;
226 | break;
227 | case AlignType.UntangleVertically:
228 | displacementVector = point - UpLeft;
229 | break;
230 | case AlignType.UntangleHorizontally:
231 | displacementVector = point - UpLeft;
232 | break;
233 | default:
234 | break;
235 | }
236 |
237 | if (!displacementVector.IsAlmostEqualTo(new XYZ(0, 0, 0)))
238 | {
239 | Transform tr = Transform.CreateTranslation(_ownerView.CropBox.Transform.OfVector(displacementVector));
240 |
241 | if (Parent.GetType() == typeof(IndependentTag))
242 | {
243 | IndependentTag tag = Parent as IndependentTag;
244 | CustomLeader customLeader = new CustomLeader();
245 | if (tag.HasLeader && tag.LeaderEndCondition == LeaderEndCondition.Free)
246 | {
247 | #if Version2022 || Version2023 || Version2024
248 | Reference referencedElement = tag.GetTaggedReferences().FirstOrDefault();
249 | if (referencedElement != null)
250 | {
251 | XYZ leaderEnd = tag.GetLeaderEnd(referencedElement);
252 | customLeader = new CustomLeader(leaderEnd, new XYZ(0, 0, 0));
253 | }
254 | else
255 | {
256 | customLeader = new CustomLeader(new XYZ(0, 0, 0), new XYZ(0, 0, 0));
257 | }
258 |
259 | #elif Version2019 || Version2020 || Version2021
260 | customLeader = new CustomLeader(tag.LeaderEnd, new XYZ(0, 0, 0));
261 | #endif
262 |
263 | }
264 |
265 | tag.TagHeadPosition = tr.OfPoint(tag.TagHeadPosition);
266 |
267 | if (tag.HasLeader && tag.LeaderEndCondition == LeaderEndCondition.Free)
268 | {
269 | #if Version2022 || Version2023 || Version2024
270 | Reference referencedElement = tag.GetTaggedReferences().FirstOrDefault();
271 | if (referencedElement != null)
272 | {
273 | tag.SetLeaderEnd(referencedElement, customLeader.End);
274 | }
275 |
276 | #elif Version2019 || Version2020 || Version2021
277 | tag.LeaderEnd = customLeader.End;
278 | #endif
279 |
280 | }
281 |
282 | }
283 | else if (Parent.GetType() == typeof(TextNote))
284 | {
285 | List leaders = new List();
286 | TextNote note = Parent as TextNote;
287 | if (note.LeaderCount != 0)
288 | {
289 | foreach (Leader leader in note.GetLeaders())
290 | {
291 | leaders.Add(new CustomLeader(leader));
292 | }
293 | }
294 |
295 | note.Coord = tr.OfPoint(note.Coord);
296 |
297 | if (leaders.Count != 0)
298 | {
299 | int i = 0;
300 | foreach (Leader leader in note.GetLeaders())
301 | {
302 | leader.End = leaders[i].End;
303 | leader.Elbow = leaders[i].Elbow;
304 | i++;
305 | }
306 | }
307 | }
308 | else if (Parent.GetType().IsSubclassOf(typeof(SpatialElementTag)))
309 | {
310 | SpatialElementTag spatialElementTag = Parent as SpatialElementTag;
311 |
312 | CustomLeader leader = null;
313 | if (spatialElementTag.HasLeader)
314 | {
315 | leader = new CustomLeader(spatialElementTag.LeaderEnd, new XYZ(0, 0, 0));
316 | }
317 |
318 | Parent.Location.Move(_ownerView.CropBox.Transform.OfVector(displacementVector));
319 |
320 | if (!spatialElementTag.IsOrphaned && !spatialElementTag.HasLeader)
321 | {
322 | RoomTag roomTag = spatialElementTag as RoomTag;
323 | if (roomTag != null && !roomTag.Room.IsPointInRoom(roomTag.TagHeadPosition))
324 | {
325 | spatialElementTag.HasLeader = true;
326 | }
327 |
328 | SpaceTag spaceTag = spatialElementTag as SpaceTag;
329 | if (spaceTag != null && !spaceTag.Space.IsPointInSpace(spaceTag.TagHeadPosition))
330 | {
331 | spatialElementTag.HasLeader = true;
332 | }
333 |
334 | AreaTag areaTag = spatialElementTag as AreaTag;
335 | if (areaTag != null)
336 | {
337 | areaTag.HasLeader = true;
338 | }
339 | }
340 |
341 | if (leader != null)
342 | {
343 | spatialElementTag.LeaderEnd = leader.End;
344 | }
345 |
346 |
347 | }
348 | else
349 | {
350 | Parent.Location.Move(_ownerView.CropBox.Transform.OfVector(displacementVector));
351 | }
352 | }
353 |
354 | }
355 |
356 | }
357 | }
358 |
359 | class CustomLeader
360 | {
361 | public XYZ End { get; set; }
362 | public XYZ Elbow { get; set; }
363 |
364 | public CustomLeader(Leader leader)
365 | {
366 | End = leader.End;
367 | Elbow = leader.Elbow;
368 | }
369 |
370 | public CustomLeader()
371 | {
372 | End = new XYZ(0, 0, 0);
373 | Elbow = new XYZ(0, 0, 0);
374 | }
375 |
376 | public CustomLeader(XYZ end, XYZ elbow)
377 | {
378 | End = end;
379 | Elbow = elbow;
380 | }
381 | }
382 |
383 | class PreparationElement
384 | {
385 | public PreparationElement(Element element, XYZ displacementVector)
386 | {
387 | Element = element;
388 | DisplacementVector = displacementVector;
389 | }
390 | public Element Element { get; set; }
391 | public XYZ DisplacementVector { get; set; }
392 | }
393 |
394 | public enum AlignType { Left, Right, Up, Down, Center, Middle, Vertically, Horizontally, UntangleVertically, UntangleHorizontally };
395 |
396 | class OffsetedElement
397 | {
398 | public OffsetedElement(Element e, XYZ offset)
399 | {
400 | Element = e;
401 | Offset = offset;
402 | }
403 |
404 | public Element Element { get; set; }
405 | public XYZ Offset { get; set; }
406 | }
407 | }
408 |
--------------------------------------------------------------------------------
/AlignTag/Align.cs:
--------------------------------------------------------------------------------
1 | #region Namespaces
2 | using System;
3 | using System.Linq;
4 | using System.Collections.Generic;
5 | using Autodesk.Revit.DB;
6 | using Autodesk.Revit.UI;
7 | using Autodesk.Revit.UI.Selection;
8 | using Autodesk.Revit.DB.Architecture;
9 | using Autodesk.Revit.DB.Mechanical;
10 | using System.Diagnostics;
11 | #endregion
12 |
13 | namespace AlignTag
14 | {
15 | public class Align
16 | {
17 | private UIDocument UIdoc;
18 | public Result AlignElements(ExternalCommandData commandData, ref string message, AlignType alignType)
19 | {
20 | // Get the handle of current document.
21 | UIdoc = commandData.Application.ActiveUIDocument;
22 | Document document = UIdoc.Document;
23 |
24 | using (TransactionGroup txg = new TransactionGroup(document))
25 | {
26 | try
27 | {
28 | ICollection selectedIds = UIdoc.Selection.GetElementIds();
29 |
30 | bool empty = false;
31 |
32 | if (selectedIds.Count == 0)
33 | {
34 | empty = true;
35 |
36 | IList selectedReferences = UIdoc.Selection.PickObjects(ObjectType.Element, "Pick elements to be aligned");
37 | selectedIds = Tools.RevitReferencesToElementIds(document, selectedReferences);
38 | UIdoc.Selection.SetElementIds(selectedIds);
39 | }
40 |
41 | AlignTag(alignType, txg, selectedIds, document);
42 |
43 | // Disselect if the selection was empty to begin with
44 | if (empty) selectedIds = new List { ElementId.InvalidElementId };
45 |
46 | UIdoc.Selection.SetElementIds(selectedIds);
47 |
48 | // Return Success
49 | return Result.Succeeded;
50 | }
51 |
52 | catch (Autodesk.Revit.Exceptions.OperationCanceledException exceptionCanceled)
53 | {
54 | Console.WriteLine(exceptionCanceled.Message);
55 | //message = exceptionCanceled.Message;
56 | if (txg.HasStarted())
57 | {
58 | txg.RollBack();
59 | }
60 | return Result.Cancelled;
61 | }
62 | catch (ErrorMessageException errorEx)
63 | {
64 | // checked exception need to show in error messagebox
65 | message = errorEx.Message;
66 | if (txg.HasStarted())
67 | {
68 | txg.RollBack();
69 | }
70 | return Result.Failed;
71 | }
72 | catch (Exception ex)
73 | {
74 | // unchecked exception cause command failed
75 | message = ex.Message;
76 | //Trace.WriteLine(ex.ToString());
77 | if (txg.HasStarted())
78 | {
79 | txg.RollBack();
80 | }
81 | return Result.Failed;
82 | }
83 | }
84 | }
85 |
86 |
87 | public void AlignTag(AlignType alignType, TransactionGroup txg, ICollection selectedIds, Document document)
88 | {
89 |
90 | // 1. First Proposed Change
91 | // First check if there is something that's been seleted, and if so - operate on that
92 | // However, if the Uidoc.Slection is empty, prompt for selection.
93 | // This allows you to stay on the 'Add-ins' Tab and keep using the 'Align' tab without going back and forth to 'Modify'
94 | // TO-DO: Should we disselect after we are done? (delete the boolean stuff if you don't think it's worth disselecting)
95 |
96 | using (Transaction tx = new Transaction(document))
97 | {
98 | txg.Start(AlignTypeToText(alignType));
99 |
100 | tx.Start("Prepare tags");
101 | Debug.WriteLine(DateTime.Now.ToString() + " - Start Prepare tags");
102 |
103 | List annotationElements = RetriveAnnotationElementsFromSelection(document, tx, selectedIds);
104 |
105 | txg.RollBack();
106 | // txg.Assimilate();
107 | Debug.WriteLine(DateTime.Now.ToString() + " - Rollback Prepare tags");
108 |
109 | txg.Start(AlignTypeToText(alignType));
110 |
111 | tx.Start(AlignTypeToText(alignType));
112 | Debug.WriteLine(DateTime.Now.ToString() + " - Start align tags");
113 |
114 | if (annotationElements.Count > 1)
115 | {
116 | AlignAnnotationElements(annotationElements, alignType, document);
117 | }
118 |
119 | Debug.WriteLine(DateTime.Now.ToString() + " - Commit align tags");
120 |
121 | tx.Commit();
122 |
123 | txg.Assimilate();
124 | }
125 | }
126 |
127 | private List RetriveAnnotationElementsFromSelection(Document document, Transaction tx, ICollection ids)
128 | {
129 | List preparationElements = new List();
130 |
131 | List annotationElements = new List();
132 |
133 |
134 | //Remove all leader to find the correct tag height and width
135 | foreach (ElementId id in ids)
136 | {
137 | Element e = document.GetElement(id);
138 |
139 | if (e.GetType() == typeof(IndependentTag))
140 | {
141 | IndependentTag tag = e as IndependentTag;
142 |
143 | //XYZ displacementVector = null;
144 | //if (tag.LeaderEndCondition == LeaderEndCondition.Free)
145 | //{
146 | // displacementVector = tag.LeaderEnd - tag.TagHeadPosition;
147 | //}
148 |
149 | if (tag.HasLeader)
150 | {
151 | tag.HasLeader = false;
152 | }
153 |
154 | preparationElements.Add(new PreparationElement(e, null));
155 |
156 |
157 | }
158 | else if (e.GetType() == typeof(TextNote))
159 | {
160 | TextNote note = e as TextNote;
161 | note.RemoveLeaders();
162 | preparationElements.Add(new PreparationElement(e, null));
163 | }
164 | else if (e.GetType().IsSubclassOf(typeof(SpatialElementTag)))
165 | {
166 | SpatialElementTag tag = e as SpatialElementTag;
167 |
168 | XYZ displacementVector = null;
169 |
170 | if (tag.HasLeader)
171 | {
172 | displacementVector = tag.LeaderEnd - tag.TagHeadPosition;
173 | tag.HasLeader = false;
174 | }
175 |
176 | preparationElements.Add(new PreparationElement(e, displacementVector));
177 | }
178 | else
179 | {
180 | preparationElements.Add(new PreparationElement(e, null));
181 | }
182 | }
183 |
184 | FailureHandlingOptions options = tx.GetFailureHandlingOptions();
185 |
186 | options.SetFailuresPreprocessor(new TemporaryCommitPreprocessor());
187 | // Now, showing of any eventual mini-warnings will be postponed until the following transaction.
188 | tx.Commit(options);
189 |
190 | foreach (PreparationElement e in preparationElements)
191 | {
192 | annotationElements.Add(new AnnotationElement(e));
193 | }
194 |
195 | return annotationElements;
196 | }
197 |
198 | private void AlignAnnotationElements(List annotationElements, AlignType alignType, Document document)
199 | {
200 | View currentView = document.ActiveView;
201 | XYZ displacementDirection = currentView.UpDirection;
202 |
203 | switch (alignType)
204 | {
205 | case AlignType.Left:
206 | AnnotationElement farthestAnnotation =
207 | annotationElements.OrderBy(x => x.UpLeft.X).FirstOrDefault();
208 | foreach (AnnotationElement annotationElement in annotationElements)
209 | {
210 | XYZ resultingPoint = new XYZ(farthestAnnotation.UpLeft.X, annotationElement.UpLeft.Y, 0);
211 | annotationElement.MoveTo(resultingPoint, AlignType.Left);
212 | }
213 | break;
214 | case AlignType.Right:
215 | farthestAnnotation =
216 | annotationElements.OrderByDescending(x => x.UpRight.X).FirstOrDefault();
217 | foreach (AnnotationElement annotationElement in annotationElements)
218 | {
219 | XYZ resultingPoint = new XYZ(farthestAnnotation.UpRight.X, annotationElement.UpRight.Y, 0);
220 | annotationElement.MoveTo(resultingPoint, AlignType.Right);
221 | }
222 | break;
223 | case AlignType.Up:
224 | farthestAnnotation =
225 | annotationElements.OrderByDescending(x => x.UpRight.Y).FirstOrDefault();
226 | foreach (AnnotationElement annotationElement in annotationElements)
227 | {
228 | XYZ resultingPoint = new XYZ(annotationElement.UpRight.X, farthestAnnotation.UpRight.Y, 0);
229 | annotationElement.MoveTo(resultingPoint, AlignType.Up);
230 | }
231 | break;
232 | case AlignType.Down:
233 | farthestAnnotation =
234 | annotationElements.OrderBy(x => x.DownRight.Y).FirstOrDefault();
235 | foreach (AnnotationElement annotationElement in annotationElements)
236 | {
237 | XYZ resultingPoint = new XYZ(annotationElement.DownRight.X, farthestAnnotation.DownRight.Y, 0);
238 | annotationElement.MoveTo(resultingPoint, AlignType.Down);
239 | }
240 | break;
241 | case AlignType.Center: //On the same vertical axe
242 | List sortedAnnotationElements = annotationElements.OrderBy(x => x.UpRight.X).ToList();
243 | AnnotationElement rightAnnotation = sortedAnnotationElements.LastOrDefault();
244 | AnnotationElement leftAnnotation = sortedAnnotationElements.FirstOrDefault();
245 | double XCoord = (rightAnnotation.Center.X + leftAnnotation.Center.X) / 2;
246 | foreach (AnnotationElement annotationElement in sortedAnnotationElements)
247 | {
248 | XYZ resultingPoint = new XYZ(XCoord, annotationElement.Center.Y, 0);
249 | annotationElement.MoveTo(resultingPoint, AlignType.Center);
250 | }
251 | break;
252 | case AlignType.Middle: //On the same horizontal axe
253 | sortedAnnotationElements = annotationElements.OrderBy(x => x.UpRight.Y).ToList();
254 | AnnotationElement upperAnnotation = sortedAnnotationElements.LastOrDefault();
255 | AnnotationElement lowerAnnotation = sortedAnnotationElements.FirstOrDefault();
256 | double YCoord = (upperAnnotation.Center.Y + lowerAnnotation.Center.Y) / 2;
257 | foreach (AnnotationElement annotationElement in sortedAnnotationElements)
258 | {
259 | XYZ resultingPoint = new XYZ(annotationElement.Center.X, YCoord, 0);
260 | annotationElement.MoveTo(resultingPoint, AlignType.Middle);
261 | }
262 | break;
263 | case AlignType.Vertically:
264 | sortedAnnotationElements = annotationElements.OrderBy(x => x.UpRight.Y).ToList();
265 | upperAnnotation = sortedAnnotationElements.LastOrDefault();
266 | lowerAnnotation = sortedAnnotationElements.FirstOrDefault();
267 | double spacing = (upperAnnotation.Center.Y - lowerAnnotation.Center.Y) / (annotationElements.Count - 1);
268 | int i = 0;
269 | foreach (AnnotationElement annotationElement in sortedAnnotationElements)
270 | {
271 | XYZ resultingPoint = new XYZ(annotationElement.Center.X, lowerAnnotation.Center.Y + i * spacing, 0);
272 | annotationElement.MoveTo(resultingPoint, AlignType.Vertically);
273 | i++;
274 | }
275 | break;
276 | case AlignType.Horizontally:
277 | sortedAnnotationElements = annotationElements.OrderBy(x => x.UpRight.X).ToList();
278 | rightAnnotation = sortedAnnotationElements.LastOrDefault();
279 | leftAnnotation = sortedAnnotationElements.FirstOrDefault();
280 | spacing = (rightAnnotation.Center.X - leftAnnotation.Center.X) / (annotationElements.Count - 1);
281 | i = 0;
282 | foreach (AnnotationElement annotationElement in sortedAnnotationElements)
283 | {
284 | XYZ resultingPoint = new XYZ(leftAnnotation.Center.X + i * spacing, annotationElement.Center.Y, 0);
285 | annotationElement.MoveTo(resultingPoint, AlignType.Horizontally);
286 | i++;
287 | }
288 | break;
289 | case AlignType.UntangleVertically:
290 | sortedAnnotationElements = annotationElements.OrderBy(y => y.GetLeaderEnd().Y).ToList();
291 | upperAnnotation = sortedAnnotationElements.FirstOrDefault();
292 | spacing = 0;
293 | foreach (AnnotationElement annotationElement in sortedAnnotationElements)
294 | {
295 | XYZ resultingPoint = new XYZ(annotationElement.UpLeft.X, upperAnnotation.UpLeft.Y + spacing, 0);
296 | annotationElement.MoveTo(resultingPoint, AlignType.UntangleVertically);
297 | spacing = spacing + (annotationElement.UpLeft.Y - annotationElement.DownLeft.Y);
298 | }
299 | break;
300 | case AlignType.UntangleHorizontally:
301 | sortedAnnotationElements = annotationElements.OrderBy(x => x.GetLeaderEnd().X).ToList();
302 | leftAnnotation = sortedAnnotationElements.FirstOrDefault();
303 | spacing = 0;
304 | foreach (AnnotationElement annotationElement in sortedAnnotationElements)
305 | {
306 | XYZ resultingPoint = new XYZ(leftAnnotation.UpLeft.X + spacing, annotationElement.UpLeft.Y, 0);
307 | annotationElement.MoveTo(resultingPoint, AlignType.UntangleHorizontally);
308 | spacing = spacing + (annotationElement.UpRight.X - annotationElement.UpLeft.X);
309 | }
310 | break;
311 | default:
312 | break;
313 | }
314 | }
315 |
316 | private string AlignTypeToText(AlignType alignType)
317 | {
318 | string text = "";
319 |
320 | switch (alignType)
321 | {
322 | case AlignType.Left:
323 | text = "Align Left";
324 | break;
325 | case AlignType.Right:
326 | text = "Align Right";
327 | break;
328 | case AlignType.Up:
329 | text = "Align Top";
330 | break;
331 | case AlignType.Down:
332 | text = "Align Bottom";
333 | break;
334 | case AlignType.Center:
335 | text = "Align Center";
336 | break;
337 | case AlignType.Middle:
338 | text = "Align Middle";
339 | break;
340 | case AlignType.Vertically:
341 | text = "Distribute Vertically";
342 | break;
343 | case AlignType.Horizontally:
344 | text = "Distribute Horizontally";
345 | break;
346 | case AlignType.UntangleVertically:
347 | text = "Untangle Vertically";
348 | break;
349 | case AlignType.UntangleHorizontally:
350 | text = "Untangle Horizontally";
351 | break;
352 | default:
353 | break;
354 | }
355 |
356 | return text;
357 | }
358 |
359 | }
360 | }
361 |
--------------------------------------------------------------------------------
/AlignTag/Arrange.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Autodesk.Revit.DB;
7 | using Autodesk.Revit.UI;
8 | using Autodesk.Revit.Attributes;
9 |
10 | namespace AlignTag
11 | {
12 | [Transaction(TransactionMode.Manual)]
13 | class Arrange : IExternalCommand
14 | {
15 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
16 | {
17 | UIDocument UIdoc = commandData.Application.ActiveUIDocument;
18 | Document doc = UIdoc.Document;
19 | using (TransactionGroup transGroup = new TransactionGroup(doc))
20 | {
21 |
22 | using (Transaction tx = new Transaction(doc))
23 | {
24 | try
25 | {
26 | transGroup.Start("Arrange Tags");
27 | // Add Your Code Here
28 | ArrangeTag(UIdoc, tx);
29 | transGroup.Assimilate();
30 | // Return Success
31 | return Result.Succeeded;
32 |
33 | }
34 |
35 | catch (Autodesk.Revit.Exceptions.OperationCanceledException exceptionCanceled)
36 | {
37 | message = exceptionCanceled.Message;
38 | if (tx.HasStarted())
39 | {
40 | tx.RollBack();
41 | }
42 | return Autodesk.Revit.UI.Result.Cancelled;
43 | }
44 | catch (ErrorMessageException errorEx)
45 | {
46 | // checked exception need to show in error messagebox
47 | message = errorEx.Message;
48 | if (tx.HasStarted())
49 | {
50 | tx.RollBack();
51 | }
52 | return Autodesk.Revit.UI.Result.Failed;
53 | }
54 | catch (Exception ex)
55 | {
56 | // unchecked exception cause command failed
57 | message = ex.Message;
58 | //Trace.WriteLine(ex.ToString());
59 | if (tx.HasStarted())
60 | {
61 | tx.RollBack();
62 | }
63 | return Autodesk.Revit.UI.Result.Failed;
64 | }
65 | }
66 |
67 | }
68 |
69 | }
70 |
71 | private void ArrangeTag(UIDocument uidoc, Transaction tx)
72 | {
73 | Document doc = uidoc.Document;
74 | View activeView = doc.ActiveView;
75 |
76 | //Check the current view
77 | if (!activeView.CropBoxActive)
78 | {
79 | throw new ErrorMessageException("Please set a crop box to the view");
80 | }
81 |
82 | IEnumerable tags = from elem in new FilteredElementCollector(doc, activeView.Id).OfClass(typeof(IndependentTag)).WhereElementIsNotElementType()
83 | let type = elem as IndependentTag
84 | where type.HasLeader == true
85 | select type;
86 |
87 | tx.Start("Prepare Tags");
88 |
89 | //Remove all leader to find the correct tag height and width
90 | foreach (IndependentTag tag in tags)
91 | {
92 | tag.LeaderEndCondition = LeaderEndCondition.Free;
93 |
94 | #if Version2022 || Version2023 || Version2024
95 | Reference referencedElement = tag.GetTaggedReferences().FirstOrDefault();
96 | tag.SetLeaderElbow(referencedElement, tag.TagHeadPosition);
97 | #elif Version2019 || Version2020 || Version2021
98 | tag.LeaderEnd = tag.TagHeadPosition;
99 | #endif
100 |
101 | }
102 |
103 |
104 |
105 | tx.Commit();
106 | tx.Start("Arrange Tags");
107 |
108 | //Create two lists of TagLeader
109 | List leftTagLeaders = new List();
110 | List rightTagLeaders = new List();
111 |
112 | foreach (IndependentTag tag in tags)
113 | {
114 | TagLeader currentTag = new TagLeader(tag, doc);
115 | if (currentTag.Side == ViewSides.Left)
116 | {
117 | leftTagLeaders.Add(currentTag);
118 | }
119 | else
120 | {
121 | rightTagLeaders.Add(currentTag);
122 | }
123 | }
124 |
125 | //Create a list of potential location points for tag headers
126 | List leftTagHeadPoints = CreateTagPositionPoints(activeView, leftTagLeaders, ViewSides.Left);
127 | List rightTagHeadPoints = CreateTagPositionPoints(activeView, rightTagLeaders, ViewSides.Right);
128 |
129 | //Sort tag by Y position
130 | leftTagLeaders = leftTagLeaders.OrderBy(x => x.LeaderEnd.X).ToList();
131 | leftTagLeaders = leftTagLeaders.OrderBy(x => x.LeaderEnd.Y).ToList();
132 |
133 | //place and sort
134 | PlaceAndSort(leftTagHeadPoints, leftTagLeaders);
135 |
136 |
137 | //Sort tag by Y position
138 | rightTagLeaders = rightTagLeaders.OrderByDescending(x => x.LeaderEnd.X).ToList();
139 | rightTagLeaders = rightTagLeaders.OrderBy(x => x.LeaderEnd.Y).ToList();
140 |
141 | //place and sort
142 | PlaceAndSort(rightTagHeadPoints, rightTagLeaders);
143 |
144 | tx.Commit();
145 |
146 | }
147 |
148 | private void PlaceAndSort(List positionPoints,List tags)
149 | {
150 | //place TagLeader
151 | foreach (TagLeader tag in tags)
152 | {
153 | XYZ nearestPoint = FindNearestPoint(positionPoints, tag.TagCenter);
154 | tag.TagCenter = nearestPoint;
155 |
156 | //remove this point from the list
157 | positionPoints.Remove(nearestPoint);
158 | }
159 |
160 | //unCross leaders (2 times)
161 | UnCross(tags);
162 | UnCross(tags);
163 |
164 | //update their position
165 | foreach (TagLeader tag in tags)
166 | {
167 | tag.UpdateTagPosition();
168 | }
169 | }
170 |
171 | private void UnCross(List tags)
172 | {
173 | foreach (TagLeader tag in tags)
174 | {
175 | foreach (TagLeader otherTag in tags)
176 | {
177 | if (tag != otherTag)
178 | {
179 | if (tag.BaseLine.Intersect(otherTag.BaseLine) == SetComparisonResult.Overlap
180 | || tag.BaseLine.Intersect(otherTag.EndLine) == SetComparisonResult.Overlap
181 | || tag.EndLine.Intersect(otherTag.BaseLine) == SetComparisonResult.Overlap
182 | || tag.EndLine.Intersect(otherTag.EndLine) == SetComparisonResult.Overlap)
183 | {
184 | XYZ newPosition = tag.TagCenter;
185 | tag.TagCenter = otherTag.TagCenter;
186 | otherTag.TagCenter = newPosition;
187 | }
188 | }
189 | }
190 | }
191 | }
192 |
193 | private XYZ FindNearestPoint(List points, XYZ basePoint)
194 | {
195 | XYZ nearestPoint = points.FirstOrDefault();
196 | double nearestDistance = basePoint.DistanceTo(nearestPoint);
197 | double currentDistance = basePoint.DistanceTo(nearestPoint);
198 |
199 | foreach (XYZ point in points)
200 | {
201 | currentDistance = basePoint.DistanceTo(point);
202 | if (currentDistance < nearestDistance)
203 | {
204 | nearestPoint = point;
205 | nearestDistance = basePoint.DistanceTo(point);
206 | }
207 | }
208 | return nearestPoint;
209 | }
210 |
211 | private List CreateTagPositionPoints(View activeView, List tagLeaders, ViewSides side)
212 | {
213 | List points = new List();
214 |
215 | BoundingBoxXYZ bbox = activeView.CropBox;
216 |
217 | if (tagLeaders.Count != 0)
218 | {
219 | //Get largest tag dimension
220 | double tagHeight = tagLeaders.Max(x => x.TagHeight);
221 | double tagWidth = tagLeaders.Max(x => x.TagWidth);
222 |
223 | double step = tagHeight*1.2;
224 | //double step = (bbox.Max.Y - bbox.Min.Y) / 20;
225 | int max = (int)Math.Round((bbox.Max.Y - bbox.Min.Y) / step);
226 | XYZ baseRight = new XYZ(bbox.Max.X, bbox.Min.Y, 0);
227 | XYZ baseLeft = new XYZ(bbox.Min.X, bbox.Min.Y, 0);
228 |
229 | //create sides points
230 | for (int i = max*2; i > 0; i--)
231 | {
232 | if (side == ViewSides.Left)
233 | {
234 | //Add left point
235 | points.Add(baseLeft + new XYZ(0, step * i, 0));
236 | }
237 | else
238 | {
239 | //Add right point
240 | points.Add(baseRight + new XYZ(0, step * i, 0));
241 | }
242 | }
243 | }
244 |
245 |
246 | return points;
247 | }
248 | }
249 |
250 | class TagLeader
251 | {
252 | private Document _doc;
253 | private View _currentView;
254 | private Element _taggedElement;
255 | private IndependentTag _tag;
256 |
257 | public TagLeader(IndependentTag tag, Document doc)
258 | {
259 | _doc = doc;
260 | _currentView = _doc.GetElement(tag.OwnerViewId) as View;
261 | _tag = tag;
262 |
263 | _taggedElement = GetTaggedElement(_doc,_tag);
264 | _tagHeadPosition = _currentView.CropBox.Transform.Inverse.OfPoint(tag.TagHeadPosition);
265 | _tagHeadPosition = new XYZ(_tagHeadPosition.X, _tagHeadPosition.Y, 0);
266 | _leaderEnd = GetLeaderEnd(_taggedElement,_currentView);
267 |
268 | //View center
269 | XYZ viewCenter = (_currentView.CropBox.Max + _currentView.CropBox.Min) / 2;
270 | if (viewCenter.X > _leaderEnd.X)
271 | {
272 | _side = ViewSides.Left;
273 | }
274 | else
275 | {
276 | _side = ViewSides.Right;
277 | }
278 |
279 | GetTagDimension();
280 | }
281 |
282 | private XYZ _tagHeadPosition;
283 | private XYZ _headOffset;
284 |
285 | private XYZ _tagCenter;
286 | public XYZ TagCenter
287 | {
288 | get { return _tagCenter; }
289 | set
290 | {
291 | _tagCenter = value;
292 | UpdateLeaderPosition();
293 | }
294 | }
295 |
296 | private Line _endLine;
297 | public Line EndLine
298 | {
299 | get { return _endLine; }
300 | }
301 |
302 | private Line _baseLine;
303 | public Line BaseLine
304 | {
305 | get { return _baseLine; }
306 | }
307 |
308 | private ViewSides _side;
309 | public ViewSides Side
310 | {
311 | get { return _side; }
312 | }
313 |
314 | private XYZ _elbowPosition;
315 | public XYZ ElbowPosition
316 | {
317 | get { return _elbowPosition; }
318 | }
319 |
320 | private void UpdateLeaderPosition()
321 | {
322 | //Update elbow position
323 | XYZ AB = _leaderEnd - _tagCenter;
324 | double mult = AB.X * AB.Y;
325 | mult = mult / Math.Abs(mult);
326 | XYZ delta = new XYZ(AB.X - AB.Y * Math.Tan(mult * Math.PI / 4), 0, 0);
327 | _elbowPosition = _tagCenter + delta;
328 |
329 | //Update lines
330 | if (_leaderEnd.DistanceTo(_elbowPosition)> _doc.Application.ShortCurveTolerance)
331 | {
332 | _endLine = Line.CreateBound(_leaderEnd, _elbowPosition);
333 | }
334 | else
335 | {
336 | _endLine = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(0, 0, 1));
337 | }
338 | if (_elbowPosition.DistanceTo(_tagCenter) > _doc.Application.ShortCurveTolerance)
339 | {
340 | _baseLine = Line.CreateBound(_elbowPosition, _tagCenter);
341 | }
342 | else
343 | {
344 | _baseLine = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(0, 0, 1));
345 | }
346 | }
347 |
348 | private XYZ _leaderEnd;
349 | public XYZ LeaderEnd
350 | {
351 | get { return _leaderEnd; }
352 | }
353 |
354 | private double _tagHeight;
355 | public double TagHeight
356 | {
357 | get { return _tagHeight; }
358 | }
359 |
360 | private double _tagWidth;
361 | public double TagWidth
362 | {
363 | get { return _tagWidth; }
364 | }
365 |
366 | private void GetTagDimension()
367 | {
368 | BoundingBoxXYZ bbox = _tag.get_BoundingBox(_currentView);
369 | BoundingBoxXYZ viewBox = _currentView.CropBox;
370 |
371 | _tagHeight = viewBox.Transform.Inverse.OfPoint(bbox.Max).Y - viewBox.Transform.Inverse.OfPoint(bbox.Min).Y;
372 | _tagWidth = viewBox.Transform.Inverse.OfPoint(bbox.Max).X - viewBox.Transform.Inverse.OfPoint(bbox.Min).X;
373 | _tagCenter = (viewBox.Transform.Inverse.OfPoint(bbox.Max) + viewBox.Transform.Inverse.OfPoint(bbox.Min)) / 2;
374 | _tagCenter = new XYZ(_tagCenter.X, _tagCenter.Y, 0);
375 | _headOffset = _tagHeadPosition - _tagCenter;
376 | }
377 |
378 | public static Element GetTaggedElement(Document doc, IndependentTag tag)
379 | {
380 | #if Version2019 || Version2020 || Version2021
381 | LinkElementId linkElementId = tag.TaggedElementId;
382 | #elif Version2022 || Version2023 || Version2024
383 | LinkElementId linkElementId = tag.GetTaggedElementIds().FirstOrDefault();
384 | #endif
385 | Element taggedElement;
386 | if (linkElementId.HostElementId == ElementId.InvalidElementId)
387 | {
388 | RevitLinkInstance linkInstance = doc.GetElement(linkElementId.LinkInstanceId) as RevitLinkInstance;
389 | Document linkedDocument = linkInstance.GetLinkDocument();
390 |
391 | taggedElement = linkedDocument.GetElement(linkElementId.LinkedElementId);
392 | }
393 | else
394 | {
395 | taggedElement = doc.GetElement(linkElementId.HostElementId);
396 | }
397 |
398 | return taggedElement;
399 | }
400 |
401 | public static XYZ GetLeaderEnd(Element taggedElement, View currentView)
402 | {
403 | BoundingBoxXYZ bbox = taggedElement.get_BoundingBox(currentView);
404 | BoundingBoxXYZ viewBox = currentView.CropBox;
405 |
406 | //Retrive leader end
407 | XYZ leaderEnd = new XYZ();
408 | if (bbox != null)
409 | {
410 | leaderEnd = (bbox.Max + bbox.Min) / 2;
411 | }
412 | else
413 | {
414 | leaderEnd = (viewBox.Max + viewBox.Min) / 2 + new XYZ(0.001, 0, 0);
415 | }
416 |
417 | //Get leader end in view reference
418 | leaderEnd = viewBox.Transform.Inverse.OfPoint(leaderEnd);
419 | leaderEnd = new XYZ(Math.Round(leaderEnd.X,4), Math.Round(leaderEnd.Y,4) ,0);
420 |
421 | return leaderEnd;
422 | }
423 |
424 | public void UpdateTagPosition()
425 | {
426 | _tag.LeaderEndCondition = LeaderEndCondition.Attached;
427 |
428 | XYZ offsetFromView = new XYZ();
429 | if (_side == ViewSides.Left)
430 | {
431 | offsetFromView = new XYZ(-Math.Abs(_tagWidth)*0.5-0.1, 0, 0);
432 | }
433 | else
434 | {
435 | offsetFromView = new XYZ(Math.Abs(_tagWidth )* 0.5+0.1, 0, 0);
436 | }
437 |
438 |
439 | _tag.TagHeadPosition = _currentView.CropBox.Transform.OfPoint(_headOffset + _tagCenter + offsetFromView);
440 | #if Version2022 || Version2023 || Version2024
441 | Reference referencedElement = _tag.GetTaggedReferences().FirstOrDefault();
442 | _tag.SetLeaderElbow(referencedElement, _currentView.CropBox.Transform.OfPoint(_elbowPosition));
443 |
444 | #elif Version2019 || Version2020 || Version2021
445 | _tag.LeaderElbow = _currentView.CropBox.Transform.OfPoint(_elbowPosition);
446 | #endif
447 |
448 | }
449 | }
450 |
451 | enum ViewSides { Left, Right };
452 | }
453 |
--------------------------------------------------------------------------------