├── .gitattributes ├── .gitignore ├── Gile.AutoCAD.Extension.sln ├── Gile.AutoCAD.R20.Extension ├── AbstractViewTableRecordExtension.cs ├── Active.cs ├── Assert.cs ├── AttributeCollectionExtension.cs ├── BlockReferenceExtension.cs ├── BlockTableExtension.cs ├── BlockTableRecordExtension.cs ├── DBDictionaryExtension.cs ├── DBObjectCollectionExtension.cs ├── DBObjectExtension.cs ├── DBTextExtension.cs ├── DatabaseExtension.cs ├── DisposableList.cs ├── DisposableSet.cs ├── DocumentCollectionExtension.cs ├── EditorExtension.cs ├── EntityExtension.cs ├── Gile.AutoCAD.R20.Extension.csproj ├── IDisposableCollection.cs ├── IEnumerableExtension.cs ├── MTextExtension.cs ├── ObjectIdCollectionExtension.cs ├── ObjectIdExtension.cs ├── PolylineExtension.cs ├── Properties │ └── AssemblyInfo.cs ├── ResultBufferExtension.cs ├── SymbolTableExtension.cs └── WorkingDatabase.cs ├── Gile.AutoCAD.R25.Extension ├── AbstractViewTableRecordExtension.cs ├── Active.cs ├── AttributeCollectionExtension.cs ├── BlockReferenceExtension.cs ├── BlockTableExtension.cs ├── BlockTableRecordExtension.cs ├── DBDictionaryExtension.cs ├── DBObjectCollectionExtension.cs ├── DBObjectExtension.cs ├── DBTextExtension.cs ├── DatabaseExtension.cs ├── DisposableList.cs ├── DisposableSet.cs ├── DocumentCollectionExtension.cs ├── EditorExtension.cs ├── EntityExtension.cs ├── Gile.AutoCAD.R25.Extension.csproj ├── IDisposableCollection.cs ├── IEnumerableExtension.cs ├── MTextExtension.cs ├── ObjectIdCollectionExtension.cs ├── ObjectIdExtension.cs ├── PolylineExtension.cs ├── Properties │ └── AssemblyInfo.cs ├── RuntimeExtension.cs ├── SymbolTableExtension.cs └── WorkingDatabase.cs ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /Gile.AutoCAD.Extension.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34511.84 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gile.AutoCAD.R20.Extension", "Gile.AutoCAD.R20.Extension\Gile.AutoCAD.R20.Extension.csproj", "{32EBFF40-CE54-4B05-AEBA-2EEFFEDB443B}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gile.AutoCAD.R25.Extension", "Gile.AutoCAD.R25.Extension\Gile.AutoCAD.R25.Extension.csproj", "{2F921473-0497-44E3-A535-76BC7900035D}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2F921473-0497-44E3-A535-76BC7900035D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {2F921473-0497-44E3-A535-76BC7900035D}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {2F921473-0497-44E3-A535-76BC7900035D}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {2F921473-0497-44E3-A535-76BC7900035D}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {32EBFF40-CE54-4B05-AEBA-2EEFFEDB443B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {32EBFF40-CE54-4B05-AEBA-2EEFFEDB443B}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {32EBFF40-CE54-4B05-AEBA-2EEFFEDB443B}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {32EBFF40-CE54-4B05-AEBA-2EEFFEDB443B}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {FBC4AA09-A2F5-4BD5-A6E7-69F0E397BDE4} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/AbstractViewTableRecordExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | 4 | namespace Gile.AutoCAD.R20.Extension 5 | { 6 | /// 7 | /// Provides extension for the AbstractViewTableRecord type. 8 | /// 9 | public static class AbstractViewTableRecordExtension 10 | { 11 | /// 12 | /// Gets the transformation matrix from the view Display Coordinate System (DCS) to World Coordinate System (WCS). 13 | /// 14 | /// Instance to which the method applies. 15 | /// The DCS to WCS transformation matrix. 16 | /// Thrown if is null. 17 | public static Matrix3d EyeToWorld(this AbstractViewTableRecord view) 18 | { 19 | Assert.IsNotNull(view, nameof(view)); 20 | 21 | return 22 | Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * 23 | Matrix3d.Displacement(view.Target.GetAsVector()) * 24 | Matrix3d.PlaneToWorld(view.ViewDirection); 25 | } 26 | 27 | /// 28 | /// Gets the transformation matrix from World Coordinate System (WCS) to the view Display Coordinate System (DCS). 29 | /// 30 | /// Instance to which the method applies. 31 | /// The WCS to DCS transformation matrix. 32 | /// Thrown if is null. 33 | public static Matrix3d WorldToEye(this AbstractViewTableRecord view) 34 | { 35 | Assert.IsNotNull(view, nameof(view)); 36 | 37 | return 38 | Matrix3d.WorldToPlane(view.ViewDirection) * 39 | Matrix3d.Displacement(view.Target.GetAsVector().Negate()) * 40 | Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/Active.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.ApplicationServices.Core; 2 | using Autodesk.AutoCAD.DatabaseServices; 3 | using Autodesk.AutoCAD.EditorInput; 4 | 5 | using AcAp = Autodesk.AutoCAD.ApplicationServices; 6 | 7 | // Inspired by Scott McFarlane 8 | // https://www.autodesk.com/autodesk-university/class/Being-Remarkable-C-NET-AutoCAD-Developer-2015#handout 9 | 10 | namespace Gile.AutoCAD.R20.Extension 11 | { 12 | /// 13 | /// Provides easy access to several "active" objects in AutoCAD runtime environment. 14 | /// 15 | public static class Active 16 | { 17 | /// 18 | /// Gets the active Document object. 19 | /// 20 | public static AcAp.Document Document => Application.DocumentManager.MdiActiveDocument; 21 | 22 | /// 23 | /// Gets the active Database object. 24 | /// 25 | public static Database Database => Document.Database; 26 | 27 | /// 28 | /// Gets the active Editor object. 29 | /// 30 | public static Editor Editor => Document.Editor; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/Assert.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | 5 | namespace Gile.AutoCAD.R20.Extension 6 | { 7 | /// 8 | /// Provides methods to throw an exception if an assertion is wrong. 9 | /// 10 | /// This class is not available for projects tageting .NET 8.0 (since AutoCAD 2025). 11 | public static class Assert 12 | { 13 | /// 14 | /// Throws ArgumentNullException if the object is null. 15 | /// 16 | /// Type of the object. 17 | /// The instance to which the assertion applies. 18 | /// Name of the parameter. 19 | public static void IsNotNull(T obj, string paramName) where T : class 20 | { 21 | if (obj == null) 22 | { 23 | throw new System.ArgumentNullException(paramName); 24 | } 25 | } 26 | 27 | /// 28 | /// Throws eNullObjectId if the ObjectId is null. 29 | /// 30 | /// The ObjectId to which the assertion applies. 31 | /// Name of the parameter. 32 | public static void IsNotObjectIdNull(ObjectId id, string paramName) 33 | { 34 | if (id.IsNull) 35 | { 36 | throw new Exception(ErrorStatus.NullObjectId, paramName); 37 | } 38 | } 39 | 40 | /// 41 | /// Throws ArgumentException if the string is null or empty. 42 | /// 43 | /// The string to which the assertion applies. 44 | /// Name of the parameter. 45 | public static void IsNotNullOrWhiteSpace(string str, string paramName) 46 | { 47 | if (string.IsNullOrWhiteSpace(str)) 48 | { 49 | throw new System.ArgumentException("eNullOrWhiteSpace", paramName); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/AttributeCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System.Collections.Generic; 4 | 5 | namespace Gile.AutoCAD.R20.Extension 6 | { 7 | /// 8 | /// Provides extension methods for the AttributeCollection type. 9 | /// 10 | public static class AttributeCollectionExtension 11 | { 12 | /// 13 | /// Opens the attribute references in the given open mode. 14 | /// 15 | /// Attribute collection. 16 | /// Transaction or OpenCloseTransaction to use. 17 | /// Open mode to obtain in. 18 | /// Value indicating whether to obtain erased objects. 19 | /// Value indicating if locked layers should be opened. 20 | /// The sequence of attribute references. 21 | /// Thrown if is null. 22 | /// Thrown if is null. 23 | public static IEnumerable GetObjects( 24 | this AttributeCollection source, 25 | Transaction tr, 26 | OpenMode mode = OpenMode.ForRead, 27 | bool openErased = false, 28 | bool forceOpenOnLockedLayers = false) 29 | { 30 | Assert.IsNotNull(source, nameof(source)); 31 | Assert.IsNotNull(tr, nameof(tr)); 32 | 33 | if (source.Count > 0) 34 | { 35 | foreach (ObjectId id in source) 36 | { 37 | if (!id.IsErased || openErased) 38 | { 39 | yield return (AttributeReference)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/BlockTableExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | namespace Gile.AutoCAD.R20.Extension 4 | { 5 | /// 6 | /// Provides extension methods for the BlockTable type. 7 | /// 8 | public static class BlockTableExtension 9 | { 10 | /// 11 | /// Gets the objectId of a block definition (BlockTableRecord) from its name. 12 | /// If the block is not found in the block table, a dwg file is searched in the support paths and added to the block table. 13 | /// 14 | /// Block table. 15 | /// Block name. 16 | /// The ObjectId of the block table record or ObjectId.Null if not found. 17 | /// Thrown if is null. 18 | /// Thrown if is null or empty. 19 | public static ObjectId GetBlock(this BlockTable blockTable, string blockName) 20 | { 21 | Assert.IsNotNull(blockTable, nameof(blockTable)); 22 | Assert.IsNotNullOrWhiteSpace(blockName, nameof(blockName)); 23 | 24 | if (blockTable.Has(blockName)) 25 | return blockTable[blockName]; 26 | try 27 | { 28 | string blockPath = HostApplicationServices.Current.FindFile(blockName + ".dwg", blockTable.Database, FindFileHint.Default); 29 | using (var tmpDb = new Database(false, true)) 30 | { 31 | tmpDb.ReadDwgFile(blockPath, FileOpenMode.OpenForReadAndAllShare, true, null); 32 | return blockTable.Database.Insert(blockName, tmpDb, true); 33 | } 34 | } 35 | catch 36 | { 37 | return ObjectId.Null; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/BlockTableRecordExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | using Autodesk.AutoCAD.Runtime; 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Gile.AutoCAD.R20.Extension 9 | { 10 | /// 11 | /// Provides extension methods for the BlockTableRecord type. 12 | /// 13 | public static class BlockTableRecordExtension 14 | { 15 | /// 16 | /// Opens the entities which type matches to the given one, and return them. 17 | /// 18 | /// Type of objects to return. 19 | /// Block table record. 20 | /// Transaction or OpenCloseTransaction to use. 21 | /// Open mode to obtain in. 22 | /// Value indicating whether to obtain erased objects. 23 | /// Value indicating if locked layers should be opened. 24 | /// The sequence of opened objects. 25 | /// Thrown if is null. 26 | /// Thrown if is null. 27 | public static IEnumerable GetObjects( 28 | this BlockTableRecord btr, 29 | Transaction tr, 30 | OpenMode mode = OpenMode.ForRead, 31 | bool openErased = false, 32 | bool forceOpenOnLockedLayers = false) where T : Entity 33 | { 34 | Assert.IsNotNull(btr, nameof(btr)); 35 | Assert.IsNotNull(tr, nameof(tr)); 36 | 37 | var source = openErased ? btr.IncludingErased : btr; 38 | if (typeof(T) == typeof(Entity)) 39 | { 40 | foreach (ObjectId id in source) 41 | { 42 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 43 | } 44 | } 45 | else 46 | { 47 | var rxClass = RXObject.GetClass(typeof(T)); 48 | foreach (ObjectId id in source) 49 | { 50 | if (id.ObjectClass.IsDerivedFrom(rxClass)) 51 | { 52 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 53 | } 54 | } 55 | } 56 | } 57 | 58 | /// 59 | /// Appends the entities to the BlockTableRecord. 60 | /// 61 | /// Instance to which the method applies. 62 | /// Transaction or OpenCloseTransaction to use. 63 | /// Sequence of entities. 64 | /// The collection of added entities ObjectId. 65 | /// Thrown if is null. 66 | /// Thrown if is null. 67 | /// Thrown if is null. 68 | public static ObjectIdCollection Add(this BlockTableRecord owner, Transaction tr, IEnumerable entities) 69 | { 70 | Assert.IsNotNull(owner, nameof(owner)); 71 | Assert.IsNotNull(tr, nameof(tr)); 72 | Assert.IsNotNull(entities, nameof(entities)); 73 | 74 | var ids = new ObjectIdCollection(); 75 | using (var ents = new DisposableSet(entities)) 76 | { 77 | foreach (Entity ent in ents) 78 | { 79 | ids.Add(owner.AppendEntity(ent)); 80 | tr.AddNewlyCreatedDBObject(ent, true); 81 | } 82 | } 83 | return ids; 84 | } 85 | 86 | /// 87 | /// Appends the entities to the BlockTableRecord. 88 | /// 89 | /// Instance to which the method applies. 90 | /// Active transaction 91 | /// Collection of entities. 92 | /// The collection of added entities ObjectId. 93 | /// Thrown if is null. 94 | /// Thrown if is null. 95 | /// Thrown if is null. 96 | public static ObjectIdCollection AddRange(this BlockTableRecord owner, Transaction tr, params Entity[] entities) 97 | { 98 | Assert.IsNotNull(owner, nameof(owner)); 99 | Assert.IsNotNull(tr, nameof(tr)); 100 | Assert.IsNotNull(entities, nameof(entities)); 101 | 102 | return owner.Add(tr, entities); 103 | } 104 | 105 | /// 106 | /// Appends the entity to the BlockTableRecord. 107 | /// 108 | /// Instance to which the method applies. 109 | /// Transaction or OpenCloseTransaction to use. 110 | /// Entity to add. 111 | /// The ObjectId of added entity. 112 | /// Thrown if is null. 113 | /// Thrown if is null. 114 | /// Thrown if is null. 115 | public static ObjectId Add(this BlockTableRecord owner, Transaction tr, Entity entity) 116 | { 117 | Assert.IsNotNull(owner, nameof(owner)); 118 | Assert.IsNotNull(tr, nameof(tr)); 119 | Assert.IsNotNull(entity, nameof(entity)); 120 | 121 | try 122 | { 123 | var id = owner.AppendEntity(entity); 124 | tr.AddNewlyCreatedDBObject(entity, true); 125 | return id; 126 | } 127 | catch 128 | { 129 | entity.Dispose(); 130 | throw; 131 | } 132 | } 133 | 134 | /// 135 | /// Inserts a block reference. 136 | /// 137 | /// Instance to which the method applies. 138 | /// Transaction or OpenCloseTransaction to use. 139 | /// Nlock name. 140 | /// Insertion point. 141 | /// X scale factor. 142 | /// Y scale factor. 143 | /// Z scale factor. 144 | /// Rotation 145 | /// Collection of key/value pairs (Tag/Value). 146 | /// The newly created BlockReference. 147 | /// Thrown if is null. 148 | /// Thrown if is null. 149 | /// Thrown if is null or empty. 150 | public static BlockReference InsertBlockReference( 151 | this BlockTableRecord target, 152 | Transaction tr, 153 | string blkName, 154 | Point3d insertPoint, 155 | double xScale = 1.0, 156 | double yScale = 1.0, 157 | double zScale = 1.0, 158 | double rotation = 0.0, 159 | Dictionary attribValues = null) 160 | { 161 | Assert.IsNotNull(target, nameof(target)); 162 | Assert.IsNotNull(tr, nameof(tr)); 163 | Assert.IsNotNullOrWhiteSpace(blkName, nameof(blkName)); 164 | 165 | var db = target.Database; 166 | BlockReference br = null; 167 | var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); 168 | var btrId = bt.GetBlock(blkName); 169 | if (btrId != ObjectId.Null) 170 | { 171 | br = new BlockReference(insertPoint, btrId) { ScaleFactors = new Scale3d(xScale, yScale, zScale), Rotation = rotation }; 172 | var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead); 173 | if (btr.Annotative == AnnotativeStates.True) 174 | { 175 | var objectContextManager = db.ObjectContextManager; 176 | var objectContextCollection = objectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES"); 177 | Autodesk.AutoCAD.Internal.ObjectContexts.AddContext(br, objectContextCollection.CurrentContext); 178 | } 179 | target.Add(tr, br); 180 | br.AddAttributeReferences(tr, attribValues); 181 | } 182 | return br; 183 | } 184 | 185 | /// 186 | /// Synchronizes the attributes of all block references. 187 | /// 188 | /// Instance which the method applies. 189 | /// Transaction or OpenCloseTransaction to use. 190 | /// Thrown if is null. 191 | /// Thrown if is null. 192 | public static void SynchronizeAttributes(this BlockTableRecord target, Transaction tr) 193 | { 194 | Assert.IsNotNull(target, nameof(target)); 195 | Assert.IsNotNull(tr, nameof(tr)); 196 | 197 | AttributeDefinition[] attDefs = target.GetObjects(tr).ToArray(); 198 | foreach (BlockReference br in target.GetBlockReferenceIds(true, false).GetObjects(tr, OpenMode.ForWrite)) 199 | { 200 | br.ResetAttributes(tr, attDefs); 201 | } 202 | if (target.IsDynamicBlock) 203 | { 204 | target.UpdateAnonymousBlocks(); 205 | foreach (BlockTableRecord btr in target.GetAnonymousBlockIds().GetObjects(tr)) 206 | { 207 | attDefs = btr.GetObjects(tr).ToArray(); 208 | foreach (BlockReference br in btr.GetBlockReferenceIds(true, false).GetObjects(tr, OpenMode.ForWrite)) 209 | { 210 | br.ResetAttributes(tr, attDefs); 211 | } 212 | } 213 | } 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DBDictionaryExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System.Collections.Generic; 5 | 6 | namespace Gile.AutoCAD.R20.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the DBDictionary type. 10 | /// 11 | public static class DBDictionaryExtension 12 | { 13 | /// 14 | /// Tries to open the object of the dictionary corresponding to the given type, in the given open mode. 15 | /// 16 | /// Type of the returned object. 17 | /// Instance to which the method applies. 18 | /// Transaction or OpenCloseTransaction to use. 19 | /// Key of the entry in the dictionary. 20 | /// Output object. 21 | /// Open mode to obtain in. 22 | /// Value indicating whether to obtain erased objects. 23 | /// true, if the operations succeeded; false, otherwise. 24 | /// Thrown if is null. 25 | /// Thrown if is null. 26 | /// Thrown if is null or empty. 27 | public static bool TryGetObject( 28 | this DBDictionary source, 29 | Transaction tr, 30 | string key, 31 | out T obj, 32 | OpenMode mode = OpenMode.ForRead, 33 | bool openErased = false) where T : DBObject 34 | { 35 | Assert.IsNotNull(source, nameof(source)); 36 | Assert.IsNotNull(tr, nameof(tr)); 37 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 38 | 39 | obj = default; 40 | return source.Contains(key) && source.GetAt(key).TryGetObject(tr, out obj, mode, openErased); 41 | } 42 | 43 | /// 44 | /// Tries to get the named dictionary. 45 | /// 46 | /// Instance to which the method applies. 47 | /// Transaction or OpenCloseTransaction to use. 48 | /// Name of the dictionary. 49 | /// Output dictionary. 50 | /// Open mode to obtain in. 51 | /// Value indicating whether to obtain erased objects. 52 | /// true, if the operations succeeded; false, otherwise. 53 | /// Thrown if is null. 54 | /// Thrown if is null. 55 | /// Thrown if is null or empty. 56 | public static bool TryGetNamedDictionary( 57 | this DBDictionary parent, 58 | Transaction tr, 59 | string key, 60 | out DBDictionary dictionary, 61 | OpenMode mode = OpenMode.ForRead, 62 | bool openErased = false) 63 | { 64 | Assert.IsNotNull(parent, nameof(parent)); 65 | Assert.IsNotNull(tr, nameof(tr)); 66 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 67 | 68 | dictionary = default; 69 | if (parent.Contains(key)) 70 | { 71 | var id = parent.GetAt(key); 72 | if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(DBDictionary)))) 73 | { 74 | dictionary = (DBDictionary)tr.GetObject(id, mode, openErased); 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | /// 82 | /// Opens the entities which type matches to the given one, and return them. 83 | /// 84 | /// Type of returned objects. 85 | /// Instance to which the method applies. 86 | /// Transaction or OpenCloseTransaction to use. 87 | /// Open mode to obtain in. 88 | /// Value indicating whether to obtain erased objects. 89 | /// The sequence of collected objects. 90 | /// Thrown if is null. 91 | /// Thrown if is null. 92 | public static IEnumerable GetObjects( 93 | this DBDictionary source, 94 | Transaction tr, 95 | OpenMode mode = OpenMode.ForRead, 96 | bool openErased = false) 97 | where T : DBObject 98 | { 99 | Assert.IsNotNull(source, nameof(source)); 100 | Assert.IsNotNull(tr, nameof(tr)); 101 | 102 | var rxc = RXObject.GetClass(typeof(T)); 103 | foreach (DBDictionaryEntry entry in openErased ? source.IncludingErased : source) 104 | { 105 | if (entry.Value.ObjectClass.IsDerivedFrom(rxc)) 106 | { 107 | yield return (T)tr.GetObject(entry.Value, mode, openErased, false); 108 | } 109 | } 110 | } 111 | 112 | /// 113 | /// Gets or creates the named dictionary. 114 | /// 115 | /// Instance to which the method applies. 116 | /// Transaction or OpenCloseTransaction to use. 117 | /// Name of the dictionary. 118 | /// The found or newly created dictionary. 119 | /// Thrown if is null. 120 | /// Thrown if is null. 121 | /// Thrown if is null or empty. 122 | /// Throw if the is not a DBDictionary. 123 | public static DBDictionary GetOrCreateNamedDictionary( 124 | this DBDictionary parent, 125 | Transaction tr, 126 | string name) 127 | { 128 | Assert.IsNotNull(parent, nameof(parent)); 129 | Assert.IsNotNull(tr, nameof(tr)); 130 | Assert.IsNotNullOrWhiteSpace(name, nameof(name)); 131 | 132 | if (parent.Contains(name)) 133 | { 134 | var id = parent.GetAt(name); 135 | if (!id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(DBDictionary)))) 136 | throw new System.ArgumentException("Not a DBDictionary", nameof(name)); 137 | return (DBDictionary)tr.GetObject(id, OpenMode.ForRead); 138 | } 139 | else 140 | { 141 | var dictionary = new DBDictionary(); 142 | parent.OpenForWrite(tr); 143 | parent.SetAt(name, dictionary); 144 | tr.AddNewlyCreatedDBObject(dictionary, true); 145 | return dictionary; 146 | } 147 | } 148 | 149 | /// 150 | /// Tries to get the xrecord data. 151 | /// 152 | /// Instance to which the method applies. 153 | /// Transaction or OpenCloseTransaction to use. 154 | /// Key of the xrecord. 155 | /// Output data. 156 | /// true, if the operation succeeded; false, otherwise. 157 | /// Thrown if is null. 158 | /// Thrown if is null. 159 | /// Thrown if is null or empty. 160 | public static bool TryGetXrecordData( 161 | this DBDictionary dictionary, 162 | Transaction tr, 163 | string key, 164 | out ResultBuffer data) 165 | { 166 | Assert.IsNotNull(dictionary, nameof(dictionary)); 167 | Assert.IsNotNull(tr, nameof(tr)); 168 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 169 | 170 | data = default; 171 | if (dictionary.Contains(key)) 172 | { 173 | var id = dictionary.GetAt(key); 174 | if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(Xrecord)))) 175 | { 176 | var xrecord = (Xrecord)tr.GetObject(id, OpenMode.ForRead); 177 | data = xrecord.Data; 178 | return data != null; 179 | } 180 | } 181 | return false; 182 | } 183 | 184 | /// 185 | /// Sets the xrecord data. 186 | /// 187 | /// Instance to which the method applies. 188 | /// Transaction or OpenCloseTransaction to use. 189 | /// Key of the xrecord, the xrecord is created if it does not already exist. 190 | /// Data 191 | /// The got or newlycreated Xrecord. 192 | /// Thrown if is null. 193 | /// Thrown if is null. 194 | /// Thrown if is null or empty. 195 | /// Thrown if is null. 196 | public static Xrecord SetXrecordData(this DBDictionary dictionary, Transaction tr, string key, params TypedValue[] data) 197 | { 198 | Assert.IsNotNull(dictionary, nameof(dictionary)); 199 | Assert.IsNotNull(tr, nameof(tr)); 200 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 201 | 202 | return dictionary.SetXrecordData(tr, key, new ResultBuffer(data)); 203 | } 204 | 205 | /// 206 | /// Sets the xrecord data. 207 | /// 208 | /// Instance to which the method applies. 209 | /// Transaction or OpenCloseTransaction to use. 210 | /// Key of the xrecord, the xrecord is created if it does not already exist. 211 | /// Data 212 | /// The got or newlycreated Xrecord. 213 | /// Thrown if is null. 214 | /// Thrown if is null. 215 | /// Thrown if is null or empty. 216 | /// Thrown if is null. 217 | public static Xrecord SetXrecordData(this DBDictionary dictionary, Transaction tr, string key, ResultBuffer data) 218 | { 219 | Assert.IsNotNull(dictionary, nameof(dictionary)); 220 | Assert.IsNotNull(tr, nameof(tr)); 221 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 222 | Assert.IsNotNull(data, nameof(data)); 223 | Xrecord xrecord; 224 | if (dictionary.Contains(key)) 225 | { 226 | var id = dictionary.GetAt(key); 227 | if (!id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(Xrecord)))) 228 | throw new System.ArgumentException("Not an Xrecord'", nameof(key)); 229 | { 230 | xrecord = (Xrecord)tr.GetObject(id, OpenMode.ForWrite); 231 | } 232 | } 233 | else 234 | { 235 | xrecord = new Xrecord(); 236 | dictionary.OpenForWrite(tr); 237 | dictionary.SetAt(key, xrecord); 238 | tr.AddNewlyCreatedDBObject(xrecord, true); 239 | } 240 | xrecord.Data = data; 241 | return xrecord; 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DBObjectCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System.Linq; 4 | 5 | namespace Gile.AutoCAD.R20.Extension 6 | { 7 | /// 8 | /// Provides extension methods for the DBObjectCollection type. 9 | /// 10 | public static class DBObjectCollectionExtension 11 | { 12 | /// 13 | /// Disposes of all objects in the collections. 14 | /// 15 | /// Instance to which the method applies. 16 | /// Thrown if is null. 17 | public static void DisposeAll(this DBObjectCollection source) 18 | { 19 | Assert.IsNotNull(source, nameof(source)); 20 | 21 | var list = source.Cast().ToList(); 22 | source.Clear(); 23 | list.DisposeAll(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DBObjectExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | namespace Gile.AutoCAD.R20.Extension 5 | { 6 | /// 7 | /// Provides extension methods for the DBObject type. 8 | /// 9 | public static class DBObjectExtension 10 | { 11 | /// 12 | /// Tries to get the object extension dictionary. 13 | /// 14 | /// Instance to which the method applies. 15 | /// Transaction or OpenCloseTransaction to use. 16 | /// Output dictionary. 17 | /// Open mode to obtain in. 18 | /// Value indicating whether to obtain erased objects. 19 | /// true, if the operation succeeded; false, otherwise. 20 | /// Thrown if is null. 21 | /// Thrown if is null. 22 | public static bool TryGetExtensionDictionary( 23 | this DBObject dbObject, 24 | Transaction tr, 25 | out DBDictionary dictionary, 26 | OpenMode mode = OpenMode.ForRead, 27 | bool openErased = false) 28 | { 29 | Assert.IsNotNull(dbObject, nameof(dbObject)); 30 | Assert.IsNotNull(tr, nameof(tr)); 31 | 32 | dictionary = default; 33 | var id = dbObject.ExtensionDictionary; 34 | if (id.IsNull) 35 | return false; 36 | dictionary = (DBDictionary)tr.GetObject(id, mode, openErased); 37 | return true; 38 | } 39 | 40 | /// 41 | /// Gets or creates the extension dictionary. 42 | /// 43 | /// Instance to which the method applies. 44 | /// Transaction or OpenCloseTransaction to use. 45 | /// Open mode to obtain in. 46 | /// The extension dictionary. 47 | /// Thrown if is null. 48 | /// Thrown if is null. 49 | public static DBDictionary GetOrCreateExtensionDictionary( 50 | this DBObject dbObject, 51 | Transaction tr, 52 | OpenMode mode = OpenMode.ForRead) 53 | { 54 | Assert.IsNotNull(dbObject, nameof(dbObject)); 55 | Assert.IsNotNull(tr, nameof(tr)); 56 | 57 | if (dbObject.ExtensionDictionary.IsNull) 58 | { 59 | dbObject.OpenForWrite(tr); 60 | dbObject.CreateExtensionDictionary(); 61 | } 62 | return (DBDictionary)tr.GetObject(dbObject.ExtensionDictionary, mode); 63 | } 64 | 65 | /// 66 | /// Tries to get the xrecord data of the extension dictionary of the object. 67 | /// 68 | /// Instance to which the method applies. 69 | /// Transaction or OpenCloseTransaction to use. 70 | /// Xrecord key. 71 | /// Output data. 72 | /// The xrecord data or null if the xrecord does not exists. 73 | /// Thrown if is null. 74 | /// Thrown if is null. 75 | /// Thrown if is null or empty. 76 | public static bool TryGetXDictionaryXrecordData(this DBObject source, Transaction tr, string key, out ResultBuffer data) 77 | { 78 | Assert.IsNotNull(source, nameof(source)); 79 | Assert.IsNotNull(tr, nameof(tr)); 80 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 81 | 82 | data = default; 83 | return 84 | source.TryGetExtensionDictionary(tr, out DBDictionary xdict) && 85 | xdict.TryGetXrecordData(tr, key, out data); 86 | } 87 | 88 | /// 89 | /// Sets the xrecord data of the extension dictionary of the object. 90 | /// 91 | /// Instance to which the method applies. 92 | /// Transaction or OpenCloseTransaction to use. 93 | /// The xrecord key. 94 | /// The new xrecord data. 95 | /// The got or newlycreated Xrecord. 96 | /// Thrown if is null. 97 | /// Thrown if is null. 98 | /// Thrown if is null or empty. 99 | public static Xrecord SetXDictionaryXrecordData(this DBObject target, Transaction tr, string key, params TypedValue[] values) 100 | { 101 | Assert.IsNotNull(target, nameof(target)); 102 | Assert.IsNotNull(tr, nameof(tr)); 103 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 104 | 105 | return target.SetXDictionaryXrecordData(tr, key, new ResultBuffer(values)); 106 | } 107 | 108 | /// 109 | /// Sets the xrecord data of the extension dictionary of the object. 110 | /// 111 | /// Instance to which the method applies. 112 | /// Transaction or OpenCloseTransaction to use. 113 | /// The xrecord key. 114 | /// The new xrecord data. 115 | /// The got or newlycreated Xrecord. 116 | /// Thrown if is null. 117 | /// Thrown if is null. 118 | /// Thrown if is null or empty. 119 | public static Xrecord SetXDictionaryXrecordData(this DBObject target, Transaction tr, string key, ResultBuffer data) 120 | { 121 | Assert.IsNotNull(target, nameof(target)); 122 | Assert.IsNotNull(tr, nameof(tr)); 123 | Assert.IsNotNullOrWhiteSpace(key, nameof(key)); 124 | 125 | return target.GetOrCreateExtensionDictionary(tr).SetXrecordData(tr, key, data); 126 | } 127 | 128 | /// 129 | /// Sets the object extended data (xdata) for the application. 130 | /// 131 | /// Instance to which the method applies. 132 | /// Transaction or OpenCloseTransaction to use. 133 | /// Extended data (the first TypedValue must be: (1001, <regAppName>)). 134 | /// Thrown if is null. 135 | /// Thrown if is null. 136 | /// Thrown if is null. 137 | /// eBadDxfSequence is thrown if the result buffer is not valid. 138 | public static void SetXDataForApplication(this DBObject target, Transaction tr, ResultBuffer data) 139 | { 140 | Assert.IsNotNull(target, nameof(target)); 141 | Assert.IsNotNull(tr, nameof(tr)); 142 | Assert.IsNotNull(data, nameof(data)); 143 | 144 | var db = target.Database; 145 | var typedValue = data.AsArray()[0]; 146 | if (typedValue.TypeCode != 1001) 147 | throw new Exception(ErrorStatus.BadDxfSequence); 148 | string appName = (string)typedValue.Value; 149 | var regAppTable = (RegAppTable)tr.GetObject(db.RegAppTableId, OpenMode.ForRead); 150 | if (!regAppTable.Has(appName)) 151 | { 152 | var regApp = new RegAppTableRecord 153 | { 154 | Name = appName 155 | }; 156 | tr.GetObject(db.RegAppTableId, OpenMode.ForWrite); 157 | regAppTable.Add(regApp); 158 | tr.AddNewlyCreatedDBObject(regApp, true); 159 | } 160 | target.XData = data; 161 | } 162 | 163 | /// 164 | /// Opens the object for write. 165 | /// 166 | /// Instance to which the method applies. 167 | /// Transaction or OpenCloseTransaction to use. 168 | /// Thrown if is null. 169 | /// Thrown if is null. 170 | public static void OpenForWrite(this DBObject dbObj, Transaction tr) 171 | { 172 | Assert.IsNotNull(dbObj, nameof(dbObj)); 173 | Assert.IsNotNull(tr, nameof(tr)); 174 | 175 | if (!dbObj.IsWriteEnabled) 176 | { 177 | tr.GetObject(dbObj.ObjectId, OpenMode.ForWrite); 178 | } 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DBTextExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Gile.AutoCAD.R20.Extension 8 | { 9 | /// 10 | /// Provides extension methods for the DBText type. 11 | /// 12 | public static class DBTextExtension 13 | { 14 | /// 15 | /// Gets the 'text box' of the DBText instance. 16 | /// 17 | /// Instance to which the method applies. 18 | /// Lower left corner of the box ('DBText coordinate system'). 19 | /// Upper right corner of the box ('DBText coordinate system') 20 | /// Transformation matrix from 'DBText coordinate system' to WCS. 21 | public static void GetTextBox(this DBText dbText, out Point3d point1, out Point3d point2, out Matrix3d transform) 22 | { 23 | Assert.IsNotNull(dbText, nameof(dbText)); 24 | 25 | int mirrored = dbText.IsMirroredInX ? 2 : 0; 26 | mirrored |= dbText.IsMirroredInY ? 4 : 0; 27 | var rb = new ResultBuffer( 28 | new TypedValue(1, dbText.TextString), 29 | new TypedValue(40, dbText.Height), 30 | new TypedValue(41, dbText.WidthFactor), 31 | new TypedValue(51, dbText.Oblique), 32 | new TypedValue(7, dbText.TextStyleName), 33 | new TypedValue(71, mirrored), 34 | new TypedValue(72, (int)dbText.HorizontalMode), 35 | new TypedValue(73, (int)dbText.VerticalMode)); 36 | var pt1 = new double[3]; 37 | var pt2 = new double[3]; 38 | acedTextBox(rb.UnmanagedObject, pt1, pt2); 39 | point1 = new Point3d(pt1); 40 | point2 = new Point3d(pt2); 41 | transform = 42 | Matrix3d.Displacement(dbText.Position.GetAsVector()) * 43 | Matrix3d.Rotation(dbText.Rotation, dbText.Normal, Point3d.Origin) * 44 | Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, dbText.Normal)); 45 | } 46 | 47 | /// 48 | /// Gets the center of the text bounding box. 49 | /// 50 | /// Instance to which the method applies. 51 | /// The center point of the text. 52 | /// Thrown if is null. 53 | public static Point3d GetTextBoxCenter(this DBText dbText) 54 | { 55 | dbText.GetTextBox(out Point3d point1, out Point3d point2, out Matrix3d xform); 56 | return new Point3d( 57 | (point1.X + point2.X) / 2.0, 58 | (point1.Y + point2.Y) / 2.0, 59 | (point1.Z + point2.Z) / 2.0) 60 | .TransformBy(xform); 61 | } 62 | 63 | /// 64 | /// Gets the points at corners of the text bounding box. 65 | /// 66 | /// Instance to which the method applies. 67 | /// The points(counter-clockwise from lower left). 68 | /// Thrown if is null. 69 | public static Point3d[] GetTextBoxCorners(this DBText dbText) 70 | { 71 | dbText.GetTextBox(out Point3d point1, out Point3d point2, out Matrix3d xform); 72 | return new[] 73 | { 74 | point1.TransformBy(xform), 75 | new Point3d(point2.X, point1.Y, 0.0).TransformBy(xform), 76 | point2.TransformBy(xform), 77 | new Point3d(point1.X, point2.Y, 0.0).TransformBy(xform) 78 | }; 79 | } 80 | 81 | /// 82 | /// Mirrors the text honoring the value of MIRRTEXT system variable. 83 | /// 84 | /// Instance to which the method applies. 85 | /// Transaction or OpenCloseTransaction to use. 86 | /// Axis of the mirroring operation. 87 | /// Value indicating if the source block reference have to be erased. 88 | /// Thrown if is null. 89 | /// Thrown if is null. 90 | /// Thrown if is null. 91 | public static void Mirror(this DBText source, Transaction tr, Line3d axis, bool eraseSource) 92 | { 93 | Assert.IsNotNull(source, nameof(source)); 94 | Assert.IsNotNull(tr, nameof(tr)); 95 | Assert.IsNotNull(axis, nameof(axis)); 96 | 97 | var db = source.Database; 98 | DBText mirrored; 99 | if (eraseSource) 100 | { 101 | mirrored = source; 102 | mirrored.OpenForWrite(tr); 103 | } 104 | else 105 | { 106 | var ids = new ObjectIdCollection(new[] { source.ObjectId }); 107 | var mapping = new IdMapping(); 108 | db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, false); 109 | mirrored = (DBText)tr.GetObject(mapping[source.ObjectId].Value, OpenMode.ForWrite); 110 | } 111 | mirrored.TransformBy(Matrix3d.Mirroring(axis)); 112 | if (!db.Mirrtext) 113 | { 114 | var pts = mirrored.GetTextBoxCorners(); 115 | var cen = new LineSegment3d(pts[0], pts[2]).MidPoint; 116 | var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ? 117 | pts[0].GetVectorTo(pts[3]) : 118 | pts[0].GetVectorTo(pts[1]); 119 | mirrored.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen)); 120 | } 121 | } 122 | 123 | /// 124 | /// P/Invokes the unmanaged acedTextBox method. 125 | /// 126 | /// ResultBuffer cotaining the DBtext DXF definition. 127 | /// Minimum point of the bounding box. 128 | /// Maximum point of the bounding box. 129 | /// RTNORM, if succeeds; RTERROR, otherwise. 130 | [System.Security.SuppressUnmanagedCodeSecurity] 131 | [DllImport("accore.dll", CharSet = CharSet.Unicode, 132 | CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTextBox")] 133 | static extern IntPtr acedTextBox(IntPtr rb, double[] point1, double[] point2); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DisposableList.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Gile.AutoCAD.R20.Extension 8 | { 9 | /// 10 | /// Describes a list of disposable values. 11 | /// 12 | /// Type of the items. 13 | public class DisposableList : List, IDisposableCollection 14 | where T : IDisposable 15 | { 16 | /// 17 | /// Creates a new empty instance. 18 | /// 19 | public DisposableList() { } 20 | 21 | /// 22 | /// Creates a new instance by copying the sequence items. 23 | /// 24 | /// Sequence whose elements are copied into the new set. 25 | public DisposableList(IEnumerable collection) 26 | : base(collection) { } 27 | 28 | /// 29 | /// Creates a new instance by copying the collection items. 30 | /// 31 | /// Collection whose elements are copied into the new set. 32 | public DisposableList(DBObjectCollection collection) 33 | : base((IEnumerable)collection.Cast()) { } 34 | 35 | /// 36 | /// Creates a new empty instance. 37 | /// 38 | /// Initial cpacity 39 | public DisposableList(int capacity) 40 | : base(capacity) { } 41 | 42 | /// 43 | /// Disposes of all items. 44 | /// 45 | public void Dispose() 46 | { 47 | var list = this.ToList(); 48 | Clear(); 49 | list.DisposeAll(); 50 | } 51 | 52 | /// 53 | /// Removes items from the active instance. 54 | /// 55 | /// Items to remove. 56 | /// The sequence of effectively removed items. 57 | public IEnumerable RemoveRange(IEnumerable items) 58 | { 59 | Assert.IsNotNull(items, nameof(items)); 60 | foreach (T item in items) 61 | { 62 | if (Remove(item)) 63 | { 64 | yield return item; 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DisposableSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Gile.AutoCAD.R20.Extension 6 | { 7 | /// 8 | /// Describes a set of disposable values. 9 | /// 10 | /// Type of the items. 11 | public class DisposableSet : HashSet, IDisposableCollection 12 | where T : IDisposable 13 | { 14 | /// 15 | /// Creates a new empty instance using the default comparer. 16 | /// 17 | public DisposableSet() 18 | { } 19 | 20 | /// 21 | /// Creates a new instance using the default comparer by copying the sequence items. 22 | /// 23 | /// Sequence whose elements are copied into the new set. 24 | public DisposableSet(IEnumerable collection) 25 | : base(collection) 26 | { } 27 | 28 | /// 29 | /// Creates a new empty instance using the specified comparer. 30 | /// 31 | /// IEqualityComparer<T> implementation. 32 | public DisposableSet(IEqualityComparer comparer) 33 | : base(comparer) 34 | { } 35 | 36 | /// 37 | /// Creates a new instance using the specified comparer by copying the sequence items. 38 | /// 39 | /// Sequence whose elements are copied into the new set. 40 | /// IEqualityComparer<T> implementation. 41 | public DisposableSet(IEnumerable collection, IEqualityComparer comparer) 42 | : base(collection, comparer) 43 | { } 44 | 45 | /// 46 | /// Disposes of all items. 47 | /// 48 | public void Dispose() 49 | { 50 | var list = this.ToList(); 51 | Clear(); 52 | list.DisposeAll(); 53 | } 54 | 55 | /// 56 | /// Adds items to the active instance. 57 | /// 58 | /// Items to add. 59 | public void AddRange(IEnumerable items) 60 | { 61 | Assert.IsNotNull(items, nameof(items)); 62 | 63 | UnionWith(items); 64 | } 65 | 66 | /// 67 | /// Removes items from the active instance. 68 | /// 69 | /// Items to remove. 70 | /// The sequence of effectively removed items. 71 | public IEnumerable RemoveRange(IEnumerable items) 72 | { 73 | Assert.IsNotNull(items, nameof(items)); 74 | 75 | ExceptWith(items); 76 | return items; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/DocumentCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.ApplicationServices; 2 | 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | using AcRx = Autodesk.AutoCAD.Runtime; 7 | 8 | namespace Gile.AutoCAD.R20.Extension 9 | { 10 | /// 11 | /// Provides extension methods for the DocumentCollection type. 12 | /// 13 | public static class DocumentCollectionExtension 14 | { 15 | /// 16 | /// Invokes an action in the document context that can be safely called from the application context. 17 | /// Credit: Tony Tanzillo. 18 | /// 19 | /// Documents collection. 20 | /// Action to invoke. 21 | /// Task.CompletedTask. 22 | /// Thrown if is null; 23 | /// Thrown if is null; 24 | /// eNoDocument thrown if no active document. 25 | /// eInvalidContext thrown if not called from application context. 26 | /// Must be called in a try / catch statement. 27 | public static async Task InvokeAsCommandAsync(this DocumentCollection docs, Action action) 28 | { 29 | if (docs == null) 30 | throw new ArgumentNullException(nameof(docs)); 31 | 32 | if (action == null) 33 | throw new ArgumentNullException(nameof(action)); 34 | 35 | Document doc = docs.MdiActiveDocument ?? throw new AcRx.Exception(AcRx.ErrorStatus.NoDocument); 36 | 37 | if (!docs.IsApplicationContext) 38 | throw new AcRx.Exception(AcRx.ErrorStatus.InvalidContext); 39 | 40 | Task task = Task.CompletedTask; 41 | await docs.ExecuteInCommandContextAsync( 42 | (_) => 43 | { 44 | try 45 | { 46 | action(doc); 47 | return task; 48 | } 49 | catch (Exception ex) 50 | { 51 | return task = Task.FromException(ex); 52 | } 53 | }, 54 | null 55 | ); 56 | if (task.IsFaulted) 57 | { 58 | throw task.Exception; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/EditorExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.ApplicationServices.Core; 2 | using Autodesk.AutoCAD.DatabaseServices; 3 | using Autodesk.AutoCAD.EditorInput; 4 | using Autodesk.AutoCAD.Geometry; 5 | 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace Gile.AutoCAD.R20.Extension 10 | { 11 | /// 12 | /// Provides extension methods for the Editor type. 13 | /// 14 | public static class EditorExtension 15 | { 16 | #region Zoom 17 | 18 | /// 19 | /// Zooms to given extents in the current viewport. 20 | /// 21 | /// Instance to which the method applies. 22 | /// Extents of the zoom. 23 | /// Thrown if is null. 24 | public static void Zoom(this Editor ed, Extents3d ext) 25 | { 26 | Assert.IsNotNull(ed, nameof(ed)); 27 | 28 | using (ViewTableRecord view = ed.GetCurrentView()) 29 | { 30 | ext.TransformBy(view.WorldToEye()); 31 | view.Width = ext.MaxPoint.X - ext.MinPoint.X; 32 | view.Height = ext.MaxPoint.Y - ext.MinPoint.Y; 33 | view.CenterPoint = new Point2d( 34 | (ext.MaxPoint.X + ext.MinPoint.X) / 2.0, 35 | (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0); 36 | ed.SetCurrentView(view); 37 | } 38 | } 39 | 40 | /// 41 | /// Zooms to the extents of the current viewport. 42 | /// 43 | /// Instance to which the method applies. 44 | /// Thrown if is null. 45 | public static void ZoomExtents(this Editor ed) 46 | { 47 | Assert.IsNotNull(ed, nameof(ed)); 48 | 49 | Database db = ed.Document.Database; 50 | db.UpdateExt(false); 51 | Extents3d ext = (short)Application.GetSystemVariable("cvport") == 1 ? 52 | new Extents3d(db.Pextmin, db.Pextmax) : 53 | new Extents3d(db.Extmin, db.Extmax); 54 | ed.Zoom(ext); 55 | } 56 | 57 | /// 58 | /// Zooms to the given window. 59 | /// 60 | /// Instance to which the method applies. 61 | /// First window corner. 62 | /// Opposite window corner. 63 | /// Thrown if is null. 64 | public static void ZoomWindow(this Editor ed, Point3d p1, Point3d p2) 65 | { 66 | Assert.IsNotNull(ed, nameof(ed)); 67 | 68 | var extents = new Extents3d(); 69 | extents.AddPoint(p1); 70 | extents.AddPoint(p2); 71 | ed.Zoom(extents); 72 | } 73 | 74 | /// 75 | /// Zooms to the specified entity collection. 76 | /// 77 | /// Instance to which the method applies. 78 | /// Collection of the entities ObjectId on which to zoom. 79 | /// Thrown if is null. 80 | public static void ZoomObjects(this Editor ed, IEnumerable ids) 81 | { 82 | Assert.IsNotNull(ed, nameof(ed)); 83 | Assert.IsNotNull(ids, nameof(ids)); 84 | 85 | using (Transaction tr = ed.Document.TransactionManager.StartOpenCloseTransaction()) 86 | { 87 | Extents3d ext = ids 88 | .GetObjects(tr) 89 | .Select(ent => ent.Bounds) 90 | .Where(b => b.HasValue) 91 | .Select(b => b.Value) 92 | .Aggregate((e1, e2) => { e1.AddExtents(e2); return e1; }); 93 | ed.Zoom(ext); 94 | tr.Commit(); 95 | } 96 | } 97 | 98 | /// 99 | /// Zooms in current viewport to the specified scale. 100 | /// 101 | /// Instance to which the method applies. 102 | /// Scale. 103 | /// Thrown if is null. 104 | public static void ZoomScale(this Editor ed, double scale) 105 | { 106 | Assert.IsNotNull(ed, nameof(ed)); 107 | 108 | using (ViewTableRecord view = ed.GetCurrentView()) 109 | { 110 | view.Width /= scale; 111 | view.Height /= scale; 112 | ed.SetCurrentView(view); 113 | } 114 | } 115 | 116 | /// 117 | /// Zooms in current viewport to the specified scale and center. 118 | /// 119 | /// Instance to which the method applies. 120 | /// Viewport center. 121 | /// Scale (default = 1). 122 | /// Thrown if is null. 123 | public static void ZoomCenter(this Editor ed, Point3d center, double scale = 1.0) 124 | { 125 | Assert.IsNotNull(ed, nameof(ed)); 126 | 127 | using (ViewTableRecord view = ed.GetCurrentView()) 128 | { 129 | center = center.TransformBy(view.WorldToEye()); 130 | view.Height /= scale; 131 | view.Width /= scale; 132 | view.CenterPoint = new Point2d(center.X, center.Y); 133 | ed.SetCurrentView(view); 134 | } 135 | } 136 | 137 | #endregion 138 | 139 | #region Selection 140 | 141 | /// 142 | /// Gets a selection set using the supplied prompt selection options, the supplied filter and the supplied predicate. 143 | /// 144 | /// Instance to which the method applies. 145 | /// Selection options. 146 | /// Selection filter 147 | /// Selection predicate. 148 | /// The selection result. 149 | /// Thrown if is null. 150 | /// Thrown if is null. 151 | public static PromptSelectionResult GetSelection(this Editor ed, PromptSelectionOptions options, SelectionFilter filter, System.Predicate predicate) => 152 | GetPredicatedSelection(ed, predicate, options, filter); 153 | 154 | /// 155 | /// Gets a selection set using the supplied prompt selection options and the supplied predicate. 156 | /// 157 | /// Instance to which the method applies. 158 | /// Selection options. 159 | /// Selection predicate. 160 | /// The selection result. 161 | /// Thrown if is null. 162 | /// Thrown if is null. 163 | public static PromptSelectionResult GetSelection(this Editor ed, PromptSelectionOptions options, System.Predicate predicate) => 164 | GetPredicatedSelection(ed, predicate, options); 165 | 166 | /// 167 | /// Gets a selection set using the supplied filter and the supplied predicate. 168 | /// 169 | /// Instance to which the method applies. 170 | /// Selection filter 171 | /// Selection predicate. 172 | /// The selection result. 173 | /// Thrown if is null. 174 | /// Thrown if is null. 175 | public static PromptSelectionResult GetSelection(this Editor ed, SelectionFilter filter, System.Predicate predicate) => 176 | GetPredicatedSelection(ed, predicate, null, filter); 177 | 178 | /// 179 | /// Gets a selection set using the supplied predicate. 180 | /// 181 | /// Instance to which the method applies. 182 | /// Selection predicate. 183 | /// The selection result. 184 | /// Thrown if is null. 185 | /// Thrown if is null. 186 | public static PromptSelectionResult GetSelection(this Editor ed, System.Predicate predicate) => 187 | GetPredicatedSelection(ed, predicate, null, null); 188 | 189 | private static PromptSelectionResult GetPredicatedSelection( 190 | Editor ed, 191 | System.Predicate predicate, 192 | PromptSelectionOptions options = null, 193 | SelectionFilter filter = null) 194 | { 195 | Assert.IsNotNull(ed, nameof(ed)); 196 | Assert.IsNotNull(predicate, nameof(predicate)); 197 | 198 | void onSelectionAdded(object sender, SelectionAddedEventArgs e) 199 | { 200 | var ids = e.AddedObjects.GetObjectIds(); 201 | for (int i = 0; i < ids.Length; i++) 202 | { 203 | if (!predicate(ids[i])) 204 | { 205 | e.Remove(i); 206 | } 207 | } 208 | } 209 | 210 | PromptSelectionResult result; 211 | ed.SelectionAdded += onSelectionAdded; 212 | if (options == null) 213 | { 214 | if (filter == null) 215 | { 216 | result = ed.GetSelection(); 217 | } 218 | else 219 | { 220 | result = ed.GetSelection(filter); 221 | } 222 | } 223 | else 224 | { 225 | if (filter == null) 226 | { 227 | result = ed.GetSelection(options); 228 | } 229 | else 230 | { 231 | result = ed.GetSelection(options, filter); 232 | } 233 | } 234 | ed.SelectionAdded -= onSelectionAdded; 235 | return result; 236 | } 237 | 238 | #endregion 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/EntityExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | namespace Gile.AutoCAD.R20.Extension 4 | { 5 | /// 6 | /// Provides extension methods for the Entity type. 7 | /// 8 | public static class EntityExtension 9 | { 10 | /// 11 | /// Evaluates if the owner of is a Layout. 12 | /// 13 | /// Instance to which the method applies. 14 | /// Transaction or OpenCloseTransaction to use. 15 | /// true, if the owner is a Layout; false, otherwise. 16 | /// Thrown if is null. 17 | /// Thrown if is null. 18 | public static bool IsOwnedByLayout(this Entity entity, Transaction tr) 19 | { 20 | Assert.IsNotNull(entity, nameof(entity)); 21 | Assert.IsNotNull(entity, nameof(tr)); 22 | 23 | 24 | var owner = tr.GetObject(entity.OwnerId, OpenMode.ForRead); 25 | return owner is BlockTableRecord btr && btr.IsLayout; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/Gile.AutoCAD.R20.Extension.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {32EBFF40-CE54-4B05-AEBA-2EEFFEDB443B} 8 | Library 9 | Properties 10 | Gile.AutoCAD.R20.Extension 11 | Gile.AutoCAD.R20.Extension 12 | v4.8 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | Program 25 | C:\Program Files\Autodesk\AutoCAD 2017\acad.exe 26 | /nologo /b "start.scr" 27 | 28 | 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | bin\Release\Gile.AutoCAD.R20.Extension.xml 38 | 39 | 40 | 41 | F:\ObjectARX 2016\inc\AcCoreMgd.dll 42 | False 43 | 44 | 45 | F:\ObjectARX 2016\inc\AcDbMgd.dll 46 | False 47 | 48 | 49 | F:\ObjectARX 2016\inc\AcMgd.dll 50 | False 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 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 | 96 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/IDisposableCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Gile.AutoCAD.R20.Extension 5 | { 6 | /// 7 | /// Defines methods to add or removes items from a sequence of disposable objects. 8 | /// 9 | /// Type of the items. 10 | public interface IDisposableCollection : ICollection, IDisposable 11 | where T : IDisposable 12 | { 13 | /// 14 | /// Adds items to the sequence. 15 | /// 16 | /// Items to add. 17 | void AddRange(IEnumerable items); 18 | 19 | /// 20 | /// Removes items from the sequence. 21 | /// 22 | /// Items to remove. 23 | /// The sequence of removed items. 24 | IEnumerable RemoveRange(IEnumerable items); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/IEnumerableExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Gile.AutoCAD.R20.Extension 9 | { 10 | /// 11 | /// Provides extension methods for the IEnumerable(T) type. 12 | /// 13 | public static class IEnumerableExtension 14 | { 15 | /// 16 | /// Opens the objects which type matches to the given one, and return them. 17 | /// 18 | /// Type of object to return. 19 | /// Sequence of ObjectIds. 20 | /// Transaction or OpenCloseTransaction to use. 21 | /// Open mode to obtain in. 22 | /// Value indicating whether to obtain erased objects. 23 | /// Value indicating if locked layers should be opened. 24 | /// The sequence of opened objects. 25 | /// Thrown if is null. 26 | /// Thrown if is null. 27 | public static IEnumerable GetObjects( 28 | this IEnumerable source, 29 | Transaction tr, 30 | OpenMode mode = OpenMode.ForRead, 31 | bool openErased = false, 32 | bool forceOpenOnLockedLayers = false) where T : DBObject 33 | { 34 | Assert.IsNotNull(source, nameof(source)); 35 | Assert.IsNotNull(tr, nameof(source)); 36 | 37 | if (source.Any()) 38 | { 39 | var rxClass = RXObject.GetClass(typeof(T)); 40 | foreach (ObjectId id in source) 41 | { 42 | if (id.ObjectClass.IsDerivedFrom(rxClass) && 43 | (!id.IsErased || openErased)) 44 | { 45 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 46 | } 47 | } 48 | } 49 | } 50 | 51 | /// 52 | /// Upgrades the open mode of all objects in the sequence. 53 | /// 54 | /// Type of objects. 55 | /// Sequence of DBObjects to upgrade. 56 | /// Transaction or OpenCloseTransaction to use. 57 | /// The sequence of opened for write objects (objets on locked layers are discared). 58 | /// Thrown if is null. 59 | /// Thrown if is null. 60 | public static IEnumerable UpgradeOpen(this IEnumerable source, Transaction tr) where T : DBObject 61 | { 62 | Assert.IsNotNull(source, nameof(source)); 63 | 64 | foreach (T item in source) 65 | { 66 | try 67 | { 68 | item.OpenForWrite(tr); 69 | } 70 | catch (Autodesk.AutoCAD.Runtime.Exception ex) 71 | { 72 | if (ex.ErrorStatus != ErrorStatus.OnLockedLayer) 73 | { 74 | throw; 75 | } 76 | continue; 77 | } 78 | yield return item; 79 | } 80 | } 81 | 82 | /// 83 | /// Disposes of all items of the sequence. 84 | /// 85 | /// Type of the items. 86 | /// Sequence of disposable objects. 87 | /// Thrown if is null. 88 | public static void DisposeAll(this IEnumerable source) where T : IDisposable 89 | { 90 | Assert.IsNotNull(source, nameof(source)); 91 | 92 | if (source.Any()) 93 | { 94 | System.Exception last = null; 95 | foreach (T item in source) 96 | { 97 | if (item != null) 98 | { 99 | try 100 | { 101 | item.Dispose(); 102 | } 103 | catch (System.Exception ex) 104 | { 105 | last = last ?? ex; 106 | } 107 | } 108 | } 109 | if (last != null) 110 | { 111 | throw last; 112 | } 113 | } 114 | } 115 | 116 | /// 117 | /// Runs the action for each item of the collection. 118 | /// 119 | /// Type of the items. 120 | /// Sequence to process. 121 | /// Action to run. 122 | /// Thrown if is null. 123 | /// Thrown if is null. 124 | public static void ForEach(this IEnumerable source, Action action) 125 | { 126 | Assert.IsNotNull(source, nameof(source)); 127 | Assert.IsNotNull(action, nameof(action)); 128 | 129 | foreach (T item in source) 130 | { 131 | action(item); 132 | } 133 | } 134 | 135 | /// 136 | /// Runs the indexed action for each item of the collection. 137 | /// 138 | /// Type of the items. 139 | /// Sequence to process. 140 | /// Indexed action to run. 141 | /// Thrown if is null. 142 | /// Thrown if is null. 143 | public static void ForEach(this IEnumerable source, Action action) 144 | { 145 | Assert.IsNotNull(source, nameof(source)); 146 | Assert.IsNotNull(action, nameof(action)); 147 | 148 | int i = 0; 149 | foreach (T item in source) 150 | { 151 | action(item, i++); 152 | } 153 | } 154 | 155 | /// 156 | /// Gets the greatest item of the sequence using with the function returned values. 157 | /// 158 | /// Type the items. 159 | /// Type of the returned value of function. 160 | /// Sequence to which the method applies. 161 | /// Mapping function from TSource to TKey. 162 | /// Comparer used for the TKey type; uses Comparer<TKey>.Default if null or omitted. 163 | /// The greatest item in the sequence. 164 | /// Thrown if is null. 165 | /// Thrown if is null. 166 | public static TSource MaxBy( 167 | this IEnumerable source, 168 | Func selector, 169 | IComparer comparer = null) 170 | { 171 | Assert.IsNotNull(source, nameof(source)); 172 | Assert.IsNotNull(selector, nameof(selector)); 173 | 174 | comparer = comparer ?? Comparer.Default; 175 | using (var iterator = source.GetEnumerator()) 176 | { 177 | if (!iterator.MoveNext()) 178 | { 179 | throw new InvalidOperationException("Empty sequence"); 180 | } 181 | var max = iterator.Current; 182 | var maxKey = selector(max); 183 | while (iterator.MoveNext()) 184 | { 185 | var current = iterator.Current; 186 | var currentKey = selector(current); 187 | if (comparer.Compare(currentKey, maxKey) > 0) 188 | { 189 | max = current; 190 | maxKey = currentKey; 191 | } 192 | } 193 | return max; 194 | } 195 | } 196 | 197 | /// 198 | /// Gets the smallest item of the sequence using the with the function returned values. 199 | /// 200 | /// Type the items. 201 | /// Type of the returned value of function. 202 | /// Sequence to which the method applies. 203 | /// Mapping function from TSource to TKey. 204 | /// Comparer used for the TKey type; uses Comparer<TKey>.Default if null or omitted. 205 | /// The smallest item in the sequence. 206 | /// Thrown if is null. 207 | /// Thrown if is null. 208 | public static TSource MinBy( 209 | this IEnumerable source, 210 | Func selector, 211 | IComparer comparer = null) 212 | { 213 | Assert.IsNotNull(source, nameof(source)); 214 | Assert.IsNotNull(selector, nameof(selector)); 215 | 216 | comparer = comparer ?? Comparer.Default; 217 | using (var iterator = source.GetEnumerator()) 218 | { 219 | if (!iterator.MoveNext()) 220 | { 221 | throw new InvalidOperationException("Empty sequence"); 222 | } 223 | var min = iterator.Current; 224 | var minKey = selector(min); 225 | while (iterator.MoveNext()) 226 | { 227 | var current = iterator.Current; 228 | var currentKey = selector(current); 229 | if (comparer.Compare(currentKey, minKey) < 0) 230 | { 231 | min = current; 232 | minKey = currentKey; 233 | } 234 | } 235 | return min; 236 | } 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/MTextExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | 4 | using System; 5 | 6 | namespace Gile.AutoCAD.R20.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the MText Type. 10 | /// 11 | public static class MTextExtension 12 | { 13 | /// 14 | /// Gets the points at corners of the mtext bounding box. 15 | /// 16 | /// Instance to which the method applies. 17 | /// The points (counter-clockwise from lower left). 18 | /// Thrown if is null. 19 | public static Point3d[] GetMTextBoxCorners(this MText mtext) 20 | { 21 | Assert.IsNotNull(mtext, nameof(mtext)); 22 | 23 | double width = mtext.ActualWidth; 24 | double height = mtext.ActualHeight; 25 | Point3d point1, point2; 26 | switch (mtext.Attachment) 27 | { 28 | case AttachmentPoint.TopLeft: 29 | default: 30 | point1 = new Point3d(0.0, -height, 0.0); 31 | point2 = new Point3d(width, 0.0, 0.0); 32 | break; 33 | case AttachmentPoint.TopCenter: 34 | point1 = new Point3d(-width * 0.5, -height, 0.0); 35 | point2 = new Point3d(width * 0.5, 0.0, 0.0); 36 | break; 37 | case AttachmentPoint.TopRight: 38 | point1 = new Point3d(-width, -height, 0.0); 39 | point2 = new Point3d(0.0, 0.0, 0.0); 40 | break; 41 | case AttachmentPoint.MiddleLeft: 42 | point1 = new Point3d(0.0, -height * 0.5, 0.0); 43 | point2 = new Point3d(width, height * 0.5, 0.0); 44 | break; 45 | case AttachmentPoint.MiddleCenter: 46 | point1 = new Point3d(-width * 0.5, -height * 0.5, 0.0); 47 | point2 = new Point3d(width * 0.5, height * 0.5, 0.0); 48 | break; 49 | case AttachmentPoint.MiddleRight: 50 | point1 = new Point3d(-width, -height * 0.5, 0.0); 51 | point2 = new Point3d(0.0, height * 0.5, 0.0); 52 | break; 53 | case AttachmentPoint.BottomLeft: 54 | point1 = new Point3d(0.0, 0.0, 0.0); 55 | point2 = new Point3d(width, height, 0.0); 56 | break; 57 | case AttachmentPoint.BottomCenter: 58 | point1 = new Point3d(-width * 0.5, 0.0, 0.0); 59 | point2 = new Point3d(width * 0.5, height, 0.0); 60 | break; 61 | case AttachmentPoint.BottomRight: 62 | point1 = new Point3d(-width, 0.0, 0.0); 63 | point2 = new Point3d(0.0, height, 0.0); 64 | break; 65 | } 66 | 67 | var xform = 68 | Matrix3d.Displacement(mtext.Location.GetAsVector()) * 69 | Matrix3d.Rotation(mtext.Rotation, mtext.Normal, Point3d.Origin) * 70 | Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, mtext.Normal)); 71 | 72 | return new[] 73 | { 74 | point1.TransformBy(xform), 75 | new Point3d(point2.X, point1.Y, 0.0).TransformBy(xform), 76 | point2.TransformBy(xform), 77 | new Point3d(point1.X, point2.Y, 0.0).TransformBy(xform) 78 | }; 79 | } 80 | 81 | /// 82 | /// Mirrors the mtext honoring the value of MIRRTEXT system variable. 83 | /// 84 | /// Instance to which the method applies. 85 | /// Transaction or OpenCloseTransaction to use. 86 | /// Axis of the mirroring operation. 87 | /// Value indicating if the source block reference have to be erased. 88 | /// Thrown if is null. 89 | /// Thrown if is null. 90 | /// Thrown if is null. 91 | public static void Mirror(this MText source, Transaction tr, Line3d axis, bool eraseSource) 92 | { 93 | Assert.IsNotNull(source, nameof(source)); 94 | Assert.IsNotNull(tr, nameof(tr)); 95 | Assert.IsNotNull(axis, nameof(axis)); 96 | 97 | var db = source.Database; 98 | MText mirrored; 99 | if (eraseSource) 100 | { 101 | mirrored = source; 102 | if (!mirrored.IsWriteEnabled) 103 | { 104 | tr.GetObject(mirrored.ObjectId, OpenMode.ForWrite); 105 | } 106 | } 107 | else 108 | { 109 | var ids = new ObjectIdCollection(new[] { source.ObjectId }); 110 | var mapping = new IdMapping(); 111 | db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, false); 112 | mirrored = (MText)tr.GetObject(mapping[source.ObjectId].Value, OpenMode.ForWrite); 113 | } 114 | mirrored.TransformBy(Matrix3d.Mirroring(axis)); 115 | 116 | if (!db.Mirrtext) 117 | { 118 | var pts = mirrored.GetMTextBoxCorners(); 119 | var cen = new LineSegment3d(pts[0], pts[2]).MidPoint; 120 | var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ? 121 | pts[0].GetVectorTo(pts[3]) : 122 | pts[0].GetVectorTo(pts[1]); 123 | mirrored.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen)); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/ObjectIdCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System.Collections.Generic; 5 | 6 | namespace Gile.AutoCAD.R20.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the ObjectIdCollection type. 10 | /// 11 | public static class ObjectIdCollectionExtension 12 | { 13 | 14 | /// 15 | /// Opens the objects which type matches to the given one, and return them. 16 | /// 17 | /// Type of objects to return. 18 | /// Instance to which the method applies. 19 | /// Transaction or OpenCloseTransaction to use. 20 | /// Open mode to obtain in. 21 | /// Value indicating whether to obtain erased objects. 22 | /// Value indicating if locked layers should be opened. 23 | /// The sequence of opened objects. 24 | /// Thrown if is null. 25 | /// Thrown if is null. 26 | public static IEnumerable GetObjects( 27 | this ObjectIdCollection source, 28 | Transaction tr, 29 | OpenMode mode = OpenMode.ForRead, 30 | bool openErased = false, 31 | bool forceOpenOnLockedLayers = false) 32 | where T : DBObject 33 | { 34 | Assert.IsNotNull(source, nameof(source)); 35 | Assert.IsNotNull(tr, nameof(tr)); 36 | 37 | if (0 < source.Count) 38 | { 39 | var rxClass = RXObject.GetClass(typeof(T)); 40 | foreach (ObjectId id in source) 41 | { 42 | if ((id.ObjectClass == rxClass || id.ObjectClass.IsDerivedFrom(rxClass)) && 43 | (!id.IsErased || openErased)) 44 | { 45 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/ObjectIdExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System.Runtime.InteropServices; 5 | 6 | namespace Gile.AutoCAD.R20.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the ObjectId type. 10 | /// 11 | public static class ObjectIdExtension 12 | { 13 | /// 14 | /// Tries to open an AutoCAD object of the given type in the given open mode. 15 | /// 16 | /// Type of the output object. 17 | /// ObjectId to open. 18 | /// Transaction or OpenCloseTransaction to use. 19 | /// Output object. 20 | /// Open mode to obtain in. 21 | /// Value indicating whether to obtain erased objects. 22 | /// Value indicating if locked layers should be opened. 23 | /// true, if the operation succeeded; false, otherwise. 24 | /// eNullObjectId is thrown if equals ObjectId.Null. 25 | /// Thrown if is null. 26 | public static bool TryGetObject( 27 | this ObjectId id, 28 | Transaction tr, 29 | out T obj, 30 | OpenMode mode = OpenMode.ForRead, 31 | bool openErased = false, 32 | bool forceOpenOnLockedLayer = false) 33 | where T : DBObject 34 | { 35 | Assert.IsNotObjectIdNull(id, nameof(id)); 36 | Assert.IsNotNull(tr, nameof(tr)); 37 | 38 | obj = default; 39 | if (!id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(T)))) 40 | { 41 | return false; 42 | } 43 | obj = (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayer); 44 | return true; 45 | } 46 | 47 | /// 48 | /// Opens an AutoCAD object of the given type in the given open mode. 49 | /// 50 | /// Type of the object to return. 51 | /// ObjectId to open. 52 | /// Transaction or OpenCloseTransaction to use. 53 | /// Open mode to obtain in. 54 | /// Value indicating whether to obtain erased objects. 55 | /// Value indicating if locked layers should be opened. 56 | /// The object opened in given open mode. 57 | /// Thrown if the object type does not match the given type 58 | /// eNullObjectId is thrown if equals ObjectId.Null. 59 | /// Thrown if is null. 60 | public static T GetObject( 61 | this ObjectId id, 62 | Transaction tr, 63 | OpenMode mode = OpenMode.ForRead, 64 | bool openErased = false, 65 | bool forceOpenOnLockedLayer = false) 66 | where T : DBObject 67 | { 68 | Assert.IsNotObjectIdNull(id, nameof(id)); 69 | Assert.IsNotNull(tr, nameof(tr)); 70 | 71 | return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayer); 72 | } 73 | 74 | /// 75 | /// Get the DXF definition data (like AutoLISP entget function). 76 | /// 77 | /// Instance to which the method applies. 78 | /// The DXF data. 79 | /// Thrown in case of invalid objectId. 80 | public static ResultBuffer EntGet(this ObjectId id) 81 | { 82 | var errorStatus = acdbGetAdsName(out AdsName ename, id); 83 | if (errorStatus != ErrorStatus.OK) 84 | { 85 | throw new Exception(errorStatus); 86 | } 87 | var result = acdbEntGet(ename); 88 | if (result != System.IntPtr.Zero) 89 | { 90 | return ResultBuffer.Create(result, true); 91 | } 92 | return null; 93 | } 94 | 95 | // Replace the DLL name according to the AutoCAD targeted version 96 | // 2013-2014: "acdb19.dll" 97 | // 2015-2016: "acdb20.dll" 98 | // 2017: "acdb21.dll" 99 | // 2018: "acdb22.dll" 100 | // 2019-2020: "acdb23.dll" 101 | // 2021-2024: "acdb24.dll" 102 | // Replace the EntryPoint according to AutoCAD plateform 103 | // 32 bits: "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z" 104 | // 64 bits: "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z" 105 | [System.Security.SuppressUnmanagedCodeSecurity] 106 | [DllImport("acdb24.dll", CallingConvention = CallingConvention.Cdecl, 107 | EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] 108 | private static extern ErrorStatus acdbGetAdsName(out AdsName ename, ObjectId id); 109 | 110 | [System.Security.SuppressUnmanagedCodeSecurity] 111 | [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, 112 | EntryPoint = "acdbEntGet")] 113 | private static extern System.IntPtr acdbEntGet(AdsName ename); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/PolylineExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Gile.AutoCAD.R20.Extension 8 | { 9 | /// 10 | /// Enumeration of offset side options 11 | /// 12 | public enum OffsetSide 13 | { 14 | /// 15 | /// Inside. 16 | /// 17 | In, 18 | /// 19 | /// Outside. 20 | /// 21 | Out, 22 | /// 23 | /// Left side. 24 | /// 25 | Left, 26 | /// 27 | /// Right side. 28 | /// 29 | Right, 30 | /// 31 | /// Both sides. 32 | /// 33 | Both 34 | } 35 | 36 | // credits to Tony 'TheMaster' Tanzillo 37 | // http://www.theswamp.org/index.php?topic=31862.msg494503#msg494503 38 | 39 | /// 40 | /// Provides the Offset() extension method for the Polyline type 41 | /// 42 | public static class PolylineExtension 43 | { 44 | /// 45 | /// Offset the source polyline to specified side(s). 46 | /// 47 | /// Instance to which the method applies. 48 | /// Offset distance. 49 | /// Offset side(s). 50 | /// A polyline sequence resulting from the offset of the source polyline. 51 | /// Thrown if is null. 52 | public static IEnumerable Offset(this Polyline source, double offsetDist, OffsetSide side) 53 | { 54 | Assert.IsNotNull(source, nameof(source)); 55 | 56 | offsetDist = Math.Abs(offsetDist); 57 | using (var plines = new DisposableSet()) 58 | { 59 | IEnumerable offsetRight = source.GetOffsetCurves(offsetDist).Cast(); 60 | plines.AddRange(offsetRight); 61 | IEnumerable offsetLeft = source.GetOffsetCurves(-offsetDist).Cast(); 62 | plines.AddRange(offsetLeft); 63 | double areaRight = offsetRight.Select(pline => pline.Area).Sum(); 64 | double areaLeft = offsetLeft.Select(pline => pline.Area).Sum(); 65 | switch (side) 66 | { 67 | case OffsetSide.In: 68 | return plines.RemoveRange( 69 | areaRight < areaLeft ? offsetRight : offsetLeft); 70 | case OffsetSide.Out: 71 | return plines.RemoveRange( 72 | areaRight < areaLeft ? offsetLeft : offsetRight); 73 | case OffsetSide.Left: 74 | return plines.RemoveRange(offsetLeft); 75 | case OffsetSide.Right: 76 | return plines.RemoveRange(offsetRight); 77 | case OffsetSide.Both: 78 | plines.Clear(); 79 | return offsetRight.Concat(offsetLeft); 80 | default: 81 | return null; 82 | } 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Les informations générales relatives à un assembly dépendent de 6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations 7 | // associées à un assembly. 8 | [assembly: AssemblyTitle("Gile.AutoCAD.R20.Extension")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("gileCAD")] 12 | [assembly: AssemblyProduct("Gile.AutoCAD.R20.Extension")] 13 | [assembly: AssemblyCopyright("Copyright © Gilles Chanteau 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly 18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de 19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM 23 | [assembly: Guid("32ebff40-ce54-4b05-aeba-2eeffedb443b")] 24 | 25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes : 26 | // 27 | // Version principale 28 | // Version secondaire 29 | // Numéro de build 30 | // Révision 31 | // 32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut 33 | // en utilisant '*', comme indiqué ci-dessous : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2.0.0.0")] 36 | [assembly: AssemblyFileVersion("2.0.0.0")] 37 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/ResultBufferExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Gile.AutoCAD.Extension 8 | { 9 | internal class ResultBufferExtension 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/SymbolTableExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Gile.AutoCAD.R20.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the SymbolTable type. 10 | /// 11 | public static class SymbolTableExtension 12 | { 13 | /// 14 | /// Opens the table records in the given open mode. 15 | /// 16 | /// Type of returned object. 17 | /// Instance to which the method applies. 18 | /// Transaction or OpenCloseTransaction to use. 19 | /// Open mode to obtain in. 20 | /// Value indicating whether to obtain erased objects. 21 | /// The sequence of records. 22 | /// Thrown if is null. 23 | /// Thrown if is null. 24 | public static IEnumerable GetObjects(this SymbolTable source, Transaction tr, OpenMode mode = OpenMode.ForRead, bool openErased = false) 25 | where T : SymbolTableRecord 26 | { 27 | Assert.IsNotNull(source, nameof(source)); 28 | Assert.IsNotNull(tr, nameof(tr)); 29 | 30 | foreach (ObjectId id in openErased ? source.IncludingErased : source) 31 | { 32 | yield return (T)tr.GetObject(id, mode, openErased, false); 33 | } 34 | } 35 | 36 | /// 37 | /// Purges the unreferenced symbol table records. 38 | /// 39 | /// Instance to which the method applies. 40 | /// Transaction or OpenCloseTransaction to use. 41 | /// The number of pruged records. 42 | /// Thrown if is null. 43 | /// Thrown if is null. 44 | public static int Purge(this SymbolTable symbolTable, Transaction tr) 45 | { 46 | Assert.IsNotNull(symbolTable, nameof(symbolTable)); 47 | Assert.IsNotNull(tr, nameof(tr)); 48 | 49 | Database db = symbolTable.Database; 50 | int cnt = 0; 51 | var unpurgeable = new HashSet(); 52 | while (true) 53 | { 54 | var ids = new ObjectIdCollection(symbolTable.Cast().Except(unpurgeable).ToArray()); 55 | db.Purge(ids); 56 | if (ids.Count == 0) 57 | { 58 | break; 59 | } 60 | foreach (ObjectId id in ids) 61 | { 62 | try 63 | { 64 | tr.GetObject(id, OpenMode.ForWrite).Erase(); 65 | cnt++; 66 | } 67 | catch 68 | { 69 | unpurgeable.Add(id); 70 | } 71 | } 72 | } 73 | return cnt; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R20.Extension/WorkingDatabase.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System; 4 | 5 | namespace Gile.AutoCAD.R20.Extension 6 | { 7 | /// 8 | /// Provides a safe way to temporarily set the working database. 9 | /// Credits Tony Tanzillo: https://forums.autodesk.com/t5/net/want-to-have-c-program-to-modify-dwg-and-save-into-dwg-format/m-p/12439905/highlight/true#M79788 10 | /// 11 | public class WorkingDatabase : IDisposable 12 | { 13 | Database previous; 14 | 15 | /// 16 | /// Creates a new instance of WorkingDatabase. 17 | /// 18 | /// Database to be temporarily set as working database. 19 | public WorkingDatabase(Database newWorkingDb) 20 | { 21 | Assert.IsNotNull(newWorkingDb, nameof(newWorkingDb)); 22 | 23 | Database current = HostApplicationServices.WorkingDatabase; 24 | if (newWorkingDb != current) 25 | { 26 | previous = current; 27 | HostApplicationServices.WorkingDatabase = newWorkingDb; 28 | } 29 | } 30 | 31 | /// 32 | /// Restores the previous working database. 33 | /// 34 | public void Dispose() 35 | { 36 | if (previous != null) 37 | { 38 | HostApplicationServices.WorkingDatabase = previous; 39 | previous = null; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/AbstractViewTableRecordExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | 4 | namespace Gile.AutoCAD.R25.Extension 5 | { 6 | /// 7 | /// Provides extension for the AbstractViewTableRecord type. 8 | /// 9 | public static class AbstractViewTableRecordExtension 10 | { 11 | /// 12 | /// Gets the transformation matrix from the view Display Coordinate System (DCS) to World Coordinate System (WCS). 13 | /// 14 | /// Instance to which the method applies. 15 | /// The DCS to WCS transformation matrix. 16 | /// Thrown if is null. 17 | public static Matrix3d EyeToWorld(this AbstractViewTableRecord view) 18 | { 19 | System.ArgumentNullException.ThrowIfNull(view); 20 | 21 | return 22 | Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * 23 | Matrix3d.Displacement(view.Target.GetAsVector()) * 24 | Matrix3d.PlaneToWorld(view.ViewDirection); 25 | } 26 | 27 | /// 28 | /// Gets the transformation matrix from World Coordinate System (WCS) to the view Display Coordinate System (DCS). 29 | /// 30 | /// Instance to which the method applies. 31 | /// The WCS to DCS transformation matrix. 32 | /// Thrown if is null. 33 | public static Matrix3d WorldToEye(this AbstractViewTableRecord view) 34 | { 35 | System.ArgumentNullException.ThrowIfNull(view); 36 | 37 | return 38 | Matrix3d.WorldToPlane(view.ViewDirection) * 39 | Matrix3d.Displacement(view.Target.GetAsVector().Negate()) * 40 | Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/Active.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.ApplicationServices.Core; 2 | using Autodesk.AutoCAD.DatabaseServices; 3 | using Autodesk.AutoCAD.EditorInput; 4 | 5 | using AcAp = Autodesk.AutoCAD.ApplicationServices; 6 | 7 | // Inspired by Scott McFarlane 8 | // https://www.autodesk.com/autodesk-university/class/Being-Remarkable-C-NET-AutoCAD-Developer-2015#handout 9 | 10 | namespace Gile.AutoCAD.R25.Extension 11 | { 12 | /// 13 | /// Provides easy access to several "active" objects in AutoCAD runtime environment. 14 | /// 15 | public static class Active 16 | { 17 | /// 18 | /// Gets the active Document object. 19 | /// 20 | public static AcAp.Document Document => Application.DocumentManager.MdiActiveDocument; 21 | 22 | /// 23 | /// Gets the active Database object. 24 | /// 25 | public static Database Database => Document.Database; 26 | 27 | /// 28 | /// Gets the active Editor object. 29 | /// 30 | public static Editor Editor => Document.Editor; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/AttributeCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System.Collections.Generic; 4 | 5 | namespace Gile.AutoCAD.R25.Extension 6 | { 7 | /// 8 | /// Provides extension methods for the AttributeCollection type. 9 | /// 10 | public static class AttributeCollectionExtension 11 | { 12 | /// 13 | /// Opens the attribute references in the given open mode. 14 | /// 15 | /// Attribute collection. 16 | /// Transaction or OpenCloseTransaction to use. 17 | /// Open mode to obtain in. 18 | /// Value indicating whether to obtain erased objects. 19 | /// Value indicating if locked layers should be opened. 20 | /// The sequence of attribute references. 21 | /// Thrown if is null. 22 | /// Thrown if is null. 23 | public static IEnumerable GetObjects( 24 | this AttributeCollection source, 25 | Transaction tr, 26 | OpenMode mode = OpenMode.ForRead, 27 | bool openErased = false, 28 | bool forceOpenOnLockedLayers = false) 29 | { 30 | System.ArgumentNullException.ThrowIfNull(source); 31 | System.ArgumentNullException.ThrowIfNull(tr); 32 | 33 | if (source.Count > 0) 34 | { 35 | foreach (ObjectId id in source) 36 | { 37 | if (!id.IsErased || openErased) 38 | { 39 | yield return (AttributeReference)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/BlockTableExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | namespace Gile.AutoCAD.R25.Extension 4 | { 5 | /// 6 | /// Provides extension methods for the BlockTable type. 7 | /// 8 | public static class BlockTableExtension 9 | { 10 | /// 11 | /// Gets the objectId of a block definition (BlockTableRecord) from its name. 12 | /// If the block is not found in the block table, a dwg file is searched in the support paths and added to the block table. 13 | /// 14 | /// Block table. 15 | /// Block name. 16 | /// The ObjectId of the block table record or ObjectId.Null if not found. 17 | /// Thrown if is null. 18 | /// Thrown if is null or empty. 19 | public static ObjectId GetBlock(this BlockTable blockTable, string blockName) 20 | { 21 | System.ArgumentNullException.ThrowIfNull(blockTable); 22 | System.ArgumentException.ThrowIfNullOrWhiteSpace(blockName); 23 | 24 | if (blockTable.Has(blockName)) 25 | return blockTable[blockName]; 26 | try 27 | { 28 | string blockPath = HostApplicationServices.Current.FindFile(blockName + ".dwg", blockTable.Database, FindFileHint.Default); 29 | using var tmpDb = new Database(false, true); 30 | tmpDb.ReadDwgFile(blockPath, FileOpenMode.OpenForReadAndAllShare, true, null); 31 | return blockTable.Database.Insert(blockName, tmpDb, true); 32 | } 33 | catch 34 | { 35 | return ObjectId.Null; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/BlockTableRecordExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | using Autodesk.AutoCAD.Runtime; 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Gile.AutoCAD.R25.Extension 9 | { 10 | /// 11 | /// Provides extension methods for the BlockTableRecord type. 12 | /// 13 | public static class BlockTableRecordExtension 14 | { 15 | /// 16 | /// Opens the entities which type matches to the given one, and return them. 17 | /// 18 | /// Type of objects to return. 19 | /// Block table record. 20 | /// Transaction or OpenCloseTransaction to use. 21 | /// Open mode to obtain in. 22 | /// Value indicating whether to obtain erased objects. 23 | /// Value indicating if locked layers should be opened. 24 | /// The sequence of opened objects. 25 | /// Thrown if is null. 26 | /// Thrown if is null. 27 | public static IEnumerable GetObjects( 28 | this BlockTableRecord btr, 29 | Transaction tr, 30 | OpenMode mode = OpenMode.ForRead, 31 | bool openErased = false, 32 | bool forceOpenOnLockedLayers = false) where T : Entity 33 | { 34 | System.ArgumentNullException.ThrowIfNull(btr); 35 | System.ArgumentNullException.ThrowIfNull(tr); 36 | 37 | var source = openErased ? btr.IncludingErased : btr; 38 | if (typeof(T) == typeof(Entity)) 39 | { 40 | foreach (ObjectId id in source) 41 | { 42 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 43 | } 44 | } 45 | else 46 | { 47 | var rxClass = RXObject.GetClass(typeof(T)); 48 | foreach (ObjectId id in source) 49 | { 50 | if (id.ObjectClass.IsDerivedFrom(rxClass)) 51 | { 52 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 53 | } 54 | } 55 | } 56 | } 57 | 58 | /// 59 | /// Appends the entities to the BlockTableRecord. 60 | /// 61 | /// Instance to which the method applies. 62 | /// Transaction or OpenCloseTransaction to use. 63 | /// Sequence of entities. 64 | /// The collection of added entities ObjectId. 65 | /// Thrown if is null. 66 | /// Thrown if is null. 67 | /// Thrown if is null. 68 | public static ObjectIdCollection Add(this BlockTableRecord owner, Transaction tr, IEnumerable entities) 69 | { 70 | System.ArgumentNullException.ThrowIfNull(owner); 71 | System.ArgumentNullException.ThrowIfNull(tr); 72 | System.ArgumentNullException.ThrowIfNull(entities); 73 | 74 | var ids = new ObjectIdCollection(); 75 | using (var ents = new DisposableSet(entities)) 76 | { 77 | foreach (Entity ent in ents) 78 | { 79 | ids.Add(owner.AppendEntity(ent)); 80 | tr.AddNewlyCreatedDBObject(ent, true); 81 | } 82 | } 83 | return ids; 84 | } 85 | 86 | /// 87 | /// Appends the entities to the BlockTableRecord. 88 | /// 89 | /// Instance to which the method applies. 90 | /// Active transaction 91 | /// Collection of entities. 92 | /// The collection of added entities ObjectId. 93 | /// Thrown if is null. 94 | /// Thrown if is null. 95 | /// Thrown if is null. 96 | public static ObjectIdCollection AddRange(this BlockTableRecord owner, Transaction tr, params Entity[] entities) 97 | { 98 | System.ArgumentNullException.ThrowIfNull(owner); 99 | System.ArgumentNullException.ThrowIfNull(tr); 100 | System.ArgumentNullException.ThrowIfNull(entities); 101 | 102 | return owner.Add(tr, entities); 103 | } 104 | 105 | /// 106 | /// Appends the entity to the BlockTableRecord. 107 | /// 108 | /// Instance to which the method applies. 109 | /// Transaction or OpenCloseTransaction to use. 110 | /// Entity to add. 111 | /// The ObjectId of added entity. 112 | /// Thrown if is null. 113 | /// Thrown if is null. 114 | /// Thrown if is null. 115 | public static ObjectId Add(this BlockTableRecord owner, Transaction tr, Entity entity) 116 | { 117 | System.ArgumentNullException.ThrowIfNull(owner); 118 | System.ArgumentNullException.ThrowIfNull(tr); 119 | System.ArgumentNullException.ThrowIfNull(entity); 120 | 121 | try 122 | { 123 | var id = owner.AppendEntity(entity); 124 | tr.AddNewlyCreatedDBObject(entity, true); 125 | return id; 126 | } 127 | catch 128 | { 129 | entity.Dispose(); 130 | throw; 131 | } 132 | } 133 | 134 | /// 135 | /// Inserts a block reference. 136 | /// 137 | /// Instance to which the method applies. 138 | /// Transaction or OpenCloseTransaction to use. 139 | /// Nlock name. 140 | /// Insertion point. 141 | /// X scale factor. 142 | /// Y scale factor. 143 | /// Z scale factor. 144 | /// Rotation 145 | /// Collection of key/value pairs (Tag/Value). 146 | /// The newly created BlockReference. 147 | /// Thrown if is null. 148 | /// Thrown if is null. 149 | /// Thrown if is null or empty. 150 | public static BlockReference? InsertBlockReference( 151 | this BlockTableRecord target, 152 | Transaction tr, 153 | string blkName, 154 | Point3d insertPoint, 155 | double xScale = 1.0, 156 | double yScale = 1.0, 157 | double zScale = 1.0, 158 | double rotation = 0.0, 159 | Dictionary? attribValues = null) 160 | { 161 | System.ArgumentNullException.ThrowIfNull(target); 162 | System.ArgumentNullException.ThrowIfNull(target); 163 | System.ArgumentNullException.ThrowIfNull(tr); 164 | System.ArgumentException.ThrowIfNullOrWhiteSpace(blkName); 165 | 166 | var db = target.Database; 167 | BlockReference? br = null; 168 | var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); 169 | var btrId = bt.GetBlock(blkName); 170 | if (btrId != ObjectId.Null) 171 | { 172 | br = new BlockReference(insertPoint, btrId) { ScaleFactors = new Scale3d(xScale, yScale, zScale), Rotation = rotation }; 173 | var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead); 174 | if (btr.Annotative == AnnotativeStates.True) 175 | { 176 | var objectContextManager = db.ObjectContextManager; 177 | var objectContextCollection = objectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES"); 178 | Autodesk.AutoCAD.Internal.ObjectContexts.AddContext(br, objectContextCollection.CurrentContext); 179 | } 180 | target.Add(tr, br); 181 | br.AddAttributeReferences(tr, attribValues); 182 | } 183 | return br; 184 | } 185 | 186 | /// 187 | /// Synchronizes the attributes of all block references. 188 | /// 189 | /// Instance which the method applies. 190 | /// Transaction or OpenCloseTransaction to use. 191 | /// Thrown if is null. 192 | /// Thrown if is null. 193 | public static void SynchronizeAttributes(this BlockTableRecord target, Transaction tr) 194 | { 195 | System.ArgumentNullException.ThrowIfNull(target); 196 | System.ArgumentNullException.ThrowIfNull(tr); 197 | 198 | AttributeDefinition[] attDefs = target.GetObjects(tr).ToArray(); 199 | foreach (BlockReference br in target.GetBlockReferenceIds(true, false).GetObjects(tr, OpenMode.ForWrite)) 200 | { 201 | br.ResetAttributes(tr, attDefs); 202 | } 203 | if (target.IsDynamicBlock) 204 | { 205 | target.UpdateAnonymousBlocks(); 206 | foreach (BlockTableRecord btr in target.GetAnonymousBlockIds().GetObjects(tr)) 207 | { 208 | attDefs = btr.GetObjects(tr).ToArray(); 209 | foreach (BlockReference br in btr.GetBlockReferenceIds(true, false).GetObjects(tr, OpenMode.ForWrite)) 210 | { 211 | br.ResetAttributes(tr, attDefs); 212 | } 213 | } 214 | } 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/DBObjectCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System.Linq; 4 | 5 | namespace Gile.AutoCAD.R25.Extension 6 | { 7 | /// 8 | /// Provides extension methods for the DBObjectCollection type. 9 | /// 10 | public static class DBObjectCollectionExtension 11 | { 12 | /// 13 | /// Disposes of all objects in the collections. 14 | /// 15 | /// Instance to which the method applies. 16 | /// Thrown if is null. 17 | public static void DisposeAll(this DBObjectCollection source) 18 | { 19 | System.ArgumentNullException.ThrowIfNull(source); 20 | 21 | var list = source.Cast().ToList(); 22 | source.Clear(); 23 | list.DisposeAll(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/DBObjectExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | namespace Gile.AutoCAD.R25.Extension 5 | { 6 | /// 7 | /// Provides extension methods for the DBObject type. 8 | /// 9 | public static class DBObjectExtension 10 | { 11 | /// 12 | /// Tries to get the object extension dictionary. 13 | /// 14 | /// Instance to which the method applies. 15 | /// Transaction or OpenCloseTransaction to use. 16 | /// Output dictionary. 17 | /// Open mode to obtain in. 18 | /// Value indicating whether to obtain erased objects. 19 | /// true, if the operation succeeded; false, otherwise. 20 | /// Thrown if is null. 21 | /// Thrown if is null. 22 | public static bool TryGetExtensionDictionary( 23 | this DBObject dbObject, 24 | Transaction tr, 25 | out DBDictionary? dictionary, 26 | OpenMode mode = OpenMode.ForRead, 27 | bool openErased = false) 28 | { 29 | System.ArgumentNullException.ThrowIfNull(dbObject); 30 | System.ArgumentNullException.ThrowIfNull(tr); 31 | 32 | dictionary = default; 33 | var id = dbObject.ExtensionDictionary; 34 | if (id.IsNull) 35 | return false; 36 | dictionary = (DBDictionary)tr.GetObject(id, mode, openErased); 37 | return true; 38 | } 39 | 40 | /// 41 | /// Gets or creates the extension dictionary. 42 | /// 43 | /// Instance to which the method applies. 44 | /// Transaction or OpenCloseTransaction to use. 45 | /// Open mode to obtain in. 46 | /// The extension dictionary. 47 | /// Thrown if is null. 48 | /// Thrown if is null. 49 | public static DBDictionary GetOrCreateExtensionDictionary( 50 | this DBObject dbObject, 51 | Transaction tr, 52 | OpenMode mode = OpenMode.ForRead) 53 | { 54 | System.ArgumentNullException.ThrowIfNull(dbObject); 55 | System.ArgumentNullException.ThrowIfNull(tr); 56 | 57 | if (dbObject.ExtensionDictionary.IsNull) 58 | { 59 | dbObject.OpenForWrite(tr); 60 | dbObject.CreateExtensionDictionary(); 61 | } 62 | return (DBDictionary)tr.GetObject(dbObject.ExtensionDictionary, mode); 63 | } 64 | 65 | /// 66 | /// Tries to get the xrecord data of the extension dictionary of the object. 67 | /// 68 | /// Instance to which the method applies. 69 | /// Transaction or OpenCloseTransaction to use. 70 | /// Xrecord key. 71 | /// Output data. 72 | /// The xrecord data or null if the xrecord does not exists. 73 | /// Thrown if is null. 74 | /// Thrown if is null. 75 | /// Thrown if is null or empty. 76 | public static bool TryGetXDictionaryXrecordData(this DBObject source, Transaction tr, string key, out ResultBuffer? data) 77 | { 78 | System.ArgumentNullException.ThrowIfNull(source); 79 | System.ArgumentNullException.ThrowIfNull(tr); 80 | System.ArgumentException.ThrowIfNullOrWhiteSpace(key); 81 | 82 | data = default; 83 | return 84 | source.TryGetExtensionDictionary(tr, out DBDictionary? xdict) && 85 | xdict!.TryGetXrecordData(tr, key, out data); 86 | } 87 | 88 | /// 89 | /// Sets the xrecord data of the extension dictionary of the object. 90 | /// 91 | /// Instance to which the method applies. 92 | /// Transaction or OpenCloseTransaction to use. 93 | /// The xrecord key. 94 | /// The new xrecord data. 95 | /// The got or newlycreated Xrecord. 96 | /// Thrown if is null. 97 | /// Thrown if is null. 98 | /// Thrown if is null or empty. 99 | public static Xrecord SetXDictionaryXrecordData(this DBObject target, Transaction tr, string key, params TypedValue[] values) 100 | { 101 | System.ArgumentNullException.ThrowIfNull(target); 102 | System.ArgumentNullException.ThrowIfNull(tr); 103 | System.ArgumentException.ThrowIfNullOrWhiteSpace(key); 104 | 105 | return target.SetXDictionaryXrecordData(tr, key, new ResultBuffer(values)); 106 | } 107 | 108 | /// 109 | /// Sets the xrecord data of the extension dictionary of the object. 110 | /// 111 | /// Instance to which the method applies. 112 | /// Transaction or OpenCloseTransaction to use. 113 | /// The xrecord key. 114 | /// The new xrecord data. 115 | /// The got or newlycreated Xrecord. 116 | /// Thrown if is null. 117 | /// Thrown if is null. 118 | /// Thrown if is null or empty. 119 | public static Xrecord SetXDictionaryXrecordData(this DBObject target, Transaction tr, string key, ResultBuffer data) 120 | { 121 | System.ArgumentNullException.ThrowIfNull(target); 122 | System.ArgumentNullException.ThrowIfNull(tr); 123 | System.ArgumentException.ThrowIfNullOrWhiteSpace(key); 124 | 125 | return target.GetOrCreateExtensionDictionary(tr).SetXrecordData(tr, key, data); 126 | } 127 | 128 | /// 129 | /// Sets the object extended data (xdata) for the application. 130 | /// 131 | /// Instance to which the method applies. 132 | /// Transaction or OpenCloseTransaction to use. 133 | /// Extended data (the first TypedValue must be: (1001, <regAppName>)). 134 | /// Thrown if is null. 135 | /// Thrown if is null. 136 | /// Thrown if is null. 137 | /// eBadDxfSequence is thrown if the result buffer is not valid. 138 | public static void SetXDataForApplication(this DBObject target, Transaction tr, ResultBuffer data) 139 | { 140 | System.ArgumentNullException.ThrowIfNull(target); 141 | System.ArgumentNullException.ThrowIfNull(tr); 142 | System.ArgumentNullException.ThrowIfNull(data); 143 | 144 | var db = target.Database; 145 | var typedValue = data.AsArray()[0]; 146 | ErrorStatus.BadDxfSequence.ThrowIf(typedValue.TypeCode != 1001); 147 | string appName = (string)typedValue.Value; 148 | var regAppTable = (RegAppTable)tr.GetObject(db.RegAppTableId, OpenMode.ForRead); 149 | if (!regAppTable.Has(appName)) 150 | { 151 | var regApp = new RegAppTableRecord 152 | { 153 | Name = appName 154 | }; 155 | tr.GetObject(db.RegAppTableId, OpenMode.ForWrite); 156 | regAppTable.Add(regApp); 157 | tr.AddNewlyCreatedDBObject(regApp, true); 158 | } 159 | target.XData = data; 160 | } 161 | 162 | /// 163 | /// Opens the object for write. 164 | /// 165 | /// Instance to which the method applies. 166 | /// Transaction or OpenCloseTransaction to use. 167 | /// Thrown if is null. 168 | /// Thrown if is null. 169 | public static void OpenForWrite(this DBObject dbObj, Transaction tr) 170 | { 171 | System.ArgumentNullException.ThrowIfNull(dbObj); 172 | System.ArgumentNullException.ThrowIfNull(tr); 173 | 174 | if (!dbObj.IsWriteEnabled) 175 | { 176 | tr.GetObject(dbObj.ObjectId, OpenMode.ForWrite); 177 | } 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/DBTextExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Gile.AutoCAD.R25.Extension 8 | { 9 | /// 10 | /// Provides extension methods for the DBText type. 11 | /// 12 | public static partial class DBTextExtension 13 | { 14 | /// 15 | /// Gets the 'text box' of the DBText instance. 16 | /// 17 | /// Instance to which the method applies. 18 | /// Lower left corner of the box ('DBText coordinate system'). 19 | /// Upper right corner of the box ('DBText coordinate system') 20 | /// Transformation matrix from 'DBText coordinate system' to WCS. 21 | public static void GetTextBox(this DBText dbText, out Point3d point1, out Point3d point2, out Matrix3d transform) 22 | { 23 | ArgumentNullException.ThrowIfNull(dbText); 24 | 25 | int mirrored = dbText.IsMirroredInX ? 2 : 0; 26 | mirrored |= dbText.IsMirroredInY ? 4 : 0; 27 | var rb = new ResultBuffer( 28 | new TypedValue(1, dbText.TextString), 29 | new TypedValue(40, dbText.Height), 30 | new TypedValue(41, dbText.WidthFactor), 31 | new TypedValue(51, dbText.Oblique), 32 | new TypedValue(7, dbText.TextStyleName), 33 | new TypedValue(71, mirrored), 34 | new TypedValue(72, (int)dbText.HorizontalMode), 35 | new TypedValue(73, (int)dbText.VerticalMode)); 36 | var pt1 = new double[3]; 37 | var pt2 = new double[3]; 38 | acedTextBox(rb.UnmanagedObject, pt1, pt2); 39 | point1 = new Point3d(pt1); 40 | point2 = new Point3d(pt2); 41 | transform = 42 | Matrix3d.Displacement(dbText.Position.GetAsVector()) * 43 | Matrix3d.Rotation(dbText.Rotation, dbText.Normal, Point3d.Origin) * 44 | Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, dbText.Normal)); 45 | } 46 | 47 | /// 48 | /// Gets the center of the text bounding box. 49 | /// 50 | /// Instance to which the method applies. 51 | /// The center point of the text. 52 | /// Thrown if is null. 53 | public static Point3d GetTextBoxCenter(this DBText dbText) 54 | { 55 | dbText.GetTextBox(out Point3d point1, out Point3d point2, out Matrix3d xform); 56 | return new Point3d( 57 | (point1.X + point2.X) / 2.0, 58 | (point1.Y + point2.Y) / 2.0, 59 | (point1.Z + point2.Z) / 2.0) 60 | .TransformBy(xform); 61 | } 62 | 63 | /// 64 | /// Gets the points at corners of the text bounding box. 65 | /// 66 | /// Instance to which the method applies. 67 | /// The points (counter-clockwise from lower left). 68 | /// Thrown if is null. 69 | public static Point3d[] GetTextBoxCorners(this DBText dbText) 70 | { 71 | dbText.GetTextBox(out Point3d point1, out Point3d point2, out Matrix3d xform); 72 | return 73 | [ 74 | point1.TransformBy(xform), 75 | new Point3d(point2.X, point1.Y, 0.0).TransformBy(xform), 76 | point2.TransformBy(xform), 77 | new Point3d(point1.X, point2.Y, 0.0).TransformBy(xform) 78 | ]; 79 | } 80 | 81 | /// 82 | /// Mirrors the text honoring the value of MIRRTEXT system variable. 83 | /// 84 | /// Instance to which the method applies. 85 | /// Transaction or OpenCloseTransaction to use. 86 | /// Axis of the mirroring operation. 87 | /// Value indicating if the source block reference have to be erased. 88 | /// Thrown if is null. 89 | /// Thrown if is null. 90 | /// Thrown if is null. 91 | public static void Mirror(this DBText source, Transaction tr, Line3d axis, bool eraseSource) 92 | { 93 | ArgumentNullException.ThrowIfNull(source); 94 | ArgumentNullException.ThrowIfNull(tr); 95 | ArgumentNullException.ThrowIfNull(axis); 96 | 97 | var db = source.Database; 98 | DBText mirrored; 99 | if (eraseSource) 100 | { 101 | mirrored = source; 102 | mirrored.OpenForWrite(tr); 103 | } 104 | else 105 | { 106 | var ids = new ObjectIdCollection([source.ObjectId]); 107 | var mapping = new IdMapping(); 108 | db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, false); 109 | mirrored = (DBText)tr.GetObject(mapping[source.ObjectId].Value, OpenMode.ForWrite); 110 | } 111 | mirrored.TransformBy(Matrix3d.Mirroring(axis)); 112 | if (!db.Mirrtext) 113 | { 114 | var pts = mirrored.GetTextBoxCorners(); 115 | var cen = new LineSegment3d(pts[0], pts[2]).MidPoint; 116 | var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ? 117 | pts[0].GetVectorTo(pts[3]) : 118 | pts[0].GetVectorTo(pts[1]); 119 | mirrored.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen)); 120 | } 121 | } 122 | 123 | /// 124 | /// P/Invokes the unmanaged acedTextBox method. 125 | /// 126 | /// ResultBuffer cotaining the DBtext DXF definition. 127 | /// Minimum point of the bounding box. 128 | /// Maximum point of the bounding box. 129 | /// RTNORM, if succeeds; RTERROR, otherwise. 130 | [System.Security.SuppressUnmanagedCodeSecurity] 131 | [LibraryImport("accore.dll", EntryPoint = "acedTextBox")] 132 | [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] 133 | private static partial IntPtr acedTextBox(IntPtr rb, [Out] double[] point1, [Out] double[] point2); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/DisposableList.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Gile.AutoCAD.R25.Extension 8 | { 9 | /// 10 | /// Describes a list of disposable values. 11 | /// 12 | /// Type of the items. 13 | public class DisposableList : List, IDisposableCollection 14 | where T : IDisposable 15 | { 16 | /// 17 | /// Creates a new empty instance. 18 | /// 19 | public DisposableList() { } 20 | 21 | /// 22 | /// Creates a new instance by copying the sequence items. 23 | /// 24 | /// Sequence whose elements are copied into the new set. 25 | public DisposableList(IEnumerable collection) 26 | : base(collection) { } 27 | 28 | /// 29 | /// Creates a new instance by copying the collection items. 30 | /// 31 | /// Collection whose elements are copied into the new set. 32 | public DisposableList(DBObjectCollection collection) 33 | : base((IEnumerable)collection.Cast()) { } 34 | 35 | /// 36 | /// Creates a new empty instance. 37 | /// 38 | /// Initial cpacity 39 | public DisposableList(int capacity) 40 | : base(capacity) { } 41 | 42 | /// 43 | /// Disposes of all items. 44 | /// 45 | public void Dispose() 46 | { 47 | var list = this.ToList(); 48 | Clear(); 49 | list.DisposeAll(); 50 | } 51 | 52 | /// 53 | /// Removes items from the active instance. 54 | /// 55 | /// Items to remove. 56 | /// The sequence of effectively removed items. 57 | public IEnumerable RemoveRange(IEnumerable items) 58 | { 59 | ArgumentNullException.ThrowIfNull(items); 60 | foreach (T item in items) 61 | { 62 | if (Remove(item)) 63 | { 64 | yield return item; 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/DisposableSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Gile.AutoCAD.R25.Extension 6 | { 7 | /// 8 | /// Describes a set of disposable values. 9 | /// 10 | /// Type of the items. 11 | public class DisposableSet : HashSet, IDisposableCollection 12 | where T : IDisposable 13 | { 14 | /// 15 | /// Creates a new empty instance using the default comparer. 16 | /// 17 | public DisposableSet() 18 | { } 19 | 20 | /// 21 | /// Creates a new instance using the default comparer by copying the sequence items. 22 | /// 23 | /// Sequence whose elements are copied into the new set. 24 | public DisposableSet(IEnumerable collection) 25 | : base(collection) 26 | { } 27 | 28 | /// 29 | /// Creates a new empty instance using the specified comparer. 30 | /// 31 | /// IEqualityComparer<T> implementation. 32 | public DisposableSet(IEqualityComparer comparer) 33 | : base(comparer) 34 | { } 35 | 36 | /// 37 | /// Creates a new instance using the specified comparer by copying the sequence items. 38 | /// 39 | /// Sequence whose elements are copied into the new set. 40 | /// IEqualityComparer<T> implementation. 41 | public DisposableSet(IEnumerable collection, IEqualityComparer comparer) 42 | : base(collection, comparer) 43 | { } 44 | 45 | /// 46 | /// Disposes of all items. 47 | /// 48 | public void Dispose() 49 | { 50 | var list = this.ToList(); 51 | Clear(); 52 | list.DisposeAll(); 53 | } 54 | 55 | /// 56 | /// Adds items to the active instance. 57 | /// 58 | /// Items to add. 59 | public void AddRange(IEnumerable items) 60 | { 61 | ArgumentNullException.ThrowIfNull(items); 62 | 63 | UnionWith(items); 64 | } 65 | 66 | /// 67 | /// Removes items from the active instance. 68 | /// 69 | /// Items to remove. 70 | /// The sequence of effectively removed items. 71 | public IEnumerable RemoveRange(IEnumerable items) 72 | { 73 | ArgumentNullException.ThrowIfNull(items); 74 | 75 | ExceptWith(items); 76 | return items; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/DocumentCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.ApplicationServices; 2 | 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | using AcRx = Autodesk.AutoCAD.Runtime; 7 | 8 | namespace Gile.AutoCAD.R25.Extension 9 | { 10 | /// 11 | /// Provides extension methods for the DocumentCollection type. 12 | /// 13 | public static class DocumentCollectionExtension 14 | { 15 | /// 16 | /// Invokes an action in the document context that can be safely called from the application context. 17 | /// Credit: Tony Tanzillo. 18 | /// 19 | /// Documents collection. 20 | /// Action to invoke. 21 | /// Task.CompletedTask. 22 | /// Thrown if is null; 23 | /// Thrown if is null; 24 | /// eNoDocument thrown if no active document. 25 | /// eInvalidContext thrown if not called from application context. 26 | /// Must be called in a try / catch statement. 27 | public static async Task InvokeAsCommandAsync(this DocumentCollection docs, Action action) 28 | { 29 | ArgumentNullException.ThrowIfNull(docs); 30 | 31 | ArgumentNullException.ThrowIfNull(action); 32 | 33 | Document doc = docs.MdiActiveDocument ?? throw new AcRx.Exception(AcRx.ErrorStatus.NoDocument); 34 | 35 | if (!docs.IsApplicationContext) 36 | throw new AcRx.Exception(AcRx.ErrorStatus.InvalidContext); 37 | 38 | Task task = Task.CompletedTask; 39 | await docs.ExecuteInCommandContextAsync( 40 | (_) => 41 | { 42 | try 43 | { 44 | action(doc); 45 | return task; 46 | } 47 | catch (Exception ex) 48 | { 49 | return task = Task.FromException(ex); 50 | } 51 | }, 52 | null 53 | ); 54 | if (task.IsFaulted) 55 | { 56 | throw task.Exception; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/EditorExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.ApplicationServices.Core; 2 | using Autodesk.AutoCAD.DatabaseServices; 3 | using Autodesk.AutoCAD.EditorInput; 4 | using Autodesk.AutoCAD.Geometry; 5 | 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace Gile.AutoCAD.R25.Extension 10 | { 11 | /// 12 | /// Provides extension methods for the Editor type. 13 | /// 14 | public static class EditorExtension 15 | { 16 | #region Zoom 17 | 18 | /// 19 | /// Zooms to given extents in the current viewport. 20 | /// 21 | /// Instance to which the method applies. 22 | /// Extents of the zoom. 23 | /// Thrown if is null. 24 | public static void Zoom(this Editor ed, Extents3d ext) 25 | { 26 | System.ArgumentNullException.ThrowIfNull(ed); 27 | 28 | using ViewTableRecord view = ed.GetCurrentView(); 29 | ext.TransformBy(view.WorldToEye()); 30 | view.Width = ext.MaxPoint.X - ext.MinPoint.X; 31 | view.Height = ext.MaxPoint.Y - ext.MinPoint.Y; 32 | view.CenterPoint = new Point2d( 33 | (ext.MaxPoint.X + ext.MinPoint.X) / 2.0, 34 | (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0); 35 | ed.SetCurrentView(view); 36 | } 37 | 38 | /// 39 | /// Zooms to the extents of the current viewport. 40 | /// 41 | /// Instance to which the method applies. 42 | /// Thrown if is null. 43 | public static void ZoomExtents(this Editor ed) 44 | { 45 | System.ArgumentNullException.ThrowIfNull(ed); 46 | 47 | Database db = ed.Document.Database; 48 | db.UpdateExt(false); 49 | Extents3d ext = (short)Application.GetSystemVariable("cvport") == 1 ? 50 | new Extents3d(db.Pextmin, db.Pextmax) : 51 | new Extents3d(db.Extmin, db.Extmax); 52 | ed.Zoom(ext); 53 | } 54 | 55 | /// 56 | /// Zooms to the given window. 57 | /// 58 | /// Instance to which the method applies. 59 | /// First window corner. 60 | /// Opposite window corner. 61 | /// Thrown if is null. 62 | public static void ZoomWindow(this Editor ed, Point3d p1, Point3d p2) 63 | { 64 | System.ArgumentNullException.ThrowIfNull(ed); 65 | 66 | var extents = new Extents3d(); 67 | extents.AddPoint(p1); 68 | extents.AddPoint(p2); 69 | ed.Zoom(extents); 70 | } 71 | 72 | /// 73 | /// Zooms to the specified entity collection. 74 | /// 75 | /// Instance to which the method applies. 76 | /// Collection of the entities ObjectId on which to zoom. 77 | /// Thrown if is null. 78 | public static void ZoomObjects(this Editor ed, IEnumerable ids) 79 | { 80 | System.ArgumentNullException.ThrowIfNull(ed); 81 | System.ArgumentNullException.ThrowIfNull(ids); 82 | 83 | using Transaction tr = ed.Document.TransactionManager.StartOpenCloseTransaction(); 84 | Extents3d ext = ids 85 | .GetObjects(tr) 86 | .Select(ent => ent.Bounds) 87 | .Where(b => b.HasValue) 88 | .Select(b => b!.Value) 89 | .Aggregate((e1, e2) => { e1.AddExtents(e2); return e1; }); 90 | ed.Zoom(ext); 91 | tr.Commit(); 92 | } 93 | 94 | /// 95 | /// Zooms in current viewport to the specified scale. 96 | /// 97 | /// Instance to which the method applies. 98 | /// Scale. 99 | /// Thrown if is null. 100 | public static void ZoomScale(this Editor ed, double scale) 101 | { 102 | System.ArgumentNullException.ThrowIfNull(ed); 103 | 104 | using ViewTableRecord view = ed.GetCurrentView(); 105 | view.Width /= scale; 106 | view.Height /= scale; 107 | ed.SetCurrentView(view); 108 | } 109 | 110 | /// 111 | /// Zooms in current viewport to the specified scale and center. 112 | /// 113 | /// Instance to which the method applies. 114 | /// Viewport center. 115 | /// Scale (default = 1). 116 | /// Thrown if is null. 117 | public static void ZoomCenter(this Editor ed, Point3d center, double scale = 1.0) 118 | { 119 | System.ArgumentNullException.ThrowIfNull(ed); 120 | 121 | using ViewTableRecord view = ed.GetCurrentView(); 122 | center = center.TransformBy(view.WorldToEye()); 123 | view.Height /= scale; 124 | view.Width /= scale; 125 | view.CenterPoint = new Point2d(center.X, center.Y); 126 | ed.SetCurrentView(view); 127 | } 128 | 129 | #endregion 130 | 131 | #region Selection 132 | 133 | /// 134 | /// Gets a selection set using the supplied prompt selection options, the supplied filter and the supplied predicate. 135 | /// 136 | /// Instance to which the method applies. 137 | /// Selection options. 138 | /// Selection filter 139 | /// Selection predicate. 140 | /// The selection result. 141 | /// Thrown if is null. 142 | /// Thrown if is null. 143 | public static PromptSelectionResult GetSelection(this Editor ed, PromptSelectionOptions options, SelectionFilter filter, System.Predicate predicate) => 144 | GetPredicatedSelection(ed, predicate, options, filter); 145 | 146 | /// 147 | /// Gets a selection set using the supplied prompt selection options and the supplied predicate. 148 | /// 149 | /// Instance to which the method applies. 150 | /// Selection options. 151 | /// Selection predicate. 152 | /// The selection result. 153 | /// Thrown if is null. 154 | /// Thrown if is null. 155 | public static PromptSelectionResult GetSelection(this Editor ed, PromptSelectionOptions options, System.Predicate predicate) => 156 | GetPredicatedSelection(ed, predicate, options); 157 | 158 | /// 159 | /// Gets a selection set using the supplied filter and the supplied predicate. 160 | /// 161 | /// Instance to which the method applies. 162 | /// Selection filter 163 | /// Selection predicate. 164 | /// The selection result. 165 | /// Thrown if is null. 166 | /// Thrown if is null. 167 | public static PromptSelectionResult GetSelection(this Editor ed, SelectionFilter filter, System.Predicate predicate) => 168 | GetPredicatedSelection(ed, predicate, null, filter); 169 | 170 | /// 171 | /// Gets a selection set using the supplied predicate. 172 | /// 173 | /// Instance to which the method applies. 174 | /// Selection predicate. 175 | /// The selection result. 176 | /// Thrown if is null. 177 | /// Thrown if is null. 178 | public static PromptSelectionResult GetSelection(this Editor ed, System.Predicate predicate) => 179 | GetPredicatedSelection(ed, predicate, null, null); 180 | 181 | private static PromptSelectionResult GetPredicatedSelection( 182 | Editor ed, 183 | System.Predicate predicate, 184 | PromptSelectionOptions ?options = null, 185 | SelectionFilter? filter = null) 186 | { 187 | System.ArgumentNullException.ThrowIfNull(ed); 188 | System.ArgumentNullException.ThrowIfNull(predicate); 189 | 190 | void onSelectionAdded(object sender, SelectionAddedEventArgs e) 191 | { 192 | var ids = e.AddedObjects.GetObjectIds(); 193 | for (int i = 0; i < ids.Length; i++) 194 | { 195 | if (!predicate(ids[i])) 196 | { 197 | e.Remove(i); 198 | } 199 | } 200 | } 201 | 202 | PromptSelectionResult result; 203 | ed.SelectionAdded += onSelectionAdded; 204 | if (options == null) 205 | { 206 | if (filter == null) 207 | { 208 | result = ed.GetSelection(); 209 | } 210 | else 211 | { 212 | result = ed.GetSelection(filter); 213 | } 214 | } 215 | else 216 | { 217 | if (filter == null) 218 | { 219 | result = ed.GetSelection(options); 220 | } 221 | else 222 | { 223 | result = ed.GetSelection(options, filter); 224 | } 225 | } 226 | ed.SelectionAdded -= onSelectionAdded; 227 | return result; 228 | } 229 | 230 | #endregion 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/EntityExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | namespace Gile.AutoCAD.R25.Extension 4 | { 5 | /// 6 | /// Provides extension methods for the Entity type. 7 | /// 8 | public static class EntityExtension 9 | { 10 | /// 11 | /// Evaluates if the owner of is a Layout. 12 | /// 13 | /// Instance to which the method applies. 14 | /// Transaction or OpenCloseTransaction to use. 15 | /// true, if the owner is a Layout; false, otherwise. 16 | /// Thrown if is null. 17 | /// Thrown if is null. 18 | public static bool IsOwnedByLayout(this Entity entity, Transaction tr) 19 | { 20 | System.ArgumentNullException.ThrowIfNull(entity); 21 | System.ArgumentNullException.ThrowIfNull(tr); 22 | 23 | var owner = tr.GetObject(entity.OwnerId, OpenMode.ForRead); 24 | return owner is BlockTableRecord btr && btr.IsLayout; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/Gile.AutoCAD.R25.Extension.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0-windows 4 | Library 5 | false 6 | Gile.AutoCAD.R25.Extension 7 | gileCAD 8 | Gile.AutoCAD.R25.Extension 9 | Copyright © Gilles Chanteau 2017 10 | 2.0.0.0 11 | 2.0.0.0 12 | x64 13 | enable 14 | true 15 | Gile.AutoCAD.R25.Extension 16 | 17 | 18 | bin\Release\Gile.AutoCAD.R25.Extension.xml 19 | 20 | 21 | 22 | 23 | 24 | 25 | F:\ObjectARX 2025\inc\AcCoreMgd.dll 26 | False 27 | 28 | 29 | F:\ObjectARX 2025\inc\AcDbMgd.dll 30 | False 31 | 32 | 33 | F:\ObjectARX 2025\inc\AcMgd.dll 34 | False 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/IDisposableCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Gile.AutoCAD.R25.Extension 5 | { 6 | /// 7 | /// Defines methods to add or removes items from a sequence of disposable objects. 8 | /// 9 | /// Type of the items. 10 | public interface IDisposableCollection : ICollection, IDisposable 11 | where T : IDisposable 12 | { 13 | /// 14 | /// Adds items to the sequence. 15 | /// 16 | /// Items to add. 17 | void AddRange(IEnumerable items); 18 | 19 | /// 20 | /// Removes items from the sequence. 21 | /// 22 | /// Items to remove. 23 | /// The sequence of removed items. 24 | IEnumerable RemoveRange(IEnumerable items); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/IEnumerableExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace Gile.AutoCAD.R25.Extension 9 | { 10 | /// 11 | /// Provides extension methods for the IEnumerable(T) type. 12 | /// 13 | public static class IEnumerableExtension 14 | { 15 | /// 16 | /// Opens the objects which type matches to the given one, and return them. 17 | /// 18 | /// Type of object to return. 19 | /// Sequence of ObjectIds. 20 | /// Transaction or OpenCloseTransaction to use. 21 | /// Open mode to obtain in. 22 | /// Value indicating whether to obtain erased objects. 23 | /// Value indicating if locked layers should be opened. 24 | /// The sequence of opened objects. 25 | /// Thrown if is null. 26 | /// Thrown if is null. 27 | public static IEnumerable GetObjects( 28 | this IEnumerable source, 29 | Transaction tr, 30 | OpenMode mode = OpenMode.ForRead, 31 | bool openErased = false, 32 | bool forceOpenOnLockedLayers = false) where T : DBObject 33 | { 34 | ArgumentNullException.ThrowIfNull(source); 35 | ArgumentNullException.ThrowIfNull(tr); 36 | 37 | if (source.Any()) 38 | { 39 | var rxClass = RXObject.GetClass(typeof(T)); 40 | foreach (ObjectId id in source) 41 | { 42 | if (id.ObjectClass.IsDerivedFrom(rxClass) && 43 | (!id.IsErased || openErased)) 44 | { 45 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 46 | } 47 | } 48 | } 49 | } 50 | 51 | /// 52 | /// Upgrades the open mode of all objects in the sequence. 53 | /// 54 | /// Type of objects. 55 | /// Sequence of DBObjects to upgrade. 56 | /// Transaction or OpenCloseTransaction to use. 57 | /// The sequence of opened for write objects (objets on locked layers are discared). 58 | /// Thrown if is null. 59 | /// Thrown if is null. 60 | public static IEnumerable UpgradeOpen(this IEnumerable source, Transaction tr) where T : DBObject 61 | { 62 | ArgumentNullException.ThrowIfNull(source); 63 | 64 | foreach (T item in source) 65 | { 66 | try 67 | { 68 | item.OpenForWrite(tr); 69 | } 70 | catch (Autodesk.AutoCAD.Runtime.Exception ex) 71 | { 72 | if (ex.ErrorStatus != ErrorStatus.OnLockedLayer) 73 | { 74 | throw; 75 | } 76 | continue; 77 | } 78 | yield return item; 79 | } 80 | } 81 | 82 | /// 83 | /// Disposes of all items of the sequence. 84 | /// 85 | /// Type of the items. 86 | /// Sequence of disposable objects. 87 | /// Thrown if is null. 88 | public static void DisposeAll(this IEnumerable source) where T : IDisposable 89 | { 90 | ArgumentNullException.ThrowIfNull(source); 91 | 92 | if (source.Any()) 93 | { 94 | System.Exception? last = null; 95 | foreach (T item in source) 96 | { 97 | if (item != null) 98 | { 99 | try 100 | { 101 | item.Dispose(); 102 | } 103 | catch (System.Exception ex) 104 | { 105 | last ??= ex; 106 | } 107 | } 108 | } 109 | if (last != null) 110 | { 111 | throw last; 112 | } 113 | } 114 | } 115 | 116 | /// 117 | /// Runs the action for each item of the collection. 118 | /// 119 | /// Type of the items. 120 | /// Sequence to process. 121 | /// Action to run. 122 | /// Thrown if is null. 123 | /// Thrown if is null. 124 | public static void ForEach(this IEnumerable source, Action action) 125 | { 126 | ArgumentNullException.ThrowIfNull(source); 127 | ArgumentNullException.ThrowIfNull(action); 128 | 129 | foreach (T item in source) 130 | { 131 | action(item); 132 | } 133 | } 134 | 135 | /// 136 | /// Runs the indexed action for each item of the collection. 137 | /// 138 | /// Type of the items. 139 | /// Sequence to process. 140 | /// Indexed action to run. 141 | /// Thrown if is null. 142 | /// Thrown if is null. 143 | public static void ForEach(this IEnumerable source, Action action) 144 | { 145 | ArgumentNullException.ThrowIfNull(source); 146 | ArgumentNullException.ThrowIfNull(action); 147 | 148 | int i = 0; 149 | foreach (T item in source) 150 | { 151 | action(item, i++); 152 | } 153 | } 154 | 155 | /// 156 | /// Gets the greatest item of the sequence using with the function returned values. 157 | /// 158 | /// Type the items. 159 | /// Type of the returned value of function. 160 | /// Sequence to which the method applies. 161 | /// Mapping function from TSource to TKey. 162 | /// Comparer used for the TKey type; uses Comparer<TKey>.Default if null or omitted. 163 | /// The greatest item in the sequence. 164 | /// Thrown if is null. 165 | /// Thrown if is null. 166 | public static TSource MaxBy( 167 | this IEnumerable source, 168 | Func selector, 169 | IComparer? comparer = null) 170 | { 171 | ArgumentNullException.ThrowIfNull(source); 172 | ArgumentNullException.ThrowIfNull(selector); 173 | 174 | comparer ??= Comparer.Default; 175 | using var iterator = source.GetEnumerator(); 176 | if (!iterator.MoveNext()) 177 | { 178 | throw new InvalidOperationException("Empty sequence"); 179 | } 180 | var max = iterator.Current; 181 | var maxKey = selector(max); 182 | while (iterator.MoveNext()) 183 | { 184 | var current = iterator.Current; 185 | var currentKey = selector(current); 186 | if (comparer.Compare(currentKey, maxKey) > 0) 187 | { 188 | max = current; 189 | maxKey = currentKey; 190 | } 191 | } 192 | return max; 193 | } 194 | 195 | /// 196 | /// Gets the smallest item of the sequence using the with the function returned values. 197 | /// 198 | /// Type the items. 199 | /// Type of the returned value of function. 200 | /// Sequence to which the method applies. 201 | /// Mapping function from TSource to TKey. 202 | /// Comparer used for the TKey type; uses Comparer<TKey>.Default if null or omitted. 203 | /// The smallest item in the sequence. 204 | /// Thrown if is null. 205 | /// Thrown if is null. 206 | public static TSource MinBy( 207 | this IEnumerable source, 208 | Func selector, 209 | IComparer? comparer = null) 210 | { 211 | ArgumentNullException.ThrowIfNull(source); 212 | ArgumentNullException.ThrowIfNull(selector); 213 | 214 | comparer ??= Comparer.Default; 215 | using var iterator = source.GetEnumerator(); 216 | if (!iterator.MoveNext()) 217 | { 218 | throw new InvalidOperationException("Empty sequence"); 219 | } 220 | var min = iterator.Current; 221 | var minKey = selector(min); 222 | while (iterator.MoveNext()) 223 | { 224 | var current = iterator.Current; 225 | var currentKey = selector(current); 226 | if (comparer.Compare(currentKey, minKey) < 0) 227 | { 228 | min = current; 229 | minKey = currentKey; 230 | } 231 | } 232 | return min; 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/MTextExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Geometry; 3 | 4 | using System; 5 | 6 | namespace Gile.AutoCAD.R25.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the MText Type. 10 | /// 11 | public static class MTextExtension 12 | { 13 | /// 14 | /// Gets the points at corners of the mtext bounding box. 15 | /// 16 | /// Instance to which the method applies. 17 | /// The points (counter-clockwise from lower left). 18 | /// Thrown if is null. 19 | public static Point3d[] GetMTextBoxCorners(this MText mtext) 20 | { 21 | ArgumentNullException.ThrowIfNull(mtext); 22 | 23 | double width = mtext.ActualWidth; 24 | double height = mtext.ActualHeight; 25 | Point3d point1, point2; 26 | switch (mtext.Attachment) 27 | { 28 | case AttachmentPoint.TopLeft: 29 | default: 30 | point1 = new Point3d(0.0, -height, 0.0); 31 | point2 = new Point3d(width, 0.0, 0.0); 32 | break; 33 | case AttachmentPoint.TopCenter: 34 | point1 = new Point3d(-width * 0.5, -height, 0.0); 35 | point2 = new Point3d(width * 0.5, 0.0, 0.0); 36 | break; 37 | case AttachmentPoint.TopRight: 38 | point1 = new Point3d(-width, -height, 0.0); 39 | point2 = new Point3d(0.0, 0.0, 0.0); 40 | break; 41 | case AttachmentPoint.MiddleLeft: 42 | point1 = new Point3d(0.0, -height * 0.5, 0.0); 43 | point2 = new Point3d(width, height * 0.5, 0.0); 44 | break; 45 | case AttachmentPoint.MiddleCenter: 46 | point1 = new Point3d(-width * 0.5, -height * 0.5, 0.0); 47 | point2 = new Point3d(width * 0.5, height * 0.5, 0.0); 48 | break; 49 | case AttachmentPoint.MiddleRight: 50 | point1 = new Point3d(-width, -height * 0.5, 0.0); 51 | point2 = new Point3d(0.0, height * 0.5, 0.0); 52 | break; 53 | case AttachmentPoint.BottomLeft: 54 | point1 = new Point3d(0.0, 0.0, 0.0); 55 | point2 = new Point3d(width, height, 0.0); 56 | break; 57 | case AttachmentPoint.BottomCenter: 58 | point1 = new Point3d(-width * 0.5, 0.0, 0.0); 59 | point2 = new Point3d(width * 0.5, height, 0.0); 60 | break; 61 | case AttachmentPoint.BottomRight: 62 | point1 = new Point3d(-width, 0.0, 0.0); 63 | point2 = new Point3d(0.0, height, 0.0); 64 | break; 65 | } 66 | 67 | var xform = 68 | Matrix3d.Displacement(mtext.Location.GetAsVector()) * 69 | Matrix3d.Rotation(mtext.Rotation, mtext.Normal, Point3d.Origin) * 70 | Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, mtext.Normal)); 71 | 72 | return 73 | [ 74 | point1.TransformBy(xform), 75 | new Point3d(point2.X, point1.Y, 0.0).TransformBy(xform), 76 | point2.TransformBy(xform), 77 | new Point3d(point1.X, point2.Y, 0.0).TransformBy(xform) 78 | ]; 79 | } 80 | 81 | /// 82 | /// Mirrors the mtext honoring the value of MIRRTEXT system variable. 83 | /// 84 | /// Instance to which the method applies. 85 | /// Transaction or OpenCloseTransaction to use. 86 | /// Axis of the mirroring operation. 87 | /// Value indicating if the source block reference have to be erased. 88 | /// Thrown if is null. 89 | /// Thrown if is null. 90 | /// Thrown if is null. 91 | public static void Mirror(this MText source, Transaction tr, Line3d axis, bool eraseSource) 92 | { 93 | ArgumentNullException.ThrowIfNull(source); 94 | ArgumentNullException.ThrowIfNull(tr); 95 | ArgumentNullException.ThrowIfNull(axis); 96 | 97 | var db = source.Database; 98 | MText mirrored; 99 | if (eraseSource) 100 | { 101 | mirrored = source; 102 | if (!mirrored.IsWriteEnabled) 103 | { 104 | tr.GetObject(mirrored.ObjectId, OpenMode.ForWrite); 105 | } 106 | } 107 | else 108 | { 109 | var ids = new ObjectIdCollection([source.ObjectId]); 110 | var mapping = new IdMapping(); 111 | db.DeepCloneObjects(ids, db.CurrentSpaceId, mapping, false); 112 | mirrored = (MText)tr.GetObject(mapping[source.ObjectId].Value, OpenMode.ForWrite); 113 | } 114 | mirrored.TransformBy(Matrix3d.Mirroring(axis)); 115 | 116 | if (!db.Mirrtext) 117 | { 118 | var pts = mirrored.GetMTextBoxCorners(); 119 | var cen = new LineSegment3d(pts[0], pts[2]).MidPoint; 120 | var rotAxis = Math.Abs(axis.Direction.X) < Math.Abs(axis.Direction.Y) ? 121 | pts[0].GetVectorTo(pts[3]) : 122 | pts[0].GetVectorTo(pts[1]); 123 | mirrored.TransformBy(Matrix3d.Rotation(Math.PI, rotAxis, cen)); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/ObjectIdCollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System.Collections.Generic; 5 | 6 | namespace Gile.AutoCAD.R25.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the ObjectIdCollection type. 10 | /// 11 | public static class ObjectIdCollectionExtension 12 | { 13 | 14 | /// 15 | /// Opens the objects which type matches to the given one, and return them. 16 | /// 17 | /// Type of objects to return. 18 | /// Instance to which the method applies. 19 | /// Transaction or OpenCloseTransaction to use. 20 | /// Open mode to obtain in. 21 | /// Value indicating whether to obtain erased objects. 22 | /// Value indicating if locked layers should be opened. 23 | /// The sequence of opened objects. 24 | /// Thrown if is null. 25 | /// Thrown if is null. 26 | public static IEnumerable GetObjects( 27 | this ObjectIdCollection source, 28 | Transaction tr, 29 | OpenMode mode = OpenMode.ForRead, 30 | bool openErased = false, 31 | bool forceOpenOnLockedLayers = false) 32 | where T : DBObject 33 | { 34 | System.ArgumentNullException.ThrowIfNull(source); 35 | System.ArgumentNullException.ThrowIfNull(tr); 36 | 37 | if (0 < source.Count) 38 | { 39 | var rxClass = RXObject.GetClass(typeof(T)); 40 | foreach (ObjectId id in source) 41 | { 42 | if ((id.ObjectClass == rxClass || id.ObjectClass.IsDerivedFrom(rxClass)) && 43 | (!id.IsErased || openErased)) 44 | { 45 | yield return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayers); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/ObjectIdExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | using Autodesk.AutoCAD.Runtime; 3 | 4 | using System.Runtime.InteropServices; 5 | 6 | namespace Gile.AutoCAD.R25.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the ObjectId type. 10 | /// 11 | public static partial class ObjectIdExtension 12 | { 13 | /// 14 | /// Tries to open an AutoCAD object of the given type in the given open mode. 15 | /// 16 | /// Type of the output object. 17 | /// ObjectId to open. 18 | /// Transaction or OpenCloseTransaction to use. 19 | /// Output object. 20 | /// Open mode to obtain in. 21 | /// Value indicating whether to obtain erased objects. 22 | /// Value indicating if locked layers should be opened. 23 | /// true, if the operation succeeded; false, otherwise. 24 | /// eNullObjectId is thrown if equals ObjectId.Null. 25 | /// Thrown if is null. 26 | public static bool TryGetObject( 27 | this ObjectId id, 28 | Transaction tr, 29 | out T? obj, 30 | OpenMode mode = OpenMode.ForRead, 31 | bool openErased = false, 32 | bool forceOpenOnLockedLayer = false) 33 | where T : DBObject 34 | { 35 | ErrorStatus.NullObjectId.ThrowIf(id.IsNull); 36 | System.ArgumentNullException.ThrowIfNull(tr); 37 | 38 | obj = default; 39 | if (!id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(T)))) 40 | { 41 | return false; 42 | } 43 | obj = (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayer); 44 | return true; 45 | } 46 | 47 | /// 48 | /// Opens an AutoCAD object of the given type in the given open mode. 49 | /// 50 | /// Type of the object to return. 51 | /// ObjectId to open. 52 | /// Transaction or OpenCloseTransaction to use. 53 | /// Open mode to obtain in. 54 | /// Value indicating whether to obtain erased objects. 55 | /// Value indicating if locked layers should be opened. 56 | /// The object opened in given open mode. 57 | /// Thrown if the object type does not match the given type 58 | /// eNullObjectId is thrown if equals ObjectId.Null. 59 | /// Thrown if is null. 60 | public static T GetObject( 61 | this ObjectId id, 62 | Transaction tr, 63 | OpenMode mode = OpenMode.ForRead, 64 | bool openErased = false, 65 | bool forceOpenOnLockedLayer = false) 66 | where T : DBObject 67 | { 68 | ErrorStatus.NullObjectId.ThrowIf(id.IsNull); 69 | System.ArgumentNullException.ThrowIfNull(tr); 70 | 71 | return (T)tr.GetObject(id, mode, openErased, forceOpenOnLockedLayer); 72 | } 73 | 74 | /// 75 | /// Get the DXF definition data (like AutoLISP entget function). 76 | /// 77 | /// Instance to which the method applies. 78 | /// The DXF data. 79 | /// Thrown in case of invalid objectId. 80 | public static ResultBuffer? EntGet(this ObjectId id) 81 | { 82 | var errorStatus = acdbGetAdsName(out AdsName ename, id); 83 | if (errorStatus != ErrorStatus.OK) 84 | { 85 | throw new Exception(errorStatus); 86 | } 87 | var result = acdbEntGet(ename); 88 | if (result != nint.Zero) 89 | { 90 | return ResultBuffer.Create(result, true); 91 | } 92 | return null; 93 | } 94 | 95 | // Replace the DLL name according to the AutoCAD targeted version 96 | // 2013-2014: "acdb19.dll" 97 | // 2015-2016: "acdb20.dll" 98 | // 2017: "acdb21.dll" 99 | // 2018: "acdb22.dll" 100 | // 2019-2020: "acdb23.dll" 101 | // 2021-2024: "acdb24.dll" 102 | // Replace the EntryPoint according to AutoCAD plateform 103 | // 32 bits: "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z" 104 | // 64 bits: "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z" 105 | [System.Security.SuppressUnmanagedCodeSecurity] 106 | [LibraryImport("acdb24.dll", EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] 107 | [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] 108 | private static partial ErrorStatus acdbGetAdsName(out AdsName ename, ObjectId id); 109 | 110 | [System.Security.SuppressUnmanagedCodeSecurity] 111 | [LibraryImport("accore.dll", EntryPoint = "acdbEntGet")] 112 | [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] 113 | private static partial nint acdbEntGet(AdsName ename); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/PolylineExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Gile.AutoCAD.R25.Extension 8 | { 9 | /// 10 | /// Enumeration of offset side options 11 | /// 12 | public enum OffsetSide 13 | { 14 | /// 15 | /// Inside. 16 | /// 17 | In, 18 | /// 19 | /// Outside. 20 | /// 21 | Out, 22 | /// 23 | /// Left side. 24 | /// 25 | Left, 26 | /// 27 | /// Right side. 28 | /// 29 | Right, 30 | /// 31 | /// Both sides. 32 | /// 33 | Both 34 | } 35 | 36 | // credits to Tony 'TheMaster' Tanzillo 37 | // http://www.theswamp.org/index.php?topic=31862.msg494503#msg494503 38 | 39 | /// 40 | /// Provides the Offset() extension method for the Polyline type 41 | /// 42 | public static class PolylineExtension 43 | { 44 | /// 45 | /// Offset the source polyline to specified side(s). 46 | /// 47 | /// Instance to which the method applies. 48 | /// Offset distance. 49 | /// Offset side(s). 50 | /// A polyline sequence resulting from the offset of the source polyline. 51 | /// Thrown if is null. 52 | public static IEnumerable? Offset(this Polyline source, double offsetDist, OffsetSide side) 53 | { 54 | ArgumentNullException.ThrowIfNull(source); 55 | 56 | offsetDist = Math.Abs(offsetDist); 57 | using var plines = new DisposableSet(); 58 | IEnumerable offsetRight = source.GetOffsetCurves(offsetDist).Cast(); 59 | plines.AddRange(offsetRight); 60 | IEnumerable offsetLeft = source.GetOffsetCurves(-offsetDist).Cast(); 61 | plines.AddRange(offsetLeft); 62 | double areaRight = offsetRight.Select(pline => pline.Area).Sum(); 63 | double areaLeft = offsetLeft.Select(pline => pline.Area).Sum(); 64 | switch (side) 65 | { 66 | case OffsetSide.In: 67 | return plines.RemoveRange( 68 | areaRight < areaLeft ? offsetRight : offsetLeft); 69 | case OffsetSide.Out: 70 | return plines.RemoveRange( 71 | areaRight < areaLeft ? offsetLeft : offsetRight); 72 | case OffsetSide.Left: 73 | return plines.RemoveRange(offsetLeft); 74 | case OffsetSide.Right: 75 | return plines.RemoveRange(offsetRight); 76 | case OffsetSide.Both: 77 | plines.Clear(); 78 | return offsetRight.Concat(offsetLeft); 79 | default: 80 | return null; 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | [assembly: AssemblyTrademark("")] 5 | [assembly: AssemblyCulture("")] 6 | 7 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly 8 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de 9 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type. 10 | [assembly: ComVisible(false)] 11 | 12 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM 13 | [assembly: Guid("32ebff40-ce54-4b05-aeba-2eeffedb443b")] 14 | [assembly: DisableRuntimeMarshalling] 15 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/RuntimeExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.Runtime; 2 | 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace Gile.AutoCAD.R25.Extension 6 | { 7 | /// 8 | /// Provides extension related to AutoCAD Runtime. 9 | /// 10 | public static class RuntimeExtension 11 | { 12 | /// 13 | /// Throws Autodesk.AutoCAD.Exception(errorStatus) it condition is true. 14 | /// Credit Tony Tanzillo http://www.theswamp.org/index.php?topic=59013.msg619828#msg619828 15 | /// 16 | /// Error status. 17 | /// Condition. 18 | /// Message. 19 | /// 20 | public static void ThrowIf( 21 | this ErrorStatus errorStatus, 22 | bool condition, 23 | [CallerArgumentExpression(nameof(condition))] string? message = null) 24 | { 25 | if (condition) 26 | throw new Exception(errorStatus, message); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/SymbolTableExtension.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Gile.AutoCAD.R25.Extension 7 | { 8 | /// 9 | /// Provides extension methods for the SymbolTable type. 10 | /// 11 | public static class SymbolTableExtension 12 | { 13 | /// 14 | /// Opens the table records in the given open mode. 15 | /// 16 | /// Type of returned object. 17 | /// Instance to which the method applies. 18 | /// Transaction or OpenCloseTransaction to use. 19 | /// Open mode to obtain in. 20 | /// Value indicating whether to obtain erased objects. 21 | /// The sequence of records. 22 | /// Thrown if is null. 23 | /// Thrown if is null. 24 | public static IEnumerable GetObjects(this SymbolTable source, Transaction tr, OpenMode mode = OpenMode.ForRead, bool openErased = false) 25 | where T : SymbolTableRecord 26 | { 27 | System.ArgumentNullException.ThrowIfNull(source); 28 | System.ArgumentNullException.ThrowIfNull(tr); 29 | 30 | foreach (ObjectId id in openErased ? source.IncludingErased : source) 31 | { 32 | yield return (T)tr.GetObject(id, mode, openErased, false); 33 | } 34 | } 35 | 36 | /// 37 | /// Purges the unreferenced symbol table records. 38 | /// 39 | /// Instance to which the method applies. 40 | /// Transaction or OpenCloseTransaction to use. 41 | /// The number of pruged records. 42 | /// Thrown if is null. 43 | /// Thrown if is null. 44 | public static int Purge(this SymbolTable symbolTable, Transaction tr) 45 | { 46 | System.ArgumentNullException.ThrowIfNull(symbolTable); 47 | System.ArgumentNullException.ThrowIfNull(tr); 48 | 49 | Database db = symbolTable.Database; 50 | int cnt = 0; 51 | var unpurgeable = new HashSet(); 52 | while (true) 53 | { 54 | var ids = new ObjectIdCollection(symbolTable.Cast().Except(unpurgeable).ToArray()); 55 | db.Purge(ids); 56 | if (ids.Count == 0) 57 | { 58 | break; 59 | } 60 | foreach (ObjectId id in ids) 61 | { 62 | try 63 | { 64 | tr.GetObject(id, OpenMode.ForWrite).Erase(); 65 | cnt++; 66 | } 67 | catch 68 | { 69 | unpurgeable.Add(id); 70 | } 71 | } 72 | } 73 | return cnt; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Gile.AutoCAD.R25.Extension/WorkingDatabase.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.AutoCAD.DatabaseServices; 2 | 3 | using System; 4 | 5 | namespace Gile.AutoCAD.R25.Extension 6 | { 7 | /// 8 | /// Provides a safe way to temporarily set the working database. 9 | /// Credits Tony Tanzillo: https://forums.autodesk.com/t5/net/want-to-have-c-program-to-modify-dwg-and-save-into-dwg-format/m-p/12439905/highlight/true#M79788 10 | /// 11 | public class WorkingDatabase : IDisposable 12 | { 13 | Database? previous; 14 | 15 | /// 16 | /// Creates a new instance of WorkingDatabase. 17 | /// 18 | /// Database to be temporarily set as working database. 19 | public WorkingDatabase(Database newWorkingDb) 20 | { 21 | ArgumentNullException.ThrowIfNull(newWorkingDb); 22 | 23 | Database current = HostApplicationServices.WorkingDatabase; 24 | if (newWorkingDb != current) 25 | { 26 | previous = current; 27 | HostApplicationServices.WorkingDatabase = newWorkingDb; 28 | } 29 | } 30 | 31 | /// 32 | /// Restores the previous working database. 33 | /// 34 | public void Dispose() 35 | { 36 | if (previous != null) 37 | { 38 | HostApplicationServices.WorkingDatabase = previous; 39 | previous = null; 40 | GC.SuppressFinalize(this); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Gilles Chanteau 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gile.AutoCAD.Extension 2 | ### AutoCAD Helpers Class Library 3 | Thanks to all the [Swampers](http://www.theswamp.org/index.php) who helped me learning AutoCAD .NET programming, with a special mention to Tony 'TheMaster' Tanzillo and Thorsten 'kaefer' Meinecke for the discussions about the GetObject and GetObjects methods which were the start points of this library. 4 | 5 | #### This library should help to write code in a more concise and declarative way. 6 | Example with a method to erase lines in model space which are smaller than a given distance: 7 | 8 | ```c# 9 | public void EraseShortLines(double minLength) 10 | { 11 | var db = Application.DocumentManager.MdiActiveDocument.Database; 12 | using (var tr = db.TransactionManager.StartOpenCloseTransaction()) 13 | { 14 | var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); 15 | var modelSpace = (BlockTableRecord)tr.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead); 16 | var lineClass = RXObject.GetClass(typeof(Line)); 17 | foreach (ObjectId id in modelSpace) 18 | { 19 | if (id.ObjectClass == lineClass) 20 | { 21 | var line = (Line)tr.GetObject(id, OpenMode.ForRead); 22 | if (line.Length < minLength) 23 | { 24 | tr.GetObject(id, OpenMode.ForWrite); 25 | line.Erase(); 26 | } 27 | } 28 | } 29 | tr.Commit(); 30 | } 31 | } 32 | ``` 33 | The same method can be written: 34 | 35 | ```c# 36 | public void EraseShortLines(double minLength) 37 | { 38 | var db = Active.Database; 39 | using (var tr = db.TransactionManager.StartOpenCloseTransaction()) 40 | { 41 | db.GetModelSpace(tr) 42 | .GetObjects(tr) 43 | .Where(line => line.Length < minLength) 44 | .UpgradeOpen(tr) 45 | .ForEach(line => line.Erase()); 46 | tr.Commit(); 47 | } 48 | } 49 | ``` 50 | 51 | Reference one of these assemblies in AutoCAD .NET projects setting the Copy Locale property to True. 52 | 53 | Download the [assemblies](https://gilecad.azurewebsites.net/Resources/Gile.AutoCAD.Extension.zip) (Gile.AutoCAD.R20.Extension.dll for AutoCAD 2015 to 2024, Gile.AutoCAD.R25.Extension.dll for AutoCAD 2025+). 54 | 55 | See the [documentation](https://gilecad.azurewebsites.net/Resources/AcadExtensionHelp/index.html). 56 | --------------------------------------------------------------------------------