Skip to content

Commit f375759

Browse files
committed
Add view capturing capability
1 parent a9849ea commit f375759

File tree

10 files changed

+658
-11
lines changed

10 files changed

+658
-11
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* This file is part of the Buildings and Habitats object Model (BHoM)
3+
* Copyright (c) 2015 - 2022, the respective contributors. All rights reserved.
4+
*
5+
* Each contributor holds copyright over their respective contributions.
6+
* The project versioning (Git) records all such contribution source information.
7+
*
8+
*
9+
* The BHoM is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License as published by
11+
* the Free Software Foundation, either version 3.0 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* The BHoM is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public License
20+
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
21+
*/
22+
23+
using BH.oM.Base;
24+
using BH.oM.Base.Attributes;
25+
using System;
26+
using System.Collections.Generic;
27+
using System.ComponentModel;
28+
using System.Linq;
29+
using System.IO;
30+
using Rhino;
31+
using Rhino.Display;
32+
using System.Drawing;
33+
using BH.oM.Rhinoceros.ViewCapture;
34+
using System.Drawing.Imaging;
35+
36+
namespace BH.Engine.Rhinoceros
37+
{
38+
public static partial class Compute
39+
{
40+
/***************************************************/
41+
/**** Public Methods ****/
42+
/***************************************************/
43+
44+
[Description("Captures all named views to files.")]
45+
[Input("active", "Toggle to activate. Toggle to true to capture the view port.")]
46+
[Input("folderPath", "Folder path to store the image in. To folder that the currently open rhino model is stored in will be used if nothing is provided.")]
47+
[Input("imageName", "Name of the image, without file ending. THe name of the image will be this name + _viewName. To update the file ending, please see the viewcapture settings. If nothing is provided, the named view name will be the full filename.")]
48+
[Input("namedViewFilter", "Optional filter of which named views that should be captured to file. All named views are captured if nothing is provided.")]
49+
[Input("settings", "Settings to control the view capture.")]
50+
[Output("success", "Returns true if the view capture was successful.")]
51+
public static bool CaptureNamedViews(bool active = false, string folderPath = "", string imageName = "", List<string> namedViewFilter = null, IViewCaptureSettings settings = null)
52+
{
53+
RhinoDoc doc = RhinoDoc.ActiveDoc;
54+
55+
folderPath = ValidateFolderPath(folderPath, doc);
56+
if (folderPath == null)
57+
return false;
58+
59+
if (!active)
60+
return false;
61+
62+
bool success = true;
63+
64+
settings = settings ?? new ScaleViewCaptureSettings(); //Default view capture settings
65+
66+
for (int i = 0; i < doc.NamedViews.Count; i++)
67+
{
68+
string namedView = doc.NamedViews[i].Name;
69+
70+
if (namedViewFilter != null && namedViewFilter.Count != 0) //If named view filter provided
71+
if (!namedViewFilter.Contains(namedView)) //Filter out items in the list. If no filter provided, assume all to be captured
72+
continue;
73+
74+
doc.NamedViews.Restore(i, doc.Views.ActiveView.ActiveViewport);
75+
string name;
76+
if (string.IsNullOrEmpty(imageName))
77+
name = namedView;
78+
else
79+
name = imageName + "_" + namedView;
80+
success &= CaptureActiveView(doc, settings, folderPath, name);
81+
82+
}
83+
84+
return success;
85+
}
86+
87+
/***************************************************/
88+
}
89+
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* This file is part of the Buildings and Habitats object Model (BHoM)
3+
* Copyright (c) 2015 - 2022, the respective contributors. All rights reserved.
4+
*
5+
* Each contributor holds copyright over their respective contributions.
6+
* The project versioning (Git) records all such contribution source information.
7+
*
8+
*
9+
* The BHoM is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License as published by
11+
* the Free Software Foundation, either version 3.0 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* The BHoM is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public License
20+
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
21+
*/
22+
23+
using BH.oM.Base;
24+
using BH.oM.Base.Attributes;
25+
using System;
26+
using System.Collections.Generic;
27+
using System.ComponentModel;
28+
using System.Linq;
29+
using System.IO;
30+
using Rhino;
31+
using Rhino.Display;
32+
using System.Drawing;
33+
using BH.oM.Rhinoceros.ViewCapture;
34+
using System.Drawing.Imaging;
35+
36+
namespace BH.Engine.Rhinoceros
37+
{
38+
public static partial class Compute
39+
{
40+
/***************************************************/
41+
/**** Public Methods ****/
42+
/***************************************************/
43+
44+
[Description("Captures the currently active view to file.")]
45+
[Input("active", "Toggle to activate. Toggle to true to capture the view port.")]
46+
[Input("folderPath", "Folder path to store the image in. To folder that the currently open rhino model is stored in will be used if nothing is provided.")]
47+
[Input("imageName", "Name of the image, without file ending. To update the file ending, please see the viewcapture settings. The viewport name will be used if nothing is provided.")]
48+
[Input("settings", "Settings to control the view capture.")]
49+
[Output("success", "Returns true if the view capture was successful.")]
50+
public static bool CaptureView(bool active = false, string folderPath = "", string imageName = "", IViewCaptureSettings settings = null)
51+
{
52+
RhinoDoc doc = Rhino.RhinoDoc.ActiveDoc;
53+
54+
folderPath = ValidateFolderPath(folderPath, doc);
55+
if (folderPath == null)
56+
return false;
57+
58+
if (!active)
59+
return false;
60+
61+
settings = settings ?? new ScaleViewCaptureSettings(); //Default view capture settings
62+
63+
return CaptureActiveView(doc, settings, folderPath, imageName);
64+
}
65+
66+
67+
/***************************************************/
68+
/**** Private Methods ****/
69+
/***************************************************/
70+
71+
[Description("")]
72+
[Input("", "")]
73+
[Output("", "")]
74+
private static bool CaptureActiveView(RhinoDoc doc, IViewCaptureSettings settings, string folderName, string imageName)
75+
{
76+
var view = doc.Views.ActiveView;
77+
78+
if (string.IsNullOrWhiteSpace(imageName))
79+
{
80+
Engine.Base.Compute.RecordNote("No image name provided. Name of active viewport will be used.");
81+
imageName = view.ActiveViewport.Name;
82+
}
83+
84+
ViewCapture viewCapture = settings.IViewCapture(view.ActiveViewport);
85+
86+
if (viewCapture == null)
87+
return false;
88+
89+
var bitmap = viewCapture.CaptureToBitmap(view);
90+
91+
if (null != bitmap)
92+
{
93+
string fileEnding;
94+
ImageFormat imageFormat = settings.GetImageFormat(out fileEnding);
95+
if (imageFormat == null)
96+
return false;
97+
98+
var filename = Path.Combine(folderName, imageName + fileEnding);
99+
bitmap.Save(filename, imageFormat);
100+
return true;
101+
}
102+
103+
return false;
104+
}
105+
106+
/***************************************************/
107+
108+
private static string ValidateFolderPath(string folderPath, RhinoDoc doc)
109+
{
110+
if (string.IsNullOrEmpty(folderPath))
111+
{
112+
folderPath = Path.GetDirectoryName(doc.Path);
113+
Engine.Base.Compute.RecordNote($"No path provided. Images will be saved in the same folder as the Open rhino model.");
114+
}
115+
116+
if (!Directory.Exists(folderPath))
117+
{
118+
Engine.Base.Compute.RecordError($"Directory {folderPath} does not exist.");
119+
return null;
120+
}
121+
return folderPath;
122+
}
123+
124+
/***************************************************/
125+
126+
private static ImageFormat GetImageFormat(this IViewCaptureSettings settings, out string fileEnding)
127+
{
128+
string imageFormat = settings.FileFormat.ToUpper();
129+
130+
switch (imageFormat)
131+
{
132+
case "BMP":
133+
fileEnding = ".bmp";
134+
return ImageFormat.Bmp;
135+
case "EMF":
136+
fileEnding = ".emf";
137+
return ImageFormat.Emf;
138+
case "WMF":
139+
fileEnding = ".wmf";
140+
return ImageFormat.Wmf;
141+
case "GIF":
142+
fileEnding = ".gif";
143+
return ImageFormat.Gif;
144+
case "JPG":
145+
case "JPEG":
146+
fileEnding = ".jpg";
147+
return ImageFormat.Jpeg;
148+
case "PNG":
149+
fileEnding = ".png";
150+
return ImageFormat.Png;
151+
case "TIFF":
152+
fileEnding = ".tiff";
153+
return ImageFormat.Tiff;
154+
case "EXIF":
155+
fileEnding = ".exif";
156+
return ImageFormat.Exif;
157+
case "ICON":
158+
fileEnding = ".icon";
159+
return ImageFormat.Icon;
160+
default:
161+
Engine.Base.Compute.RecordError("Unknown image format.");
162+
fileEnding = "";
163+
return null;
164+
}
165+
}
166+
167+
/***************************************************/
168+
169+
private static ViewCapture IViewCapture(this IViewCaptureSettings settings, RhinoViewport viewport)
170+
{
171+
ViewCapture viewCapture = ViewCapture(settings as dynamic, viewport);
172+
viewCapture.ScaleScreenItems = settings.ScaleScreenItems;
173+
viewCapture.DrawAxes = settings.DrawAxes;
174+
viewCapture.DrawGrid = settings.DrawGrid;
175+
viewCapture.DrawGridAxes = settings.DrawGridAxes;
176+
viewCapture.TransparentBackground = settings.TransparentBackground;
177+
viewCapture.Preview = settings.Preview;
178+
return viewCapture;
179+
}
180+
181+
/***************************************************/
182+
183+
private static ViewCapture ViewCapture(this ScaleViewCaptureSettings settings, RhinoViewport viewport)
184+
{
185+
return new ViewCapture
186+
{
187+
Height = (int)Math.Round(viewport.Size.Height * settings.Scale),
188+
Width = (int)Math.Round(viewport.Size.Width * settings.Scale)
189+
};
190+
}
191+
192+
/***************************************************/
193+
194+
private static ViewCapture ViewCapture(this DimensionViewCaptureSettings settings, RhinoViewport viewport)
195+
{
196+
return new ViewCapture
197+
{
198+
Height = settings.Height,
199+
Width = settings.Width
200+
};
201+
}
202+
203+
/***************************************************/
204+
}
205+
}

Rhinoceros_Engine/Rhinoceros_Engine.csproj

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
44
<PropertyGroup>
@@ -47,6 +47,9 @@
4747
<HintPath>C:\ProgramData\BHoM\Assemblies\Dimensional_oM.dll</HintPath>
4848
<Private>False</Private>
4949
</Reference>
50+
<Reference Include="Eto, Version=2.5.0.0, Culture=neutral, PublicKeyToken=552281e97c755530, processorArchitecture=MSIL">
51+
<HintPath>..\packages\RhinoCommon.6.33.20343.16431\lib\net45\Eto.dll</HintPath>
52+
</Reference>
5053
<Reference Include="Geometry_Engine">
5154
<HintPath>C:\ProgramData\BHoM\Assemblies\Geometry_Engine.dll</HintPath>
5255
<Private>False</Private>
@@ -62,9 +65,11 @@
6265
<HintPath>C:\ProgramData\BHoM\Assemblies\Graphics_oM.dll</HintPath>
6366
<Private>False</Private>
6467
</Reference>
65-
<Reference Include="RhinoCommon, Version=5.1.30000.16, Culture=neutral, PublicKeyToken=552281e97c755530, processorArchitecture=MSIL">
66-
<HintPath>..\packages\RhinoCommon.5.12.50810.13095\lib\net35\RhinoCommon.dll</HintPath>
67-
<Private>True</Private>
68+
<Reference Include="Rhino.UI, Version=6.33.20343.16430, Culture=neutral, PublicKeyToken=552281e97c755530, processorArchitecture=MSIL">
69+
<HintPath>..\packages\RhinoCommon.6.33.20343.16431\lib\net45\Rhino.UI.dll</HintPath>
70+
</Reference>
71+
<Reference Include="RhinoCommon, Version=6.33.20343.16430, Culture=neutral, PublicKeyToken=552281e97c755530, processorArchitecture=MSIL">
72+
<HintPath>..\packages\RhinoCommon.6.33.20343.16431\lib\net45\RhinoCommon.dll</HintPath>
6873
</Reference>
6974
<Reference Include="System" />
7075
<Reference Include="System.Core" />
@@ -77,6 +82,8 @@
7782
<Reference Include="System.Xml" />
7883
</ItemGroup>
7984
<ItemGroup>
85+
<Compile Include="Compute\CaptureNamedViews.cs" />
86+
<Compile Include="Compute\CaptureView.cs" />
8087
<Compile Include="Convert\FromRhino.cs" />
8188
<Compile Include="Convert\ToRhino.cs" />
8289
<Compile Include="Convert\ToRhino6.cs" />
@@ -109,22 +116,28 @@
109116
<ItemGroup>
110117
<None Include="packages.config" />
111118
</ItemGroup>
119+
<ItemGroup>
120+
<ProjectReference Include="..\Rhinoceros_oM\Rhinoceros_oM.csproj">
121+
<Project>{5c0492bc-0ff4-45c9-963c-2514add35263}</Project>
122+
<Name>Rhinoceros_oM</Name>
123+
</ProjectReference>
124+
</ItemGroup>
112125
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
113-
<Import Project="..\packages\RhinoCommon.5.12.50810.13095\build\net35\RhinoCommon.targets" Condition="Exists('..\packages\RhinoCommon.5.12.50810.13095\build\net35\RhinoCommon.targets')" />
126+
<PropertyGroup>
127+
<PostBuildEvent>xcopy "$(TargetDir)$(TargetFileName)" "C:\\ProgramData\\BHoM\\Assemblies" /Y</PostBuildEvent>
128+
</PropertyGroup>
129+
<Import Project="..\packages\RhinoCommon.6.33.20343.16431\build\net45\RhinoCommon.targets" Condition="Exists('..\packages\RhinoCommon.6.33.20343.16431\build\net45\RhinoCommon.targets')" />
114130
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
115131
<PropertyGroup>
116132
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
117133
</PropertyGroup>
118-
<Error Condition="!Exists('..\packages\RhinoCommon.5.12.50810.13095\build\net35\RhinoCommon.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RhinoCommon.5.12.50810.13095\build\net35\RhinoCommon.targets'))" />
134+
<Error Condition="!Exists('..\packages\RhinoCommon.6.33.20343.16431\build\net45\RhinoCommon.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RhinoCommon.6.33.20343.16431\build\net45\RhinoCommon.targets'))" />
119135
</Target>
120-
<PropertyGroup>
121-
<PostBuildEvent>xcopy "$(TargetDir)$(TargetFileName)" "C:\\ProgramData\\BHoM\\Assemblies" /Y</PostBuildEvent>
122-
</PropertyGroup>
123136
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
124137
Other similar extension points exist, see Microsoft.Common.targets.
125138
<Target Name="BeforeBuild">
126139
</Target>
127140
<Target Name="AfterBuild">
128141
</Target>
129142
-->
130-
</Project>
143+
</Project>

Rhinoceros_Engine/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="RhinoCommon" version="5.12.50810.13095" targetFramework="net452" />
3+
<package id="RhinoCommon" version="6.33.20343.16431" targetFramework="net472" />
44
</packages>

Rhinoceros_Toolkit.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29728.190
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhinoceros_Engine", "Rhinoceros_Engine\Rhinoceros_Engine.csproj", "{93CEDC69-F9C0-4E08-9E94-07F120D811DC}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rhinoceros_oM", "Rhinoceros_oM\Rhinoceros_oM.csproj", "{5C0492BC-0FF4-45C9-963C-2514ADD35263}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
1517
{93CEDC69-F9C0-4E08-9E94-07F120D811DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{93CEDC69-F9C0-4E08-9E94-07F120D811DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{93CEDC69-F9C0-4E08-9E94-07F120D811DC}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{5C0492BC-0FF4-45C9-963C-2514ADD35263}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{5C0492BC-0FF4-45C9-963C-2514ADD35263}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{5C0492BC-0FF4-45C9-963C-2514ADD35263}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{5C0492BC-0FF4-45C9-963C-2514ADD35263}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)