Skip to content

Commit

Permalink
Merge pull request #8 from Dangl-IT/feature/#3-section-box-in-revit
Browse files Browse the repository at this point in the history
Add support for bounding box
  • Loading branch information
GeorgDangl authored Apr 7, 2024
2 parents d4a8ba8 + 83e1e92 commit dca7913
Show file tree
Hide file tree
Showing 13 changed files with 774 additions and 2 deletions.
1 change: 1 addition & 0 deletions build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ public static class FileVersionProvider
File.Copy(pluginOutputDirectory / "Dangl.BCF.dll", installerDirectory / "Dangl.BCF.dll");
File.Copy(pluginOutputDirectory / "IPA.Bcfier.dll", installerDirectory/ "IPA.Bcfier.dll");
File.Copy(pluginOutputDirectory / "IPA.Bcfier.Revit.dll", installerDirectory/ "IPA.Bcfier.Revit.dll");
File.Copy(pluginOutputDirectory / "DecimalEx.dll", installerDirectory/ "DecimalEx.dll");
File.Copy(pluginOutputDirectory / "IPA.Bcfier.Revit.addin", installerDirectory/ "IPA.Bcfier.Revit.addin");

InnoSetup($"/dAppVersion=\"{GitVersion.AssemblySemVer}\" {pluginOutputDirectory / "Installer.iss"}");
Expand Down
3 changes: 2 additions & 1 deletion src/IPA.Bcfier.Revit/IPA.Bcfier.Revit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
</PackageReference>
<PackageReference Include="cef.redist.x64" Version="105.3.39" ExcludeAssets="all">
</PackageReference>
<PackageReference Include="Revit_All_Main_Versions_API_x64" Version="2024.0.0" ExcludeAssets="build;runtime;contentFiles"/>
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
<PackageReference Include="Revit_All_Main_Versions_API_x64" Version="2024.0.0" ExcludeAssets="build;runtime;contentFiles" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/IPA.Bcfier.Revit/Installer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Name: revit24; Description: Addin for Autodesk Revit 2024; Types: full
[Files]

;REVIT 2024
Source: "{#Repository}\DecimalEx.dll"; DestDir: "{#RevitAddin24}"; Flags: ignoreversion; Components: revit24
Source: "{#Repository}\Dangl.BCF.dll"; DestDir: "{#RevitAddin24}"; Flags: ignoreversion; Components: revit24
Source: "{#Repository}\IPA.Bcfier.dll"; DestDir: "{#RevitAddin24}"; Flags: ignoreversion; Components: revit24
Source: "{#Repository}\IPA.Bcfier.Revit.dll"; DestDir: "{#RevitAddin24}"; Flags: ignoreversion; Components: revit24
Expand Down
67 changes: 67 additions & 0 deletions src/IPA.Bcfier.Revit/OpenProject/AxisAlignedBoundingBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This was mostly taken from:
// https://github.com/opf/openproject-revit-add-in

namespace IPA.Bcfier.Revit.OpenProject
{
/// <summary>
/// Immutable implementation of an axis aligned bounding box with decimal precision.
/// </summary>
public sealed class AxisAlignedBoundingBox : IEquatable<AxisAlignedBoundingBox>
{
/// <summary>
/// A bounding box with max values, representing an infinite bounding box
/// </summary>
public static AxisAlignedBoundingBox Infinite =>
new AxisAlignedBoundingBox(Vector3.InfiniteMin, Vector3.InfiniteMax);

/// <summary>
/// This min corner of the axis aligned bounding box.
/// </summary>
public Vector3 Min { get; }

/// <summary>
/// This min corner of the axis aligned bounding box.
/// </summary>
public Vector3 Max { get; }

public AxisAlignedBoundingBox(Vector3 min, Vector3 max)
{
Min = min;
Max = max;
}

/// <summary>
/// Merges this bounding box with the given one and returns the resulting bounding box, that
/// is included in both bounding boxes. If there is no intersection between both bounding
/// boxes, an infinite bounding box is returned.
/// </summary>
/// <param name="box">The other bounding box</param>
/// <returns>The merged bounding box.</returns>
public AxisAlignedBoundingBox MergeReduce(AxisAlignedBoundingBox box)
{
var min = new Vector3(
Math.Max(Min.X, box.Min.X),
Math.Max(Min.Y, box.Min.Y),
Math.Max(Min.Z, box.Min.Z));
var max = new Vector3(
Math.Min(Max.X, box.Max.X),
Math.Min(Max.Y, box.Max.Y),
Math.Min(Max.Z, box.Max.Z));

// validity check
if (min.X < max.X && min.Y < max.Y && min.Z < max.Z)
return new AxisAlignedBoundingBox(min, max);

return Infinite;
}

/// <inheritdoc/>
public bool Equals(AxisAlignedBoundingBox other)
{
if (other == null)
return false;

return Min.Equals(other.Min) && Max.Equals(other.Max);
}
}
}
131 changes: 131 additions & 0 deletions src/IPA.Bcfier.Revit/OpenProject/BcfExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// This was mostly taken from:
// https://github.com/opf/openproject-revit-add-in

using IPA.Bcfier.Models.Bcf;

namespace IPA.Bcfier.Revit.OpenProject
{
public static class BcfExtensions
{
public static Vector3 ToVector3(this BcfViewpointVector direction) =>
new Vector3(
direction.X.ToDecimal(),
direction.Y.ToDecimal(),
direction.Z.ToDecimal());

public static Vector3 ToVector3(this BcfViewpointPoint point) =>
new Vector3(
point.X.ToDecimal(),
point.Y.ToDecimal(),
point.Z.ToDecimal());

/// <summary>
/// Converts a axis aligned bounding box into a list of bcf api clipping planes.
/// </summary>
/// <param name="clippingBox">
/// The bounding box that defines the clipping. Can contain infinite values, which are
/// interpreted as if the view is not clipped in that direction.
/// </param>
/// <param name="clippingCenter">
/// An optional clipping center. Important for positioning the clipping planes not too far
/// away from the model. If no clipping center is given, the center of the clipping box is
/// used, which can result in very odd clipping plane locations, if the clipping box
/// contains infinite values.
/// </param>
/// <returns>A list of clipping planes.</returns>
public static List<BcfViewpointClippingPlane> ToClippingPlanes(
this AxisAlignedBoundingBox clippingBox,
Vector3 clippingCenter = null)
{
Vector3 center = clippingCenter ?? (clippingBox.Min + clippingBox.Max) * 0.5m;

var planes = new List<BcfViewpointClippingPlane>();

if (clippingBox.Min.X.IsFinite())
{
planes.Add(new BcfViewpointClippingPlane
{
Location = new BcfViewpointPoint
{
X = Convert.ToSingle(clippingBox.Min.X),
Y = Convert.ToSingle(center.Y),
Z = Convert.ToSingle(center.Z)
},
Direction = new BcfViewpointVector { X = -1, Y = 0, Z = 0 }
});
}

if (clippingBox.Min.Y.IsFinite())
{
planes.Add(new BcfViewpointClippingPlane
{
Location = new BcfViewpointPoint
{
X = Convert.ToSingle(center.X),
Y = Convert.ToSingle(clippingBox.Min.Y),
Z = Convert.ToSingle(center.Z)
},
Direction = new BcfViewpointVector { X = 0, Y = -1, Z = 0 }
});
}

if (clippingBox.Min.Z.IsFinite())
{
planes.Add(new BcfViewpointClippingPlane
{
Location = new BcfViewpointPoint
{
X = Convert.ToSingle(center.X),
Y = Convert.ToSingle(center.Y),
Z = Convert.ToSingle(clippingBox.Min.Z)
},
Direction = new BcfViewpointVector { X = 0, Y = 0, Z = -1 }
});
}

if (clippingBox.Max.X.IsFinite())
{
planes.Add(new BcfViewpointClippingPlane
{
Location = new BcfViewpointPoint
{
X = Convert.ToSingle(clippingBox.Max.X),
Y = Convert.ToSingle(center.Y),
Z = Convert.ToSingle(center.Z)
},
Direction = new BcfViewpointVector { X = 1, Y = 0, Z = 0 }
});
}

if (clippingBox.Max.Y.IsFinite())
{
planes.Add(new BcfViewpointClippingPlane
{
Location = new BcfViewpointPoint
{
X = Convert.ToSingle(center.X),
Y = Convert.ToSingle(clippingBox.Max.Y),
Z = Convert.ToSingle(center.Z)
},
Direction = new BcfViewpointVector { X = 0, Y = 1, Z = 0 }
});
}

if (clippingBox.Max.Z.IsFinite())
{
planes.Add(new BcfViewpointClippingPlane
{
Location = new BcfViewpointPoint
{
X = Convert.ToSingle(center.X),
Y = Convert.ToSingle(center.Y),
Z = Convert.ToSingle(clippingBox.Max.Z)
},
Direction = new BcfViewpointVector { X = 0, Y = 0, Z = 1 }
});
}

return planes;
}
}
}
79 changes: 79 additions & 0 deletions src/IPA.Bcfier.Revit/OpenProject/ClippingPlaneUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// This was mostly taken from:
// https://github.com/opf/openproject-revit-add-in

using IPA.Bcfier.Models.Bcf;

namespace IPA.Bcfier.Revit.OpenProject
{
public static class ClippingPlaneUtils
{
private static Vector3 XPositive() => new Vector3(1, 0, 0);

private static Vector3 XNegative() => new Vector3(-1, 0, 0);

private static Vector3 YPositive() => new Vector3(0, 1, 0);

private static Vector3 YNegative() => new Vector3(0, -1, 0);

private static Vector3 ZPositive() => new Vector3(0, 0, 1);

private static Vector3 ZNegative() => new Vector3(0, 0, -1);

/// <summary>
/// Converts a bcf clipping plane into an axis aligned clipping bounding box. The clipping
/// plane direction vector (plane normal) is compared to the coordinate axes. If the angle
/// is below a given delta, the plane is converted to one side of an axis aligned clipping
/// bounding box. The rest of the box's sides are set to max value.
/// </summary>
/// <param name="plane">The bcf clipping plane.</param>
/// <param name="delta">
/// The maximum angle the plane direction can differ from a XYZ coordinate axis.
/// </param>
/// <returns>The axis aligned bounding box.</returns>
public static AxisAlignedBoundingBox ToAxisAlignedBoundingBox(this BcfViewpointClippingPlane plane, decimal delta = 0)
{
var infiniteMax = new Vector3(decimal.MaxValue, decimal.MaxValue, decimal.MaxValue);
var infiniteMin = new Vector3(decimal.MinValue, decimal.MinValue, decimal.MinValue);

var normal = new Vector3(
(decimal)plane.Direction.X,
(decimal)plane.Direction.Y,
(decimal)plane.Direction.Z);

var boundingBox = new AxisAlignedBoundingBox(infiniteMin, infiniteMax);

if (normal.AngleBetween(ZPositive()) < delta)
{
var max = new Vector3(decimal.MaxValue, decimal.MaxValue, (decimal)plane.Location.Z);
boundingBox = new AxisAlignedBoundingBox(infiniteMin, max);
}
else if (normal.AngleBetween(ZNegative()) < delta)
{
var min = new Vector3(decimal.MinValue, decimal.MinValue, (decimal)plane.Location.Z);
boundingBox = new AxisAlignedBoundingBox(min, infiniteMax);
}
else if (normal.AngleBetween(YPositive()) < delta)
{
var max = new Vector3(decimal.MaxValue, (decimal)plane.Location.Y, decimal.MaxValue);
boundingBox = new AxisAlignedBoundingBox(infiniteMin, max);
}
else if (normal.AngleBetween(YNegative()) < delta)
{
var min = new Vector3(decimal.MinValue, (decimal)plane.Location.Y, decimal.MinValue);
boundingBox = new AxisAlignedBoundingBox(min, infiniteMax);
}
else if (normal.AngleBetween(XPositive()) < delta)
{
var max = new Vector3((decimal)plane.Location.X, decimal.MaxValue, decimal.MaxValue);
boundingBox = new AxisAlignedBoundingBox(infiniteMin, max);
}
else if (normal.AngleBetween(XNegative()) < delta)
{
var min = new Vector3((decimal)plane.Location.X, decimal.MinValue, decimal.MinValue);
boundingBox = new AxisAlignedBoundingBox(min, infiniteMax);
}

return boundingBox;
}
}
}
45 changes: 45 additions & 0 deletions src/IPA.Bcfier.Revit/OpenProject/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// This was mostly taken from:
// https://github.com/opf/openproject-revit-add-in

namespace IPA.Bcfier.Revit.OpenProject
{
public static class Extensions
{
/// <summary>
/// Checks a decimal number against infinity.
/// </summary>
/// <param name="number">A decimal value</param>
/// <returns>true, if a decimal value is finite, false otherwise</returns>
public static bool IsFinite(this decimal number) => number > decimal.MinValue && number < decimal.MaxValue;

/// <summary>
/// Converts a double value to a decimal value without throwing a <see
/// cref="OverflowException"/>. If the double is bigger then the maximal value of decimals,
/// the decimal maximal value is returned.
/// </summary>
/// <param name="double">The double value</param>
/// <returns>The converted decimal value</returns>
public static decimal ToDecimal(this double @double)
{
if (@double < 0)
return @double < (double)decimal.MinValue ? decimal.MinValue : (decimal)@double;

return @double > (double)decimal.MaxValue ? decimal.MaxValue : (decimal)@double;
}

/// <summary>
/// Converts a float value to a decimal value without throwing a <see
/// cref="OverflowException"/>. If the float is bigger then the maximal value of decimals,
/// the decimal maximal value is returned.
/// </summary>
/// <param name="float">The float value</param>
/// <returns>The converted decimal value</returns>
public static decimal ToDecimal(this float @float)
{
if (@float < 0)
return @float < (float)decimal.MinValue ? decimal.MinValue : (decimal)@float;

return @float > (float)decimal.MaxValue ? decimal.MaxValue : (decimal)@float;
}
}
}
Loading

0 comments on commit dca7913

Please sign in to comment.