forked from teocomi/BCFier
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create viewpoint bounding boxes depending on the selected elements
- Loading branch information
1 parent
42f5b3c
commit 5526d1e
Showing
7 changed files
with
567 additions
and
1 deletion.
There are no files selected for viewing
67 changes: 67 additions & 0 deletions
67
src/IPA.Bcfier.Navisworks/OpenProject/AxisAlignedBoundingBox.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.Navisworks.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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.Navisworks.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
79
src/IPA.Bcfier.Navisworks/OpenProject/ClippingPlaneUtils.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.Navisworks.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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.Navisworks.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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// This was mostly taken from: | ||
// https://github.com/opf/openproject-revit-add-in | ||
|
||
namespace IPA.Bcfier.Navisworks.OpenProject | ||
{ | ||
/// <summary> | ||
/// This immutable class describes a directed location in 3d space. It contains a center point | ||
/// and a forward and up vector to describe a defined orientation in 3d space. | ||
/// </summary> | ||
public sealed class Position : IEquatable<Position> | ||
{ | ||
/// <summary> | ||
/// The center position vector. | ||
/// </summary> | ||
public Vector3 Center { get; } | ||
|
||
/// <summary> | ||
/// The forward direction vector. | ||
/// </summary> | ||
public Vector3 Forward { get; } | ||
|
||
/// <summary> | ||
/// The up direction vector. | ||
/// </summary> | ||
public Vector3 Up { get; } | ||
|
||
public Position() | ||
{ | ||
Center = Vector3.Zero; | ||
Forward = Vector3.Zero; | ||
Up = Vector3.Zero; | ||
} | ||
|
||
public Position(Vector3 center, Vector3 forward, Vector3 up) | ||
{ | ||
Center = center; | ||
Forward = forward; | ||
Up = up; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public bool Equals(Position other) | ||
{ | ||
if (other == null) return false; | ||
|
||
return Center.Equals(other.Center) && | ||
Forward.Equals(other.Forward) && | ||
Up.Equals(other.Up); | ||
} | ||
} | ||
} |
Oops, something went wrong.