Skip to content

Commit 2ede5c7

Browse files
committed
update: add VisualizationServer
1 parent 2b4980b commit 2ede5c7

13 files changed

+2737
-0
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
3+
namespace RevitDevTool.Visualization.Helpers;
4+
5+
public static class RenderGeometryHelper
6+
{
7+
public static List<List<XYZ>> GetSegmentationTube(IList<XYZ> vertices, double diameter)
8+
{
9+
var points = new List<List<XYZ>>();
10+
11+
for (var i = 0; i < vertices.Count; i++)
12+
{
13+
var center = vertices[i];
14+
XYZ normal;
15+
if (i == 0)
16+
{
17+
normal = (vertices[i + 1] - center).Normalize();
18+
}
19+
else if (i == vertices.Count - 1)
20+
{
21+
normal = (center - vertices[i - 1]).Normalize();
22+
}
23+
else
24+
{
25+
normal = ((vertices[i + 1] - vertices[i - 1]) / 2.0).Normalize();
26+
}
27+
28+
points.Add(TessellateCircle(center, normal, diameter / 2));
29+
}
30+
31+
return points;
32+
}
33+
34+
public static XYZ GetMeshVertexNormal(Mesh mesh, int index, DistributionOfNormals normalDistribution)
35+
{
36+
switch (normalDistribution)
37+
{
38+
case DistributionOfNormals.AtEachPoint:
39+
return mesh.GetNormal(index);
40+
case DistributionOfNormals.OnEachFacet:
41+
var vertex = mesh.Vertices[index];
42+
for (var i = 0; i < mesh.NumTriangles; i++)
43+
{
44+
var triangle = mesh.get_Triangle(i);
45+
var triangleVertex = triangle.get_Vertex(0);
46+
if (triangleVertex.IsAlmostEqualTo(vertex)) return mesh.GetNormal(i);
47+
triangleVertex = triangle.get_Vertex(1);
48+
if (triangleVertex.IsAlmostEqualTo(vertex)) return mesh.GetNormal(i);
49+
triangleVertex = triangle.get_Vertex(2);
50+
if (triangleVertex.IsAlmostEqualTo(vertex)) return mesh.GetNormal(i);
51+
}
52+
53+
return XYZ.Zero;
54+
case DistributionOfNormals.OnePerFace:
55+
return mesh.GetNormal(0);
56+
default:
57+
throw new ArgumentOutOfRangeException(nameof(normalDistribution), normalDistribution, null);
58+
}
59+
}
60+
61+
public static List<XYZ> TessellateCircle(XYZ center, XYZ normal, double radius)
62+
{
63+
var vertices = new List<XYZ>();
64+
var segmentCount = InterpolateSegmentsCount(radius);
65+
var xDirection = normal.CrossProduct(XYZ.BasisZ).Normalize() * radius;
66+
if (xDirection.IsZeroLength())
67+
{
68+
xDirection = normal.CrossProduct(XYZ.BasisX).Normalize() * radius;
69+
}
70+
71+
var yDirection = normal.CrossProduct(xDirection).Normalize() * radius;
72+
73+
for (var i = 0; i < segmentCount; i++)
74+
{
75+
var angle = 2 * Math.PI * i / segmentCount;
76+
var vertex = center + xDirection * Math.Cos(angle) + yDirection * Math.Sin(angle);
77+
vertices.Add(vertex);
78+
}
79+
80+
return vertices;
81+
}
82+
83+
public static Solid ScaleSolid(Solid solid, double scale)
84+
{
85+
if (scale is 1) scale = EvaluateScale(solid, Context.Application.VertexTolerance * 3);
86+
87+
var centroid = solid.GetBoundingBox().Transform.Origin;
88+
var moveToCentroid = Transform.CreateTranslation(-centroid);
89+
var scaleTransform = Transform.Identity.ScaleBasis(scale);
90+
var moveBack = Transform.CreateTranslation(centroid);
91+
var combinedTransform = moveBack.Multiply(scaleTransform).Multiply(moveToCentroid);
92+
return SolidUtils.CreateTransformed(solid, combinedTransform);
93+
}
94+
95+
public static int InterpolateSegmentsCount(double diameter)
96+
{
97+
const int minSegments = 6;
98+
const int maxSegments = 33;
99+
const double minDiameter = 0.1 / 12d;
100+
const double maxDiameter = 3 / 12d;
101+
102+
if (diameter <= minDiameter) return minSegments;
103+
if (diameter >= maxDiameter) return maxSegments;
104+
105+
var normalDiameter = (diameter - minDiameter) / (maxDiameter - minDiameter);
106+
return (int) (minSegments + normalDiameter * (maxSegments - minSegments));
107+
}
108+
109+
public static double InterpolateOffsetByDiameter(double diameter)
110+
{
111+
const double minOffset = 0.01d;
112+
const double maxOffset = 0.1d;
113+
const double minDiameter = 0.1 / 12d;
114+
const double maxDiameter = 3 / 12d;
115+
116+
if (diameter <= minDiameter) return minOffset;
117+
if (diameter >= maxDiameter) return maxOffset;
118+
119+
var normalOffset = (diameter - minDiameter) / (maxDiameter - minDiameter);
120+
return minOffset + normalOffset * (maxOffset - minOffset);
121+
}
122+
123+
public static double InterpolateOffsetByArea(double area)
124+
{
125+
const double minOffset = 0.01d;
126+
const double maxOffset = 0.1d;
127+
const double minArea = 0.01d;
128+
const double maxArea = 1d;
129+
130+
if (area <= minArea) return minOffset;
131+
if (area >= maxArea) return maxOffset;
132+
133+
var normalOffset = (area - minArea) / (maxArea - minArea);
134+
return minOffset + normalOffset * (maxOffset - minOffset);
135+
}
136+
137+
public static double InterpolateAxisLengthByArea(double area)
138+
{
139+
const double minLength = 0.1d;
140+
const double maxLength = 1d;
141+
const double minArea = 0.01d;
142+
const double maxArea = 1d;
143+
144+
if (area <= minArea) return minLength;
145+
if (area >= maxArea) return maxLength;
146+
147+
var normalOffset = (area - minArea) / (maxArea - minArea);
148+
return minLength + normalOffset * (maxLength - minLength);
149+
}
150+
151+
public static double InterpolateAxisLengthByPoints(XYZ min, XYZ max)
152+
{
153+
const double maxLength = 1d;
154+
155+
var width = max.X - min.X;
156+
var height = max.Y - min.Y;
157+
var depth = max.Z - min.Z;
158+
159+
var maxSize = Math.Max(width, Math.Max(height, depth));
160+
161+
if (maxLength * 2 < maxSize)
162+
{
163+
return maxLength;
164+
}
165+
166+
return maxSize * 0.35;
167+
}
168+
169+
public static double ComputeMeshSurfaceArea(Mesh mesh)
170+
{
171+
#if REVIT2024_OR_GREATER
172+
return mesh.ComputeSurfaceArea();
173+
#else
174+
var surfaceArea = 0.0;
175+
176+
for (var i = 0; i < mesh.NumTriangles; i++)
177+
{
178+
var triangle = mesh.get_Triangle(i);
179+
180+
var vertex0 = triangle.get_Vertex(0);
181+
var vertex1 = triangle.get_Vertex(1);
182+
var vertex2 = triangle.get_Vertex(2);
183+
184+
var side1 = vertex1 - vertex0;
185+
var side2 = vertex2 - vertex0;
186+
187+
var crossProduct = side1.CrossProduct(side2);
188+
189+
surfaceArea += crossProduct.GetLength() / 2.0;
190+
}
191+
192+
return surfaceArea;
193+
#endif
194+
}
195+
196+
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
197+
private static double EvaluateScale(Solid solid, double offset)
198+
{
199+
var boundingBox = solid.GetBoundingBox();
200+
201+
var currentLength = boundingBox.Max.X - boundingBox.Min.X;
202+
var currentWidth = boundingBox.Max.Y - boundingBox.Min.Y;
203+
var currentHeight = boundingBox.Max.Z - boundingBox.Min.Z;
204+
205+
var maxDimension = Math.Max(Math.Max(currentLength, currentWidth), currentHeight);
206+
207+
if (maxDimension == currentLength) return (currentLength + offset) / currentLength;
208+
if (maxDimension == currentWidth) return (currentWidth + offset) / currentWidth;
209+
return (currentHeight + offset) / currentHeight;
210+
}
211+
}

0 commit comments

Comments
 (0)