Skip to content

Commit

Permalink
Added more primitive shapes; Bug fixes;
Browse files Browse the repository at this point in the history
  • Loading branch information
qkmaxware committed Jul 8, 2020
1 parent e375717 commit 6853458
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 12 deletions.
19 changes: 19 additions & 0 deletions Geometry.Test/suites/Geometry/Primitives/Capsule.test.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using Qkmaxware.Geometry;
using Qkmaxware.Geometry.IO;
using Qkmaxware.Geometry.Primitives;

namespace Astro.Testing {

[TestClass]
public class CapsuleTest : PrimitiveTest {
[TestMethod]
public void TestCapsule() {
var geom = new Capsule(0.5, 2, Vec3.Zero, 16, 16);
SaveGeometry("capsule", geom);
}
}

}
19 changes: 19 additions & 0 deletions Geometry.Test/suites/Geometry/Primitives/Hemisphere.test.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using Qkmaxware.Geometry;
using Qkmaxware.Geometry.IO;
using Qkmaxware.Geometry.Primitives;

namespace Astro.Testing {

[TestClass]
public class HemisphereTest : PrimitiveTest {
[TestMethod]
public void TestHemisphere() {
var geom = new Hemisphere(1, Vec3.Zero, 16, 16);
SaveGeometry("hemisphere", geom);
}
}

}
4 changes: 2 additions & 2 deletions Geometry/Geometry.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

<PropertyGroup>
<PackageId>Qkmaxware.Geometry</PackageId>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<Authors>Colin Halseth</Authors>
<PackageTags>geometry creation manipulation</PackageTags>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<RepositoryUrl>https://github.com/qkmaxware/Geometry.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageDescription>
Geometry is a c# library for the creation, and manipulation of 3d geometry
Geometry is a c# library for the creation, and manipulation of triangle based 3d geometry
</PackageDescription>
</PropertyGroup>
<ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions Geometry/src/Geometry/Mesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ public Box3 Bounds {
}
}

/// <summary>
/// Compute the surface area of this mesh
/// </summary>
/// <returns>sum of all triangular areas</returns>
public double SurfaceArea => this.Select(tri => tri.Area).Sum();

/// <summary>
/// Empty solid
/// </summary>
Expand Down
125 changes: 125 additions & 0 deletions Geometry/src/Geometry/Primitives/Capsule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System;
using System.Linq;
using System.Collections.Generic;

namespace Qkmaxware.Geometry.Primitives {

public class Capsule : Mesh {

private static Vec3 ToCartesian(double zrot, double inc, double r) {
double sTheta = Math.Sin(inc);
return new Vec3(
r * sTheta * Math.Cos(zrot),
r * sTheta * Math.Sin(zrot),
r * Math.Cos(inc)
);
}

private static List<Triangle> GenerateHemisphere(
double radius,
Vec3 centre,
int horiResolution,
int vertResolution
) {
List<Triangle> triangles = new List<Triangle>();

double xStep = (2 * Math.PI) / horiResolution;
double yStep = (0.5 * Math.PI) / (vertResolution - 1);

/*
top
/ \
te-ti
| /|
-------
*/

for (int i = 1; i <= horiResolution; i++) {
double prevXAngle = (i - 1) * xStep;
double xAngle = i * xStep;

for(int j = 1; j < vertResolution; j++) {
if (j == 1) {
// Top Triangle
double yAngle = (j) * yStep;

Vec3 top = new Vec3(0, 0, radius) + centre;
Vec3 be = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 bi = ToCartesian(prevXAngle, yAngle, radius) + centre;

triangles.Add(new Triangle(bi, be, top));
} else {
double yAngle = (j) * yStep;
double prevYAngle = (j - 1) * yStep;

// Middle rectangle
{
Vec3 te = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius) + centre;

Vec3 be = ToCartesian(xAngle, prevYAngle, radius) + centre;
Vec3 bi = ToCartesian(prevXAngle, prevYAngle, radius) + centre;

triangles.Add(new Triangle(ti, te, be));
triangles.Add(new Triangle(bi, ti, be));
}
}
}
}

return triangles;
}

private static List<Triangle> GenerateCylinder(double upperRadius, double lowerRadius, double h, Vec3 centre, int resolution) {
List<Triangle> triangles = new List<Triangle>();
double step = 2 * Math.PI / resolution;
double hStep = h / 2;

for (int i = 1; i <= resolution; i++) {
double prevAngle = (i - 1) * step;
double xi = Math.Cos(prevAngle);
double yi = Math.Sin(prevAngle);

double angle = i * step;
double xe = Math.Cos(angle);
double ye = Math.Sin(angle);

/*
te -- ti
| / |
| / |
be -- bi
*/
// Create top points
Vec3 te = new Vec3(xe * upperRadius, ye * upperRadius, hStep) + centre;
Vec3 ti = new Vec3(xi * upperRadius, yi * upperRadius, hStep) + centre;
// Create bottom points
Vec3 be = new Vec3(xe * lowerRadius, ye * lowerRadius, -hStep) + centre;
Vec3 bi = new Vec3(xi * lowerRadius, yi * lowerRadius, -hStep) + centre;

// Create triangles
triangles.Add(new Triangle(be, te, ti));
triangles.Add(new Triangle(be, ti, bi));
}

return triangles;
}

public Capsule(double radius, double height, Vec3 centre, int horizontalResolution = 8, int verticalResolution = 8) {
height = Math.Max(height, 2*radius); // height must be greater than 2*radius or else its a squashed sphere

// Capsule is a cylinder
var cylinderHeight = height - 2 * radius;
var cylinder = GenerateCylinder(radius, radius, cylinderHeight, centre, horizontalResolution);
this.AppendRange(cylinder);

// Plus 2 spheres
Vec3 delta = cylinderHeight * 0.5 * Vec3.K;
var topSphere = GenerateHemisphere(radius, centre + delta, horizontalResolution, verticalResolution);
this.AppendRange(topSphere);
this.AppendRange(topSphere.Select(tri => new Triangle(tri.Item1.Flipped, tri.Item3.Flipped ,tri.Item2.Flipped)));
}

}

}
95 changes: 95 additions & 0 deletions Geometry/src/Geometry/Primitives/Hemisphere.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;

namespace Qkmaxware.Geometry.Primitives {

/// <summary>
/// Half sphere mesh
/// </summary>
public class Hemisphere : Mesh {

private static Vec3 ToCartesian(double zrot, double inc, double r) {
double sTheta = Math.Sin(inc);
return new Vec3(
r * sTheta * Math.Cos(zrot),
r * sTheta * Math.Sin(zrot),
r * Math.Cos(inc)
);
}

private static List<Triangle> Generate(
double radius,
Vec3 centre,
int horiResolution,
int vertResolution,
bool useEndCap = true
) {
List<Triangle> triangles = new List<Triangle>();

double xStep = (2 * Math.PI) / horiResolution;
double yStep = (0.5 * Math.PI) / (vertResolution - 1);

/*
top
/ \
te-ti
| /|
-------
*/

for (int i = 1; i <= horiResolution; i++) {
double prevXAngle = (i - 1) * xStep;
double xAngle = i * xStep;

for(int j = 1; j < vertResolution; j++) {
if (j == 1) {
// Top Triangle
double yAngle = (j) * yStep;

Vec3 top = new Vec3(0, 0, radius) + centre;
Vec3 be = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 bi = ToCartesian(prevXAngle, yAngle, radius) + centre;

triangles.Add(new Triangle(bi, be, top));
} else {
double yAngle = (j) * yStep;
double prevYAngle = (j - 1) * yStep;

// Bottom Triangle
if (useEndCap && j == vertResolution - 1) {
Vec3 bottom = new Vec3(0, 0, 0) + centre;
Vec3 te = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius) + centre;

triangles.Add(new Triangle(ti, bottom, te));
}

// Middle rectangle
{
Vec3 te = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius) + centre;

Vec3 be = ToCartesian(xAngle, prevYAngle, radius) + centre;
Vec3 bi = ToCartesian(prevXAngle, prevYAngle, radius) + centre;

triangles.Add(new Triangle(ti, te, be));
triangles.Add(new Triangle(bi, ti, be));
}
}
}
}

return triangles;
}

/// <summary>
/// Create a hemisphere
/// </summary>
/// <param name="radius">radius</param>
/// <param name="centre">centre point</param>
/// <param name="horizontalResolution">longitude subdivision levels</param>
/// <param name="verticalResolution">latitude subdivision level</param>
public Hemisphere(double radius, Vec3 centre, int horizontalResolution = 8, int verticalResolution = 8) : base(Generate(radius, centre, horizontalResolution, verticalResolution)) {}
}

}
16 changes: 8 additions & 8 deletions Geometry/src/Geometry/Primitives/Sphere.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,29 +50,29 @@ int vertResolution
double yAngle = (j) * yStep;

Vec3 top = new Vec3(0, 0, radius) + centre;
Vec3 be = ToCartesian(xAngle, yAngle, radius);
Vec3 bi = ToCartesian(prevXAngle, yAngle, radius);
Vec3 be = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 bi = ToCartesian(prevXAngle, yAngle, radius) + centre;

triangles.Add(new Triangle(bi, be, top));
} else if (j == vertResolution - 1) {
// Bottom Triangle
double yAngle = (j - 1) * yStep;

Vec3 bottom = new Vec3(0, 0, -radius) + centre;
Vec3 te = ToCartesian(xAngle, yAngle, radius);
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius);
Vec3 te = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius) + centre;

triangles.Add(new Triangle(ti, bottom, te));
} else {
// Middle rectangle
double yAngle = (j) * yStep;
double prevYAngle = (j - 1) * yStep;

Vec3 te = ToCartesian(xAngle, yAngle, radius);
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius);
Vec3 te = ToCartesian(xAngle, yAngle, radius) + centre;
Vec3 ti = ToCartesian(prevXAngle, yAngle, radius) + centre;

Vec3 be = ToCartesian(xAngle, prevYAngle, radius);
Vec3 bi = ToCartesian(prevXAngle, prevYAngle, radius);
Vec3 be = ToCartesian(xAngle, prevYAngle, radius) + centre;
Vec3 bi = ToCartesian(prevXAngle, prevYAngle, radius) + centre;

triangles.Add(new Triangle(ti, te, be));
triangles.Add(new Triangle(bi, ti, be));
Expand Down
2 changes: 1 addition & 1 deletion Geometry/src/Geometry/Transformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public class Transformation {
/// <param name="e22"></param>
/// <param name="e23"></param>
/// <param name="e24"></param>
private Transformation(
public Transformation(
double e01, double e02, double e03, double e04,
double e11, double e12, double e13, double e14,
double e21, double e22, double e23, double e24
Expand Down
13 changes: 13 additions & 0 deletions Geometry/src/Geometry/Triangle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ public Triangle Flipped {
}
}

/// <summary>
/// Compute the area of the triangle
/// </summary>
/// <value>area</value>
public double Area {
get {
var AB = Edge12;
var AC = Edge13;

return Vec3.Cross(AB, AC).Length * 0.5;
}
}

private Box3? box = null;
/// <summary>
/// Compute an axis aligned bounding box that completely contains the triangle
Expand Down
4 changes: 3 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ Geometry in this library is modeled as a collection of triangular faces whose ve
| Cube | 6 sided cube | <img width="128" src="docs/images/PrimitiveCube.png"/> |
| Cylinder | Solid cylinder with configurable radii | <img width="128" src="docs/images/PrimitiveCylinder.png"/> |
| Tube | Hollowed out cylinder with an inner and outer radius | <img width="128" src="docs/images/PrimitiveTube.png"/> |
| Capsule | Cylinder capped with two hemispheres | <img width="128" src="docs/images/PrimitiveCapsule.png"/> |
| Cone | Cone with a given radius | <img width="128" src="docs/images/PrimitiveCone.png"/> |
| Sphere | UV sphere | <img width="128" src="docs/images/PrimitiveSphere.png"/> |
| Hemisphere | Half of a sphere | <img width="128" src="docs/images/PrimitiveHemisphere.png"/> |
| Torus | Torus with configurable radii | <img width="128" src="docs/images/PrimitiveTorus.png"/> |
| Frustum | Pyramidal Frustums | <img width="128" src="docs/images/PrimitiveFrustum.png"/> |
| Nosecone | Varieties of aerodynamic nosecones | <img width="128" src="docs/images/PrimitiveNoseconeBiconic.png"/> <img width="128" src="docs/images/PrimitiveNoseconeParabolic.png"/> <img width="128" src="docs/images/PrimitiveNoseconeSecant.png"/>|
| Nosecone | Varieties of aerodynamic nosecones | <img width="128" height="256" src="docs/images/PrimitiveNoseconeBiconic.png"/> <img width="128" height="256" src="docs/images/PrimitiveNoseconeParabolic.png"/>|

## Transformations for Building Geometries
| Name | Effect | Result |
Expand Down
Binary file added docs/images/PrimitiveCapsule.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/PrimitiveHemisphere.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6853458

Please sign in to comment.