diff --git a/docs/Navisworks connector.md b/docs/Navisworks connector.md new file mode 100644 index 00000000..63bf10fd --- /dev/null +++ b/docs/Navisworks connector.md @@ -0,0 +1,13 @@ +# OpenProject BIM + +## Revit <-> Navisworks + +![demo](images/demo.gif) + +## Future ideas + +- [x] Revit +- [x] Navisworks +- [ ] Tekla Structures + +![roadmap](images/roadmap2.png) \ No newline at end of file diff --git a/docs/images/demo.gif b/docs/images/demo.gif new file mode 100644 index 00000000..08950536 Binary files /dev/null and b/docs/images/demo.gif differ diff --git a/docs/images/roadmap.png b/docs/images/roadmap.png new file mode 100644 index 00000000..30c0c23f Binary files /dev/null and b/docs/images/roadmap.png differ diff --git a/docs/images/roadmap2.png b/docs/images/roadmap2.png new file mode 100644 index 00000000..30c0c23f Binary files /dev/null and b/docs/images/roadmap2.png differ diff --git a/openproject-revit-add-in.sln b/openproject-revit-add-in.sln index ed447128..5e8e312e 100644 --- a/openproject-revit-add-in.sln +++ b/openproject-revit-add-in.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30204.135 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33502.453 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C185EC12-235E-4F88-8831-91F677F8DC90}" ProjectSection(SolutionItems) = preProject @@ -28,110 +28,314 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A7C3B085-2 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenProject.Tests", "test\OpenProject.Tests\OpenProject.Tests.csproj", "{C08A902A-404B-4CB9-A395-5743A4453733}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenProject.Navisworks", "src\OpenProject.Navisworks\OpenProject.Navisworks.csproj", "{7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 + Debug-2019|Any CPU = Debug-2019|Any CPU + Debug-2019|x64 = Debug-2019|x64 + Debug-2020|Any CPU = Debug-2020|Any CPU Debug-2020|x64 = Debug-2020|x64 + Debug-2021|Any CPU = Debug-2021|Any CPU Debug-2021|x64 = Debug-2021|x64 + Debug-2022|Any CPU = Debug-2022|Any CPU + Debug-2022|x64 = Debug-2022|x64 + Debug-2024|Any CPU = Debug-2024|Any CPU + Debug-2024|x64 = Debug-2024|x64 + Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 + Release-2019|Any CPU = Release-2019|Any CPU + Release-2019|x64 = Release-2019|x64 + Release-2020|Any CPU = Release-2020|Any CPU Release-2020|x64 = Release-2020|x64 + Release-2021|Any CPU = Release-2021|Any CPU Release-2021|x64 = Release-2021|x64 - Debug-2022|x64 = Debug-2022|x64 + Release-2022|Any CPU = Release-2022|Any CPU Release-2022|x64 = Release-2022|x64 - Debug-2019|x64 = Debug-2019|x64 - Release-2019|x64 = Release-2019|x64 + Release-2024|Any CPU = Release-2024|Any CPU + Release-2024|x64 = Release-2024|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug|Any CPU.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug|Any CPU.Build.0 = Debug|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug|x64.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2019|Any CPU.ActiveCfg = Debug-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2019|Any CPU.Build.0 = Debug-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2019|x64.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2020|Any CPU.ActiveCfg = Debug-2020|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2020|Any CPU.Build.0 = Debug-2020|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2020|x64.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2021|Any CPU.ActiveCfg = Debug-2021|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2021|Any CPU.Build.0 = Debug-2021|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2021|x64.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2022|Any CPU.ActiveCfg = Debug-2022|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2022|Any CPU.Build.0 = Debug-2022|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2022|x64.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2024|Any CPU.ActiveCfg = Debug-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2024|Any CPU.Build.0 = Debug-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2024|x64.ActiveCfg = Debug-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2024|x64.Build.0 = Debug-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release|Any CPU.ActiveCfg = Release|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release|Any CPU.Build.0 = Release|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release|x64.ActiveCfg = Release|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2019|Any CPU.ActiveCfg = Release-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2019|Any CPU.Build.0 = Release-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2019|x64.ActiveCfg = Release|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2020|Any CPU.ActiveCfg = Release-2020|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2020|Any CPU.Build.0 = Release-2020|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2020|x64.ActiveCfg = Release|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2021|Any CPU.ActiveCfg = Release-2021|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2021|Any CPU.Build.0 = Release-2021|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2021|x64.ActiveCfg = Release|x64 - {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2022|x64.ActiveCfg = Debug|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2022|Any CPU.ActiveCfg = Release-2022|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2022|Any CPU.Build.0 = Release-2022|x64 {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2022|x64.ActiveCfg = Release|x64 - {09319316-391C-4F82-8EFE-82C2CAE539BD}.Debug-2019|x64.ActiveCfg = Debug|x64 - {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2019|x64.ActiveCfg = Release|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2024|Any CPU.ActiveCfg = Release-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2024|Any CPU.Build.0 = Release-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2024|x64.ActiveCfg = Release-2019|x64 + {09319316-391C-4F82-8EFE-82C2CAE539BD}.Release-2024|x64.Build.0 = Release-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug|Any CPU.Build.0 = Debug|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug|x64.ActiveCfg = Debug|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug|x64.Build.0 = Debug|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2019|Any CPU.ActiveCfg = Debug-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2019|Any CPU.Build.0 = Debug-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2019|x64.ActiveCfg = Debug-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2019|x64.Build.0 = Debug-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2020|Any CPU.ActiveCfg = Debug-2020|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2020|Any CPU.Build.0 = Debug-2020|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2020|x64.ActiveCfg = Debug-2020|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2020|x64.Build.0 = Debug-2020|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2021|Any CPU.ActiveCfg = Debug-2021|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2021|Any CPU.Build.0 = Debug-2021|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2021|x64.ActiveCfg = Debug-2021|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2021|x64.Build.0 = Debug-2021|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2022|Any CPU.ActiveCfg = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2022|Any CPU.Build.0 = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2022|x64.ActiveCfg = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2022|x64.Build.0 = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2024|Any CPU.ActiveCfg = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2024|Any CPU.Build.0 = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2024|x64.ActiveCfg = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2024|x64.Build.0 = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release|Any CPU.ActiveCfg = Release|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release|Any CPU.Build.0 = Release|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release|x64.ActiveCfg = Release|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release|x64.Build.0 = Release|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2019|Any CPU.ActiveCfg = Release-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2019|Any CPU.Build.0 = Release-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2019|x64.ActiveCfg = Release-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2019|x64.Build.0 = Release-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2020|Any CPU.ActiveCfg = Release-2020|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2020|Any CPU.Build.0 = Release-2020|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2020|x64.ActiveCfg = Release-2020|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2020|x64.Build.0 = Release-2020|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2021|Any CPU.ActiveCfg = Release-2021|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2021|Any CPU.Build.0 = Release-2021|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2021|x64.ActiveCfg = Release-2021|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2021|x64.Build.0 = Release-2021|x64 - {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2022|x64.ActiveCfg = Debug-2022|x64 - {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2022|x64.Build.0 = Debug-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2022|Any CPU.ActiveCfg = Release-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2022|Any CPU.Build.0 = Release-2022|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2022|x64.ActiveCfg = Release-2022|x64 {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2022|x64.Build.0 = Release-2022|x64 - {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2019|x64.ActiveCfg = Debug-2019|x64 - {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Debug-2019|x64.Build.0 = Debug-2019|x64 - {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2019|x64.ActiveCfg = Release-2019|x64 - {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2019|x64.Build.0 = Release-2019|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2024|Any CPU.ActiveCfg = Release-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2024|Any CPU.Build.0 = Release-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2024|x64.ActiveCfg = Release-2022|x64 + {4F1C0A21-9543-49D1-AA7E-F69EEA02F905}.Release-2024|x64.Build.0 = Release-2022|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug|Any CPU.Build.0 = Debug|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Debug|x64.ActiveCfg = Debug|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Debug|x64.Build.0 = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2019|Any CPU.ActiveCfg = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2019|Any CPU.Build.0 = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2019|x64.ActiveCfg = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2019|x64.Build.0 = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2020|Any CPU.ActiveCfg = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2020|Any CPU.Build.0 = Debug|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2020|x64.ActiveCfg = Debug|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2020|x64.Build.0 = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2021|Any CPU.ActiveCfg = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2021|Any CPU.Build.0 = Debug|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2021|x64.ActiveCfg = Debug|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2021|x64.Build.0 = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2022|Any CPU.ActiveCfg = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2022|Any CPU.Build.0 = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2022|x64.ActiveCfg = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2022|x64.Build.0 = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2024|Any CPU.ActiveCfg = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2024|Any CPU.Build.0 = Debug|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2024|x64.ActiveCfg = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2024|x64.Build.0 = Debug|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release|Any CPU.Build.0 = Release|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Release|x64.ActiveCfg = Release|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Release|x64.Build.0 = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2019|Any CPU.ActiveCfg = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2019|Any CPU.Build.0 = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2019|x64.ActiveCfg = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2019|x64.Build.0 = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2020|Any CPU.ActiveCfg = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2020|Any CPU.Build.0 = Release|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Release-2020|x64.ActiveCfg = Release|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Release-2020|x64.Build.0 = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2021|Any CPU.ActiveCfg = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2021|Any CPU.Build.0 = Release|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Release-2021|x64.ActiveCfg = Release|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Release-2021|x64.Build.0 = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2022|Any CPU.ActiveCfg = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2022|Any CPU.Build.0 = Release|Any CPU {171002DA-A573-4549-BBB5-708277683B4D}.Release-2022|x64.ActiveCfg = Release|x64 - {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2022|x64.ActiveCfg = Debug|x64 - {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2022|x64.Build.0 = Debug|x64 {171002DA-A573-4549-BBB5-708277683B4D}.Release-2022|x64.Build.0 = Release|x64 - {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2019|x64.ActiveCfg = Debug|x64 - {171002DA-A573-4549-BBB5-708277683B4D}.Debug-2019|x64.Build.0 = Debug|x64 - {171002DA-A573-4549-BBB5-708277683B4D}.Release-2019|x64.ActiveCfg = Release|x64 - {171002DA-A573-4549-BBB5-708277683B4D}.Release-2019|x64.Build.0 = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2024|Any CPU.ActiveCfg = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2024|Any CPU.Build.0 = Release|Any CPU + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2024|x64.ActiveCfg = Release|x64 + {171002DA-A573-4549-BBB5-708277683B4D}.Release-2024|x64.Build.0 = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug|Any CPU.ActiveCfg = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug|Any CPU.Build.0 = Debug|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug|x64.ActiveCfg = Debug|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug|x64.Build.0 = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2019|Any CPU.ActiveCfg = Debug-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2019|Any CPU.Build.0 = Debug-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2019|x64.ActiveCfg = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2019|x64.Build.0 = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2020|Any CPU.ActiveCfg = Debug-2020|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2020|Any CPU.Build.0 = Debug-2020|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2020|x64.ActiveCfg = Debug|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2020|x64.Build.0 = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2021|Any CPU.ActiveCfg = Debug-2021|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2021|Any CPU.Build.0 = Debug-2021|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2021|x64.ActiveCfg = Debug|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2021|x64.Build.0 = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2022|Any CPU.ActiveCfg = Debug-2022|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2022|Any CPU.Build.0 = Debug-2022|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2022|x64.ActiveCfg = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2022|x64.Build.0 = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2024|Any CPU.ActiveCfg = Debug-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2024|Any CPU.Build.0 = Debug-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2024|x64.ActiveCfg = Debug-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2024|x64.Build.0 = Debug-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release|Any CPU.ActiveCfg = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release|Any CPU.Build.0 = Release|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release|x64.ActiveCfg = Release|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release|x64.Build.0 = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2019|Any CPU.ActiveCfg = Release-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2019|Any CPU.Build.0 = Release-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2019|x64.ActiveCfg = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2019|x64.Build.0 = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2020|Any CPU.ActiveCfg = Release-2020|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2020|Any CPU.Build.0 = Release-2020|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2020|x64.ActiveCfg = Release|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2020|x64.Build.0 = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2021|Any CPU.ActiveCfg = Release-2021|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2021|Any CPU.Build.0 = Release-2021|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2021|x64.ActiveCfg = Release|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2021|x64.Build.0 = Release|x64 - {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2022|x64.ActiveCfg = Debug|x64 - {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2022|x64.Build.0 = Debug|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2022|Any CPU.ActiveCfg = Release-2022|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2022|Any CPU.Build.0 = Release-2022|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2022|x64.ActiveCfg = Release|x64 {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2022|x64.Build.0 = Release|x64 - {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2019|x64.ActiveCfg = Debug|x64 - {2388D458-990B-4573-B1EF-E13E27C3A003}.Debug-2019|x64.Build.0 = Debug|x64 - {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2019|x64.ActiveCfg = Release|x64 - {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2019|x64.Build.0 = Release|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2024|Any CPU.ActiveCfg = Release-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2024|Any CPU.Build.0 = Release-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2024|x64.ActiveCfg = Release-2019|x64 + {2388D458-990B-4573-B1EF-E13E27C3A003}.Release-2024|x64.Build.0 = Release-2019|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug|Any CPU.Build.0 = Debug|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Debug|x64.ActiveCfg = Debug|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Debug|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2019|Any CPU.ActiveCfg = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2019|Any CPU.Build.0 = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2019|x64.ActiveCfg = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2019|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2020|Any CPU.ActiveCfg = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2020|Any CPU.Build.0 = Debug|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2020|x64.ActiveCfg = Debug|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2020|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2021|Any CPU.ActiveCfg = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2021|Any CPU.Build.0 = Debug|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2021|x64.ActiveCfg = Debug|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2021|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2022|Any CPU.ActiveCfg = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2022|Any CPU.Build.0 = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2022|x64.ActiveCfg = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2022|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2024|Any CPU.ActiveCfg = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2024|Any CPU.Build.0 = Debug|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2024|x64.ActiveCfg = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2024|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release|Any CPU.Build.0 = Release|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Release|x64.ActiveCfg = Release|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Release|x64.Build.0 = Release|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2019|Any CPU.ActiveCfg = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2019|Any CPU.Build.0 = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2019|x64.ActiveCfg = Release|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2019|x64.Build.0 = Release|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2020|Any CPU.ActiveCfg = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2020|Any CPU.Build.0 = Release|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2020|x64.ActiveCfg = Release|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2020|x64.Build.0 = Release|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2021|Any CPU.ActiveCfg = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2021|Any CPU.Build.0 = Release|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2021|x64.ActiveCfg = Release|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2021|x64.Build.0 = Release|x64 - {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2022|x64.ActiveCfg = Debug|x64 - {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2022|x64.Build.0 = Debug|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2022|Any CPU.ActiveCfg = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2022|Any CPU.Build.0 = Release|Any CPU {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2022|x64.ActiveCfg = Release|x64 {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2022|x64.Build.0 = Release|x64 - {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2019|x64.ActiveCfg = Debug|x64 - {C08A902A-404B-4CB9-A395-5743A4453733}.Debug-2019|x64.Build.0 = Debug|x64 - {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2019|x64.ActiveCfg = Release|x64 - {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2019|x64.Build.0 = Release|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2024|Any CPU.ActiveCfg = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2024|Any CPU.Build.0 = Release|Any CPU + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2024|x64.ActiveCfg = Release|x64 + {C08A902A-404B-4CB9-A395-5743A4453733}.Release-2024|x64.Build.0 = Release|x64 + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug|Any CPU.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug|Any CPU.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug|x64.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug|x64.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2019|Any CPU.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2019|Any CPU.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2019|x64.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2019|x64.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2020|Any CPU.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2020|Any CPU.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2020|x64.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2020|x64.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2021|Any CPU.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2021|Any CPU.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2021|x64.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2021|x64.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2022|Any CPU.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2022|Any CPU.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2022|x64.ActiveCfg = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2022|x64.Build.0 = Debug-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2024|Any CPU.ActiveCfg = Debug-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2024|Any CPU.Build.0 = Debug-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2024|x64.ActiveCfg = Debug-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Debug-2024|x64.Build.0 = Debug-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release|Any CPU.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release|Any CPU.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release|x64.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release|x64.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2019|Any CPU.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2019|Any CPU.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2019|x64.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2019|x64.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2020|Any CPU.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2020|Any CPU.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2020|x64.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2020|x64.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2021|Any CPU.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2021|Any CPU.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2021|x64.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2021|x64.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2022|Any CPU.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2022|Any CPU.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2022|x64.ActiveCfg = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2022|x64.Build.0 = Release-2022|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2024|Any CPU.ActiveCfg = Release-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2024|Any CPU.Build.0 = Release-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2024|x64.ActiveCfg = Release-2024|Any CPU + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88}.Release-2024|x64.Build.0 = Release-2024|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -141,6 +345,7 @@ Global {171002DA-A573-4549-BBB5-708277683B4D} = {B6823317-E2AC-47C9-944B-093A084DCB86} {2388D458-990B-4573-B1EF-E13E27C3A003} = {B6823317-E2AC-47C9-944B-093A084DCB86} {C08A902A-404B-4CB9-A395-5743A4453733} = {A7C3B085-2345-4D50-8D75-16C4429D18C0} + {7B1C7490-A794-4B21-AD7A-1DAF47AB2B88} = {B6823317-E2AC-47C9-944B-093A084DCB86} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {440C743A-A1DD-46EA-A56F-5A92471914C6} diff --git a/src/OpenProject.Navisworks/Application/App.cs b/src/OpenProject.Navisworks/Application/App.cs new file mode 100644 index 00000000..27c04bf5 --- /dev/null +++ b/src/OpenProject.Navisworks/Application/App.cs @@ -0,0 +1,67 @@ +using Autodesk.Navisworks.Api.Plugins; +using OpenProjectNavisworks.Command; +using OpenProjectNavisworks.Properties; +using Serilog; +using Test = OpenProjectNavisworks.Command.Test; +using OpenProject.Shared.Logging; +using System; + + +namespace OpenProjectNavisworks.Application; + +[Plugin("IDP", "PavelNedviga,TachkovMaksim", DisplayName = "IDP-ViewPoint")] +[RibbonLayout("AddinManagerRibbon.xaml")] +[RibbonTab("ID_AddinManager_TAB", DisplayName = "IDP")] +[Command("IDE_ButtonConnectOpenProject", + DisplayName = "IDP-ViewPoint", + Icon = "Resources\\OpenProjectLogo16.png", + LargeIcon = "Resources\\OpenProjectLogo32.png", + ToolTip = "Plugin IDP-ViewPoint")] + + +public class App : CommandHandlerPlugin +{ + public override int ExecuteCommand(string name, params string[] parameters) + { + + + // Buttons + switch (name) + { + case "ID_ButtonAddinManagerManual": + AddInManagerManual addInManagerManual = new AddInManagerManual(); + addInManagerManual.Execute(); + break; + case "ID_ButtonAddinManagerFaceless": + AddInManagerFaceLess addInManagerFaceless = new AddInManagerFaceLess(); + addInManagerFaceless.Execute(); + break; + case "ID_ButtonDockPanelCommand": + DockPanelCommand dockPanelCommand = new DockPanelCommand(); + dockPanelCommand.Execute(); + break; + case "ID_ButtonTest": + Test test = new Test(); + test.Execute(); + break; + case "IDE_ButtonConnectOpenProject": + ConnectOpenProject connOP = new ConnectOpenProject(); + connOP.Execute(); + break; + case "IDE_ButtonSettingsOpenProject": + ConnectSettingsOpenProject connSetOP = new ConnectSettingsOpenProject(); + connSetOP.Execute(); + break; + case "IDE_ButtonGuide": + Guide guide = new Guide(); + guide.Execute(); + break; + case "IDE_ButtonInfo": + Info info = new Info(); + info.Execute(); + break; + } + + return 0; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Command/AddInManagerCommand.cs b/src/OpenProject.Navisworks/Command/AddInManagerCommand.cs new file mode 100644 index 00000000..f8175682 --- /dev/null +++ b/src/OpenProject.Navisworks/Command/AddInManagerCommand.cs @@ -0,0 +1,107 @@ +using System.Data.Common; +using System.Diagnostics; +using System.IO; +using System.Windows; +using Autodesk.Navisworks.Api.Plugins; +using OpenProjectNavisworks.Model; +using OpenProjectNavisworks.Entry; +using MessageBox = System.Windows.MessageBox; + +namespace OpenProjectNavisworks.Command; + +public abstract class IAddinCommand +{ + public abstract int Action(params string[] parameters); + + public void Execute(params string[] parameters) + { + try + { + Action(parameters); + } + catch (Exception e) + { + MessageBox.Show(e.ToString()); + } + } +} +/// +/// Executer the command Addin Manager Manual +/// +public class AddInManagerManual : IAddinCommand +{ + public override int Action(params string[] parameters) + { + Debug.Listeners.Clear(); + Trace.Listeners.Clear(); + CodeListener codeListener = new CodeListener(); + Debug.Listeners.Add(codeListener); + return AddinManagerBase.Instance.ExecuteCommand(false, parameters); + } +} + +/// +/// Execute the command Addin Manager Faceless +/// +public class AddInManagerFaceLess : IAddinCommand +{ + public override int Action(params string[] parameters) + { + return AddinManagerBase.Instance.ExecuteCommand(true, parameters); + } +} + + +/// +/// Execute the command for connection to project +/// +public class ConnectOpenProject : IAddinCommand +{ + public override int Action(params string[] parameters) + { + Model.NavisworksWrapper.Document = Autodesk.Navisworks.Api.Application.ActiveDocument; + //Model.NavisworksWrapper.Document Autodesk.Navisworks.Api.Application; + return CmdMain.ExecuteCommand(true, parameters); + } +} + + +/// +/// Execute the command for connection settings to project +/// +public class ConnectSettingsOpenProject : IAddinCommand +{ + public override int Action(params string[] parameters) + { + Model.NavisworksWrapper.Document = Autodesk.Navisworks.Api.Application.ActiveDocument; + return CmdMainSettings.ExecuteCommand(true, parameters); + } +} + + +public class Test : IAddinCommand +{ + public override int Action(params string[] parameters) + { + MessageBox.Show("Hello World"); + return 0; + } +} + +public class Guide : IAddinCommand +{ + public override int Action(params string[] parameters) + { + Process.Start("http://books.ide-spb.com/books/autodesk-revit/page/idp-viewpoint"); + return 0; + } +} + +public class Info : IAddinCommand +{ + public override int Action(params string[] parameters) + { + Process.Start("https://gitlab.ide-spb.com/Nedviga.Pavel/openprojectnavisbcf/-/releases"); + return 0; + } +} diff --git a/src/OpenProject.Navisworks/Command/AddinManagerBase.cs b/src/OpenProject.Navisworks/Command/AddinManagerBase.cs new file mode 100644 index 00000000..ac62d085 --- /dev/null +++ b/src/OpenProject.Navisworks/Command/AddinManagerBase.cs @@ -0,0 +1,159 @@ +using System.IO; +using System.Windows; +using Autodesk.Navisworks.Api.Plugins; +using OpenProjectNavisworks.Model; +using OpenProjectNavisworks.View; +using OpenProjectNavisworks.ViewModel; +using MessageBox = System.Windows.MessageBox; + +namespace OpenProjectNavisworks.Command; + +public sealed class AddinManagerBase +{ + public int ExecuteCommand(bool faceless, params string[] parameters) + { + var vm = new AddInManagerViewModel(); + if (_activeCmd != null && faceless) + { + return RunActiveCommand(vm, parameters); + } + var FrmAddInManager = new FrmAddInManager(vm); + FrmAddInManager.WindowStartupLocation = WindowStartupLocation.CenterScreen; + FrmAddInManager.SetNavisAsWindowOwner(); + FrmAddInManager.ShowDialog(); + return 0; + } + + public string ActiveTempFolder + { + get => _activeTempFolder; + set => _activeTempFolder = value; + } + + public int RunActiveCommand(AddInManagerViewModel vm, params string[] parameters) + { + var filePath = _activeCmd.FilePath; + if (!File.Exists(filePath)) + { + MessageBox.Show("File not found: " + filePath,DefaultSetting.AppName, MessageBoxButton.OK, MessageBoxImage.Error); + return 0; + } + int result; + try + { + vm.AssemLoader.HookAssemblyResolve(); + var assembly = vm.AssemLoader.LoadAddinsToTempFolder(filePath, false); + if (null == assembly) + { + result = 0; + } + else + { + _activeTempFolder = vm.AssemLoader.TempFolder; + if (assembly.CreateInstance(_activeCmdItem.FullClassName) is not AddInPlugin AddInPlugin) + { + result = 0; + } + else + { + _activeEc = AddInPlugin; + return _activeEc.Execute(parameters); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + result = 0; + } + finally + { + vm.AssemLoader.UnhookAssemblyResolve(); + vm.AssemLoader.CopyGeneratedFilesBack(); + } + + return result; + } + + public static AddinManagerBase Instance + { + get + { + if (_instance == null) + { +#pragma warning disable RCS1059 // Avoid locking on publicly accessible instance. + lock (typeof(AddinManagerBase)) + { + if (_instance == null) + { + _instance = new AddinManagerBase(); + } + } +#pragma warning restore RCS1059 // Avoid locking on publicly accessible instance. + } + + return _instance; + } + } + + private AddinManagerBase() + { + _addinManager = new AddinManager(); + _activeCmd = null; + _activeCmdItem = null; + _activeApp = null; + _activeAppItem = null; + } + + public AddInPlugin ActiveEC + { + get => _activeEc; + set => _activeEc = value; + } + + public Addin ActiveCmd + { + get => _activeCmd; + set => _activeCmd = value; + } + + public AddinItem ActiveCmdItem + { + get => _activeCmdItem; + set => _activeCmdItem = value; + } + + public Addin ActiveApp + { + get => _activeApp; + set => _activeApp = value; + } + + public AddinItem ActiveAppItem + { + get => _activeAppItem; + set => _activeAppItem = value; + } + + public AddinManager AddinManager + { + get => _addinManager; + set => _addinManager = value; + } + + private string _activeTempFolder = string.Empty; + + private static volatile AddinManagerBase _instance; + + private AddInPlugin _activeEc; + + private Addin _activeCmd; + + private AddinItem _activeCmdItem; + + private Addin _activeApp; + + private AddinItem _activeAppItem; + + private AddinManager _addinManager; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Command/DocpanelCommand.cs b/src/OpenProject.Navisworks/Command/DocpanelCommand.cs new file mode 100644 index 00000000..02fb2180 --- /dev/null +++ b/src/OpenProject.Navisworks/Command/DocpanelCommand.cs @@ -0,0 +1,35 @@ +using Autodesk.Navisworks.Api.ApplicationParts; +using Autodesk.Navisworks.Api.Plugins; +using OpenProjectNavisworks.Model; + +namespace OpenProjectNavisworks.Command; + +public class DockPanelCommand : IAddinCommand +{ + public override int Action(params string[] parameters) + { + string PluginId = $"OpenProjectNavisworks.ShowHidePanel.ChuongMep"; + if (Autodesk.Navisworks.Api.Application.IsAutomated) + { + throw new InvalidOperationException("Invalid when running using Automation"); + } + ApplicationPlugins applicationPlugins = Autodesk.Navisworks.Api.Application.Plugins; + PluginRecord pr = applicationPlugins.FindPlugin(PluginId); + if (pr != null && pr is DockPanePluginRecord && pr.IsEnabled) + { + //check if it needs loading + if (pr.LoadedPlugin == null) + { + pr.LoadPlugin(); + } + + if (pr.LoadedPlugin is DockPanePlugin dpp) + { + //switch the Visible flag + dpp.Visible = !dpp.Visible; + } + } + + return 0; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Data/NavisworksUtils.cs b/src/OpenProject.Navisworks/Data/NavisworksUtils.cs new file mode 100644 index 00000000..5f00ac85 --- /dev/null +++ b/src/OpenProject.Navisworks/Data/NavisworksUtils.cs @@ -0,0 +1,198 @@ +using System; +//using Autodesk.Revit.DB; +using Autodesk.Navisworks.Api; +using OpenProject.Shared.Math3D; +using decMath = DecimalMath.DecimalEx; +using OpenProjectNavisworks.Model; + +namespace OpenProjectNavisworks.Data +{ + public static class NavisworksUtils + { + public static Dictionary ModelItems { get; set; } + public static Dictionary> ModelModelItems { get; set; } + public static IEnumerable HiddenModelItems { get; set; } + + /// + /// Converts a camera position according to a projects base position. + /// It takes a position in coordinates of the project base location and + /// transform them to global coordinates or does so in reverse, if the flag is set to true. + /// + /// The revit project base location + /// The source position + /// Default is false, if set to true, transformation is done from global coordinates to + /// revit project base location coordinates + /// The resulting position + public static Position TransformCameraPosition( + ProjectPositionWrapper projectBase, + Position position, + bool reverse = false) + { + var i = reverse ? -1 : 1; + + Vector3 translation = projectBase.GetTranslation() * i; + var rotation = i * projectBase.Angle; + + // do translation before rotation if we transform from global to local coordinates + Vector3 center = reverse + ? new Vector3( + position.Center.X + translation.X, + position.Center.Y + translation.Y, + position.Center.Z + translation.Z) + : position.Center; + + // rotation + var centerX = center.X * decMath.Cos(rotation) - center.Y * decMath.Sin(rotation); + var centerY = center.X * decMath.Sin(rotation) + center.Y * decMath.Cos(rotation); + + // do translation after rotation if we transform from local to global coordinates + Vector3 newCenter = reverse + ? new Vector3(centerX, centerY, center.Z) + : new Vector3(centerX + translation.X, centerY + translation.Y, center.Z + translation.Z); + + var forwardX = position.Forward.X * decMath.Cos(rotation) - + position.Forward.Y * decMath.Sin(rotation); + var forwardY = position.Forward.X * decMath.Sin(rotation) + + position.Forward.Y * decMath.Cos(rotation); + var newForward = new Vector3(forwardX, forwardY, position.Forward.Z); + + var upX = position.Up.X * decMath.Cos(rotation) - position.Up.Y * decMath.Sin(rotation); + var upY = position.Up.X * decMath.Sin(rotation) + position.Up.Y * decMath.Cos(rotation); + var newUp = new Vector3(upX, upY, position.Up.Z); + + return new Position(newCenter, newForward, newUp); + } + + /// + /// Converts a object into a + /// + /// The position object + /// the converted view orientation object + public static Tuple ToViewOrientation3D(this Position position) => + //new(position.Center.ToNavisworksPoint3D(), + // position.Up.ToNavisworksPoint3D(), + // position.Forward.ToNavisworksPoint3D()); + new(position.Center.ToNavisworksPoint3DWithoutUnitsConversion(), + position.Up.ToNavisworksPoint3DWithoutUnitsConversion(), + position.Forward.ToNavisworksPoint3DWithoutUnitsConversion()); + + /// + /// Converts a object into a + /// + /// The vector3 object + /// The Revit vector object + public static Point3D ToNavisworksPoint3D(this Vector3 vec) => + new ( + ToInternalAppUnit(Convert.ToDouble(vec.X)), + ToInternalAppUnit(Convert.ToDouble(vec.Y)), + ToInternalAppUnit(Convert.ToDouble(vec.Z))); + public static Point3D ToNavisworksPoint3DWithoutUnitsConversion(this Vector3 vec) => + new( + Convert.ToDouble(vec.X), + Convert.ToDouble(vec.Y), + Convert.ToDouble(vec.Z)); + + /// + /// Converts a object into a + /// + /// The vector3 object + /// The Revit vector object + public static Vector3 ToVector3(this Point3D vec) => new(vec.X.ToDecimal(), vec.Y.ToDecimal(), vec.Z.ToDecimal()); + + /// + /// Converts some basic revit view values to a view box height and a view box width. + /// The revit views are defined by coordinates in project space. + /// + /// The top right corner of the revit view. + /// The bottom left corner of the revit view. + /// The right direction of the revit view. + /// A tuple of the height and the width of the view box. + //public static (double viewBoxHeight, double viewBoxWidth) ConvertToViewBoxValues( + // Point3D topRight, Point3D bottomLeft, Point3D right) + //{ + // var diagonal = topRight.Subtract(bottomLeft); + // var distance = topRight.DistanceTo(bottomLeft); + // var angleBetweenBottomAndDiagonal = diagonal.Angle(right.ToVector3D()); + + // var height = distance * Math.Sin(angleBetweenBottomAndDiagonal); + // var width = distance * Math.Cos(angleBetweenBottomAndDiagonal); + + // return (height, width); + //} + + /// + /// Converts feet units to meters. Feet are the internal Revit units. + /// + /// Value in internal Revit units to be converted to meters + /// + public static double ToMeters(this double internalUnits) + { + return UnitConversion.ScaleFactor(OpenProjectNavisworks.Model.NavisworksWrapper.Document.Units/*Units.Meters*/, Units.Meters)* internalUnits; +//#if !(Version2021 || Version2022) +// return UnitUtils.ConvertFromInternalUnits(internalUnits, DisplayUnitType.DUT_METERS); +//#else +// return UnitUtils.ConvertFromInternalUnits(internalUnits, UnitTypeId.Meters); +//#endif + } + + /// + /// Converts meters units to feet. Feet are the internal Revit units. + /// + /// Value in feet to be converted to feet + /// + public static double ToInternalAppUnit(this double meters) + { + return meters*UnitConversion.ScaleFactor(Units.Meters, OpenProjectNavisworks.Model.NavisworksWrapper.Document.Units); +//#if Version2021 || Version2022 +// return UnitUtils.ConvertToInternalUnits(meters, UnitTypeId.Meters); +//#else +// return UnitUtils.ConvertToInternalUnits(meters, DisplayUnitType.DUT_METERS); +//#endif + } + + /// + /// Converts a vector containing values in feet units to meter. Feet are the internal Revit units. + /// + /// The vector with values in feet + /// The vector with values in meter + public static Vector3 ToMeters(this Vector3 vec) + { + var x = vec.X.IsFinite() ? Convert.ToDouble(vec.X).ToMeters().ToDecimal() : vec.X; + var y = vec.Y.IsFinite() ? Convert.ToDouble(vec.Y).ToMeters().ToDecimal() : vec.Y; + var z = vec.Z.IsFinite() ? Convert.ToDouble(vec.Z).ToMeters().ToDecimal() : vec.Z; + + return new Vector3(x, y, z); + } + + /// + /// Converts a vector containing values in meter units to feet. Feet are the internal Revit units. + /// + /// The vector with values in meter + /// The vector with values in feet + public static Vector3 ToInternalUnits(this Vector3 vec) + { + var x = vec.X.IsFinite() ? Convert.ToDouble(vec.X).ToInternalAppUnit().ToDecimal() : vec.X; + var y = vec.Y.IsFinite() ? Convert.ToDouble(vec.Y).ToInternalAppUnit().ToDecimal() : vec.Y; + var z = vec.Z.IsFinite() ? Convert.ToDouble(vec.Z).ToInternalAppUnit().ToDecimal() : vec.Z; + + return new Vector3(x, y, z); + } + + /// + /// Converts a position containing values in feet units to meter. Feet are the internal Revit units. + /// + /// The position with values in feet + /// The position with values in meter + public static Position ToMeters(this Position pos) => + new(pos.Center.ToMeters(), pos.Forward.ToMeters(), pos.Up.ToMeters()); + + /// + /// Converts a position containing values in meter units to feet. Feet are the internal Revit units. + /// + /// The position with values in meter + /// The position with values in feet + public static Position ToInternalUnits(this Position pos) => + //new(pos.Center.ToInternalUnits(), pos.Forward.ToInternalUnits(), pos.Up.ToInternalUnits()); + new(pos.Center.ToInternalUnits(), pos.Forward, pos.Up); + } +} diff --git a/src/OpenProject.Navisworks/Data/ProjectPositionWrapper.cs b/src/OpenProject.Navisworks/Data/ProjectPositionWrapper.cs new file mode 100644 index 00000000..9a5f3aa4 --- /dev/null +++ b/src/OpenProject.Navisworks/Data/ProjectPositionWrapper.cs @@ -0,0 +1,63 @@ +//using Autodesk.Revit.DB; +using OpenProject.Shared.Math3D; + +namespace OpenProjectNavisworks.Data +{ + /// + /// A immutable wrapper class around the + /// + public sealed class ProjectPositionWrapper + { + /// + /// The translation of the project into east-west, mostly translated into a translation into x-direction. + /// + public decimal EastWest { get; } + + /// + /// The translation of the project into north-south, mostly translated into a translation into y-direction. + /// + public decimal NorthSouth { get; } + + /// + /// The elevation of the project, mostly translated into a translation into z-direction. + /// + public decimal Elevation { get; } + + /// + /// The angle of the project north to true north. + /// + public decimal Angle { get; } + + public ProjectPositionWrapper(decimal eastWest, decimal northSouth, decimal elevation, decimal angle) + { + EastWest = eastWest; + NorthSouth = northSouth; + Elevation = elevation; + Angle = angle; + } + + public ProjectPositionWrapper() + { + EastWest = 0; + NorthSouth = 0; + Elevation = 0; + Angle = 0; + } + + //public ProjectPositionWrapper(ProjectPosition projectPosition) + //{ + // EastWest = projectPosition.EastWest.ToDecimal(); + // NorthSouth = projectPosition.NorthSouth.ToDecimal(); + // Elevation = projectPosition.Elevation.ToDecimal(); + // Angle = projectPosition.Angle.ToDecimal(); + //} + + /// + /// Returns the project position's translation as a . The east-west translation is taken as x, + /// the north-south as y and the elevation as z. This represents the coordinates of the project as an + /// xyz-coordinate system. + /// + /// The project position's location as a vector. + public Vector3 GetTranslation() => new(EastWest, NorthSouth, Elevation); + } +} diff --git a/src/OpenProject.Navisworks/DockPanel/AddinManagerPane.cs b/src/OpenProject.Navisworks/DockPanel/AddinManagerPane.cs new file mode 100644 index 00000000..94b59797 --- /dev/null +++ b/src/OpenProject.Navisworks/DockPanel/AddinManagerPane.cs @@ -0,0 +1,47 @@ +using System.Windows.Forms; +using System.Windows.Forms.Integration; +using Autodesk.Navisworks.Api.Plugins; +using OpenProjectNavisworks.View.Control; + +namespace OpenProjectNavisworks.DockPanel +{ + [Plugin($"OpenProjectNavisworks.ShowHidePanel", "ChuongMep", DisplayName = "Trace/Debug Output", ToolTip = "Add-in-Manager")] + [DockPanePlugin(350, 600, AutoScroll = true, MinimumHeight = 300)] + class AddinManagerPane : DockPaneBase + { + public override Control CreateControlPane() + { + //create an ElementHost + ElementHost elementHost = new ElementHost + { + //assign the control + AutoSize = true, + Child = new LogControl(), + + + }; + elementHost.CreateControl(); + elementHost.ParentChanged += this.ElementHost_ParentChanged; + //return the ElementHost + return elementHost; + } + + public override void DestroyControlPane(System.Windows.Forms.Control pane) + { + pane.Dispose(); + } + + /// + /// Resizing DockPane implies resizing WPF-based ElementHost + /// + /// ElementHost + /// + private void ElementHost_ParentChanged(object sender, EventArgs e) + { + if (sender is ElementHost elementHost) + { + elementHost.Dock = DockStyle.Fill; + } + } + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/DockPanel/DockPaneBase.cs b/src/OpenProject.Navisworks/DockPanel/DockPaneBase.cs new file mode 100644 index 00000000..a0d30cea --- /dev/null +++ b/src/OpenProject.Navisworks/DockPanel/DockPaneBase.cs @@ -0,0 +1,20 @@ +using System.Windows.Forms; +using Autodesk.Navisworks.Api.Plugins; + +namespace OpenProjectNavisworks.DockPanel +{ + public abstract class DockPaneBase : DockPanePlugin + { + /// + /// Add a control in navis + /// + /// + public abstract override Control CreateControlPane(); + + /// + /// dispose control from created in navis + /// + /// + public abstract override void DestroyControlPane(Control control); + } +} diff --git a/src/OpenProject.Navisworks/Entry/ActiveViewChangedZoomListener.cs b/src/OpenProject.Navisworks/Entry/ActiveViewChangedZoomListener.cs new file mode 100644 index 00000000..ef702554 --- /dev/null +++ b/src/OpenProject.Navisworks/Entry/ActiveViewChangedZoomListener.cs @@ -0,0 +1,65 @@ +////using Autodesk.Revit.DB; +////using Autodesk.Revit.UI; +////using Autodesk.Revit.UI.Events; +//using Autodesk.Navisworks.Internal; +//using Autodesk.Navisworks.Api; +//using System; +//using System.Linq; +//using OpenProjectNavisworks.Data; +//using OpenProjectNavisworks.Services; +//using Serilog; + +//namespace OpenProjectNavisworks.Entry +//{ +// /// +// /// This class collects static functions that registers asynchronous callbacks to the idling state of the +// /// , which deregister themselves after execution. +// /// +// public static class AppIdlingCallbackListener +// { +// /// +// /// Sets a callback that applies a zoom to the current view. +// /// +// /// The current UI application. +// /// The view ID for the view to be zoomed. +// /// The zoom in decimal precision. +// public static void SetPendingZoomChangedCallback(UIApplication app, ElementId viewId, decimal zoom) +// { +// void Callback(object sender, IdlingEventArgs args) +// { +// StatusBarService.SetStatusText("Zooming to scale '" + zoom + "' ..."); +// UIView currentView = app.ActiveUIDocument.GetOpenUIViews().First(); +// if (currentView.ViewId != viewId) return; + +// UIDocument uiDoc = app.ActiveUIDocument; +// View activeView = uiDoc.ActiveView; + +// var zoomCorners = currentView.GetZoomCorners(); +// XYZ bottomLeft = zoomCorners[0]; +// XYZ topRight = zoomCorners[1]; +// var (currentHeight, currentWidth) = +// RevitUtils.ConvertToViewBoxValues(topRight, bottomLeft, activeView.RightDirection); + +// var zoomedViewBoxHeight = Convert.ToDouble(zoom).ToInternalRevitUnit(); +// var zoomedViewBoxWidth = zoomedViewBoxHeight * currentWidth / currentHeight; + +// XYZ newTopRight = activeView.Origin +// .Add(activeView.UpDirection.Multiply(zoomedViewBoxHeight / 2)) +// .Add(activeView.RightDirection.Multiply(zoomedViewBoxWidth / 2)); +// XYZ newBottomLeft = activeView.Origin +// .Subtract(activeView.UpDirection.Multiply(zoomedViewBoxHeight / 2)) +// .Subtract(activeView.RightDirection.Multiply(zoomedViewBoxWidth / 2)); + +// Log.Information("Zoom to {topRight} | {bottomLeft} ...", newTopRight.ToString(), newBottomLeft.ToString()); +// currentView.ZoomAndCenterRectangle(newTopRight, newBottomLeft); + +// StatusBarService.ResetStatusBarText(); +// Log.Information("Finished applying zoom for orthogonal view."); +// app.Idling -= Callback; +// } + +// Log.Information("Append zoom callback for orthogonal view to idle state of Revit application ..."); +// app.Idling += Callback; +// } +// } +//} diff --git a/src/OpenProject.Navisworks/Entry/CmdMain.cs b/src/OpenProject.Navisworks/Entry/CmdMain.cs new file mode 100644 index 00000000..634501b6 --- /dev/null +++ b/src/OpenProject.Navisworks/Entry/CmdMain.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using Autodesk.Navisworks.Api.Plugins; +namespace OpenProjectNavisworks.Entry; + +/// +/// Obfuscation Ignore for External Interface +/// +[Obfuscation(Exclude = true, ApplyToMembers = false)] +//[Transaction(TransactionMode.Manual)] +//[Regeneration(RegenerationOption.Manual)] +public sealed class CmdMain +{ + /// + /// Main Command Entry Point + /// + /// + /// + /// + /// + public static int ExecuteCommand(bool apply, params string[] parameters) + { + var message = string.Empty; + return RibbonButtonClickHandler.OpenMainPluginWindow(Model.NavisworksWrapper.Document, ref message); + } +} + diff --git a/src/OpenProject.Navisworks/Entry/CmdMainSettings.cs b/src/OpenProject.Navisworks/Entry/CmdMainSettings.cs new file mode 100644 index 00000000..ef79f853 --- /dev/null +++ b/src/OpenProject.Navisworks/Entry/CmdMainSettings.cs @@ -0,0 +1,22 @@ +//using Autodesk.Revit.Attributes; +//using Autodesk.Revit.DB; +//using Autodesk.Revit.UI; +using System.Reflection; + +namespace OpenProjectNavisworks.Entry +{ + /// + /// Obfuscation Ignore for External Interface + /// + [Obfuscation(Exclude = true, ApplyToMembers = false)] + //[Transaction(TransactionMode.Manual)] + //[Regeneration(RegenerationOption.Manual)] + public sealed class CmdMainSettings + { + public static int ExecuteCommand(bool apply, params string[] parameters) + { + var message = string.Empty; + return RibbonButtonClickHandler.OpenSettingsPluginWindow(Model.NavisworksWrapper.Document, ref message); + } + } +} diff --git a/src/OpenProject.Navisworks/Entry/IpcHandler.cs b/src/OpenProject.Navisworks/Entry/IpcHandler.cs new file mode 100644 index 00000000..18cb51d5 --- /dev/null +++ b/src/OpenProject.Navisworks/Entry/IpcHandler.cs @@ -0,0 +1,180 @@ +using Autodesk.Navisworks.Gui; +using Autodesk.Navisworks.Api; +using Autodesk.Navisworks.Internal; +using OpenProject.Shared; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using iabi.BCF.APIObjects.V21; +using Newtonsoft.Json.Converters; +using OpenProjectNavisworks.Extensions; +using OpenProjectNavisworks.Services; +using OpenProject.Shared.BcfApi; +using ZetaIpc.Runtime.Client; +using ZetaIpc.Runtime.Server; +using ZetaIpc.Runtime.Helper; +using OpenProjectNavisworks.Data; + +namespace OpenProjectNavisworks.Entry; +public class IpcHandler +{ + private readonly Document _uiApp; + private Action _sendData; + private static readonly object _callbackStackLock = new(); + private static readonly Stack _callbackStack = new(); + + public IpcHandler(Document uiApp) + { + _uiApp = uiApp ?? throw new ArgumentNullException(nameof(uiApp)); + + + Autodesk.Navisworks.Api.Application.Idle += (_, _) => + { + lock (_callbackStackLock) + { + if (!_callbackStack.Any()) return; + + _callbackStack.Pop().Invoke(); + } + }; + } + + public int StartLocalServerAndReturnPort() + { + var freePort = FreePortHelper.GetFreePort(); + var server = new IpcServer(); + server.Start(freePort); + server.ReceivedRequest += (_, e) => + { + var eventArgs = JsonConvert.DeserializeObject(e.Request); + if (eventArgs == null) return; + + var localMessageType = eventArgs.MessageType; + var localTrackingId = eventArgs.TrackingId; + var localMessagePayload = eventArgs.MessagePayload; + + lock (_callbackStackLock) + { + _callbackStack.Push(() => + { + switch (localMessageType) + { + case MessageTypes.VIEWPOINT_DATA: + { + try + { + BcfViewpointWrapper bcfViewpoint = MessageDeserializer.DeserializeBcfViewpoint( + new WebUiMessageEventArgs(localMessageType, localTrackingId, localMessagePayload)); + + // TODO: (if else) Hiding objects feature + //if(NavisworksUtils.ModelItems != null) + OpenViewpointEventHandler.ShowBcfViewpoint(bcfViewpoint); + //else + //{ + // MessageHandler.ShowWarning( + // "Object dictionary is not ready yet!", + // "Object dictionary is ready, you can use ViewPoint now", + // "Object dictionary is ready"); + //} + } + catch (Exception exception) + { + MessageHandler.ShowError(exception, "Error opening a viewpoint."); + } + + break; + } + case MessageTypes.VIEWPOINT_GENERATION_REQUESTED: + try + { + + AddViewpoint(localTrackingId); + + } + catch (Exception exception) + { + MessageHandler.ShowError(exception, "Error generating a viewpoint."); + } + + break; + } + }); + } + }; + + return freePort; + } + + public void StartLocalClient(int ipcWinServerPort) + { + var client = new IpcClient(); + client.Initialize(ipcWinServerPort); + _sendData = message => + { + try + { + client.Send(message); + } + catch (System.Net.WebException) + { + // We can ignore the WebException, it's raised after + // the shutdown event due to the other side just closing + // the open TCP connection. This is what's expected😊 + } + }; + } + + public void SendShutdownRequestToDesktopApp() + { + var eventArgs = new WebUiMessageEventArgs(MessageTypes.CLOSE_DESKTOP_APPLICATION, "0", string.Empty); + var jsonEventArgs = JsonConvert.SerializeObject(eventArgs); + _sendData(jsonEventArgs); + } + + public void SendOpenSettingsRequestToDesktopApp() + { + var eventArgs = new WebUiMessageEventArgs(MessageTypes.GO_TO_SETTINGS, "0", string.Empty); + var jsonEventArgs = JsonConvert.SerializeObject(eventArgs); + _sendData(jsonEventArgs); + } + + public void SendBringBrowserToForegroundRequestToDesktopApp() + { + var eventArgs = new WebUiMessageEventArgs(MessageTypes.SET_BROWSER_TO_FOREGROUND, "0", string.Empty); + var jsonEventArgs = JsonConvert.SerializeObject(eventArgs); + _sendData(jsonEventArgs); + } + + /// + /// Generates a viewpoint from the active view and sends the data as an event to bridge. + /// + /// The local message tracking id. + private void AddViewpoint(string trackingId) + { + JObject payload = GenerateJsonViewpoint(); + + // TODO: remove hack of snapshot data once #39135 is deployed + payload["snapshot"] = payload["snapshot"]?["snapshot_data"]; + + var eventArgs = new WebUiMessageEventArgs(MessageTypes.VIEWPOINT_GENERATED, trackingId, payload.ToString()); + var so = JsonConvert.SerializeObject(eventArgs); + _sendData(so); + } + + private JObject GenerateJsonViewpoint() + { + var serializerSettings = new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + }; + + serializerSettings.Converters.Add(new StringEnumConverter(new SnakeCaseNamingStrategy(), false)); + + Viewpoint_POST viewpoint = _uiApp.GenerateViewpoint(); + return JObject.Parse(JsonConvert.SerializeObject(viewpoint, serializerSettings)); + } +} + diff --git a/src/OpenProject.Navisworks/Entry/OpenViewpointEventHandler.cs b/src/OpenProject.Navisworks/Entry/OpenViewpointEventHandler.cs new file mode 100644 index 00000000..fb022918 --- /dev/null +++ b/src/OpenProject.Navisworks/Entry/OpenViewpointEventHandler.cs @@ -0,0 +1,729 @@ +//using Autodesk.Revit.DB; +//using Autodesk.Revit.UI; +using Autodesk.Navisworks.Api; +using OpenProjectNavisworks.Data; +using OpenProjectNavisworks.Extensions; +using OpenProjectNavisworks.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using OpenProject.Shared.BcfApi; +using OpenProject.Shared.Math3D; +using OpenProject.Shared.Math3D.Enumeration; +using Serilog; +using System.Windows.Forms; +using iabi.BCF.APIObjects.V10.Viewpoint.Components; +using iabi.BCF.APIObjects.V21; +using System.Xml.Linq; +using System.Windows.Controls; +using System.Xml.Linq; +using OpenProject.Shared; +using System.Windows; +using System.IO; +using Optional.Collections; + +namespace OpenProjectNavisworks.Entry; + +/// +/// Obfuscation Ignore for External Interface +/// +public class OpenViewpointEventHandler +{ + private const decimal _viewpointAngleThresholdRad = 0.087266462599716m; + + /// + public void Execute(Document app) + { + try + { + ShowBCfViewpointInternal(app); + } + catch (Exception ex) + { + Log.Error(ex, "Failed to load BCF viewpoint"); + MessageHandler.ShowError(ex, "exception: " + ex); + } + } + + /// + public string GetName() => nameof(OpenViewpointEventHandler); + + private BcfViewpointWrapper _bcfViewpoint; + + private static OpenViewpointEventHandler _instance; + + private static OpenViewpointEventHandler Instance + { + get + { + if (_instance != null) return _instance; + + _instance = new OpenViewpointEventHandler(); + //ExternalEvent = ExternalEvent.Create(_instance); + + return _instance; + } + } + + //private static ExternalEvent ExternalEvent { get; set; } + + /// + /// Wraps the raising of the external event and thus the execution of the event callback, + /// that show given bcf viewpoint. + /// + /// + /// http://help.autodesk.com/view/RVT/2014/ENU/?guid=GUID-0A0D656E-5C44-49E8-A891-6C29F88E35C0 + /// http://matteocominetti.com/starting-a-transaction-from-an-external-application-running-outside-of-api-context-is-not-allowed/ + /// + /// The bcf viewpoint to be shown in current view. + public static void ShowBcfViewpoint(BcfViewpointWrapper bcfViewpoint) + { + Log.Information("Received 'Opening BCF Viewpoint event'. Attempting to open viewpoint ..."); + Instance._bcfViewpoint = bcfViewpoint; + //ExternalEvent.Raise(); + Instance.Execute(OpenProjectNavisworks.Model.NavisworksWrapper.Document); + } + + private void ShowBCfViewpointInternal(Document document) + { + var hasCamera = _bcfViewpoint.GetCamera().Match( + camera => + { + Log.Information("Found camera type {t}, opening related OpenProject view ...", camera.Type.ToString()); + + var openProjectView = document.GetOpenProjectView(camera.Type); + + //ResetView(document, openProjectView); + //Log.Information("Reset view..."); + + var viewPoint = document.CurrentViewpoint.CreateCopy(); + + Log.Information("Applied view point clipping planes in '{v}'.", "view"); + ApplyClippingPlanes(document, ref viewPoint); + + ApplyViewOrientationAndVisibility(document, camera, ref viewPoint); + Log.Information("Applied view orientation and visibility in '{v}'.", "view"); + + + + //if (!document.ActiveView.Id.Equals(openProjectView.Id)) + //{ + // Log.Information("Setting view '{t}' as active view ...", openProjectView.Name); + // document.ActiveView = openProjectView; + //} + + //document.RefreshActiveView(); + document.CurrentViewpoint.CopyFrom(viewPoint); + Log.Information("Refreshed active view."); + StatusBarService.ResetStatusBarText(); + + // MaksT + //SavedViewpoint saveViewPoint = new SavedViewpoint(document.CurrentViewpoint.ToViewpoint()); + //saveViewPoint.DisplayName = "gettedView"; + //document.SavedViewpoints.AddCopy(saveViewPoint); + + ZoomIfNeeded(document, camera, ref viewPoint); + document.CurrentViewpoint.CopyFrom(viewPoint); + Log.Information("Finished loading BCF viewpoint."); + + return true; + }, + () => false); + + if (!hasCamera) Log.Error("BCF viewpoint has no camera information. Aborting ..."); + } + + + /// + /// Zoom the view to the correct scale, if necessary. + /// + /// In Revit, orthogonal views do not change their camera positions, when zooming in or out. Hence, + /// the values stored in the BCF viewpoint are not sufficient to restore the previously exported viewpoint. + /// In order to get correct zooming, the scale value (view box height) is used, to calculate the correct zoom + /// corners according to view center. + /// See https://thebuildingcoder.typepad.com/blog/2020/10/save-and-restore-3d-view-camera-settings.html + /// + private static void ZoomIfNeeded(Document app, Camera camera, ref Viewpoint viewPoint) + { + if (camera.Type != CameraType.Orthogonal || camera is not OrthogonalCamera orthoCam) return; + + Log.Information("Found orthogonal camera, setting zoom callback ..."); + StatusBarService.SetStatusText("Waiting for view to render to apply zoom ..."); + + //AppIdlingCallbackListener.SetPendingZoomChangedCallback(app, viewId, orthoCam.ViewToWorldScale); + //var cam1 = _bcfViewpoint.GetCamera(). + + //app.CurrentViewpoint.Value.HeightField = (double)orthoCam.ViewToWorldScale; + viewPoint.HeightField = NavisworksUtils.ToInternalAppUnit((double)orthoCam.ViewToWorldScale); + + + } + + private static void ResetView(Document doc, Autodesk.Navisworks.Api.View view) + { + Log.Information("Removing current selection ..."); + doc.CurrentSelection.Clear(); + view.TrySetClippingPlanes(""); + view.Dispose(); + + var models = doc.Models; + + foreach (var model in models) + { + ModelItem rootItem = model.RootItem; + ModelItemEnumerableCollection modelItems = rootItem.DescendantsAndSelf; + doc.Models.SetHidden(modelItems, false); + Log.Information("Unhide {n} currently hidden elements in model {m}...", modelItems.Count(), model.FileName); + } + } + + private void ApplyViewOrientationAndVisibility(Document doc, Camera camera, ref Viewpoint viewPoint) + { + StatusBarService.SetStatusText("Loading view point data ..."); + Log.Information("Calculating view orientation from camera position ..."); + + var viewOrientation3D = NavisworksUtils.TransformCameraPosition( + new ProjectPositionWrapper(), + camera.Position.ToInternalUnits(), + true) + .ToViewOrientation3D(); + + if (camera.Type == CameraType.Perspective) + { + Log.Information("Setting active far viewer bound to zero ..."); + viewPoint.Projection = ViewpointProjection.Perspective; + var fov = _bcfViewpoint.Viewpoint.Perspective_camera.Field_of_view; + //var fieldOfView = _bcfViewpoint.Viewpoint.Perspective_camera.Field_of_view; + viewPoint.HeightField = fov; + } + else + { + viewPoint.Projection = ViewpointProjection.Orthographic; + } + + + + Log.Information("Applying new view orientation ..."); + viewPoint.Position = camera.Position.Center.ToNavisworksPoint3D(); + //Rotation3D rt3d = new Rotation3D(viewPoint.Rotation.ToAxisAndAngle().Axis, + // new UnitVector3D( + // Convert.ToDouble(-camera.Position.Forward.X), + // Convert.ToDouble(-camera.Position.Forward.Y), + // Convert.ToDouble(-camera.Position.Forward.Z))); + //Rotation3D rt3d = new Rotation3D(viewPoint.Rotation.ToAxisAndAngle().Axis, + //viewPoint.Rotation = rt3d; + //Rotation3D rt3d = new Rotation3D(viewPoint.Rotation.ToAxisAndAngle().Axis, new UnitVector3D( + // Convert.ToDouble(-camera.Position.Forward.X), + // Convert.ToDouble(-camera.Position.Forward.Y), + // Convert.ToDouble(-camera.Position.Forward.Z))); + //viewPoint.AlignDirection(new Vector3D( + // Convert.ToDouble(camera.Position.Forward.X), + // Convert.ToDouble(camera.Position.Forward.Y), + // Convert.ToDouble(camera.Position.Forward.Z))); + var focusPoint = new Point3D( + camera.Position.Center.ToNavisworksPoint3D().X + Convert.ToDouble(camera.Position.Forward.X), + camera.Position.Center.ToNavisworksPoint3D().Y + Convert.ToDouble(camera.Position.Forward.Y), + camera.Position.Center.ToNavisworksPoint3D().Z + Convert.ToDouble(camera.Position.Forward.Z)); + + viewPoint.PointAt(focusPoint); + + Double forwardX = Convert.ToDouble(camera.Position.Forward.X); + Double forwardY = Convert.ToDouble(camera.Position.Forward.Y); + Double forwardZ = Convert.ToDouble(camera.Position.Forward.Z); + + if (forwardX < 0.000001 && forwardY < 0.000001 && Math.Abs(forwardZ) == 1) // We should align by another vector in case of UP and DOWN view + { + viewPoint.AlignUp(new Vector3D(0, 1, 0)); + } + else { + viewPoint.AlignUp(new Vector3D(0, 0, 1)); + } + + + + //Convert.ToDouble(camera.Position.Up.X), + //Convert.ToDouble(camera.Position.Up.Y), + //Convert.ToDouble(camera.Position.Up.Z))); + + + + Log.Information("Applying element visibility ..."); + + doc.Models.ResetAllHidden(); + + // -------------------------------------------------------------------- + // SELECTION + // -------------------------------------------------------------------- + // -------------------------------------------------------------------- + // METHOD 0. OLDMETHOD BRUTEFORCE + + //var currentlyVisibleElements = doc.GetVisibleElementsOfView(); + //var map = doc.GetIfcGuidElementIdMap(currentlyVisibleElements); + //var exceptionElements = GetViewpointVisibilityExceptions(map); + //var myexceptionElements = _bcfViewpoint.GetVisibilityExceptions().ToList(); + + //var selectedElements = _bcfViewpoint.GetSelection().Select(x => (doc.Models.RootItemDescendants.WhereInstanceGuid(IfcGuid.FromIfcGUID(x.Ifc_guid))).FirstOrDefault()).Distinct().ToList(); + + //var interestedGuids = _bcfViewpoint.GetSelection().Select(x => IfcGuid.FromIfcGUID(x.Ifc_guid)); + //var selectedElements = doc.Models.RootItemDescendants.Where(elem => interestedGuids.Contains(elem.InstanceGuid)).Distinct().ToList(); + + + //var selectedElements = GetViewpointSelection(map); + //if (exceptionElements.Any()) + //{ + // //if (_bcfViewpoint.GetVisibilityDefault()) // Сделали всегда True + // //{ + // ////create a store for the visible items + // //ModelItemCollection visible = new ModelItemCollection(); + + // //doc.CurrentSelection.SelectAll(); + // ////Add all the items that are visible to the visible collection + // //foreach (ModelItem item in Autodesk.Navisworks.Api.Application.ActiveDocument.CurrentSelection.SelectedItems) + // //{ + // // if (item.AncestorsAndSelf != null) + // // visible.AddRange(item.AncestorsAndSelf); + // // if (item.Descendants != null) + // // visible.AddRange(item.Descendants); + // //} + // //view.HideElementsTemporary(exceptionElements); + // //doc.Models.SetHidden(visible, false); + + // //doc.Models.SetHidden(exceptionElements, true); + // doc.Models.SetHidden(exceptionElements, true); + // //selectedElements = selectedElements.Where(id => !exceptionElements.Contains(id)).ToList(); + // //} + // //else + // //{ + // //view.IsolateElementsTemporary(exceptionElements); + + // //var sel = doc.CurrentSelection.SelectedItems; + // //sel.Clear(); + // //sel.AddRange(exceptionElements); + // //sel.Invert(doc); + // //doc.Models.SetHidden(sel, true); + // //selectedElements = selectedElements.Where(id => exceptionElements.Contains(id)).ToList(); + // // Hello world + + // // doc.CurrentSelection.Clear(); + // // doc.Models.ResetAllHidden(); + // // doc.CurrentSelection.AddRange(exceptionElements); + // // selectedElements = selectedElements.Where(id => exceptionElements.Contains(id)).ToList(); + + // //} + // doc.CurrentSelection.Clear(); + //} + ////view.ConvertTemporaryHideIsolateToPermanent(); + + // -------------------------------------------------------------------- + // METHOD 1. BRUTEFORCE WHEREINSTANCE | SPEED 1/5 + //var selectedElements1 = GetSelectedElementsBrute(doc); + // -------------------------------------------------------------------- + // METHOD 2. BYSEARCH | SPEED 3/5 + //List selectedElements2 = GetSelectedElementsBySearch(doc); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // METHOD 3.1 BY MODELS BRUTE MINE | SPEED 3/5 + //List selectedElements2 = GetSelectedElementsByModels(doc); + // METHOD 3.2 BY MODELS SEARCH | Не удалось реализовать + //List selectedElements3 = GetSelectedElementsByModelsAndSearch(doc); + // METHOD 3.3 BY MODELS BRUTE WHERE | + List selectedElements3 = GetSelectedElementsByModelsWere(doc); + + // -------------------------------------------------------------------- + // METHOD 4. DICT | SPEED 5/5 + //Dictionary dict = NavisworksUtils.ModelItems; + ////Dictionary> dict = NavisworksUtils.ModelModelItems; + ////List exceptions = NavisworksUtils.HiddenModelItems.ToList(); + //List selectedElements4 = new List(); + //if (dict != null) + //{ + // selectedElements4 = GetSelectedElementsByDict(dict); + // //selectedElements = GetSelectedElementsByModelDict(dict); + // //exceptions = GetExceptionsByDict(dict); + + // if (selectedElements4.Any()) + // { + // Log.Information("Select {n} elements ...", selectedElements4.Count()); + // //doc.CurrentSelection.SelectedItems.Clear(); + // //doc.CurrentSelection.SelectedItems.AddRange(selectedElements); + + // doc.CurrentSelection.Clear(); + // doc.CurrentSelection.AddRange(selectedElements4); + // } + + // //if (exceptions != null) + // //{ + // // doc.Models.ResetAllHidden(); + // // doc.Models.SetHidden(exceptions, true); + // //} + //} + //else + //{ + // MessageHandler.ShowWarning( + // "Необходимо подождать", + // "Словарь объектов модели еще не сформирован, необходимо подождать. Операция может занимать несколько минут", + // "Словарь объектов не сформирован"); + //} + // -------------------------------------------------------------------- + if (selectedElements3.Any()) + { + //Log.Information("Select {n} elements ...", selectedElements3.Count()); + //doc.CurrentSelection.SelectedItems.Clear(); + //doc.CurrentSelection.SelectedItems.AddRange(selectedElements); + + doc.CurrentSelection.Clear(); + doc.CurrentSelection.AddRange(selectedElements3); + } + + var stop = 1; + // -------------------------------------------------------------------- + // SELECTION + // -------------------------------------------------------------------- + + + + + } + private List GetSelectedElementsBrute(Document doc) + { + + var selectedElements = _bcfViewpoint.GetSelection().Select(x => (doc.Models.RootItemDescendants.WhereInstanceGuid(IfcGuid.FromIfcGUID(x.Ifc_guid))).FirstOrDefault()).Distinct().ToList(); + + return selectedElements; + } + private List GetSelectedElementsBySearch(Document doc) + { + List selectedElements = new List(); + foreach (Component component in _bcfViewpoint.GetSelection()) + { + Guid id = IfcGuid.FromIfcGUID(component.Ifc_guid); + string strID = id.ToString(); + + Search search = new Search(); + search.Selection.SelectAll(); + + //var modelFileNameBCF = component.Authoring_tool_id; + //SearchCondition searchCondition2 = SearchCondition.HasPropertyByName("LcOaNode", "LcOaNodeSourceFile"); + //searchCondition2 = searchCondition2.EqualValue(VariantData.FromDisplayString(modelFileNameBCF)); + //search.SearchConditions.Add(searchCondition2); + SearchCondition searchCondition = SearchCondition.HasPropertyByName("LcOaNode", "LcOaNodeGuid"); + searchCondition = searchCondition.EqualValue(VariantData.FromDisplayString(strID)); + search.SearchConditions.Add(searchCondition); + + + + ModelItem item = search.FindFirst(doc, false); + + if (item != null) + { + selectedElements.Add(item); + } + } + return selectedElements; + } + private List GetSelectedElementsByModels(Document doc) + { + List selectedElements = new List(); + + var models = doc.Models; + foreach (var component in _bcfViewpoint.GetSelection()) + { + var modelFileNameBCF = component.Authoring_tool_id; + + foreach (var model in models) + { + if (modelFileNameBCF == Path.GetFileName(model.FileName)) + { + var descendantsModelItems = model.RootItem.Descendants; + + foreach (var descendant in descendantsModelItems) + { + if (descendant.InstanceGuid == IfcGuid.FromIfcGUID(component.Ifc_guid)) + { + selectedElements.Add(descendant); + break; + } + + } + + break; + } + } + } + + return selectedElements; + } + private List GetSelectedElementsByModelsWere(Document doc) + { + List selectedElements = new List(); + + var models = RibbonButtonClickHandler.GetItemFromLastModelBranch(doc.Models.ToList()); + foreach (var component in _bcfViewpoint.GetSelection()) + { + var modelFileNameBCF = component.Authoring_tool_id; + + foreach (var model in models) + { + if (modelFileNameBCF == Path.GetFileNameWithoutExtension(model.SourceFileName)) + { + //selectedElements = _bcfViewpoint.GetSelection().Select(x => (model.RootItem.Descendants.WhereInstanceGuid(IfcGuid.FromIfcGUID(x.Ifc_guid))).FirstOrDefault()).Distinct().ToList(); + selectedElements.Add(model.RootItem.Descendants.WhereInstanceGuid(IfcGuid.FromIfcGUID(component.Ifc_guid)).First()); + break; + + } + } + } + + return selectedElements; + } + private List GetSelectedElementsByModelsAndSearch(Document doc) + { + List selectedElements = new List(); + Search search = new Search(); + SearchCondition searchCondition = SearchCondition.HasPropertyByName("LcOaNode", "LcOaNodeGuid"); + + var models = doc.Models; + foreach (var component in _bcfViewpoint.GetSelection()) + { + search.Clear(); + Guid id = IfcGuid.FromIfcGUID(component.Ifc_guid); + string strID = id.ToString(); + var modelFileNameBCF = component.Authoring_tool_id; + foreach (var model in models) + { + if (modelFileNameBCF == Path.GetFileName(model.FileName)) + { + var descendantsModelItems = model.RootItem.Descendants; + search.Selection.Clear(); + search.Selection.Dispose(); + //search.Selection.SelectAll(); + search.Selection.CopyFrom(descendantsModelItems); + + searchCondition = searchCondition.EqualValue(VariantData.FromDisplayString(strID)); + search.SearchConditions.Add(searchCondition); + + ModelItem item = search.FindFirst(doc, false); + if (item != null) + { + selectedElements.Add(item); + } + break; + } + } + } + + return selectedElements; + } + + private List GetSelectedElementsByDict(Dictionary dict) + { + List selectedElements = new List(); + + foreach (var component in _bcfViewpoint.GetSelection()) + { + var modelFileNameBCF = component.Authoring_tool_id; + var modelGuidBCF = IfcGuid.FromIfcGUID(component.Ifc_guid).ToString(); + + if(dict.TryGetValue(modelGuidBCF, out ModelItem foundModelItem)) + { + selectedElements.Add(foundModelItem); + } + } + + return selectedElements; + } + private List GetSelectedElementsByModelDict(Dictionary> dict) + { + List selectedElements = new List(); + + foreach (var component in _bcfViewpoint.GetSelection()) + { + var modelFileNameBCF = component.Authoring_tool_id; + var modelGuidBCF = IfcGuid.FromIfcGUID(component.Ifc_guid).ToString(); + + if (dict.TryGetValue(modelFileNameBCF, out Dictionary foundModelDict)) + { + if (foundModelDict.TryGetValue(modelGuidBCF, out ModelItem foundModelItem)) + { + selectedElements.Add(foundModelItem); + } + + } + } + + return selectedElements; + } + private List GetExceptionsByDict(Dictionary dict) + { + List exceptions = new List(); + + foreach (var component in _bcfViewpoint.GetVisibilityExceptions()) + { + var modelFileNameBCF = component.Authoring_tool_id; + var modelGuidBCF = IfcGuid.FromIfcGUID(component.Ifc_guid).ToString(); + + if (dict.TryGetValue(modelGuidBCF, out ModelItem foundModelItem)) + { + exceptions.Add(foundModelItem); + } + } + + return exceptions; + } + + private void ApplyClippingPlanes(Document doc, ref Viewpoint viewPoint) + { + //Test + //var cvp = doc.CurrentViewpoint; + //var vp = cvp.Value; + //var cps = vp.InternalClipPlanes; + //var mode = cps.GetMode(); + //BoundingBox3D box = new BoundingBox3D(); + //Rotation3D rotation = new Rotation3D(); + //cps.GetOrientedBox(box, rotation); + //Vector3D dims = box.Size; + //box = box.Extend(new Point3D(-dims.X * 0.25, -dims.Y * 0.25, -dims.Z * 0.25)); + //cps.SetOrientedBox(box, rotation); + //doc.CurrentViewpoint.CopyFrom(vp); + // + + //using var trans = new Transaction(doc.Document); + //if (trans.Start($"Apply view point clipping planes in '{view.Name}'") != TransactionStatus.Started) + // return; + + Log.Information("Retrieving viewpoint clipping planes " + + "and converting them into an axis aligned bounding box ..."); + AxisAlignedBoundingBox boundingBox = GetViewpointClippingBox(); + IEnumerable clippingPlanes = _bcfViewpoint.GetClippingPlanes(); + //ClipPlane + + + if (!boundingBox.Equals(AxisAlignedBoundingBox.Infinite)) + { + Log.Information("Found axis aligned clipping planes. Setting resulting section box ..."); + string json = doc.ActiveView.GetClippingPlanes(); + + string minCorner = string.Format("{0},{1},{2}", + Convert.ToDouble(boundingBox.Min.X).ToInternalAppUnit().ToString("0.00000", System.Globalization.CultureInfo.InvariantCulture), + Convert.ToDouble(boundingBox.Min.Y).ToInternalAppUnit().ToString("0.00000", System.Globalization.CultureInfo.InvariantCulture), + Convert.ToDouble(boundingBox.Min.Z).ToInternalAppUnit().ToString("0.00000", System.Globalization.CultureInfo.InvariantCulture)); + string maxCorner = string.Format("{0},{1},{2}", + Convert.ToDouble(boundingBox.Max.X).ToInternalAppUnit().ToString("0.00000", System.Globalization.CultureInfo.InvariantCulture), + Convert.ToDouble(boundingBox.Max.Y).ToInternalAppUnit().ToString("0.00000", System.Globalization.CultureInfo.InvariantCulture), + Convert.ToDouble(boundingBox.Max.Z).ToInternalAppUnit().ToString("0.00000", System.Globalization.CultureInfo.InvariantCulture)); + + // apply the section box. + string ClippingBox = + "{\"Type\":\"ClipPlaneSet\",\"Version\":1,\"OrientedBox\":{\"Type\":\"OrientedBox3D\",\"Version\":1,\"Box\":[[" + + minCorner + + "],[" + + maxCorner + + "]],\"Rotation\":[0,0,0]},\"Enabled\":true}"; + + //MaksT ClipPlanes + string ClippingPlanes = + "{\"Type\":\"ClipPlaneSet\",\"Version\":1,\"Planes\":["; + foreach (Clipping_plane clippingPlane in clippingPlanes) + { + decimal x = Convert.ToDecimal(Convert.ToDouble(clippingPlane.Location.X).ToInternalAppUnit()); + decimal y = Convert.ToDecimal(Convert.ToDouble(clippingPlane.Location.Y).ToInternalAppUnit()); + decimal z = Convert.ToDecimal(Convert.ToDouble(clippingPlane.Location.Z).ToInternalAppUnit()); + decimal nX = Convert.ToDecimal(Convert.ToDouble(clippingPlane.Direction.X)); + decimal nY = Convert.ToDecimal(Convert.ToDouble(clippingPlane.Direction.Y)); + decimal nZ = Convert.ToDecimal(Convert.ToDouble(clippingPlane.Direction.Z)); + Vector3 n = new Vector3(nX, nY, nZ); + + decimal distance = -(nX * x + nY * y + nZ * z); + double dbDistande = Convert.ToDouble(distance); + string strDistance = dbDistande.ToString("0.0000000000", System.Globalization.CultureInfo.InvariantCulture); + + + ClippingPlanes += "{\"Type\":\"ClipPlane\",\"Version\":1," + + "\"Normal\":[" + (-nX).ToString("0.0000000000", System.Globalization.CultureInfo.InvariantCulture) + + "," + (-nY).ToString("0.0000000000", System.Globalization.CultureInfo.InvariantCulture) + + "," + (-nZ).ToString("0.0000000000", System.Globalization.CultureInfo.InvariantCulture) + "]," + + "\"Distance\":" + strDistance + "," + + "\"Enabled\":" + "true" + "}," + ; + } + ClippingPlanes = ClippingPlanes.Remove(ClippingPlanes.Length - 1); + ClippingPlanes += "],\"Linked\":false, \"Enabled\":true}"; + + // apply clipping to current view + //doc.ActiveView.SetClippingPlanes(ClippingPlanes); + Autodesk.Navisworks.Api.View activeView = doc.ActiveView; + + var clipplBefore = activeView.GetClippingPlanes(); + + + //SavedViewpoint activeViewPointBefore = new SavedViewpoint(doc.CurrentViewpoint.ToViewpoint()); + //activeViewPointBefore.DisplayName = "bcf-point-before"; + //doc.SavedViewpoints.AddCopy(activeViewPointBefore); + + activeView.SetClippingPlanes(ClippingPlanes); + viewPoint = doc.CurrentViewpoint.CreateCopy(); + + //var clipplAfter = activeView.GetClippingPlanes(); + //SavedViewpoint activeViewPointAfter = new SavedViewpoint(doc.CurrentViewpoint.ToViewpoint()); + //activeViewPointAfter.DisplayName = "bcf-point-after"; + //doc.SavedViewpoints.AddCopy(activeViewPointAfter); + + //activeView.LookFromFrontRightTop(); + + + + // doc.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All); + + + //doc.ActiveView.SetClippingPlanes(json); + //view.SetSectionBox(ToNavisSectionBox(boundingBox)); + //view.IsSectionBoxActive = true; + } + + //if clippingPlanes.Count() > 0 { + + //} + //else + //{ + + //} + } + + private AxisAlignedBoundingBox GetViewpointClippingBox() + { + var clippingPlanes = _bcfViewpoint.GetClippingPlanes() + .Select(p => p.ToAxisAlignedBoundingBox(_viewpointAngleThresholdRad)) + .Aggregate(AxisAlignedBoundingBox.Infinite, (current, nextBox) => current.MergeReduce(nextBox)); + return clippingPlanes; + } + + private List GetViewpointVisibilityExceptions(IReadOnlyDictionary filterMap) + => _bcfViewpoint.GetVisibilityExceptions() + .Where(bcfComponentException => filterMap.ContainsKey(bcfComponentException.Ifc_guid)) + .Select(bcfComponentException => filterMap[bcfComponentException.Ifc_guid]) + .ToList(); + + + private List GetViewpointSelection(IReadOnlyDictionary filterMap) + => _bcfViewpoint.GetSelection() + .Where(selectedElement => filterMap.ContainsKey(selectedElement.Ifc_guid)) + .Select(selectedElement => filterMap[selectedElement.Ifc_guid]) + .ToList(); + + + + private static BoundingBox3D ToNavisSectionBox(AxisAlignedBoundingBox box) + { + var min = new Point3D( + box.Min.X == decimal.MinValue ? double.MinValue : ((double)box.Min.X).ToInternalAppUnit(), + box.Min.Y == decimal.MinValue ? double.MinValue : ((double)box.Min.Y).ToInternalAppUnit(), + box.Min.Z == decimal.MinValue ? double.MinValue : ((double)box.Min.Z).ToInternalAppUnit()); + var max = new Point3D( + box.Max.X == decimal.MaxValue ? double.MaxValue : ((double)box.Max.X).ToInternalAppUnit(), + box.Max.Y == decimal.MaxValue ? double.MaxValue : ((double)box.Max.Y).ToInternalAppUnit(), + box.Max.Z == decimal.MaxValue ? double.MaxValue : ((double)box.Max.Z).ToInternalAppUnit()); + + return new BoundingBox3D ( min, max ); + } +} diff --git a/src/OpenProject.Navisworks/Entry/RibbonButtonClickHandler.cs b/src/OpenProject.Navisworks/Entry/RibbonButtonClickHandler.cs new file mode 100644 index 00000000..0bb294c2 --- /dev/null +++ b/src/OpenProject.Navisworks/Entry/RibbonButtonClickHandler.cs @@ -0,0 +1,286 @@ +//using Autodesk.Revit.UI; +using Autodesk.Navisworks.Api; +using ComApi = Autodesk.Navisworks.Api.Interop.ComApi; +using ComBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using OpenProjectNavisworks.Services; +using OpenProject.Shared; +using Serilog; +using ZetaIpc.Runtime.Helper; +using System.Windows.Controls; +using OpenProjectNavisworks.Data; +using System.Windows.Media.Media3D; +using static Autodesk.Navisworks.Gui.Roamer.CommandLineConfig; +using OpenProject.Shared.Logging; + + +namespace OpenProjectNavisworks.Entry; + public static class RibbonButtonClickHandler + { +#if N2024 + public const string NavisAPIVersion = "21"; + public const string NavisVersion = "2024"; +#elif N2023 + public const string NavisAPIVersion = "20"; + public const string NavisVersion = "2023"; +#elif N2022 + public const string NavisAPIVersion = "19"; + public const string NavisVersion = "2022"; +#elif N2021 + public const string NavisAPIVersion = "18"; + public const string NavisVersion = "2021"; +#elif N2020 + public const string NavisAPIVersion = "17"; + public const string NavisVersion = "2020"; +#else + public const string NavisAPIVersion = "16"; + public const string NavisVersion = "2019"; +#endif + + private static Process _opBrowserProcess; + public static IpcHandler IpcHandler { get; private set; } + + public static int OpenMainPluginWindow(Document commandData, ref string message) + { + try + { + Logger.ConfigureLogger("OpenProject.Navisworks.Log..txt"); + EnsureExternalOpenProjectAppIsRunning(commandData); + Log.Information("EnsureExternalOpenProjectAppIsRunning"); + IpcHandler.SendBringBrowserToForegroundRequestToDesktopApp(); + Log.Information("SendBringBrowserToForegroundRequestToDesktopApp"); + + return 1; + } + catch (Exception exception) + { + Logger.ConfigureLogger("OpenProject.Navisworks.Log..txt"); + + message = exception.Message; + Log.Error(exception, message); + return 0; + } + } + + public static int OpenSettingsPluginWindow(Document commandData, ref string message) + { + try + { + EnsureExternalOpenProjectAppIsRunning(commandData); + IpcHandler.SendOpenSettingsRequestToDesktopApp(); + IpcHandler.SendBringBrowserToForegroundRequestToDesktopApp(); + return 1; + } + catch (Exception exception) + { + message = exception.Message; + Logger.ConfigureLogger("OpenProject.Navisworks.Log..txt"); + Log.Error(exception, message); + return 0; + } + } + + private static async void EnsureExternalOpenProjectAppIsRunning(Document commandData) + { + Logger.ConfigureLogger("OpenProject.Navisworks.Log..txt"); + + //Version check + if (!Autodesk.Navisworks.Api.Application.Version.ApiMajor.ToString().Contains(NavisAPIVersion)) + { + MessageHandler.ShowWarning( + "Unexpected version", + "The Navisworks version does not match the expectations.", + $"This Add-In was built and tested only for Navisworks {NavisVersion}. Further usage is at your own risk"); + } + + if (_opBrowserProcess is { HasExited: false }) + return; + else + { + // Clear dict after closing browser window + NavisworksUtils.ModelItems = null; + } + + + IpcHandler = new IpcHandler(Autodesk.Navisworks.Api.Application.ActiveDocument); + var revitServerPort = IpcHandler.StartLocalServerAndReturnPort(); + + var openProjectBrowserExecutablePath = GetOpenProjectBrowserExecutable(); + if (!File.Exists(openProjectBrowserExecutablePath)) + throw new SystemException("Browser executable not found."); + + var opBrowserServerPort = FreePortHelper.GetFreePort(); + var processArguments = $"ipc {opBrowserServerPort} {revitServerPort}"; + Environment.CurrentDirectory = System.IO.Path.GetDirectoryName(openProjectBrowserExecutablePath); + _opBrowserProcess = Process.Start(openProjectBrowserExecutablePath, processArguments); + IpcHandler.StartLocalClient(opBrowserServerPort); + Log.Information("IPC bridge started between port {port1} and {port2}.", + opBrowserServerPort, revitServerPort); + + + // Initialize document ModelItems dictionary -- for hiding objects. Disabled, because not optimized. + NavisworksUtils.ModelModelItems = null; + if (NavisworksUtils.ModelModelItems == null) + { + //NavisworksUtils.ModelItems = null; + //await GenerateModelItemDictAsync(Model.NavisworksWrapper.Document); + //MessageHandler.ShowWarning("Need to wait", + // "Dictionary of objects is in process, need to wait. This can take several minutes", + // "Dictionary of objects is in process, need to wait. This can take several minutes"); + //NavisworksUtils.ModelModelItems = new Dictionary>(); + // BuildModelDictionary(Model.NavisworksWrapper.Document).Wait(); + //BuildModelDictionary(Model.NavisworksWrapper.Document); + //NavisworksUtils.ModelItems = await BuildModelDictionaryAsync(); + //GenerateModelItemDict(Model.NavisworksWrapper.Document); + } + + } + + private static string GetOpenProjectBrowserExecutable() + { + var currentAssemblyPathUri = Assembly.GetExecutingAssembly().CodeBase; + var currentAssemblyPath = Uri.UnescapeDataString(new Uri(currentAssemblyPathUri).AbsolutePath).Replace("/", "\\"); + var currentFolder = Path.GetDirectoryName(currentAssemblyPath) ?? string.Empty; + + return Path.Combine(currentFolder, ConfigurationConstant.OpenProjectBrowserExecutablePath); + } + + + + // TODO: Next functions are for hiding objects feature. Disabled for now, because not optimized -------------------------------------------------------------------- + static void GenerateModelItemDict(Document doc) + { + Dictionary modelItems = new Dictionary(); + List hiddenModelItems = new List(); + foreach (ModelItem mi in doc.Models.RootItemDescendantsAndSelf) + { + var k = mi.InstanceGuid; + if (k != null) + { + var kStr = k.ToString(); + if (!modelItems.ContainsKey(kStr)) + modelItems.Add(kStr, mi); + // if (mi.IsHidden) + // hiddenModelItems.Add(mi); + } + + } + NavisworksUtils.ModelItems = modelItems; + //NavisworksUtils.HiddenModelItems = hiddenModelItems; + MessageHandler.ShowWarning( + "Object dictionary is not ready yet!", + "Object dictionary is ready, you can use ViewPoint now", + "Object dictionary is ready"); + } + + static async Task GenerateModelItemDictAsync(Document doc) + { + await Task.Run(() => GenerateModelItemDict(doc)); + } + + + static async Task BuildModelDictionary(Document doc) + { + + // Get all models + //var models = GetDocumentModels(doc); + var models = GetItemFromLastModelBranch(doc.Models.ToList()); + + // Async process each model + //foreach (var model in models) + //{ + // Task.Run(() => ProcessModelAsync(model)); + //} + foreach (var md in models) + { + if( md == null) + { + var stop =1 ; + } + // ProcessModelAsync(md); + } + + var tasks = models.Where(t => t != null).Select(ProcessModelAsync); + await Task.WhenAll(tasks); + + MessageHandler.ShowWarning( + "Object dictionary is not ready yet!", + "Object dictionary is ready, you can use ViewPoint now", + "Object dictionary is ready"); + + var dct = NavisworksUtils.ModelModelItems; + + return true; + } + static void ProcessModel(Autodesk.Navisworks.Api.Model model) + { + // Go through each ModelItem in model + Dictionary modelItems = new Dictionary(); + + var rootItem = model.RootItem; + var descendants = rootItem.Descendants; + + foreach (ModelItem item in descendants) + { + + // Getting GUID attribute for each ModelItem + var guid = item.InstanceGuid.ToString(); + + if (guid != null) + { + if (!modelItems.ContainsKey(guid)) + { + modelItems.Add(guid, item); + } + } + } + var modelFileName = Path.GetFileName(model.SourceFileName); + if (!NavisworksUtils.ModelModelItems.ContainsKey(modelFileName)) + NavisworksUtils.ModelModelItems.Add(modelFileName, modelItems); + } + + static async Task ProcessModelAsync(Autodesk.Navisworks.Api.Model model) + { + await Task.Run(() => ProcessModel(model)); + } + + public static List GetDocumentModels(Document doc) + { + var models = doc.Models; + + + if (models.Count == 1) + { + var mainModel = models[0]; + var mainModelModelItem = mainModel.RootItem; + var mainModelChildren = mainModelModelItem.Children; + return models[0].RootItem.Children.Select(ch => ch.Model).ToList(); + } + else + { + return models.ToList(); + } + + } + public static List GetItemFromLastModelBranch(List models) + { + List modelsResult = new List(); + foreach (var model in models) + { + var modelChildren = model.RootItem.Children.ToList(); + if (modelChildren.Count == 0 || modelChildren[0].Model == null) + { + modelsResult.Add(model); + } + else + { + modelsResult.AddRange(GetItemFromLastModelBranch(modelChildren.Select(t => t.Model).ToList())); + } + } + return modelsResult; + } +} + diff --git a/src/OpenProject.Navisworks/Extensions/BcfExtensions.cs b/src/OpenProject.Navisworks/Extensions/BcfExtensions.cs new file mode 100644 index 00000000..5327438c --- /dev/null +++ b/src/OpenProject.Navisworks/Extensions/BcfExtensions.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Autodesk.Navisworks.Api; +using iabi.BCF.APIObjects.V21; +using OpenProjectNavisworks.Data; +using OpenProject.Shared; +using OpenProject.Shared.BcfApi; +using OpenProject.Shared.Math3D; +using OpenProject.Shared.Math3D.Enumeration; +using Newtonsoft.Json.Linq; +using System.Xml.Linq; +using Newtonsoft.Json; +using System.Windows.Controls; +using Autodesk.Navisworks.Gui.Roamer; + +namespace OpenProjectNavisworks.Extensions +{ + /// + /// A namespace for static extensions for Revit document classes with focus on getting BCF data out + /// of the current state. + /// + public static class BcfExtensions + { + /// + /// Generates a model meant to send a viewpoint creation request to the BCF API from a Revit UI document. + /// + /// The Revit UI document + /// A BCF model for creating viewpoints. + public static Viewpoint_POST GenerateViewpoint(this Document uiDocument) + { + (Orthogonal_camera ortho, Perspective_camera perspective) = uiDocument.GetBcfCameraValues(); + + return new Viewpoint_POST + { + Clipping_planes = uiDocument.GetBcfClippingPlanes(), + Snapshot = uiDocument.GetBcfSnapshotData(), + Components = uiDocument.GetBcfComponents(), + Orthogonal_camera = ortho, + Perspective_camera = perspective + }; + } + + private static List GetBcfClippingPlanes(this Document uiDocument) + { + var sectionBox = uiDocument.GetBoundingBox(true); + var clippl = uiDocument.ActiveView.GetClippingPlanes(); + var myCleanJsonObject = JObject.Parse(clippl); + var orBox = myCleanJsonObject.GetValue("OrientedBox"); + var planes = myCleanJsonObject["Planes"]; + List cp = new List(); + + Vector3 minCorner, maxCorner, rotation; + // If section was created by box + if (orBox != null) { + var box = orBox.Value("Box"); + var minC = box.Value(0); + var maxC = box.Value(1); + Point3D minPoint = new Point3D(minC.Value(0), minC.Value(1), minC.Value(2)); + Point3D maxPoint = new Point3D(maxC.Value(0), maxC.Value(1), maxC.Value(2)); + minCorner = minPoint.ToVector3().ToMeters(); + maxCorner = maxPoint.ToVector3().ToMeters(); + + var rot = orBox.Value("Rotation"); + var rotX = rot.Value(0); + var rotY = rot.Value(1); + var rotZ = rot.Value(2); + + Point3D rotPoint = new Point3D(rotX, rotY, rotZ); + rotation = rotPoint.ToVector3(); + + cp = BcfApiExtensions.ToClippingPlanes(minCorner, maxCorner, rotation); + } + // If section was created by planes. TODO: not implemented yet, now just takes all objects (sectionBox) + else if (planes != null) + { + minCorner = sectionBox.Min.ToVector3().ToMeters(); + maxCorner = sectionBox.Max.ToVector3().ToMeters(); + Point3D rotPoint = new Point3D(0, 0, 0); + rotation = rotPoint.ToVector3(); + + cp = BcfApiExtensions.ToClippingPlanes(minCorner, maxCorner, rotation); + } + // If there was no sections + else + { + minCorner = sectionBox.Min.ToVector3().ToMeters(); + maxCorner = sectionBox.Max.ToVector3().ToMeters(); + Point3D rotPoint = new Point3D(0, 0, 0); + rotation = rotPoint.ToVector3(); + + cp = BcfApiExtensions.ToClippingPlanes(minCorner, maxCorner, rotation); + } + + // Checking if clipping planes enabled + var isSectionEnabled = myCleanJsonObject.Value("Enabled"); + //if (isSectionEnabled) + //{ + return cp; + //} + //else + //{ + // return null; + //} + + + } + + private static Snapshot_POST GetBcfSnapshotData(this Document uiDocument) + { + return new Snapshot_POST + { + Snapshot_type = Snapshot_type.Png, + Snapshot_data = "data:image/png;base64," + uiDocument.GetBase64RevitSnapshot() + }; + } + + private static Components GetBcfComponents(this Document uiDocument) + { + + //var selectedComponents2 = uiDocument.CurrentSelection.ToSelection() + // .GetSelectedItems() // ModelItemCollection + // .SelectMany(x => NavisworksDocumentExtensions.ElementDescendants(x)) + // .Distinct() + // .ToList(); + //foreach (var item in selectedComponents2) + //{ + // var parModel = item.Model; + // if (parModel != null) + // { var parModelName = parModel.FileName; } + + //} + + + // SELECTION + var selectedComponents = uiDocument.CurrentSelection.ToSelection() + .GetSelectedItems() // ModelItemCollection + .SelectMany(x => NavisworksDocumentExtensions.ElementDescendants(x)) + .Distinct() + .Select(uiDocument.ElementIdToComponentSelector()) + .ToList(); + + //// + //IEnumerable selectedComponents2 = uiDocument.CurrentSelection.ToSelection().GetSelectedItems(); + //var enumSel = selectedComponents2.GetEnumerator(); + + //List lstMI = new List(); + //while (enumSel.MoveNext()) + //{ + // lstMI.Add(enumSel.Current); + // var descItems = enumSel.Current.DescendantsAndSelf; + //} + //// + //var selectedComponents3 = uiDocument.CurrentSelection.ToSelection() + // .GetSelectedItems().SelectMany(x => NavisworksDocumentExtensions.ElementDescendants(x)).Distinct().ToList(); + + + //// VISIBILITY -- commeted for better times + ////create a store for the visible items + //ModelItemCollection visible = new ModelItemCollection(); + + + + ////uiDocument.CurrentSelection.SelectAll(); + ////var currentSelection = Autodesk.Navisworks.Api.Application.ActiveDocument.CurrentSelection.SelectedItems; + ////Add all the items that are visible to the visible collection + ////foreach (ModelItem item in Autodesk.Navisworks.Api.Application.ActiveDocument.CurrentSelection.SelectedItems) + ////{ + //// if (item.AncestorsAndSelf != null) + //// visible.AddRange(item.AncestorsAndSelf); + //// if (item.Descendants != null) + //// visible.AddRange(item.Descendants); + ////} + //var hiddenElementsOfView = uiDocument.Models.RootItemDescendantsAndSelf + // //.SelectMany(t=>t.DescendantsAndSelf) + // .Where(t => t.IsHidden); + //var hiddenElementsOfViewCount = hiddenElementsOfView.Count(); + ////new List(); + + //var visibleElementsOfViewCount = uiDocument.Models.RootItemDescendantsAndSelf.Count() - hiddenElementsOfViewCount; + ////.SelectMany(t => t.DescendantsAndSelf) + ////.Where(t => !t.IsHidden) + ////.Count(); //new List(); + ////foreach (ModelItem item in visible) + ////{ + //// if (item.IsHidden) + //// { + //// hiddenElementsOfView.Add(item); + //// } + //// else { visibleElementsOfView.Add(item); } + ////} + + //// Optimizing visibility + //var defaultVisibility = (hiddenElementsOfViewCount < visibleElementsOfViewCount); + //var exceptions = (defaultVisibility ? + // hiddenElementsOfView + // : + // uiDocument.Models.RootItemDescendantsAndSelf + // .Except(hiddenElementsOfView)); + ////.SelectMany(t => t.DescendantsAndSelf) + ////.Where(t => !t.IsHidden)); + + var exceptions = Enumerable.Empty(); + //var exceptions = NavisworksUtils.HiddenModelItems; + var defaultVisibility = true; + + + + var componentVisibility = new Components + { + Selection = selectedComponents, + Visibility = new iabi.BCF.APIObjects.V21.Visibility + { + Default_visibility = defaultVisibility, + Exceptions = exceptions + .Select(uiDocument.ElementIdToComponentSelector()) + .ToList() + } + }; + + // uiDocument.CurrentSelection.Clear(); + + return componentVisibility; + } + + private static (Orthogonal_camera orthogonalCamera, Perspective_camera perspectiveCamera) GetBcfCameraValues( + this Document uiDocument) + { + var view3D = uiDocument.CurrentViewpoint; + + bool isPerspective = view3D.Value.Projection == ViewpointProjection.Perspective; + CameraType cameraType = isPerspective ? CameraType.Perspective : CameraType.Orthogonal; + Position cameraPosition = uiDocument.GetCameraPosition(isPerspective); + Vector3 center = cameraPosition.Center.ToMeters(); + + var cameraViewpoint = new iabi.BCF.APIObjects.V21.Point + { + X = Convert.ToSingle(center.X), + Y = Convert.ToSingle(center.Y), + Z = Convert.ToSingle(center.Z) + }; + + // Getting vector perpendicular to view + var nwv3d = cameraPosition.Up.ToNavisworksPoint3D().ToVector3D(); + var right = cameraPosition.Forward.ToNavisworksPoint3D().ToVector3D().Cross(nwv3d); + var upVorView = right.Cross(cameraPosition.Forward.ToNavisworksPoint3D().ToVector3D()).Normalize().Negate(); + + var cameraUpVector = new Direction + { + X = Convert.ToSingle(cameraPosition.Up.X), + Y = Convert.ToSingle(cameraPosition.Up.Y), + Z = Convert.ToSingle(cameraPosition.Up.Z) + }; + + var cameraDirection = new Direction + { + X = Convert.ToSingle(cameraPosition.Forward.X * 1), + Y = Convert.ToSingle(cameraPosition.Forward.Y * 1), + Z = Convert.ToSingle(cameraPosition.Forward.Z * 1) + }; + + Orthogonal_camera ortho = null; + Perspective_camera perspective = null; + + switch (cameraType) + { + case CameraType.Perspective: + var fov = (float)view3D.ToViewpoint().HeightField; + perspective = new Perspective_camera + { + Field_of_view = fov, + Camera_direction = cameraDirection, + Camera_up_vector = cameraUpVector, + Camera_view_point = cameraViewpoint + }; + break; + case CameraType.Orthogonal: + ortho = new Orthogonal_camera + { + View_to_world_scale = uiDocument.GetViewBoxHeight(), + Camera_direction = cameraDirection, + Camera_up_vector = cameraUpVector, + Camera_view_point = cameraViewpoint + }; + break; + default: + throw new ArgumentOutOfRangeException(nameof(cameraType), cameraType, "invalid camera type"); + } + + return (ortho, perspective); + } + + private static float GetViewBoxHeight(this Document uiDocument) + { + var sectionBox = uiDocument.GetBoundingBox(true); + var bottomLeft = sectionBox.Min; + var topRight = sectionBox.Max; + var heightVector = topRight - bottomLeft; + var widthVector = new Point3D(topRight.X,topRight.Y,0) - new Point3D(bottomLeft.X,bottomLeft.Y,0); + + var (viewBoxHeight, _) = (heightVector.Length, widthVector.Length); + //NavisworksUtils.ConvertToViewBoxValues(topRight, bottomLeft, uiDocument.ActiveView); + + var ViewToWorldScale = uiDocument.CurrentViewpoint.Value.HeightField; + + return Convert.ToSingle(ViewToWorldScale.ToMeters()); + } + + private static Position GetCameraPosition(this Document uiDocument, bool isPerspective) + { + var zoomCorners = uiDocument.GetBoundingBox(true); + var bottomLeft = zoomCorners.Min; + var topRight = zoomCorners.Max; + var viewCenter = uiDocument.CurrentViewpoint.Value.Position; + if (!isPerspective) + viewCenter = zoomCorners.Center; + var aa = uiDocument.CurrentViewpoint.Value.Rotation.ToAxisAndAngle(); + JObject json = JObject.Parse(uiDocument.CurrentViewpoint.Value.GetCamera()); + var vd = json["ViewDirection"]; + var ud = json["UpDirection"]; + var viewDirection = aa.Axis.ToVector3D(); + + return NavisworksUtils.TransformCameraPosition( + new ProjectPositionWrapper(), + new Position( + viewCenter.ToVector3(), + new Vector3(double.Parse(vd[0].ToString()).ToDecimal(), double.Parse(vd[1].ToString()).ToDecimal(), double.Parse(vd[2].ToString()).ToDecimal()), //viewDirection.Y + (new Vector3D( + double.Parse(ud[0].ToString()), + double.Parse(ud[1].ToString()), + double.Parse(ud[2].ToString()))) + .ToPoint3D().ToVector3())); //uiDocument.CurrentViewpoint.Value.WorldUpVector.ToVector3D() + } + + private static string GetBase64RevitSnapshot(this Document uiDocument) + { +#if N2024 + Bitmap image = uiDocument.ActiveView.GenerateImage(ImageGenerationStyle.Scene, 1200, 900, true); +#else + Bitmap image = uiDocument.ActiveView.GenerateImage(ImageGenerationStyle.Scene, 1200, 900); +#endif + + byte[] buffer; + using (var stream = new MemoryStream()) + { + image.Save(stream, System.Drawing.Imaging.ImageFormat.Png); + buffer = stream.ToArray(); + } + return Convert.ToBase64String(buffer); + } + + } +} diff --git a/src/OpenProject.Navisworks/Extensions/NavisWorksDocumentExtensions.cs b/src/OpenProject.Navisworks/Extensions/NavisWorksDocumentExtensions.cs new file mode 100644 index 00000000..f55b95a1 --- /dev/null +++ b/src/OpenProject.Navisworks/Extensions/NavisWorksDocumentExtensions.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.Linq; +//using Autodesk.Revit.DB; +using OpenProjectNavisworks.Entry; +using Autodesk.Navisworks.Api; +using Autodesk.Navisworks.Api.Data; +using Autodesk.Navisworks.Api.Plugins; +using iabi.BCF.APIObjects.V21; +using OpenProject.Shared; +using OpenProject.Shared.Math3D.Enumeration; +using Serilog; +using System.IO; + +namespace OpenProjectNavisworks.Extensions +{ + /// + /// Extensions written for handling of classes of the Revit API. + /// + public static class NavisworksDocumentExtensions + { + private const string _openProjectOrthogonalViewName = "OpenProject Orthogonal"; + private const string _openProjectPerspectiveViewName = "OpenProject Perspective"; + + /// + /// Creates a map between revit element ids and their IFC GUIDs inside the given document. + /// + /// A revit document + /// A list of element ids + /// The map between IFC GUIDs and revit element ids. + public static Dictionary GetIfcGuidElementIdMap(this Document doc, + List elements) + { + var map = new Dictionary(); + foreach (ModelItem element in elements) + { + var ifcGuid = IfcGuid.ToIfcGuid(element.InstanceGuid); + if (!map.ContainsKey(ifcGuid)) + map.Add(ifcGuid, element); + } + + return map; + } + + /// + /// + /// + /// Navisworks document + /// + public static List GetVisibleElementsOfView(this Document doc) + { + var ids = new HashSet(); + var modelItems = new List(); + GetVisibleItems(doc.Models.RootItems, modelItems); + modelItems.ForEach(m => + { + if (m.InstanceGuid != Guid.Empty) + { + ids.Add(m); //NWGetter.GetIfcGuid(m) + } + else + { + var item = m.Ancestors.First(i => i.InstanceGuid != Guid.Empty); + ids.Add(item); //NWGetter.GetIfcGuid(m) + } + }); + + return ids.ToList(); + } + + private static void GetVisibleItems(ModelItemEnumerableCollection modelItems, List visibileItems) + { + foreach (var item in modelItems) + { + if (item.IsHidden == false) + { + if (item.HasGeometry) + visibileItems.Add(item); + else + GetVisibleItems(item.Children, visibileItems); + } + } + } + + /// + /// Gets all visible elements in the given view of the document. + /// + /// The Revit document + /// The Revit view + /// A list of element ids of all elements, that are currently visible. + //public static List GetVisibleElementsOfView(this Document doc, Autodesk.Navisworks.Api.View view) => + // new FilteredElementCollector(doc, view.Id) + // .WhereElementIsNotElementType() + // .WhereElementIsViewIndependent() + // .Where(element => element.CanBeHidden(view)) + // .Select(element => element.Id); + + /// + /// Gets all invisible elements in the given view of the document. + /// + /// The Revit document + /// The Revit view + /// A list of element ids of all elements, that are currently hidden. + //public static IEnumerable GetHiddenElementsOfView(this Document doc, View view) + //{ + // bool ElementIsHiddenInView(Element element) => + // element.IsHidden(view) || + // element.Category is { CategoryType: CategoryType.Model } && + // view.GetCategoryHidden(element.Category.Id); + + // return new FilteredElementCollector(doc) + // .WhereElementIsNotElementType() + // .WhereElementIsViewIndependent() + // .Where(ElementIsHiddenInView) + // .Select(element => element.Id); + //} + + /// + /// Gets a selector, that converts Revit element ids into BCF API components. + /// This is done in the context of a specific Revit Document. + /// + /// The Revit document + /// A selector converting to . + public static Func ElementIdToComponentSelector(this Document doc) + { + + return modelItem => new Component + { + Originating_system = "Navisworks " + OpenProjectNavisworks.Entry.RibbonButtonClickHandler.NavisVersion, + Ifc_guid = IfcGuid.ToIfcGuid(modelItem.InstanceGuid), //где-то лежит айдишник из ifc + //Authoring_tool_id = modelItem.InstanceGuid.ToString() + Authoring_tool_id = GetModelFileName(modelItem) + }; + } + + public static IEnumerable ElementDescendants(ModelItem modelItem) + { + if(Guid.Empty == modelItem.InstanceGuid) + { + return modelItem.Descendants.SelectMany(x => ElementDescendants(x)).ToList(); + } + else + return new List().Append(modelItem).AsEnumerable(); + } + public static ModelItem ElementParentModel(ModelItem modelItem) + { + if (modelItem.Parent != null) + { + if (modelItem.Model != null) + { + return modelItem; + } + return ElementParentModel(modelItem.Parent); + } + else + { + return modelItem; + } + } + public static String GetModelFileName(ModelItem modelItem) + { + + ModelItem parentModel = ElementParentModel(modelItem); + + if (parentModel.Model != null) + { + return Path.GetFileNameWithoutExtension(parentModel.Model.SourceFileName); + + } + else + { + return null; + } + } + + /// + /// Gets the correct 3D view for displaying OpenProject content. The type of the view is dependent of the requested + /// camera type, either orthogonal or perspective. If the view is not yet available, it is created. + /// + /// The current revit document. + /// The camera type for the requested view. + /// A with the correct settings to display OpenProject content. + /// Throws, if camera type is neither orthogonal nor perspective. + public static Autodesk.Navisworks.Api.View GetOpenProjectView(this Document doc, CameraType type) + { + var viewName = type switch + { + CameraType.Orthogonal => _openProjectOrthogonalViewName, + CameraType.Perspective => _openProjectPerspectiveViewName, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "invalid camera type") + }; + + //if (openProjectView != null) + //{ + // Log.Information("View '{name}' already existent. Finished getting related view.", viewName); + // return openProjectView; + //} + + Log.Information("View '{name}' doesn't exist yet. Creating new view ...", viewName); + var openProjectView = doc.ActiveView;//.CurrentViewpoint.CreateCopy(); + + + + //using var trans = new Transaction(doc); + //trans.Start("Create open project view"); + + //openProjectView = type switch + //{ + // CameraType.Orthogonal => View3D.CreateIsometric(doc, doc.GetFamilyViews().First().Id), + // CameraType.Perspective => View3D.CreatePerspective(doc, doc.GetFamilyViews().First().Id), + // _ => throw new ArgumentOutOfRangeException(nameof(type), type, "invalid camera type") + //}; + + //openProjectView.Name = viewName; + //openProjectView.CropBoxActive = false; + //openProjectView.CropBoxVisible = false; + //openProjectView.DetailLevel = ViewDetailLevel.Fine; + //openProjectView.DisplayStyle = DisplayStyle.Realistic; + + //foreach (Category category in doc.Settings.Categories) + // if (category.CategoryType == CategoryType.Annotation && category.Name == "Levels") + // openProjectView.SetCategoryHidden(category.Id, true); + + //trans.Commit(); + + Log.Information("View '{name}' created. Finished getting related view.", viewName); + return openProjectView; + } + + //private static IEnumerable GetFamilyViews(this Document doc) + //{ + // return from elem in new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType)) + // let type = elem as ViewFamilyType + // where type.ViewFamily == ViewFamily.ThreeDimensional + // select type; + //} + + //private static IEnumerable Get3DViews(this Document doc) + //{ + // return from elem in new FilteredElementCollector(doc).OfClass(typeof(View3D)) + // let view = elem as View3D + // select view; + //} + } +} diff --git a/src/OpenProject.Navisworks/Model/Addin.cs b/src/OpenProject.Navisworks/Model/Addin.cs new file mode 100644 index 00000000..1c72858f --- /dev/null +++ b/src/OpenProject.Navisworks/Model/Addin.cs @@ -0,0 +1,95 @@ +using OpenProjectNavisworks.Command; + +namespace OpenProjectNavisworks.Model; + +public class Addin : IAddinNode +{ + public List ItemList + { + get => itemList; + set => itemList = value; + } + + public string FilePath + { + get => filePath; + set => filePath = value; + } + + public bool Save + { + get => save; + set => save = value; + } + + public bool Hidden + { + get => hidden; + set => hidden = value; + } + + public Addin(string filePath) + { + itemList = new List(); + this.filePath = filePath; + save = true; + } + + public Addin(string filePath, List itemList) + { + this.itemList = itemList; + this.filePath = filePath; + SortAddinItem(); + save = true; + } + + public void SortAddinItem() + { + itemList.Sort(new AddinItemComparer()); + } + + public void RemoveItem(AddinItem item) + { + itemList.Remove(item); + if (itemList.Count == 0) + { + AddinManagerBase.Instance.AddinManager.RemoveAddin(this); + } + } + + public void SaveToLocalIni(IniFile file) + { + if (itemList == null || itemList.Count == 0) + { + return; + } + file.WriteSection("ExternalCommands"); + file.Write("ExternalCommands", "ECCount", 0); + var num = 0; + foreach (var addinItem in itemList) + { + if (addinItem.Save) + { + WriteExternalCommand(file, addinItem, ++num); + } + } + + file.Write("ExternalCommands", "ECCount", num); + } + + private void WriteExternalCommand(IniFile file, AddinItem item, int number) + { + file.Write("ExternalCommands", "ECName" + number, item.Name); + file.Write("ExternalCommands", "ECClassName" + number, item.FullClassName); + file.Write("ExternalCommands", "ECAssembly" + number, item.AssemblyName); + file.Write("ExternalCommands", "ECDescription" + number, item.Description); + } + + private List itemList; + + private string filePath; + + private bool save; + + private bool hidden; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/AddinItem.cs b/src/OpenProject.Navisworks/Model/AddinItem.cs new file mode 100644 index 00000000..74c52c1c --- /dev/null +++ b/src/OpenProject.Navisworks/Model/AddinItem.cs @@ -0,0 +1,137 @@ +using System.IO; + +namespace OpenProjectNavisworks.Model; + +public class AddinItem : IAddinNode +{ + public AddinItem(AddinType type) + { + AddinType = type; + clientId = Guid.NewGuid(); + ClientIdString = clientId.ToString(); + assemblyPath = string.Empty; + AssemblyName = string.Empty; + FullClassName = string.Empty; + name = string.Empty; + Save = true; + VisibilityMode = VisibilityMode.AlwaysVisible; + } + + public AddinItem(string assemblyPath, Guid clientId, string fullClassName, AddinType type) + { + + AddinType = type; + this.assemblyPath = assemblyPath; + AssemblyName = Path.GetFileName(this.assemblyPath); + this.clientId = clientId; + ClientIdString = clientId.ToString(); + FullClassName = fullClassName; + var num = fullClassName.LastIndexOf(".", StringComparison.Ordinal); + name = fullClassName.Substring(num + 1); + Save = true; + VisibilityMode = VisibilityMode.AlwaysVisible; + } + + public void SaveToManifest() + { + var manifestFile = new ManifestFile(name + DefaultSetting.FormatExAddin); + if (AddinType == AddinType.Application) + { + manifestFile.Applications.Add(this); + } + else if (AddinType == AddinType.Command) + { + manifestFile.Commands.Add(this); + } + manifestFile.Save(); + } + + public AddinType AddinType { get; set; } + + public string AssemblyPath + { + get => assemblyPath; + set + { + assemblyPath = value; + AssemblyName = Path.GetFileName(assemblyPath); + } + } + + public string AssemblyName { get; set; } + + public Guid ClientId + { + get => clientId; + set + { + clientId = value; + ClientIdString = clientId.ToString(); + } + } + + protected internal string ClientIdString { get; set; } + + public string FullClassName { get; set; } + + public string Name + { + get + { + if (string.IsNullOrEmpty(name)) + { + return "External Tool"; + } + return name; + } + set + { + if (!string.IsNullOrEmpty(value)) + { + name = value; + return; + } + name = "External Tool"; + } + } + + public string Description + { + get + { + if (string.IsNullOrEmpty(description)) + { + return string.Empty; + } + return description; + } + set + { + if (string.IsNullOrEmpty(value)) + { + description = string.Empty; + return; + } + description = value; + } + } + + public VisibilityMode VisibilityMode { get; set; } + + public bool Save { get; set; } + + public bool Hidden { get; set; } + + public override string ToString() + { + return name; + } + + protected string assemblyPath; + + protected Guid clientId; + + private string name; + + private string description; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/AddinItemComparer.cs b/src/OpenProject.Navisworks/Model/AddinItemComparer.cs new file mode 100644 index 00000000..cdb51962 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/AddinItemComparer.cs @@ -0,0 +1,12 @@ +namespace OpenProjectNavisworks.Model; + +/// +/// Compare Sort By Full Class Name Method +/// +public class AddinItemComparer : IComparer +{ + public int Compare(AddinItem x, AddinItem y) + { + return string.Compare(x.FullClassName, y.FullClassName, StringComparison.Ordinal); + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/AddinType.cs b/src/OpenProject.Navisworks/Model/AddinType.cs new file mode 100644 index 00000000..be7f21c2 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/AddinType.cs @@ -0,0 +1,10 @@ +namespace OpenProjectNavisworks.Model; + +[Flags] +public enum AddinType +{ + Invalid = 0, + Command = 1, + Application = 2, + Mixed = 3 +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/Addins.cs b/src/OpenProject.Navisworks/Model/Addins.cs new file mode 100644 index 00000000..8fe222e8 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/Addins.cs @@ -0,0 +1,101 @@ +using System.IO; +using System.Reflection; +using System.Windows; +using Autodesk.Navisworks.Api.Plugins; + +namespace OpenProjectNavisworks.Model; + +public abstract class Addins +{ + public SortedDictionary AddinDict + { + get => addinDict; + set => addinDict = value; + } + + public int Count => addinDict.Count; + + public Addins() + { + addinDict = new SortedDictionary(); + } + + public void SortAddin() + { + foreach (var addin in addinDict.Values) + { + addin.SortAddinItem(); + } + } + + public void AddAddIn(Addin addin) + { + var fileName = Path.GetFileName(addin.FilePath); + if (addinDict.ContainsKey(fileName)) + { + addinDict.Remove(fileName); + } + addinDict[fileName] = addin; + } + + public bool RemoveAddIn(Addin addin) + { + var fileName = Path.GetFileName(addin.FilePath); + if (addinDict.ContainsKey(fileName)) + { + addinDict.Remove(fileName); + return true; + } + return false; + } + + public void AddItem(AddinItem item) + { + var assemblyName = item.AssemblyName; + if (!addinDict.ContainsKey(assemblyName)) + { + addinDict[assemblyName] = new Addin(item.AssemblyPath); + } + addinDict[assemblyName].ItemList.Add(item); + } + + public List LoadItems(Assembly assembly, string fullName, string originalAssemblyFilePath, AddinType type) + { + var list = new List(); + Type[] array; + try + { + array = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + array = ex.Types; + if (array == null) + { + return list; + } + } + foreach (var type2 in array) + { + try + { + if (!(null == type2) && type2.IsSubclassOf(typeof(AddInPlugin))) + { + var item = new AddinItem(originalAssemblyFilePath, Guid.NewGuid(), type2.FullName, type); + list.Add(item); + } + } + catch (Exception e) + { + throw new ArgumentException(e.ToString()); + } + } + return list; + } + + protected SortedDictionary addinDict; + + protected int maxCount = 100; + + protected int count; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/AssemLoader.cs b/src/OpenProject.Navisworks/Model/AssemLoader.cs new file mode 100644 index 00000000..42404b40 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/AssemLoader.cs @@ -0,0 +1,311 @@ +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Text; +using System.Windows; +using OpenProjectNavisworks.View; + +namespace OpenProjectNavisworks.Model; + +public class AssemLoader +{ + public string OriginalFolder + { + get => originalFolder; + set => originalFolder = value; + } + + public string TempFolder + { + get => tempFolder; + set => tempFolder = value; + } + + public AssemLoader() + { + tempFolder = string.Empty; + refedFolders = new List(); + copiedFiles = new Dictionary(); + } + + public void CopyGeneratedFilesBack() + { + var files = Directory.GetFiles(tempFolder, "*.*", SearchOption.AllDirectories); + if(!files.Any()) return; + foreach (var text in files) + { + if (copiedFiles.ContainsKey(text)) + { + var t = copiedFiles[text]; + var fileInfo = new FileInfo(text); + if (fileInfo.LastWriteTime > t) + { + var str = text.Remove(0, tempFolder.Length); + var destinationFilename = originalFolder + str; + FileUtils.CopyFile(text, destinationFilename); + } + } + else + { + var str2 = text.Remove(0, tempFolder.Length); + var destinationFilename2 = originalFolder + str2; + FileUtils.CopyFile(text, destinationFilename2); + } + } + } + + public void HookAssemblyResolve() + { + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + } + + public void UnhookAssemblyResolve() + { + AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; + } + + public Assembly LoadAddinsToTempFolder(string originalFilePath, bool parsingOnly) + { + if (string.IsNullOrEmpty(originalFilePath) || !File.Exists(originalFilePath)) + { + return null; + } + this.parsingOnly = parsingOnly; + originalFolder = Path.GetDirectoryName(originalFilePath); + var stringBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(originalFilePath)); + if (parsingOnly) + { + stringBuilder.Append("-Parsing-"); + } + else + { + stringBuilder.Append("-Executing-"); + } + tempFolder = FileUtils.CreateTempFolder(stringBuilder.ToString()); + var assembly = CopyAndLoadAddin(originalFilePath, parsingOnly); + + if (null == assembly || !IsAPIReferenced(assembly)) + { + return null; + } + return assembly; + } + + private Assembly CopyAndLoadAddin(string srcFilePath, bool onlyCopyRelated) + { + var text = string.Empty; + if (!FileUtils.FileExistsInFolder(srcFilePath, tempFolder)) + { + var directoryName = Path.GetDirectoryName(srcFilePath); + if (!refedFolders.Contains(directoryName)) + { + refedFolders.Add(directoryName); + } + var list = new List(); + text = FileUtils.CopyFileToFolder(srcFilePath, tempFolder, onlyCopyRelated, list); + if (string.IsNullOrEmpty(text)) + { + return null; + } + foreach (var fileInfo in list) + { + copiedFiles.Add(fileInfo.FullName, fileInfo.LastWriteTime); + } + } + return LoadAddin(text); + } + + private Assembly LoadAddin(string filePath) + { + Assembly result = null; + try + { + Monitor.Enter(this); + //Agree this error to load depend event assembly, see https://github.com/chuongmep/RevitAddInManager/issues/7 + result = Assembly.LoadFile(filePath); + } + finally + { + Monitor.Exit(this); + } + return result; + } + + private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly result; + new AssemblyName(args.Name); + var text = SearchAssemblyFileInTempFolder(args.Name); + if (File.Exists(text)) + { + result = LoadAddin(text); + } + else + { + text = SearchAssemblyFileInOriginalFolders(args.Name); + if (string.IsNullOrEmpty(text)) + { + var array = args.Name.Split(new char[] + { + ',' + }); + var text2 = array[0]; + if (array.Length > 1) + { + var text3 = array[2]; + if (text2.EndsWith(".resources", StringComparison.CurrentCultureIgnoreCase) && !text3.EndsWith("neutral", StringComparison.CurrentCultureIgnoreCase)) + { + text2 = text2.Substring(0, text2.Length - ".resources".Length); + } + text = SearchAssemblyFileInTempFolder(text2); + if (File.Exists(text)) + { + return LoadAddin(text); + } + text = SearchAssemblyFileInOriginalFolders(text2); + } + } + if (string.IsNullOrEmpty(text)) + { + var loader = new AssemblyLoader(args.Name); + loader.WindowStartupLocation = WindowStartupLocation.CenterScreen; + if (loader.ShowDialog() != true) + { + return null; + } + text = loader.resultPath; + } + result = CopyAndLoadAddin(text, true); + } + + return result; + } + + private string SearchAssemblyFileInTempFolder(string assemName) + { + try + { + var array = new string[] { ".dll", ".exe" }; + var text = string.Empty; + var str = assemName.Substring(0, assemName.IndexOf(',')); + foreach (var str2 in array) + { + text = tempFolder + "\\" + str + str2; + + if (File.Exists(text)) + { + return text; + } + } + } + catch (Exception e) + { + throw new ArgumentException(e.ToString()); + } + return string.Empty; + } + + private string SearchAssemblyFileInOriginalFolders(string assemName) + { + var array = new string[] + { + ".dll", + ".exe" + }; + string text; + var text2 = assemName.Substring(0, assemName.IndexOf(',')); + foreach (var str in array) + { + text = dotnetDir + "\\" + text2 + str; + if (File.Exists(text)) + { + return text; + } + } + foreach (var str2 in array) + { + foreach (var str3 in refedFolders) + { + text = str3 + "\\" + text2 + str2; + if (File.Exists(text)) + { + return text; + } + } + } + try + { + var directoryInfo = new DirectoryInfo(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)); + var path = directoryInfo.Parent?.FullName + "\\Regression\\_RegressionTools\\"; + if (Directory.Exists(path)) + { + foreach (var text3 in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)) + { + if (Path.GetFileNameWithoutExtension(text3).Equals(text2, StringComparison.OrdinalIgnoreCase)) + { + return text3; + } + } + } + } + catch (Exception e) + { + throw new ArgumentException(e.ToString()); + } + + try + { + var num = assemName.IndexOf("XMLSerializers", StringComparison.OrdinalIgnoreCase); + if (num != -1) + { + assemName = "System.XML" + assemName.Substring(num + "XMLSerializers".Length); + return SearchAssemblyFileInOriginalFolders(assemName); + } + } + catch (Exception e) + { + throw new ArgumentException(e.ToString()); + } + return null; + } + + private bool IsAPIReferenced(Assembly assembly) + { + + if (string.IsNullOrEmpty(revitApiAssemblyFullName)) + { + foreach (var assembly2 in AppDomain.CurrentDomain.GetAssemblies()) + { + if (String.Compare(assembly2.GetName().Name, DefaultSetting.AssNavisName, StringComparison.OrdinalIgnoreCase) == 0) + { + revitApiAssemblyFullName = assembly2.GetName().Name; + break; + } + } + } + foreach (var assemblyName in assembly.GetReferencedAssemblies()) + { + if (revitApiAssemblyFullName == assemblyName.Name) + { + return true; + } + } + return false; + } + + private readonly List refedFolders; + + private readonly Dictionary copiedFiles; + + private bool parsingOnly; + + private string originalFolder; + + private string tempFolder; + + private static string dotnetDir = Environment.GetEnvironmentVariable("windir") + "\\Microsoft.NET\\Framework\\v2.0.50727"; + + public static string ResolvedAssemPath = string.Empty; + + private string revitApiAssemblyFullName; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/BitmapSourceConverter.cs b/src/OpenProject.Navisworks/Model/BitmapSourceConverter.cs new file mode 100644 index 00000000..48b4b66d --- /dev/null +++ b/src/OpenProject.Navisworks/Model/BitmapSourceConverter.cs @@ -0,0 +1,69 @@ +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace OpenProjectNavisworks.Model; + +public static class BitmapSourceConverter +{ + public enum ImageType + { + Small, + Large + } + + public static ImageSource ToImageSource(Bitmap bitmap, ImageType imageType) + { + switch (imageType) + { + case ImageType.Small: + return ToImageSource(bitmap).Resize(16); + + case ImageType.Large: + return ToImageSource(bitmap).Resize(32); + + default: + throw new ArgumentOutOfRangeException(nameof(imageType), imageType, null); + } + } + + public static BitmapImage ToImageSource(Bitmap bitmap) + { + var ms = new MemoryStream(); + bitmap.Save(ms, ImageFormat.Png); + var image = new BitmapImage(); + image.BeginInit(); + ms.Seek(0, SeekOrigin.Begin); + image.StreamSource = ms; + image.EndInit(); + return image; + } + + /// + /// Resize ImageResource + /// + /// + /// + /// + public static ImageSource Resize(this ImageSource imageSource, int size) + { + return Thumbnail(imageSource, size); + } + + private static ImageSource Thumbnail(ImageSource source, int size) + { + var rect = new Rect(0, 0, size, size); + var drawingVisual = new DrawingVisual(); + using (var drawingContext = drawingVisual.RenderOpen()) + { + drawingContext.DrawImage(source, rect); + } + var resizedImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default); + resizedImage.Render(drawingVisual); + + return resizedImage; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/CodeListener.cs b/src/OpenProject.Navisworks/Model/CodeListener.cs new file mode 100644 index 00000000..65ed5dc5 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/CodeListener.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; +using System.IO; + +namespace OpenProjectNavisworks.Model; + +public class CodeListener : TraceListener +{ + public override void Write(string message) + { + WriteMessage(message); + } + + public override void WriteLine(string message) + { + WriteMessage(message); + } + + void WriteMessage(string message) + { + using (StreamWriter st = new StreamWriter(DefaultSetting.PathLogFile, true)) + { + string join = string.Join(": ", $"{DateTime.Now}", message); + st.WriteLine(join); + st.Close(); + } + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/DefaultSetting.cs b/src/OpenProject.Navisworks/Model/DefaultSetting.cs new file mode 100644 index 00000000..962a5882 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/DefaultSetting.cs @@ -0,0 +1,50 @@ +using System.IO; + +namespace OpenProjectNavisworks.Model; + +/// +/// All setting name default for addin +/// +public static class DefaultSetting +{ + public static string AppName = "Navis Addin Manager"; + public static string FileName = "ExternalTool"; + public static string AssNavisName = "Autodesk.Navisworks.Api"; + public static string FormatExAddin = ".addin"; + public static string FormatDisable = ".disable"; + + public static string IniName = "Navis.ini"; + + public static string TempFolderName = "NavisAddins"; + + public static string AimInternalName = "AimInternalNavis.ini"; + public static string DirLogFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "AppData", + "Local", + "Temp",TempFolderName); + + private static string pathLogFile; + public static string PathLogFile + { + get + { + + bool flag = Directory.Exists(DirLogFile); + if (!flag) Directory.CreateDirectory(DirLogFile); + DirectoryInfo directoryInfo = new DirectoryInfo(DirLogFile); + FileInfo fileInfo = directoryInfo.GetFiles("*.txt",SearchOption.TopDirectoryOnly).OrderBy(x=>x.LastWriteTime).LastOrDefault(); + if (fileInfo==null) + { + pathLogFile = Path.Combine(DirLogFile, $"{Guid.NewGuid()}.txt"); + File.Create(pathLogFile).Close(); + return pathLogFile; + } + else + { + pathLogFile = fileInfo.FullName; + } + return fileInfo.FullName; + } + set => pathLogFile = value; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/FileUtils.cs b/src/OpenProject.Navisworks/Model/FileUtils.cs new file mode 100644 index 00000000..ba5b9dca --- /dev/null +++ b/src/OpenProject.Navisworks/Model/FileUtils.cs @@ -0,0 +1,240 @@ +using System.IO; +using System.Windows; +using MessageBox = System.Windows.MessageBox; + +namespace OpenProjectNavisworks.Model; + +public static class FileUtils +{ + public static DateTime GetModifyTime(string filePath) + { + return File.GetLastWriteTime(filePath); + } + + public static string CreateTempFolder(string prefix) + { + var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var tempPath = Path.Combine(folderPath, "Temp"); + var directoryInfo = new DirectoryInfo(Path.Combine(tempPath, DefaultSetting.TempFolderName)); + if (!directoryInfo.Exists) + { + directoryInfo.Create(); + } + foreach (var directoryInfo2 in directoryInfo.GetDirectories()) + { + try + { + Directory.Delete(directoryInfo2.FullName, true); + } + catch + { + // ignored + } + } + var str = $"{DateTime.Now:yyyyMMdd_HHmmss_ffff}"; + var path = Path.Combine(directoryInfo.FullName, prefix + str); + var directoryInfo3 = new DirectoryInfo(path); + directoryInfo3.Create(); + return directoryInfo3.FullName; + } + + public static void SetWriteable(string fileName) + { + if (File.Exists(fileName)) + { + var fileAttributes = File.GetAttributes(fileName) & ~FileAttributes.ReadOnly; + File.SetAttributes(fileName, fileAttributes); + } + } + + public static bool SameFile(string file1, string file2) + { + return 0 == String.Compare(file1.Trim(), file2.Trim(), StringComparison.OrdinalIgnoreCase); + } + + public static bool CreateFile(string filePath) + { + if (File.Exists(filePath)) + { + return true; + } + try + { + var directoryName = Path.GetDirectoryName(filePath); + if (!Directory.Exists(directoryName)) + { + Directory.CreateDirectory(directoryName); + } + using (new FileInfo(filePath).Create()) + { + SetWriteable(filePath); + } + } + catch (Exception) + { + return false; + } + return File.Exists(filePath); + } + + public static void DeleteFile(string fileName) + { + if (File.Exists(fileName)) + { + var fileAttributes = File.GetAttributes(fileName) & ~FileAttributes.ReadOnly; + File.SetAttributes(fileName, fileAttributes); + try + { + File.Delete(fileName); + } + catch (Exception e) + { + MessageBox.Show(e.ToString()); + } + } + } + + public static bool FileExistsInFolder(string filePath, string destFolder) + { + var path = Path.Combine(destFolder, Path.GetFileName(filePath)); + return File.Exists(path); + } + + public static string CopyFileToFolder(string sourceFilePath, string destFolder, bool onlyCopyRelated, List allCopiedFiles) + { + if (!File.Exists(sourceFilePath)) + { + return null; + } + var directoryName = Path.GetDirectoryName(sourceFilePath); + if (onlyCopyRelated) + { + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(sourceFilePath); + var searchPattern = fileNameWithoutExtension + ".*"; + var files = Directory.GetFiles(directoryName, searchPattern, SearchOption.TopDirectoryOnly); + foreach (var text in files) + { + var fileName = Path.GetFileName(text); + var text2 = Path.Combine(destFolder, fileName); + var flag = CopyFile(text, text2); + if (flag) + { + var item = new FileInfo(text2); + allCopiedFiles.Add(item); + } + } + } + else + { + var folderSize = GetFolderSize(directoryName); + if (folderSize > 50L) + { + switch (FolderTooBigDialog.Show(directoryName, folderSize)) + { + case MessageBoxResult.Yes: + CopyDirectory(directoryName, destFolder, allCopiedFiles); + break; + + case MessageBoxResult.No: + CopyFileToFolder(sourceFilePath, destFolder, true, allCopiedFiles); + break; + + default: + return null; + } + } + else + { + CopyDirectory(directoryName, destFolder, allCopiedFiles); + } + } + var text3 = Path.Combine(destFolder, Path.GetFileName(sourceFilePath)); + if (File.Exists(text3)) + { + return text3; + } + return null; + } + + public static bool CopyFile(string sourceFilename, string destinationFilename) + { + if (!File.Exists(sourceFilename)) + { + return false; + } + var fileAttributes = File.GetAttributes(sourceFilename) & ~FileAttributes.ReadOnly; + File.SetAttributes(sourceFilename, fileAttributes); + if (File.Exists(destinationFilename)) + { + var fileAttributes2 = File.GetAttributes(destinationFilename) & ~FileAttributes.ReadOnly; + File.SetAttributes(destinationFilename, fileAttributes2); + File.Delete(destinationFilename); + } + try + { + if (!Directory.Exists(Path.GetDirectoryName(destinationFilename))) + { + Directory.CreateDirectory(Path.GetDirectoryName(destinationFilename)); + } + File.Copy(sourceFilename, destinationFilename, true); + } + catch (Exception) + { + return false; + } + return File.Exists(destinationFilename); + } + + public static void CopyDirectory(string sourceDir, string desDir, List allCopiedFiles) + { + try + { + var directories = Directory.GetDirectories(sourceDir, "*.*", SearchOption.AllDirectories); + foreach (var text in directories) + { + var str = text.Replace(sourceDir, ""); + var path = desDir + str; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + var files = Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories); + foreach (var text2 in files) + { + var str2 = text2.Replace(sourceDir, ""); + var text3 = desDir + str2; + if (!Directory.Exists(Path.GetDirectoryName(text3))) + { + Directory.CreateDirectory(Path.GetDirectoryName(text3)); + } + if (CopyFile(text2, text3)) + { + allCopiedFiles.Add(new FileInfo(text3)); + } + } + } + catch + { + // ignored + } + } + + public static long GetFolderSize(string folderPath) + { + var directoryInfo = new DirectoryInfo(folderPath); + var num = 0L; + foreach (var fileSystemInfo in directoryInfo.GetFileSystemInfos()) + { + if (fileSystemInfo is FileInfo) + { + num += ((FileInfo)fileSystemInfo).Length; + } + else + { + num += GetFolderSize(fileSystemInfo.FullName); + } + } + return num / 1024L / 1024L; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/FolderTooBigDialog.cs b/src/OpenProject.Navisworks/Model/FolderTooBigDialog.cs new file mode 100644 index 00000000..6d3fdffa --- /dev/null +++ b/src/OpenProject.Navisworks/Model/FolderTooBigDialog.cs @@ -0,0 +1,26 @@ +using System.Text; +using System.Windows; +using MessageBox = System.Windows.MessageBox; + +namespace OpenProjectNavisworks.Model; + +internal static class FolderTooBigDialog +{ + /// + /// Show a waring if file dll too large + /// + /// folder contains file resource + /// limit of dll size + /// + public static MessageBoxResult Show(string folderPath, long sizeInMB) + { + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Folder [" + folderPath + "]"); + stringBuilder.AppendLine("is " + sizeInMB + "MB large."); + stringBuilder.AppendLine("AddinManager will attempt to copy all the files to temp folder"); + stringBuilder.AppendLine("Select [Yes] to copy all the files to temp folder"); + stringBuilder.AppendLine("Select [No] to only copy test script DLL"); + var text = stringBuilder.ToString(); + return MessageBox.Show(text, DefaultSetting.AppName, MessageBoxButton.YesNoCancel, MessageBoxImage.Asterisk); + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/IAddinNode.cs b/src/OpenProject.Navisworks/Model/IAddinNode.cs new file mode 100644 index 00000000..b884d993 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/IAddinNode.cs @@ -0,0 +1,8 @@ +namespace OpenProjectNavisworks.Model; + +public interface IAddinNode +{ + bool Save { get; set; } + + bool Hidden { get; set; } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/IEConverter.cs b/src/OpenProject.Navisworks/Model/IEConverter.cs new file mode 100644 index 00000000..6f498709 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/IEConverter.cs @@ -0,0 +1,25 @@ +using System.Collections.ObjectModel; + +namespace OpenProjectNavisworks.Model; + +/// +/// Quick convert collection +/// +public static class IEConverter +{ + /// + /// Convert IEnumerableUtils To ObservableCollection + /// + /// + /// + /// + public static ObservableCollection ToObservableCollection(this IEnumerable source) + { + var newSource = new ObservableCollection(); + foreach (var t in source) + { + newSource.Add(t); + } + return newSource; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/IniFile.cs b/src/OpenProject.Navisworks/Model/IniFile.cs new file mode 100644 index 00000000..a94b262e --- /dev/null +++ b/src/OpenProject.Navisworks/Model/IniFile.cs @@ -0,0 +1,56 @@ +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace OpenProjectNavisworks.Model; + +public class IniFile +{ + public string FilePath => filePath; + + public IniFile(string filePath) + { + this.filePath = filePath; + if (!File.Exists(this.filePath)) + { + FileUtils.CreateFile(this.filePath); + FileUtils.SetWriteable(this.filePath); + } + } + + public void WriteSection(string iniSection) + { + WritePrivateProfileSection(iniSection, null, filePath); + } + + public void Write(string iniSection, string iniKey, object iniValue) + { + WritePrivateProfileString(iniSection, iniKey, iniValue.ToString(), filePath); + } + + public string ReadString(string iniSection, string iniKey) + { + var stringBuilder = new StringBuilder(255); + GetPrivateProfileString(iniSection, iniKey, "", stringBuilder, 255, filePath); + return stringBuilder.ToString(); + } + + public int ReadInt(string iniSection, string iniKey) + { + return GetPrivateProfileInt(iniSection, iniKey, 0, filePath); + } + + [DllImport("kernel32.dll")] + private static extern int WritePrivateProfileSection(string lpAppName, string lpString, string lpFileName); + + [DllImport("kernel32", CharSet = CharSet.Auto)] + private static extern int WritePrivateProfileString(string section, string key, string val, string filePath); + + [DllImport("kernel32")] + private static extern int GetPrivateProfileInt(string section, string key, int def, string filePath); + + [DllImport("kernel32", CharSet = CharSet.Auto)] + private static extern int GetPrivateProfileString(string section, string key, string defaultValue, StringBuilder retVal, int size, string filePath); + + private readonly string filePath; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/LogMessageString.cs b/src/OpenProject.Navisworks/Model/LogMessageString.cs new file mode 100644 index 00000000..186557af --- /dev/null +++ b/src/OpenProject.Navisworks/Model/LogMessageString.cs @@ -0,0 +1,33 @@ +using System.Windows; + +namespace OpenProjectNavisworks.Model; + +public class LogMessageString +{ + private int DEFAULD_FONT_SIZE = 12; + public string Message { get; set; } + public System.Windows.Media.Brush MessageColor { get; set; } + public FontWeight FontWeight { get; set; } + public int FontSize { get; set; } + public LogMessageString(string message, System.Windows.Media.Brush colore) + { + Message = message; + MessageColor = colore; + FontWeight = FontWeights.Normal; + FontSize = DEFAULD_FONT_SIZE; + } + public LogMessageString(string message, System.Windows.Media.Brush colore, FontWeight fontWeight) + { + Message = message; + MessageColor = colore; + FontWeight = fontWeight; + FontSize = DEFAULD_FONT_SIZE; + } + public LogMessageString(string message, System.Windows.Media.Brush colore, FontWeight fontWeight, int fontSize) + { + Message = message; + MessageColor = colore; + FontWeight = fontWeight; + FontSize = fontSize; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/ManifestFile.cs b/src/OpenProject.Navisworks/Model/ManifestFile.cs new file mode 100644 index 00000000..df346913 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/ManifestFile.cs @@ -0,0 +1,422 @@ +using System.IO; +using System.Reflection; +using System.Text; +using System.Xml; + +namespace OpenProjectNavisworks.Model; + +public class ManifestFile +{ + public ManifestFile() + { + local = false; + applications = new List(); + commands = new List(); + } + + public ManifestFile(string fileName) : this() + { + this.fileName = fileName; + if (string.IsNullOrEmpty(filePath)) + { + var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AddIn"); + filePath = Path.Combine(path, this.fileName); + } + } + + public ManifestFile(bool local) : this() + { + this.local = local; + } + + public void Load() + { + xmlDoc = new XmlDocument(); + xmlDoc.Load(filePath); + var documentElement = xmlDoc.DocumentElement; + if (!documentElement.Name.Equals(ROOT_NODE)) + { + throw new ArgumentException(INCORRECT_NODE); + } + if (documentElement.ChildNodes.Count == 0) + { + throw new ArgumentException(EMPTY_ADDIN); + } + applications.Clear(); + commands.Clear(); + foreach (var obj in documentElement.ChildNodes) + { + var xmlNode = (XmlNode)obj; + if (!xmlNode.Name.Equals(ADDIN_NODE) || xmlNode.Attributes.Count != 1) + { + throw new ArgumentException(INCORRECT_NODE); + } + var xmlAttribute = xmlNode.Attributes[0]; + if (xmlAttribute.Value.Equals(APPLICATION_NODE)) + { + ParseExternalApplications(xmlNode); + } + else + { + if (!xmlAttribute.Value.Equals(COMMAND_NODE)) + { + throw new ArgumentException(INCORRECT_NODE); + } + ParseExternalCommands(xmlNode); + } + } + } + + public void Save() + { + SaveAs(filePath); + } + + public void SaveAs(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + { + throw new ArgumentNullException(FILENAME_NULL_OR_EMPTY); + } + if (!filePath.ToLower().EndsWith(DefaultSetting.FormatExAddin)) + { + throw new ArgumentException(FILENAME_INCORRECT_WARNING + filePath); + } + var directoryName = Path.GetDirectoryName(filePath); + if (!Directory.Exists(directoryName)) + { + Directory.CreateDirectory(directoryName); + } + var fileInfo = new FileInfo(filePath); + xmlDoc = new XmlDocument(); + CreateXmlForManifest(); + if (File.Exists(filePath)) + { + File.SetAttributes(filePath, FileAttributes.Normal); + } + TextWriter w = new StreamWriter(filePath, false, Encoding.UTF8); + var xmlTextWriter = new XmlTextWriter(w); + xmlTextWriter.Formatting = Formatting.Indented; + xmlDoc.Save(xmlTextWriter); + xmlTextWriter.Close(); + this.filePath = fileInfo.FullName; + fileName = Path.GetFileName(fileInfo.FullName); + } + + public string FileName + { + get => fileName; + set => fileName = value; + } + + public bool Local + { + get => local; + set => local = value; + } + + private string _vendorDescription; + + public string VendorDescription + { + get => _vendorDescription; + set => _vendorDescription = value; + } + + public string FilePath + { + get + { + if (string.IsNullOrEmpty(filePath)) + { + var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AddIn"); + filePath = Path.Combine(path, DefaultSetting.AimInternalName); + } + return filePath; + } + set => filePath = value; + } + + public List Applications + { + get => applications; + set => applications = value; + } + + public List Commands + { + get => commands; + set => commands = value; + } + + private XmlDocument CreateXmlForManifest() + { + var xmlNode = xmlDoc.AppendChild(xmlDoc.CreateElement(ROOT_NODE)); + foreach (var currentApp in applications) + { + var xmlElement = xmlDoc.CreateElement(ADDIN_NODE); + xmlElement.SetAttribute(TYPE_ATTRIBUTE, APPLICATION_NODE); + xmlNode.AppendChild(xmlElement); + AddApplicationToXmlElement(xmlElement, currentApp); + var xmlElement2 = xmlDoc.CreateElement(VENDORID); + xmlElement2.InnerText = "ADSK"; + xmlElement.AppendChild(xmlElement2); + xmlElement2 = xmlDoc.CreateElement(VENDORDESCRIPTION); + xmlElement2.InnerText = "Autodesk, www.autodesk.com"; + xmlElement.AppendChild(xmlElement2); + } + foreach (var command in commands) + { + var xmlElement3 = xmlDoc.CreateElement(ADDIN_NODE); + xmlElement3.SetAttribute(TYPE_ATTRIBUTE, COMMAND_NODE); + xmlNode.AppendChild(xmlElement3); + AddCommandToXmlElement(xmlElement3, command); + var xmlElement4 = xmlDoc.CreateElement(VENDORID); + xmlElement4.InnerText = "ADSK"; + xmlElement3.AppendChild(xmlElement4); + xmlElement4 = xmlDoc.CreateElement(VENDORDESCRIPTION); + if (VendorDescription == string.Empty) xmlElement4.InnerText = "Autodesk, www.autodesk.com"; + else xmlElement4.InnerText = VendorDescription; + xmlElement3.AppendChild(xmlElement4); + } + return xmlDoc; + } + + private void AddAddInItemToXmlElement(XmlElement xmlEle, AddinItem addinItem) + { + if (!string.IsNullOrEmpty(addinItem.AssemblyPath)) + { + var xmlElement = xmlDoc.CreateElement(ASSEMBLY); + if (local) + { + xmlElement.InnerText = addinItem.AssemblyName; + } + else + { + xmlElement.InnerText = addinItem.AssemblyPath; + } + xmlEle.AppendChild(xmlElement); + } + if (!string.IsNullOrEmpty(addinItem.ClientIdString)) + { + var xmlElement2 = xmlDoc.CreateElement(CLIENTID); + xmlElement2.InnerText = addinItem.ClientIdString; + xmlEle.AppendChild(xmlElement2); + } + if (!string.IsNullOrEmpty(addinItem.FullClassName)) + { + var xmlElement3 = xmlDoc.CreateElement(FULLCLASSNAME); + xmlElement3.InnerText = addinItem.FullClassName; + xmlEle.AppendChild(xmlElement3); + } + } + + private void AddApplicationToXmlElement(XmlElement appEle, AddinItem currentApp) + { + if (!string.IsNullOrEmpty(currentApp.Name)) + { + var xmlElement = xmlDoc.CreateElement(NAME_NODE); + xmlElement.InnerText = currentApp.Name; + appEle.AppendChild(xmlElement); + } + AddAddInItemToXmlElement(appEle, currentApp); + } + + private void AddCommandToXmlElement(XmlElement commandEle, AddinItem command) + { + AddAddInItemToXmlElement(commandEle, command); + XmlElement xmlElement; + if (!string.IsNullOrEmpty(command.Name)) + { + xmlElement = xmlDoc.CreateElement(TEXT); + xmlElement.InnerText = command.Name; + commandEle.AppendChild(xmlElement); + } + if (!string.IsNullOrEmpty(command.Description)) + { + xmlElement = xmlDoc.CreateElement(DESCRIPTION); + xmlElement.InnerText = command.Description; + commandEle.AppendChild(xmlElement); + } + var text = command.VisibilityMode.ToString(); + if (!string.IsNullOrEmpty(text)) + { + text = text.Replace(",", " |"); + } + xmlElement = xmlDoc.CreateElement(VISIBILITYMODE); + xmlElement.InnerText = text; + commandEle.AppendChild(xmlElement); + } + + private void ParseExternalApplications(XmlNode nodeApplication) + { + var addinItem = new AddinItem(AddinType.Application); + ParseApplicationItems(addinItem, nodeApplication); + applications.Add(addinItem); + } + + private void ParseExternalCommands(XmlNode nodeCommand) + { + var addinItem = new AddinItem(AddinType.Command); + ParseCommandItems(addinItem, nodeCommand); + commands.Add(addinItem); + } + + private void ParseApplicationItems(AddinItem addinApp, XmlNode nodeAddIn) + { + ParseAddInItem(addinApp, nodeAddIn); + var xmlElement = nodeAddIn[NAME_NODE]; + if (xmlElement != null && !string.IsNullOrEmpty(xmlElement.InnerText)) + { + addinApp.Name = xmlElement.InnerText; + } + } + + private void ParseCommandItems(AddinItem command, XmlNode nodeAddIn) + { + ParseAddInItem(command, nodeAddIn); + var xmlElement = nodeAddIn[TEXT]; + if (xmlElement != null) + { + command.Name = xmlElement.InnerText; + } + xmlElement = nodeAddIn[DESCRIPTION]; + if (xmlElement != null) + { + command.Description = xmlElement.InnerText; + } + xmlElement = nodeAddIn[VISIBILITYMODE]; + if (xmlElement != null && !string.IsNullOrEmpty(xmlElement.InnerText)) + { + command.VisibilityMode = ParseVisibilityMode(xmlElement.InnerText); + } + } + + private void ParseAddInItem(AddinItem addinItem, XmlNode nodeAddIn) + { + var xmlElement = nodeAddIn[ASSEMBLY]; + if (xmlElement != null) + { + if (local) + { + addinItem.AssemblyName = xmlElement.InnerText; + } + else + { + addinItem.AssemblyPath = xmlElement.InnerText; + } + } + xmlElement = nodeAddIn[CLIENTID]; + if (xmlElement != null) + { + try + { + if (!string.IsNullOrEmpty(xmlElement.InnerText)) + { + addinItem.ClientId = new Guid(xmlElement.InnerText); + } + else + { + addinItem.ClientId = Guid.Empty; + } + } + catch (Exception) + { + addinItem.ClientId = Guid.Empty; + addinItem.ClientIdString = xmlElement.InnerText; + } + } + xmlElement = nodeAddIn[FULLCLASSNAME]; + if (xmlElement != null) + { + addinItem.FullClassName = xmlElement.InnerText; + } + } + + private VisibilityMode ParseVisibilityMode(string visibilityModeString) + { + var visibilityMode = VisibilityMode.AlwaysVisible; + VisibilityMode result; + try + { + var text = "|"; + var separator = text.ToCharArray(); + var array = visibilityModeString.Replace(" | ", "|").Split(separator); + foreach (var value in array) + { + var visibilityMode2 = (VisibilityMode)Enum.Parse(typeof(VisibilityMode), value); + visibilityMode |= visibilityMode2; + } + result = visibilityMode; + } + catch (Exception) + { + throw new ArgumentException(UNKNOW_VISIBILITYMODE); + } + return result; + } + + private string getFullPath(string fileName) + { + FileInfo fileInfo = null; + try + { + fileInfo = new FileInfo(fileName); + } + catch (Exception ex) + { + throw new ArgumentException(fileName + Environment.NewLine + ex.ToString()); + } + return fileInfo.FullName; + } + + private string fileName; + + private bool local; + + private string filePath; + + private List applications; + + private List commands; + + private string ROOT_NODE = "RevitAddIns"; + + private string ADDIN_NODE = "AddIn"; + + private string APPLICATION_NODE = "Application"; + + private string COMMAND_NODE = "Command"; + + private string TYPE_ATTRIBUTE = "Type"; + + private string INCORRECT_NODE = "incorrect node in addin file!"; + + private string EMPTY_ADDIN = "empty addin file!"; + + private string ASSEMBLY = "Assembly"; + + private string CLIENTID = "ClientId"; + + private string FULLCLASSNAME = "FullClassName"; + + private string NAME_NODE = "Name"; + + private string TEXT = "Text"; + + private string DESCRIPTION = "Description"; + + private string VENDORID = "VendorId"; + + private string VENDORDESCRIPTION = "VendorDescription"; + + private string VISIBILITYMODE = "VisibilityMode"; + + private string UNKNOW_VISIBILITYMODE = "Unrecognizable VisibilityMode!"; + + private string FILENAME_INCORRECT_WARNING = "File name is incorrect, not .addin file ."; + + private string FILENAME_NULL_OR_EMPTY = "File name for RevitAddInManifest is null or empty"; + + private XmlDocument xmlDoc; +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/NavisAddin.cs b/src/OpenProject.Navisworks/Model/NavisAddin.cs new file mode 100644 index 00000000..12e88a62 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/NavisAddin.cs @@ -0,0 +1,27 @@ +namespace OpenProjectNavisworks.Model; + +public class NavisAddin : ViewModelBase +{ + public bool IsReadOnly { get; set; } + public VisibleModel State { get; set; } + public string FilePath { get; set; } + public string Assembly { get; set; } + public string ClientId { get; set; } + public string Name { get; set; } + public string NameNotEx { get; set; } + public string FullClassName { get; set; } + public string Text { get; set; } + public string VisibilityMode { get; set; } + public string LanguageType { get; set; } + public string VendorId { get; set; } + public string VendorDescription { get; set; } + public AddinType AddinType { get; set; } + + private bool _IsChecked; + + public bool IsChecked + { + get => _IsChecked; + set => OnPropertyChanged(ref _IsChecked, value); + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/NavisWorksWrapper.cs b/src/OpenProject.Navisworks/Model/NavisWorksWrapper.cs new file mode 100644 index 00000000..77a0a71a --- /dev/null +++ b/src/OpenProject.Navisworks/Model/NavisWorksWrapper.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Autodesk.Navisworks.Api; +using ComApi = Autodesk.Navisworks.Api.Interop.ComApi; +using ComBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge; + + +namespace OpenProjectNavisworks.Model +{ + public static class NavisworksWrapper + { + public static Document Document { get; set; } + public static string DocumentGUID { get; set; } + public static ComBridge ComBridge { get; set; } + + //public static List GetAllSearchSets() + //{ + // List result = new List(); + // var selectionSets = Document.SelectionSets; + // var savedItemCollection = selectionSets.Value; + + // foreach (var saveItem in savedItemCollection) + // { + // if (!saveItem.IsGroup) + // { + // SelectionSet selectionSet = saveItem as SelectionSet; + + // if (selectionSet != null) + // { + // result.Add(selectionSet); + // } + // } + // } + + // return result; + //} + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/ProcessManager.cs b/src/OpenProject.Navisworks/Model/ProcessManager.cs new file mode 100644 index 00000000..3f799741 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/ProcessManager.cs @@ -0,0 +1,53 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace OpenProjectNavisworks.Model +{ + public static class ProcessManager + { + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetForegroundWindow(IntPtr hWnd); + + public static void SetNavisAsWindowOwner(this Window window) + { + if (null == window) { return; } + window.WindowStartupLocation = WindowStartupLocation.CenterScreen; + WindowInteropHelper helper = new WindowInteropHelper(window); + helper.Owner = GetActivateWindow(); + window.Closing += SetActivateWindow; + } + + private static void SetActivateWindow(object sender, CancelEventArgs e) + { + SetActivateWindow(); + } + + /// + /// Set process revert use revit + /// + /// + public static bool SetActivateWindow() + { + IntPtr ptr = GetActivateWindow(); + if (ptr != IntPtr.Zero) + { + return SetForegroundWindow(ptr); + } + return false; + } + + /// + /// return active windows is active + /// + /// + public static IntPtr GetActivateWindow() + { + return Process.GetCurrentProcess().MainWindowHandle; + } + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/StaticUtil.cs b/src/OpenProject.Navisworks/Model/StaticUtil.cs new file mode 100644 index 00000000..a5d95aa0 --- /dev/null +++ b/src/OpenProject.Navisworks/Model/StaticUtil.cs @@ -0,0 +1,26 @@ +using System.Windows; +using Autodesk.Navisworks.Api.Plugins; +using MessageBox = System.Windows.MessageBox; + +namespace OpenProjectNavisworks.Model; + +public static class StaticUtil +{ + public static void ShowWarning(string msg) + { + MessageBox.Show(msg, DefaultSetting.AppName, MessageBoxButton.OK, MessageBoxImage.Exclamation); + } + public static string CommandFullName = typeof(AddInPlugin).FullName; + + /// + /// CaseInsensitiveContains + /// + /// + /// + /// + /// + public static bool CaseInsensitiveContains(this string text, string value, StringComparison stringComparison = StringComparison.CurrentCultureIgnoreCase) + { + return text.IndexOf(value, stringComparison) >= 0; + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/ViewModelBase.cs b/src/OpenProject.Navisworks/Model/ViewModelBase.cs new file mode 100644 index 00000000..10e7feca --- /dev/null +++ b/src/OpenProject.Navisworks/Model/ViewModelBase.cs @@ -0,0 +1,73 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace OpenProjectNavisworks.Model; + +public class ViewModelBase : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler PropertyChanged; + + public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(string propertyName, object oldValue, object newValue) + { + OnPropertyChanged(propertyName); + } + + public void OnPropertyChanged(ref T property, T value, [CallerMemberName] string propertyName = "") + { + property = value; + var handler = PropertyChanged; + if (handler != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + /// + /// Sets the property value. + /// + /// The type of the property. + /// The field. + /// The value. + /// Name of the property. + /// + /// True if the property was set. + /// + /// This method uses the CallerMemberNameAttribute to determine the property name. + protected bool SetValue(ref T field, T value, [CallerMemberName] string propertyName = "") + { + // ReSharper disable once RedundantNameQualifier + if (object.Equals(field, value)) + { + return false; + } + VerifyProperty(propertyName); + //// this.OnPropertyChanging(propertyName, field, value); + var oldValue = field; + field = value; + OnPropertyChanged(propertyName, oldValue, value); + return true; + } + + /// + /// Verifies the property name. + /// + /// Name of the property. + [Conditional("DEBUG")] + private void VerifyProperty(string propertyName) + { + var type = GetType(); + + // Look for a public property with the specified name. + var propertyInfo = type.GetTypeInfo().GetDeclaredProperty(propertyName); + + Debug.Assert(propertyInfo != null, string.Format(CultureInfo.InvariantCulture, "{0} is not a property of {1}", propertyName, type.FullName)); + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Model/VisibilityMode.cs b/src/OpenProject.Navisworks/Model/VisibilityMode.cs new file mode 100644 index 00000000..6fd75a6d --- /dev/null +++ b/src/OpenProject.Navisworks/Model/VisibilityMode.cs @@ -0,0 +1,22 @@ +namespace OpenProjectNavisworks.Model; + +[Flags] +public enum VisibilityMode +{ + AlwaysVisible = 0, + NotVisibleInProject = 1, + NotVisibleInFamily = 2, + NotVisibleWhenNoActiveDocument = 4, + NotVisibleInArchitecture = 8, + NotVisibleInStructure = 16, + NotVisibleInMechanical = 32, + NotVisibleInElectrical = 64, + NotVisibleInPlumbing = 128, + NotVisibleInMEP = 224 +} + +public enum VisibleModel +{ + Enable, + Disable +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/OpenProject.Navisworks.csproj b/src/OpenProject.Navisworks/OpenProject.Navisworks.csproj new file mode 100644 index 00000000..2b2b93fc --- /dev/null +++ b/src/OpenProject.Navisworks/OpenProject.Navisworks.csproj @@ -0,0 +1,210 @@ + + + + true + latest + x64 + enable + true + net48 + Debug-2022;Debug-2024;Release-2022;Release-2024; + $(Configurations);Release-2022;;Release-2024; + OpenProjectNavisworks + + true + true + + true + + + + + true + full + $(DefineConstants);DEBUG + + + true + none + $(DefineConstants);RELEASE + + + + 2020 + $(DefineConstants);N2020 + + + 2021 + $(DefineConstants);N2021 + + + 2022 + $(DefineConstants);N2022 + + + 2023 + $(DefineConstants);N2023 + + + 2024 + $(DefineConstants);N2024 + + + + $(NavisVersion) + true + false + A Project Support for developer in Navisworks + true + true + + + + + + + + + + + + + + Always + + + Always + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + True + True + Settings.settings + + + True + True + Resource.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + PublicResXFileCodeGenerator + Resource.Designer.cs + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + MSBuild:Compile + + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/OpenProject.Navisworks/PackageContents.xml b/src/OpenProject.Navisworks/PackageContents.xml new file mode 100644 index 00000000..ba19b594 --- /dev/null +++ b/src/OpenProject.Navisworks/PackageContents.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Properties/Resources.Designer.cs b/src/OpenProject.Navisworks/Properties/Resources.Designer.cs new file mode 100644 index 00000000..bdd4d8b8 --- /dev/null +++ b/src/OpenProject.Navisworks/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenProjectNavisworks.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenProjectNavisworks.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/src/OpenProject.Navisworks/Properties/Resources.resx b/src/OpenProject.Navisworks/Properties/Resources.resx new file mode 100644 index 00000000..4fdb1b6a --- /dev/null +++ b/src/OpenProject.Navisworks/Properties/Resources.resx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Properties/Settings.Designer.cs b/src/OpenProject.Navisworks/Properties/Settings.Designer.cs new file mode 100644 index 00000000..a10a0443 --- /dev/null +++ b/src/OpenProject.Navisworks/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenProjectNavisworks.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/src/OpenProject.Navisworks/Properties/Settings.settings b/src/OpenProject.Navisworks/Properties/Settings.settings new file mode 100644 index 00000000..049245f4 --- /dev/null +++ b/src/OpenProject.Navisworks/Properties/Settings.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/OpenProject.Navisworks/Properties/launchSettings.json b/src/OpenProject.Navisworks/Properties/launchSettings.json new file mode 100644 index 00000000..c0e19c21 --- /dev/null +++ b/src/OpenProject.Navisworks/Properties/launchSettings.json @@ -0,0 +1,18 @@ +{ + "profiles": { + "Navis2022": { + "commandName": "Executable", + "executablePath": "C:\\Program Files\\Autodesk\\Navisworks Manage 2022\\Roamer.exe", + "commandLineArgs": "-lang en-US" + }, + "Navis2023": { + "commandName": "Executable", + "executablePath": "C:\\Program Files\\Autodesk\\Navisworks Manage 2023\\Roamer.exe" + }, + "Navis2024": { + "commandName": "Executable", + "executablePath": "C:\\Program Files\\Autodesk\\Navisworks Manage 2024\\Roamer.exe", + "commandLineArgs": "-lang en-US" + } + } +} \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Resource.Designer.cs b/src/OpenProject.Navisworks/Resource.Designer.cs new file mode 100644 index 00000000..d5803134 --- /dev/null +++ b/src/OpenProject.Navisworks/Resource.Designer.cs @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenProjectNavisworks { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenProjectNavisworks.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Navis Addin Manager. + /// + public static string AppName { + get { + return ResourceManager.GetString("AppName", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon dev { + get { + object obj = ResourceManager.GetObject("dev", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap dev1 { + get { + object obj = ResourceManager.GetObject("dev1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to File Not Exit, Please Check !. + /// + public static string FileNotExit { + get { + return ResourceManager.GetString("FileNotExit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File Not Found, Please Check File Again. + /// + public static string FileNotFound { + get { + return ResourceManager.GetString("FileNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap folder { + get { + object obj = ResourceManager.GetObject("folder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to File Load Is Cancelld. + /// + public static string LoadCancelled { + get { + return ResourceManager.GetString("LoadCancelled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File Load Is Invalid. + /// + public static string LoadInvalid { + get { + return ResourceManager.GetString("LoadInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please Check Again Directory And Open Full Access Admin!. + /// + public static string NeedAdmin { + get { + return ResourceManager.GetString("NeedAdmin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not Any Item Selected. + /// + public static string NoItemSelected { + get { + return ResourceManager.GetString("NoItemSelected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully. + /// + public static string Successfully { + get { + return ResourceManager.GetString("Successfully", resourceCulture); + } + } + } +} diff --git a/src/OpenProject.Navisworks/Resource.resx b/src/OpenProject.Navisworks/Resource.resx new file mode 100644 index 00000000..7731cd26 --- /dev/null +++ b/src/OpenProject.Navisworks/Resource.resx @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Navis Addin Manager + + + + Resources\dev.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\dev.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + File Not Exit, Please Check ! + + + File Not Found, Please Check File Again + + + Resources\folder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + File Load Is Cancelld + + + File Load Is Invalid + + + Please Check Again Directory And Open Full Access Admin! + + + Not Any Item Selected + + + Successfully + + \ No newline at end of file diff --git a/src/OpenProject.Navisworks/Resources/BCFierIcon16x16.png b/src/OpenProject.Navisworks/Resources/BCFierIcon16x16.png new file mode 100644 index 00000000..39e117ef Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/BCFierIcon16x16.png differ diff --git a/src/OpenProject.Navisworks/Resources/BCFierIcon32x32.png b/src/OpenProject.Navisworks/Resources/BCFierIcon32x32.png new file mode 100644 index 00000000..4b45eddb Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/BCFierIcon32x32.png differ diff --git a/src/OpenProject.Navisworks/Resources/OpenProjectLogo16.png b/src/OpenProject.Navisworks/Resources/OpenProjectLogo16.png new file mode 100644 index 00000000..8a08a2cf Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/OpenProjectLogo16.png differ diff --git a/src/OpenProject.Navisworks/Resources/OpenProjectLogo32.png b/src/OpenProject.Navisworks/Resources/OpenProjectLogo32.png new file mode 100644 index 00000000..5225c6b9 Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/OpenProjectLogo32.png differ diff --git a/src/OpenProject.Navisworks/Resources/Settings32.png b/src/OpenProject.Navisworks/Resources/Settings32.png new file mode 100644 index 00000000..03a3113d Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/Settings32.png differ diff --git a/src/OpenProject.Navisworks/Resources/dev.ico b/src/OpenProject.Navisworks/Resources/dev.ico new file mode 100644 index 00000000..6bae0f6b Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/dev.ico differ diff --git a/src/OpenProject.Navisworks/Resources/dev.png b/src/OpenProject.Navisworks/Resources/dev.png new file mode 100644 index 00000000..d1e67df9 Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/dev.png differ diff --git a/src/OpenProject.Navisworks/Resources/dev16x16.png b/src/OpenProject.Navisworks/Resources/dev16x16.png new file mode 100644 index 00000000..fb9c51e9 Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/dev16x16.png differ diff --git a/src/OpenProject.Navisworks/Resources/dev32x32.png b/src/OpenProject.Navisworks/Resources/dev32x32.png new file mode 100644 index 00000000..96eb5ddd Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/dev32x32.png differ diff --git a/src/OpenProject.Navisworks/Resources/folder.png b/src/OpenProject.Navisworks/Resources/folder.png new file mode 100644 index 00000000..ba66da71 Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/folder.png differ diff --git a/src/OpenProject.Navisworks/Resources/icon.ico b/src/OpenProject.Navisworks/Resources/icon.ico new file mode 100644 index 00000000..6a2bf0a3 Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/icon.ico differ diff --git a/src/OpenProject.Navisworks/Resources/lab16x16.png b/src/OpenProject.Navisworks/Resources/lab16x16.png new file mode 100644 index 00000000..5747dade Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/lab16x16.png differ diff --git a/src/OpenProject.Navisworks/Resources/lab32x32.png b/src/OpenProject.Navisworks/Resources/lab32x32.png new file mode 100644 index 00000000..a00be3d3 Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/lab32x32.png differ diff --git a/src/OpenProject.Navisworks/Resources/openproject.ico b/src/OpenProject.Navisworks/Resources/openproject.ico new file mode 100644 index 00000000..eeaf4d8e Binary files /dev/null and b/src/OpenProject.Navisworks/Resources/openproject.ico differ diff --git a/src/OpenProject.Navisworks/Services/MessageHandler.cs b/src/OpenProject.Navisworks/Services/MessageHandler.cs new file mode 100644 index 00000000..ebc76a2a --- /dev/null +++ b/src/OpenProject.Navisworks/Services/MessageHandler.cs @@ -0,0 +1,36 @@ +using System; +//using Autodesk.Revit.UI; +using Autodesk.Navisworks.Gui; +using Autodesk.Windows; +using Serilog; + +namespace OpenProjectNavisworks.Services +{ + public static class MessageHandler + { + public static void ShowWarning(string title, string instruction, string content) + { + Log.Warning($"{title}: {content}"); + + var dialog = new TaskDialog(); + dialog.WindowTitle = title; + dialog.ContentText = content; + dialog.ExpandedText = instruction; + dialog.Show(); + } + + public static void ShowError(Exception exception, string message) + { + if (exception != null) + Log.Error(exception, message); + else + Log.Error(message); + + var dialog = new TaskDialog(); + dialog.MainIcon = TaskDialogIcon.Error; + dialog.ContentText = message; + + dialog.Show(); + } + } +} diff --git a/src/OpenProject.Navisworks/Services/StatusBarService.cs b/src/OpenProject.Navisworks/Services/StatusBarService.cs new file mode 100644 index 00000000..da20a7f4 --- /dev/null +++ b/src/OpenProject.Navisworks/Services/StatusBarService.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.InteropServices; + +namespace OpenProjectNavisworks.Services +{ + /// + /// This service is based on the idea of Revit developer Jeremy Tammik (https://thebuildingcoder.typepad.com/blog/2011/02/status-bar-text.html) + /// + public static class StatusBarService + { + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern int SetWindowText(IntPtr hWnd, string lpString); + + [DllImport("user32.dll", SetLastError = true)] + private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, + string lpszWindow); + + /// + /// Sets a text to the revit main window status bar. + /// + /// The text to be displayed in the status bar. + public static void SetStatusText(string text) + { + IntPtr revitHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle; + IntPtr statusBar = FindWindowEx(revitHandle, IntPtr.Zero, "msctls_statusbar32", ""); + + if (statusBar != IntPtr.Zero) + SetWindowText(statusBar, text); + } + + /// + /// Resets the status bar text. + /// + public static void ResetStatusBarText() => SetStatusText("Ready"); + } +} diff --git a/src/OpenProject.Navisworks/View/AssemblyLoader.xaml b/src/OpenProject.Navisworks/View/AssemblyLoader.xaml new file mode 100644 index 00000000..4db935c8 --- /dev/null +++ b/src/OpenProject.Navisworks/View/AssemblyLoader.xaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + +