Skip to content

Commit adca0d6

Browse files
committed
See 'CHANGELOG.md' for commit details.
1 parent 5c27ab2 commit adca0d6

File tree

9 files changed

+168
-140
lines changed

9 files changed

+168
-140
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
## [Unreleased]
1111

12+
## 1.1.0 - 2023-07-05
13+
14+
### Added
15+
16+
- An untested version of constrained triangulation; along with all Triangle2D / 3D data that was required to be edited to ensure a working format.#
17+
18+
### Changed
19+
20+
- Voxelization now voxelizes spaces using grids instead of lists to ensure connectivity stays consistent.
21+
22+
### Fixed
23+
24+
- Networking/Genetics has now been re-added in an un-tested state. It (should) allow neural networks to be correctly trained using genetic algorithms.
25+
- Predicted / Expected values were swapped in a MSE calculation during a fit stage in the neural network training that could case some backwards learning gradients. I was unable to find a case in which it did infact cause said problem, but it is better to ensure it works as expected by using the right method.
26+
1227
## 1.0.2 - 2023-05-06
1328

1429
### Changed

Runtime/Geometrics/Triangle2D.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@ public Triangle2D(Edge2D a, Vector2 b) {
2828
Edges = new[] {new Edge2D(Vertices[0],Vertices[1]),new Edge2D(Vertices[1],Vertices[2]),new Edge2D(Vertices[2],Vertices[0])};
2929
UpdateCircumcircle();
3030
}
31-
31+
32+
public Triangle2D(Edge2D Edge) {
33+
Vertices = new[] { Edge.Vertices[0], Edge.Vertices[1] };
34+
Edges = new[] { Edge };
35+
36+
double Radius = Edge.GetLength();
37+
38+
RadiusSquared = Radius * Radius;
39+
Circumcenter = Edge.GetMidpoint();
40+
}
41+
3242
public Triangle2D(Triangle3D Triangle, bool FlattenToXZ=true) {
3343
Vector2 a, b, c; // Projects 3D Triangle to 2D Plane
3444
if (FlattenToXZ) { // To XZ Plane (If using XZ Plane, Y of 2d vectors will be Z of 3d vectors)

Runtime/Geometrics/Triangulation.cs

Lines changed: 77 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
namespace UniversalNumerics.Geometrics {
88
public static class Triangulation {
99

10-
public static IEnumerable<Triangle2D> BowyerWatsonTriangulation(IEnumerable<Vector2> PointCloud) {
10+
public static IEnumerable<Triangle2D> Triangulate(IEnumerable<Vector2> PointCloud) {
1111
List<Triangle2D> Triangulation = new List<Triangle2D>();
1212

1313
Triangle2D SuperTriangle = new Triangle2D(
@@ -77,17 +77,7 @@ private static bool PointInList(Vector2 Point, List<Vector2> Points, float Toler
7777
return Points.Any(OtherPoint => Vector2.DistanceSquared(OtherPoint, Point) < SqrTol);
7878
}
7979

80-
[Pure] private static IEnumerable<Vector2> CleanPoints(IEnumerable<Vector2> UncleanPoints) {
81-
List<Vector2> CleanedPoints = new List<Vector2>();
82-
foreach (Vector2 Point in UncleanPoints) {
83-
if (!PointInList(Point, CleanedPoints)) {
84-
CleanedPoints.Add(Point);
85-
}
86-
}
87-
return CleanedPoints;
88-
}
89-
90-
[Pure] public static IEnumerable<Triangle2D> BowyerWatsonTriangulation(IEnumerable<Edge2D> PSG) {
80+
[Pure] public static IEnumerable<Triangle2D> Triangulate(IEnumerable<Edge2D> PSG) {
9181
List<Vector2> PointCloud = new List<Vector2>();
9282
foreach (Edge2D Edge in PSG) {
9383
if (!PointInList(Edge.A, PointCloud)) {
@@ -97,7 +87,7 @@ [Pure] public static IEnumerable<Triangle2D> BowyerWatsonTriangulation(IEnumerab
9787
PointCloud.Add(Edge.B);
9888
}
9989
}
100-
return BowyerWatsonTriangulation(PointCloud);
90+
return Triangulate(PointCloud);
10191
}
10292

10393
[Pure] public static IEnumerable<Edge2D> VoronoiFromTriangulation(IEnumerable<Triangle2D> Triangulation) {
@@ -123,110 +113,95 @@ [Pure] private static bool IsPoorTriangle(Triangle2D Triangle, float Threshold)
123113
return (Angle1 < Threshold || Angle2 < Threshold || Angle3 < Threshold);
124114
}
125115

126-
[Pure] private static IEnumerable<Edge2D> GetEncroachedSegments(IEnumerable<Edge2D> Segments, IEnumerable<Vector2> PointCloud) {
127-
List<Edge2D> EncroachedEdges = new List<Edge2D>();
128-
foreach (Edge2D Segment in Segments) {
129-
bool Encroached = false;
130-
foreach (Vector2 Point in PointCloud) {
131-
Encroached = Segment.EncroachedByPoint(Point);
132-
if (Encroached) {
133-
break;
116+
[Pure] private static Edge2D GetIntersectingEdge(List<Triangle2D> Triangulation) {
117+
foreach (Triangle2D Tri in Triangulation) {
118+
foreach (Triangle2D OtherTri in Triangulation) {
119+
if (Tri.Equals(OtherTri)) continue;
120+
foreach (Edge2D Edge in Tri.Edges) {
121+
foreach (Edge2D OtherEdge in OtherTri.Edges) {
122+
if (Intersection.AreSegmentsIntersecting(Edge.A, Edge.B, OtherEdge.A, OtherEdge.B)) {
123+
return Edge;
124+
}
125+
}
134126
}
135127
}
136-
if (Encroached) {
137-
EncroachedEdges.Add(Segment);
138-
}
139128
}
140-
return EncroachedEdges;
129+
return null;
141130
}
142-
143-
[Pure] public static IEnumerable<Triangle2D> ConstrainedBowyerWatsonTriangulation(IEnumerable<Vector2> PointCloud, IEnumerable<Edge2D> ConstraintEdges, float Threshold = 26) {
144-
List<Vector2> PointCloudList = CleanPoints(PointCloud).ToList();
145-
List<Edge2D> ConstraintEdgeList = ConstraintEdges.ToList();
146-
List<Triangle2D> Triangulation = BowyerWatsonTriangulation(PointCloudList).ToList();
147-
List<Edge2D> EncroachedSegments = new List<Edge2D>();
148-
List<Triangle2D> PoorTriangles = new List<Triangle2D>();
149-
150-
foreach (Edge2D ConstraintEdge in ConstraintEdgeList) {
151-
152-
if (!PointInList(ConstraintEdge.A, PointCloudList)) {
153-
PointCloudList.Add(ConstraintEdge.A);
154-
}
155-
if (!PointInList(ConstraintEdge.B, PointCloudList)) {
156-
PointCloudList.Add(ConstraintEdge.B);
157-
}
158-
159-
foreach (Vector2 Point in PointCloudList) {
160-
if (ConstraintEdge.EncroachedByPoint(Point)) {
161-
EncroachedSegments.Add(ConstraintEdge);
162-
break;
131+
132+
[Pure] private static bool HasIntersectingEdges(List<Edge2D> Edges) {
133+
foreach (Edge2D Edge in Edges) {
134+
foreach (Edge2D OtherEdge in Edges) {
135+
if (Edge.Equals(OtherEdge)) continue;
136+
if (Intersection.AreSegmentsIntersecting(Edge.A, Edge.B, OtherEdge.A, OtherEdge.B)) {
137+
return true;
163138
}
164139
}
165140
}
141+
return false;
142+
}
143+
144+
[Pure] private static Triangle2D[] GetEdgeSharedTriangles(IEnumerable<Triangle2D> Triangles, Edge2D Edge) {
145+
IEnumerable<Triangle2D> OtherTriangles = Triangles.ToList();
166146

167-
foreach (Triangle2D Triangle in Triangulation) {
168-
if (IsPoorTriangle(Triangle, Threshold)) {
169-
PoorTriangles.Add(Triangle);
147+
foreach (Triangle2D Triangle in OtherTriangles) {
148+
foreach (Triangle2D OtherTriangle in OtherTriangles) {
149+
if (Triangle.Equals(OtherTriangle)) continue;
150+
if (Triangle.SharedEdgeWith(OtherTriangle).Equals(Edge)) {
151+
return new[] { Triangle, OtherTriangle };
152+
}
170153
}
171154
}
172155

173-
while (EncroachedSegments.Count > 0 || PoorTriangles.Count > 0) {
174-
List<Edge2D> EdgesToRemove = new List<Edge2D>();
175-
List<Triangle2D> TrianglesToRemove = new List<Triangle2D>();
176-
177-
foreach (Edge2D EncroachedSegment in EncroachedSegments) {
178-
Vector2 Midpoint = EncroachedSegment.GetMidpoint();
179-
PointCloudList.Add(Midpoint);
180-
EdgesToRemove.Add(EncroachedSegment);
181-
ConstraintEdgeList.Remove(EncroachedSegment);
182-
ConstraintEdgeList.Add(new Edge2D(Midpoint, EncroachedSegment.A));
183-
ConstraintEdgeList.Add(new Edge2D(Midpoint, EncroachedSegment.B));
184-
}
185-
186-
foreach (Edge2D EdgeToRemove in EdgesToRemove) {
187-
EncroachedSegments.Remove(EdgeToRemove);
188-
}
189-
190-
foreach (Triangle2D Triangle in PoorTriangles) {
191-
Vector2 Midpoint = Triangle.Circumcenter;
192-
List<Edge2D> SegmentsEncroachedByMidpoint = new List<Edge2D>();
193-
foreach (Edge2D Segment in ConstraintEdgeList) {
194-
if (Segment.EncroachedByPoint(Midpoint)) {
195-
SegmentsEncroachedByMidpoint.Add(Segment);
196-
}
197-
}
156+
return null;
157+
}
198158

199-
if (SegmentsEncroachedByMidpoint.Count > 0) {
200-
EncroachedSegments.AddRange(SegmentsEncroachedByMidpoint);
201-
}
202-
else {
203-
PointCloudList.Add(Midpoint);
204-
}
205-
TrianglesToRemove.Add(Triangle);
206-
}
207-
208-
foreach (Triangle2D TriangleToRemove in TrianglesToRemove) {
209-
PoorTriangles.Remove(TriangleToRemove);
210-
}
159+
[Pure] private static List<Triangle2D> ToTriangles(List<Edge2D> Edges) {
160+
List<Triangle2D> outputTriangles = new List<Triangle2D>();
161+
for (int i = 0; i < Edges.Count; i += 3) {
162+
outputTriangles.Add(new Triangle2D(Edges[i].A, Edges[i+1].A, Edges[i+2].A));
163+
}
164+
return outputTriangles;
165+
}
211166

212-
Triangulation = BowyerWatsonTriangulation(PointCloudList).ToList();
213-
214-
foreach (Edge2D ConstraintEdge in ConstraintEdgeList) {
215-
foreach (Vector2 Point in PointCloudList) {
216-
if (ConstraintEdge.EncroachedByPoint(Point)) {
217-
EncroachedSegments.Add(ConstraintEdge);
218-
break;
219-
}
220-
}
221-
}
222-
223-
foreach (Triangle2D Triangle in Triangulation) {
224-
if (IsPoorTriangle(Triangle, Threshold)) {
225-
PoorTriangles.Add(Triangle);
226-
}
227-
}
167+
[Pure] public static IEnumerable<Triangle2D> ConstrainedTriangulation(IEnumerable<Vector2> PointCloud, IEnumerable<Edge2D> ConstraintEdges, float Threshold = 26) {
168+
List<Triangle2D> Triangulation = Triangulate(PointCloud).ToList();
169+
foreach (Edge2D ConstraintEdge in ConstraintEdges) {
170+
Triangulation.Add(new Triangle2D(ConstraintEdge));
228171
}
229172

173+
Edge2D NextIntersectingEdge = GetIntersectingEdge(Triangulation);
174+
175+
while (NextIntersectingEdge != null) {
176+
foreach (Triangle2D Triangle in GetEdgeSharedTriangles(Triangulation, NextIntersectingEdge)) {
177+
Vector2 v1 = Triangle.A;
178+
Vector2 v2 = Triangle.B;
179+
Vector2 v3 = Triangle.C;
180+
181+
Triangulation.Remove(Triangle);
182+
183+
Triangle2D t1 = new(NextIntersectingEdge.A, v1, v2);
184+
Triangle2D t2 = new(NextIntersectingEdge.B, v1, v2);
185+
Triangle2D t3 = new(NextIntersectingEdge.A, v2, v3);
186+
Triangle2D t4 = new(NextIntersectingEdge.B, v2, v3);
187+
Triangle2D t5 = new(NextIntersectingEdge.A, v3, v1);
188+
Triangle2D t6 = new(NextIntersectingEdge.B, v3, v1);
189+
190+
t1.Vertices[2] = t2.Vertices[2] = v2;
191+
t3.Vertices[2] = t4.Vertices[2] = v3;
192+
t5.Vertices[2] = t6.Vertices[2] = v1;
193+
194+
Triangulation.Add(t1);
195+
Triangulation.Add(t2);
196+
Triangulation.Add(t3);
197+
Triangulation.Add(t4);
198+
Triangulation.Add(t5);
199+
Triangulation.Add(t6);
200+
}
201+
202+
NextIntersectingEdge = GetIntersectingEdge(Triangulation);
203+
}
204+
230205
return Triangulation;
231206
}
232207

Runtime/Geometrics/Voxel.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Numerics;
2+
3+
// ReSharper disable once CheckNamespace
4+
namespace UniversalNumerics.Geometrics {
5+
public struct Voxel {
6+
public Vector3 position;
7+
public float size;
8+
9+
public Voxel(Vector3 position, float size) {
10+
this.position = position;
11+
this.size = size;
12+
}
13+
}
14+
}

Runtime/Geometrics/Voxel.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Geometrics/Voxelization.cs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,42 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Numerics;
34

45
// ReSharper disable once CheckNamespace
56
namespace UniversalNumerics.Geometrics {
67
public static class Voxelization {
8+
public static int EstimateVoxelCount(Vector3 areaSize, float voxelSize) {
9+
int cellsX = (int)System.Math.Ceiling(areaSize.X / voxelSize);
10+
int cellsY = (int)System.Math.Ceiling(areaSize.Y / voxelSize);
11+
int cellsZ = (int)System.Math.Ceiling(areaSize.Z / voxelSize);
12+
return cellsX * cellsY * cellsZ;
13+
}
14+
15+
public static Vector3 CalculateVoxelGridSize(Vector3 areaSize, float voxelSize) {
16+
Vector3 voxelGridSize = Vector3.Zero;
17+
18+
voxelGridSize.X = (int)Math.Ceiling(areaSize.X / voxelSize);
19+
voxelGridSize.Y = (int)Math.Ceiling(areaSize.Y / voxelSize);
20+
voxelGridSize.Z = (int)Math.Ceiling(areaSize.Z / voxelSize);
721

8-
public static int GetSubvoxelEstimate(Vector3 AreaSize, Vector3 VoxelSize) {
9-
int CellsX = (int)System.Math.Ceiling(AreaSize.X / VoxelSize.X), CellsY = (int)System.Math.Ceiling(AreaSize.Y / VoxelSize.Y), CellsZ = (int)System.Math.Ceiling(AreaSize.Z / VoxelSize.Z);
10-
return CellsX * CellsZ * CellsY;
22+
return voxelGridSize;
1123
}
1224

13-
public static IEnumerable<Vector3> VoxelizeArea(Vector3 Center, Vector3 AreaSize, Vector3 VoxelSize) {
14-
Vector3 StartPosition = Center + AreaSize/2 - VoxelSize/2;
15-
int CellsX = (int)System.Math.Ceiling(AreaSize.X / VoxelSize.X), CellsY = (int)System.Math.Ceiling(AreaSize.Y / VoxelSize.Y), CellsZ = (int)System.Math.Ceiling(AreaSize.Z / VoxelSize.Z);
16-
List<Vector3> Voxels = new(CellsX*CellsY*CellsZ);
17-
for (int i = 0; i < CellsX; i++) {
18-
for (int j = 0; j < CellsZ; j++) {
19-
for (int k = 0; k < CellsY; k++) {
20-
Vector3 VoxelPosition = StartPosition - new Vector3(VoxelSize.X * i, VoxelSize.Y * k, VoxelSize.Z * j);
21-
Voxels.Add(VoxelPosition);
25+
public static Voxel[,,] VoxelizeArea(Vector3 areaCenter, Vector3 areaSize, float voxelSize) {
26+
Vector3 voxelGridSize = CalculateVoxelGridSize(areaSize, voxelSize);
27+
28+
Voxel[,,] voxelGrid = new Voxel[(int)voxelGridSize.X, (int)voxelGridSize.Y, (int)voxelGridSize.Z];
29+
30+
for (int x = 0; x < (int)voxelGridSize.X; x++) {
31+
for (int y = 0; y < (int)voxelGridSize.Y; y++) {
32+
for (int z = 0; z < (int)voxelGridSize.Z; z++) {
33+
Vector3 voxelPosition = areaCenter + new Vector3(x * voxelSize, y * voxelSize, z * voxelSize);
34+
voxelGrid[x, y, z] = new Voxel(voxelPosition, voxelSize);
2235
}
2336
}
2437
}
25-
return Voxels;
38+
39+
return voxelGrid;
2640
}
2741

2842
}

0 commit comments

Comments
 (0)