public static Matrix3D CalcRotationMatrix(double x, double y, double z, Point3D center, Vector3D up, Vector3D look, Transform3D transform, RotationType type) { //Transform3DGroup trm = new Transform3DGroup(); //trm.Children.Add(transform); Vector3D realup = transform.Transform(up); if (type != RotationType.LockAxisY) { up = realup; } if (type != RotationType.LockAxisZ) { look = transform.Transform(look); } center = transform.Transform(center); Vector3D axisX = Vector3D.CrossProduct(up, look); Matrix3D matrix = new Matrix3D(); //Quaternion q = new Quaternion(); //q. double ang = AngleBetween(realup, YAxis) + x; if (ang >= 90) { x = 90 - ang; } matrix.RotateAt(new Quaternion(axisX, x), center); matrix.RotateAt(new Quaternion(up, y), center); matrix.RotateAt(new Quaternion(look, z), center); return matrix; }
public static PerspectiveCamera GetTransformedPerspectiveCamera(PerspectiveCamera camera, Transform3D transform) { return new PerspectiveCamera { LookDirection = transform.Transform(camera.LookDirection), UpDirection = transform.Transform(camera.UpDirection), FieldOfView = camera.FieldOfView, FarPlaneDistance = camera.FarPlaneDistance, NearPlaneDistance = camera.NearPlaneDistance, Position = transform.Transform(camera.Position) }; }
public static Matrix3D CalculateRotationMatrix(double x, double y, double z, Point3D center, Vector3D up, Vector3D look, Transform3D transform) { //Transform3DGroup trm = new Transform3DGroup(); //trm.Children.Add(transform); up = transform.Transform(up); look = transform.Transform(look); center = transform.Transform(center); Vector3D axisZ = Vector3D.CrossProduct(up, look); Matrix3D matrix = new Matrix3D(); matrix.RotateAt(new Quaternion(axisZ, x), center); matrix.RotateAt(new Quaternion(up, y), center); matrix.RotateAt(new Quaternion(look, z), center); return matrix; }
// http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Components-PostAttachments/00-04-01-86-12/SceneSortingHelper_2E00_cs /// <summary> /// Sort Modelgroups in Farthest to Closest order, to enable transparency /// Should be applied whenever the scene is significantly re-oriented /// </summary> public static void AlphaSort(Point3D cameraPosition, Model3DCollection models, Transform3D worldTransform) { var sortedList = models.OrderBy(model => Point3D.Subtract(cameraPosition, worldTransform.Transform(model.Bounds.Location)).Length); models.Clear(); foreach (var model in sortedList) { models.Add(model); } }
public static MatrixTransform3D Rotate3D(Transform3D transform, Vector3D look, Vector3D dir, Point3D center) { Matrix3D m = new Matrix3D(); Vector3D realook = transform.Transform(look); Vector3D axis = Vector3D.CrossProduct(realook, dir); double angle = Math.Acos(Vector3D.DotProduct(realook, dir)); Quaternion q = new Quaternion(axis, angle); m.RotateAt(q, center); MatrixTransform3D rlt = transform as MatrixTransform3D; return new MatrixTransform3D(Matrix3D.Multiply(rlt.Matrix, m)); }
public void ExportMesh(MeshGeometry3D m, Transform3D t) { Dictionary<int, int> dictionary = new Dictionary<int, int>(); Dictionary<int, int> dictionary2 = new Dictionary<int, int>(); Dictionary<int, int> dictionary3 = new Dictionary<int, int>(); int num = 0; foreach (Point3D pointd in m.Positions) { dictionary.Add(num++, this.vertexIndex++); Point3D pointd2 = t.Transform(pointd); this.writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "v {0} {1} {2}", new object[] { pointd2.X, pointd2.Y, pointd2.Z })); } num = 0; foreach (Point point in m.TextureCoordinates) { if (!(double.IsNegativeInfinity(point.X) || double.IsPositiveInfinity(point.Y))) { dictionary2.Add(num++, this.textureIndex++); this.writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "vt {0} {1}", new object[] { point.X, point.Y })); } else { num++; } } num = 0; foreach (Vector3D vectord in m.Normals) { if (!(double.IsNegativeInfinity(vectord.X) || double.IsPositiveInfinity(vectord.Y))) { dictionary3.Add(num++, this.normalIndex++); this.writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "vn {0} {1} {2}", new object[] { vectord.X, vectord.Y, vectord.Z })); } else { num++; } } for (int i = 0; i < m.TriangleIndices.Count; i += 3) { int num6; int key = m.TriangleIndices[i]; int num4 = m.TriangleIndices[i + 1]; int num5 = m.TriangleIndices[i + 2]; this.writer.WriteLine("f {0}/{1}{2} {3}/{4}{5} {6}/{7}{8}", new object[] { dictionary[key], dictionary2.ContainsKey(key) ? (num6 = dictionary2[key]).ToString() : string.Empty, dictionary3.ContainsKey(key) ? ("/" + (num6 = dictionary3[key]).ToString()) : string.Empty, dictionary[num4], dictionary2.ContainsKey(num4) ? (num6 = dictionary2[num4]).ToString() : string.Empty, dictionary3.ContainsKey(num4) ? ("/" + (num6 = dictionary3[num4]).ToString()) : string.Empty, dictionary[num5], dictionary2.ContainsKey(num5) ? (num6 = dictionary2[num5]).ToString() : string.Empty, dictionary3.ContainsKey(num5) ? ("/" + (num6 = dictionary3[num5]).ToString()) : string.Empty }); } }
private static void GetDome(ref int pointOffset, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, int numSegmentsPhi, double radiusX, double radiusY, double radiusZ) { #region Initial calculations // NOTE: There is one more than what the passed in Point[] pointsPhi = new Point[numSegmentsPhi + 1]; pointsPhi[0] = new Point(1d, 0d); // along the equator pointsPhi[numSegmentsPhi] = new Point(0d, 1d); // north pole if (pointsPhi.Length > 2) { // Need to go from 0 to half pi double halfPi = Math.PI * .5d; double deltaPhi = halfPi / pointsPhi.Length; // there is one more point than numSegmentsPhi for (int cntr = 1; cntr < numSegmentsPhi; cntr++) { double phi = deltaPhi * cntr; // phi goes from 0 to pi for a full sphere, so start halfway up pointsPhi[cntr] = new Point(Math.Cos(phi), Math.Sin(phi)); } } #endregion #region Positions/Normals // Can't use all of the transform passed in for the normal, because translate portions will skew the normal funny Transform3DGroup normalTransform = new Transform3DGroup(); if (transform is Transform3DGroup) { foreach (var subTransform in ((Transform3DGroup)transform).Children) { if (!(subTransform is TranslateTransform3D)) { normalTransform.Children.Add(subTransform); } } } else if (transform is TranslateTransform3D) { normalTransform.Children.Add(Transform3D.Identity); } else { normalTransform.Children.Add(transform); } //for (int phiCntr = 0; phiCntr < numSegmentsPhi; phiCntr++) // The top point will be added after this loop for (int phiCntr = pointsPhi.Length - 1; phiCntr > 0; phiCntr--) { for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++) { // Phi points are going from bottom to equator. Point3D point = new Point3D( radiusX * pointsTheta[thetaCntr].X * pointsPhi[phiCntr].Y, radiusY * pointsTheta[thetaCntr].Y * pointsPhi[phiCntr].Y, radiusZ * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); //TODO: For a standalone dome, the bottom rings will point straight out. But for something like a snow cone, the normal will have to be averaged with the cone geometry.Normals.Add(normalTransform.Transform(point).ToVector().ToUnit()); // the normal is the same as the point for a sphere (but no tranlate transform) } } // This is north pole point geometry.Positions.Add(transform.Transform(new Point3D(0, 0, radiusZ))); geometry.Normals.Add(transform.Transform(new Vector3D(0, 0, 1))); #endregion #region Triangles - Rings int zOffsetBottom = pointOffset; int zOffsetTop; for (int phiCntr = 0; phiCntr < numSegmentsPhi - 1; phiCntr++) // The top cone will be added after this loop { zOffsetTop = zOffsetBottom + pointsTheta.Length; for (int thetaCntr = 0; thetaCntr < pointsTheta.Length - 1; thetaCntr++) { // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 1); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1); } // Connecting the last 2 points to the first 2 // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0); geometry.TriangleIndices.Add(zOffsetTop); // wrapping back around geometry.TriangleIndices.Add(zOffsetTop + (pointsTheta.Length - 1) + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0); geometry.TriangleIndices.Add(zOffsetBottom); geometry.TriangleIndices.Add(zOffsetTop); // Prep for the next ring zOffsetBottom = zOffsetTop; } #endregion #region Triangles - Cap int topIndex = geometry.Positions.Count - 1; for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++) { geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + cntr + 1); geometry.TriangleIndices.Add(topIndex); } // The last triangle links back to zero geometry.TriangleIndices.Add(zOffsetBottom + pointsTheta.Length - 1 + 0); geometry.TriangleIndices.Add(zOffsetBottom + 0); geometry.TriangleIndices.Add(topIndex); #endregion pointOffset = geometry.Positions.Count; }
public static MeshGeometry3D GetCircle2D(int numSides, Transform3D transform, Transform3D normalTransform) { //NOTE: This also sets the texture coordinates int pointOffset = 0; Point[] pointsTheta = Math2D.GetCircle_Cached(numSides); MeshGeometry3D retVal = new MeshGeometry3D(); #region Positions/Normals for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++) { Point3D point = new Point3D(pointsTheta[thetaCntr].X, pointsTheta[thetaCntr].Y, 0d); retVal.Positions.Add(transform.Transform(point)); Point texturePoint = new Point(.5d + (pointsTheta[thetaCntr].X * .5d), .5d + (pointsTheta[thetaCntr].Y * .5d)); retVal.TextureCoordinates.Add(texturePoint); Vector3D normal = new Vector3D(0, 0, 1); retVal.Normals.Add(normalTransform.Transform(normal)); } #endregion #region Add the triangles // Start with 0,1,2 retVal.TriangleIndices.Add(pointOffset + 0); retVal.TriangleIndices.Add(pointOffset + 1); retVal.TriangleIndices.Add(pointOffset + 2); int lowerIndex = 2; int upperIndex = pointsTheta.Length - 1; int lastUsedIndex = 0; bool shouldBumpLower = true; // Do the rest of the triangles while (lowerIndex < upperIndex) { retVal.TriangleIndices.Add(pointOffset + lowerIndex); retVal.TriangleIndices.Add(pointOffset + upperIndex); retVal.TriangleIndices.Add(pointOffset + lastUsedIndex); if (shouldBumpLower) { lastUsedIndex = lowerIndex; lowerIndex++; } else { lastUsedIndex = upperIndex; upperIndex--; } shouldBumpLower = !shouldBumpLower; } #endregion return retVal; }
/// <summary> /// This overload takes an actual mesh /// </summary> public static Point3D[] GetPointsFromMesh(MeshGeometry3D mesh, Transform3D transform = null) { if (mesh == null) { return null; } Point3D[] points = null; if (mesh.TriangleIndices != null && mesh.TriangleIndices.Count > 0) { // Referenced points points = mesh.TriangleIndices.Select(o => mesh.Positions[o]).ToArray(); } else { // Directly used points points = mesh.Positions.ToArray(); } if (transform != null) { transform.Transform(points); } // Exit Function return points; }
private static void EndCap_PlateHard(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, Transform3D normalTransform, TubeRingBase ring, bool isFirst) { Vector3D normal = normalTransform.Transform(new Vector3D(0, 0, 1)).ToUnit(); // Start with 0,1,2 geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[0].X, pointsTheta[0].Y, 0d))); geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[1].X, pointsTheta[1].Y, 0d))); geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[2].X, pointsTheta[2].Y, 0d))); geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(pointOffset + 0); geometry.TriangleIndices.Add(pointOffset + 1); geometry.TriangleIndices.Add(pointOffset + 2); int lowerIndex = 2; int upperIndex = pointsTheta.Length - 1; int lastUsedIndex = 0; bool shouldBumpLower = true; int localOffset = 3; // Do the rest of the triangles while (lowerIndex < upperIndex) { geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[lowerIndex].X, pointsTheta[lowerIndex].Y, 0d))); geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[upperIndex].X, pointsTheta[upperIndex].Y, 0d))); geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[lastUsedIndex].X, pointsTheta[lastUsedIndex].Y, 0d))); geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(pointOffset + localOffset + 0); geometry.TriangleIndices.Add(pointOffset + localOffset + 1); geometry.TriangleIndices.Add(pointOffset + localOffset + 2); if (shouldBumpLower) { lastUsedIndex = lowerIndex; lowerIndex++; } else { lastUsedIndex = upperIndex; upperIndex--; } shouldBumpLower = !shouldBumpLower; localOffset += 3; } // Update ref param pointOffset = geometry.Positions.Count; }
private static void GetRingSprtCap(ref int pointOffset, MeshGeometry3D geometry, Transform3D transform, Point[] points, int numSides, double innerRadius, double outerRadius) { // Points/Normals for (int cntr = 0; cntr < numSides; cntr++) { geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * outerRadius, points[cntr].Y * outerRadius, 0d))); geometry.Normals.Add(transform.Transform(new Vector3D(0, 0, 1)).ToUnit()); } for (int cntr = 0; cntr < numSides; cntr++) { geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * innerRadius, points[cntr].Y * innerRadius, 0d))); geometry.Normals.Add(transform.Transform(new Vector3D(0, 0, 1)).ToUnit()); } int zOffsetOuter = pointOffset; int zOffsetInner = zOffsetOuter + numSides; // Triangles for (int cntr = 0; cntr < numSides - 1; cntr++) { // Bottom Right triangle geometry.TriangleIndices.Add(zOffsetOuter + cntr + 0); geometry.TriangleIndices.Add(zOffsetOuter + cntr + 1); geometry.TriangleIndices.Add(zOffsetInner + cntr + 1); // Top Left triangle geometry.TriangleIndices.Add(zOffsetOuter + cntr + 0); geometry.TriangleIndices.Add(zOffsetInner + cntr + 1); geometry.TriangleIndices.Add(zOffsetInner + cntr + 0); } // Connecting the last 2 points to the first 2 // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetOuter + (numSides - 1) + 0); geometry.TriangleIndices.Add(zOffsetOuter); geometry.TriangleIndices.Add(zOffsetInner); // Top/Left triangle geometry.TriangleIndices.Add(zOffsetOuter + (numSides - 1) + 0); geometry.TriangleIndices.Add(zOffsetInner); // wrapping back around geometry.TriangleIndices.Add(zOffsetInner + (numSides - 1) + 0); pointOffset = geometry.Positions.Count; }
private static void EndCap_ConeHard(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, TubeRingPoint ring, double capHeight, bool isFirst) { Point3D tipPosition = transform.Transform(new Point3D(0, 0, capHeight)); int localOffset = 0; for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++) { geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[cntr].X, pointsTheta[cntr].Y, 0d))); geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[cntr + 1].X, pointsTheta[cntr + 1].Y, 0d))); geometry.Positions.Add(tipPosition); Vector3D normal = GetNormal(geometry.Positions[pointOffset + localOffset + 0], geometry.Positions[pointOffset + localOffset + 1], geometry.Positions[pointOffset + localOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(pointOffset + localOffset + 0); geometry.TriangleIndices.Add(pointOffset + localOffset + 1); geometry.TriangleIndices.Add(pointOffset + localOffset + 2); localOffset += 3; } // The last triangle links back to zero geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[pointsTheta.Length - 1].X, pointsTheta[pointsTheta.Length - 1].Y, 0d))); geometry.Positions.Add(transform.Transform(new Point3D(pointsTheta[0].X, pointsTheta[0].Y, 0d))); geometry.Positions.Add(tipPosition); Vector3D normal2 = GetNormal(geometry.Positions[pointOffset + localOffset + 0], geometry.Positions[pointOffset + localOffset + 1], geometry.Positions[pointOffset + localOffset + 2]); geometry.Normals.Add(normal2); // the normals point straight out of the face geometry.Normals.Add(normal2); geometry.Normals.Add(normal2); geometry.TriangleIndices.Add(pointOffset + localOffset + 0); geometry.TriangleIndices.Add(pointOffset + localOffset + 1); geometry.TriangleIndices.Add(pointOffset + localOffset + 2); // Update ref param pointOffset = geometry.Positions.Count; }
private static ShipDNA RotateDNA_DoIt(ShipDNA dna, Quaternion rotation, Transform3D positionTransform) { ShipDNA retVal = UtilityCore.Clone(dna); foreach (ShipPartDNA part in retVal.PartsByLayer.SelectMany(o => o.Value)) { // Rotate the orientation //part.Orientation = part.Orientation.RotateBy(rotation); part.Orientation = rotation.RotateBy(part.Orientation); // Apply a transform to the poisition part.Position = positionTransform.Transform(part.Position); //TODO: See if these need to be rotated as well //part.Neurons; //part.ExternalLinks; //part.InternalLinks; } return retVal; }
public static Dodecahedron GetDodecahedron(double radius, Transform3D transform = null) { // This is 12 pentagons #region Points double t = (1d + Math.Sqrt(5d)) / 2d; double t1 = 1d / t; Point3D[] points = new Point3D[] { //(±1, ±1, ±1) new Point3D(1, 1, 1), // 0 new Point3D(1, 1, -1), // 1 new Point3D(1, -1, 1), // 2 new Point3D(1, -1, -1), // 3 new Point3D(-1, 1, 1), // 4 new Point3D(-1, 1, -1), // 5 new Point3D(-1, -1, 1), // 6 new Point3D(-1, -1, -1), // 7 //(0, ±1/φ, ±φ) new Point3D(0, t1, t), // 8 new Point3D(0, t1, -t), // 9 new Point3D(0, -t1, t), // 10 new Point3D(0, -t1, -t), // 11 //(±1/φ, ±φ, 0) new Point3D(t1, t, 0), // 12 new Point3D(t1, -t, 0), // 13 new Point3D(-t1, t, 0), // 14 new Point3D(-t1, -t, 0), // 15 //(±φ, 0, ±1/φ) new Point3D(t, 0, t1), // 16 new Point3D(t, 0, -t1), // 17 new Point3D(-t, 0, t1), // 18 new Point3D(-t, 0, -t1), // 19 }; double maxLength = points[8].ToVector().Length; // this represents the longest vector double ratio = radius / maxLength; points = points.Select(o => (o.ToVector() * ratio).ToPoint()).ToArray(); if (transform != null) { points = points.Select(o => transform.Transform(o)).ToArray(); } #endregion int[][] pentagonPolys = new int[][] { new int [] { 2, 10, 6, 15, 13 }, new int [] { 0, 8, 10, 2, 16 }, new int [] { 0, 12, 14, 4, 8 }, new int [] { 1, 9, 5, 14, 12 }, new int [] { 1, 17, 3, 11, 9 }, new int [] { 2, 13, 3, 17, 16 }, new int [] { 3, 13, 15, 7, 11 }, new int [] { 6, 18, 19, 7, 15 }, new int [] { 4, 18, 6, 10, 8 }, new int [] { 4, 14, 5, 19, 18 }, new int [] { 5, 9, 11, 7, 19 }, new int [] { 0, 16, 17, 1, 12 }, }; return new Dodecahedron(pentagonPolys, points); }
/// <summary> /// The export mesh. /// </summary> /// <param name="m"> /// The m. /// </param> /// <param name="t"> /// The t. /// </param> public void ExportMesh(MeshGeometry3D m, Transform3D t) { if (m == null) { throw new ArgumentNullException("m"); } if (t == null) { throw new ArgumentNullException("t"); } // mapping from local indices (0-based) to the obj file indices (1-based) var vertexIndexMap = new Dictionary<int, int>(); var textureIndexMap = new Dictionary<int, int>(); var normalIndexMap = new Dictionary<int, int>(); int index = 0; if (m.Positions != null) { foreach (var v in m.Positions) { vertexIndexMap.Add(index++, this.vertexIndex++); var p = t.Transform(v); this.writer.WriteLine( string.Format( CultureInfo.InvariantCulture, "v {0} {1} {2}", p.X, this.SwitchYZ ? p.Z : p.Y, this.SwitchYZ ? -p.Y : p.Z)); } this.writer.WriteLine(string.Format("# {0} vertices", index)); } if (m.TextureCoordinates != null) { index = 0; foreach (var vt in m.TextureCoordinates) { textureIndexMap.Add(index++, this.textureIndex++); this.writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "vt {0} {1}", vt.X, 1 - vt.Y)); } this.writer.WriteLine(string.Format("# {0} texture coordinates", index)); } if (m.Normals != null && ExportNormals) { index = 0; foreach (var vn in m.Normals) { normalIndexMap.Add(index++, this.normalIndex++); this.writer.WriteLine( string.Format(CultureInfo.InvariantCulture, "vn {0} {1} {2}", vn.X, vn.Y, vn.Z)); } this.writer.WriteLine(string.Format("# {0} normals", index)); } Func<int, string> formatIndices = i0 => { bool hasTextureIndex = textureIndexMap.ContainsKey(i0); bool hasNormalIndex = normalIndexMap.ContainsKey(i0); if (hasTextureIndex && hasNormalIndex) { return string.Format("{0}/{1}/{2}", vertexIndexMap[i0], textureIndexMap[i0], normalIndexMap[i0]); } if (hasTextureIndex) { return string.Format("{0}/{1}", vertexIndexMap[i0], textureIndexMap[i0]); } if (hasNormalIndex) { return string.Format("{0}//{1}", vertexIndexMap[i0], normalIndexMap[i0]); } return vertexIndexMap[i0].ToString(); }; if (m.TriangleIndices != null) { for (int i = 0; i < m.TriangleIndices.Count; i += 3) { int i0 = m.TriangleIndices[i]; int i1 = m.TriangleIndices[i + 1]; int i2 = m.TriangleIndices[i + 2]; this.writer.WriteLine("f {0} {1} {2}", formatIndices(i0), formatIndices(i1), formatIndices(i2)); } this.writer.WriteLine(string.Format("# {0} faces", m.TriangleIndices.Count / 3)); } this.writer.WriteLine(); }
public static Rhombicuboctahedron GetRhombicuboctahedron(double sizeX, double sizeY, double sizeZ, Transform3D transform = null) { #region Points double hX = sizeX / 2d; double hY = sizeY / 2d; double hZ = sizeZ / 2d; double sqrt2_1 = Math.Sqrt(2) + 1d; double sX = (sizeX / sqrt2_1) / 2d; // sX is half the width of one of the faces (the faces form an octogon) double sY = (sizeY / sqrt2_1) / 2d; double sZ = (sizeZ / sqrt2_1) / 2d; // Points Point3D[] points = new Point3D[] { // Top 4 new Point3D(sX, sY, hZ), // 0 new Point3D(sX, -sY, hZ), // 1 new Point3D(-sX, -sY, hZ), // 2 new Point3D(-sX, sY, hZ), // 3 // Top 8 new Point3D(hX, sY, sZ), // 4 new Point3D(hX, -sY, sZ), // 5 new Point3D(sX, -hY, sZ), // 6 new Point3D(-sX, -hY, sZ), // 7 new Point3D(-hX, -sY, sZ), // 8 new Point3D(-hX, sY, sZ), // 9 new Point3D(-sX, hY, sZ), // 10 new Point3D(sX, hY, sZ), // 11 // Bottom 8 new Point3D(hX, sY, -sZ), // 12 new Point3D(hX, -sY, -sZ), // 13 new Point3D(sX, -hY, -sZ), // 14 new Point3D(-sX, -hY, -sZ), // 15 new Point3D(-hX, -sY, -sZ), // 16 new Point3D(-hX, sY, -sZ), // 17 new Point3D(-sX, hY, -sZ), // 18 new Point3D(sX, hY, -sZ), // 19 // Bottom 4 new Point3D(sX, sY, -hZ), // 20 new Point3D(sX, -sY, -hZ), // 21 new Point3D(-sX, -sY, -hZ), // 22 new Point3D(-sX, sY, -hZ), // 23 }; if (transform != null) { points = points.Select(o => transform.Transform(o)).ToArray(); } #endregion int[][] squarePolys_Orth = new int[][] { new int[] { 0, 3, 2, 1 }, // Top new int[] { 4, 5, 13, 12 }, // Right new int[] { 6, 7, 15, 14 }, // Front new int[] { 8, 9, 17, 16 }, // Left new int[] { 10, 11, 19, 18 }, // Back new int[] { 20, 21, 22, 23 }, // Bottom }; int[][] squarePolys_Diag = new int[][] { // Top 4 angled new int[] {0, 1, 5, 4 }, new int[] { 1, 2, 7, 6 }, new int[] { 2, 3, 9, 8 }, new int[] { 0, 11, 10, 3 }, // Middle 4 angled new int[] { 4, 12, 19, 11 }, new int[] { 5, 6, 14, 13 }, new int[] { 7, 8, 16, 15 }, new int[] { 9, 10, 18, 17 }, // Bottom 4 angled new int[] { 12, 13, 21, 20 }, new int[] { 14, 15, 22, 21 }, new int[] { 16, 17, 23, 22 }, new int[] { 18, 19, 20, 23 }, }; TriangleIndexed[] triangles = new TriangleIndexed[] { // Top 4 new TriangleIndexed(0, 4, 11, points), new TriangleIndexed(1, 6, 5, points), new TriangleIndexed(2, 8, 7, points), new TriangleIndexed(3, 10, 9, points), // Bottom 4 new TriangleIndexed(12, 20, 19, points), new TriangleIndexed(13, 14, 21, points), new TriangleIndexed(15, 16, 22, points), new TriangleIndexed(17, 18, 23, points), }; return new Rhombicuboctahedron(squarePolys_Orth, squarePolys_Diag, triangles, points); }
public static Icosidodecahedron GetIcosidodecahedron(double radius, Transform3D transform = null) { //NOTE: Don't confuse this with an icosahedron. That is the more common object (made of equilateral triangles). //This object is made of pentagons and triangles. I'm just making this because it looks cool #region Points double t = (1d + Math.Sqrt(5d)) / 2d; double t2 = t / 2d; double t3 = (1d + t) / 2d; Point3D[] points = new Point3D[] { //(0,0,±φ) new Point3D(0, 0, t), // 0 new Point3D(0, 0, -t), // 1 //(0,±φ,0) new Point3D(0, t, 0), // 2 new Point3D(0, -t, 0), // 3 //(±φ,0,0) new Point3D(t, 0, 0), // 4 new Point3D(-t, 0, 0), // 5 //(±1/2, ±φ/2, ±(1+φ)/2) new Point3D(.5, t2, t3), // 6 new Point3D(.5, t2, -t3), // 7 new Point3D(.5, -t2, t3), // 8 new Point3D(.5, -t2, -t3), // 9 new Point3D(-.5, t2, t3), // 10 new Point3D(-.5, t2, -t3), // 11 new Point3D(-.5, -t2, t3), // 12 new Point3D(-.5, -t2, -t3), // 13 //(±φ/2, ±(1+φ)/2, ±1/2) new Point3D(t2, t3, .5), // 14 new Point3D(t2, t3, -.5), // 15 new Point3D(t2, -t3, .5), // 16 new Point3D(t2, -t3, -.5), // 17 new Point3D(-t2, t3, .5), // 18 new Point3D(-t2, t3, -.5), // 19 new Point3D(-t2, -t3, .5), // 20 new Point3D(-t2, -t3, -.5), // 21 //(±(1+φ)/2, ±1/2, ±φ/2) new Point3D(t3, .5, t2), // 22 new Point3D(t3, .5, -t2), // 23 new Point3D(t3, -.5, t2), // 24 new Point3D(t3, -.5, -t2), // 25 new Point3D(-t3, .5, t2), // 26 new Point3D(-t3, .5, -t2), // 27 new Point3D(-t3, -.5, t2), // 28 new Point3D(-t3, -.5, -t2), // 29 }; double maxLength = points[6].ToVector().Length; // this represents the longest vector double ratio = radius / maxLength; points = points.Select(o => (o.ToVector() * ratio).ToPoint()).ToArray(); if (transform != null) { points = points.Select(o => transform.Transform(o)).ToArray(); } #endregion int[][] pentagonPolys = new int[][] { new int [] { 0, 10, 26, 28, 12 }, new int [] { 26, 18, 19, 27, 5 }, new int [] { 5, 29, 21, 20, 28 }, new int [] { 10, 6, 14, 2, 18 }, new int [] { 3, 16, 8, 12, 20 }, new int [] { 0, 8, 24, 22, 6 }, new int [] { 9, 17, 3, 21, 13 }, new int [] { 27, 11, 1, 13, 29 }, new int [] { 4, 24, 16, 17, 25 }, new int [] { 1, 7, 23, 25, 9 }, new int [] { 4, 23, 15, 14, 22 }, new int [] { 2, 15, 7, 11, 19 }, }; TriangleIndexed[] triangles = new TriangleIndexed[] { new TriangleIndexed(0, 12, 8, points), new TriangleIndexed(0, 6, 10, points), new TriangleIndexed(10, 18, 26, points), new TriangleIndexed(5, 28, 26, points), new TriangleIndexed(12, 28, 20, points), new TriangleIndexed(3, 20, 21, points), new TriangleIndexed(8, 16, 24, points), new TriangleIndexed(3, 17, 16, points), new TriangleIndexed(9, 25, 17, points), new TriangleIndexed(4, 25, 23, points), new TriangleIndexed(4, 22, 24, points), new TriangleIndexed(13, 21, 29, points), new TriangleIndexed(1, 9, 13, points), new TriangleIndexed(1, 11, 7, points), new TriangleIndexed(11, 27, 19, points), new TriangleIndexed(5, 27, 29, points), new TriangleIndexed(6, 22, 14, points), new TriangleIndexed(2, 14, 15, points), new TriangleIndexed(2, 19, 18, points), new TriangleIndexed(7, 15, 23, points), }; return new Icosidodecahedron(pentagonPolys, triangles, points); }
private static void EndCap_DomeSoft(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, Transform3D normalTransform, TubeRingDome ring, double capHeight, bool isFirst) { // NOTE: There is one more than NumSegmentsPhi Point[] pointsPhi = ring.GetUnitPointsPhi(ring.NumSegmentsPhi); #region Positions/Normals //for (int phiCntr = 0; phiCntr < numSegmentsPhi; phiCntr++) // The top point will be added after this loop for (int phiCntr = pointsPhi.Length - 1; phiCntr > 0; phiCntr--) { if (!isFirst && ring.MergeNormalWithPrevIfSoft) { // Just reuse the points/normals from the previous ring continue; } for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++) { // Phi points are going from bottom to equator. // pointsTheta are already the length they are supposed to be (not nessassarily a unit circle) Point3D point = new Point3D( pointsTheta[thetaCntr].X * pointsPhi[phiCntr].Y, pointsTheta[thetaCntr].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); if (ring.MergeNormalWithPrevIfSoft) { //TODO: Merge the normal with rotateAngleForPerp (see the GetCone method) throw new ApplicationException("finish this"); } else { geometry.Normals.Add(normalTransform.Transform(point).ToVector().ToUnit()); // the normal is the same as the point for a sphere (but no tranlate transform) } } } // This is north pole point geometry.Positions.Add(transform.Transform(new Point3D(0, 0, capHeight))); geometry.Normals.Add(normalTransform.Transform(new Vector3D(0, 0, capHeight < 0 ? -1 : 1))); // they can enter a negative height (which would make a bowl) #endregion #region Triangles - Rings int zOffsetBottom = pointOffset; int zOffsetTop; for (int phiCntr = 0; phiCntr < ring.NumSegmentsPhi - 1; phiCntr++) // The top cone will be added after this loop { zOffsetTop = zOffsetBottom + pointsTheta.Length; for (int thetaCntr = 0; thetaCntr < pointsTheta.Length - 1; thetaCntr++) { // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 1); geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1); } // Connecting the last 2 points to the first 2 // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0); geometry.TriangleIndices.Add(zOffsetTop); // wrapping back around geometry.TriangleIndices.Add(zOffsetTop + (pointsTheta.Length - 1) + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0); geometry.TriangleIndices.Add(zOffsetBottom); geometry.TriangleIndices.Add(zOffsetTop); // Prep for the next ring zOffsetBottom = zOffsetTop; } #endregion #region Triangles - Cap int topIndex = geometry.Positions.Count - 1; for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++) { geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + cntr + 1); geometry.TriangleIndices.Add(topIndex); } // The last triangle links back to zero geometry.TriangleIndices.Add(zOffsetBottom + pointsTheta.Length - 1 + 0); geometry.TriangleIndices.Add(zOffsetBottom + 0); geometry.TriangleIndices.Add(topIndex); //for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++) //{ // geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0); // geometry.TriangleIndices.Add(topIndex); // geometry.TriangleIndices.Add(zOffsetBottom + cntr + 1); //} //// The last triangle links back to zero //geometry.TriangleIndices.Add(zOffsetBottom + pointsTheta.Length - 1 + 0); //geometry.TriangleIndices.Add(topIndex); //geometry.TriangleIndices.Add(zOffsetBottom + 0); #endregion pointOffset = geometry.Positions.Count; }
private static void Middle_TubeHard(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Transform3D transform, int numSides, TubeRingRegularPolygon ring1, TubeRingRegularPolygon ring2, double curZ) { Point[] points = Math2D.GetCircle_Cached(numSides); int zOffset = pointOffset; for (int cntr = 0; cntr < numSides - 1; cntr++) { // Top/Left triangle (each triangle gets its own 3 points) geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * ring1.RadiusX, points[cntr].Y * ring1.RadiusY, curZ))); geometry.Positions.Add(transform.Transform(new Point3D(points[cntr + 1].X * ring2.RadiusX, points[cntr + 1].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * ring2.RadiusX, points[cntr].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); Vector3D normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); zOffset += 3; // Bottom/Right triangle geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * ring1.RadiusX, points[cntr].Y * ring1.RadiusY, curZ))); geometry.Positions.Add(transform.Transform(new Point3D(points[cntr + 1].X * ring1.RadiusX, points[cntr + 1].Y * ring1.RadiusY, curZ))); geometry.Positions.Add(transform.Transform(new Point3D(points[cntr + 1].X * ring2.RadiusX, points[cntr + 1].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); zOffset += 3; } // Connecting the last 2 points to the first 2 // Top/Left triangle geometry.Positions.Add(transform.Transform(new Point3D(points[numSides - 1].X * ring1.RadiusX, points[numSides - 1].Y * ring1.RadiusY, curZ))); geometry.Positions.Add(transform.Transform(new Point3D(points[0].X * ring2.RadiusX, points[0].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); geometry.Positions.Add(transform.Transform(new Point3D(points[numSides - 1].X * ring2.RadiusX, points[numSides - 1].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); Vector3D normal2 = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal2); // the normals point straight out of the face geometry.Normals.Add(normal2); geometry.Normals.Add(normal2); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); zOffset += 3; // Bottom/Right triangle geometry.Positions.Add(transform.Transform(new Point3D(points[numSides - 1].X * ring1.RadiusX, points[numSides - 1].Y * ring1.RadiusY, curZ))); geometry.Positions.Add(transform.Transform(new Point3D(points[0].X * ring1.RadiusX, points[0].Y * ring1.RadiusY, curZ))); geometry.Positions.Add(transform.Transform(new Point3D(points[0].X * ring2.RadiusX, points[0].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); normal2 = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal2); // the normals point straight out of the face geometry.Normals.Add(normal2); geometry.Normals.Add(normal2); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); // Update ref param pointOffset = geometry.Positions.Count; }
private static void Middle_TubeSoft(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Transform3D transform, int numSides, TubeRingRegularPolygon ring1, TubeRingRegularPolygon ring2, double curZ) { if (ring1.MergeNormalWithPrevIfSoft || ring2.MergeNormalWithPrevIfSoft) { throw new ApplicationException("finish this"); } Point[] points = Math2D.GetCircle_Cached(numSides); #region Points/Normals //TODO: Don't add the bottom ring's points, only the top // Ring 1 for (int cntr = 0; cntr < numSides; cntr++) { geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * ring1.RadiusX, points[cntr].Y * ring1.RadiusY, curZ))); geometry.Normals.Add(transform.Transform(new Vector3D(points[cntr].X * ring1.RadiusX, points[cntr].Y * ring1.RadiusY, 0d).ToUnit())); // the normals point straight out of the side } // Ring 2 for (int cntr = 0; cntr < numSides; cntr++) { geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * ring2.RadiusX, points[cntr].Y * ring2.RadiusY, curZ + ring2.DistFromPrevRing))); geometry.Normals.Add(transform.Transform(new Vector3D(points[cntr].X * ring2.RadiusX, points[cntr].Y * ring2.RadiusY, 0d).ToUnit())); // the normals point straight out of the side } #endregion #region Triangles int zOffsetBottom = pointOffset; int zOffsetTop = zOffsetBottom + numSides; for (int cntr = 0; cntr < numSides - 1; cntr++) { // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0); geometry.TriangleIndices.Add(zOffsetTop + cntr + 1); geometry.TriangleIndices.Add(zOffsetTop + cntr + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0); geometry.TriangleIndices.Add(zOffsetBottom + cntr + 1); geometry.TriangleIndices.Add(zOffsetTop + cntr + 1); } // Connecting the last 2 points to the first 2 // Top/Left triangle geometry.TriangleIndices.Add(zOffsetBottom + (numSides - 1) + 0); geometry.TriangleIndices.Add(zOffsetTop); // wrapping back around geometry.TriangleIndices.Add(zOffsetTop + (numSides - 1) + 0); // Bottom/Right triangle geometry.TriangleIndices.Add(zOffsetBottom + (numSides - 1) + 0); geometry.TriangleIndices.Add(zOffsetBottom); geometry.TriangleIndices.Add(zOffsetTop); #endregion pointOffset = geometry.Positions.Count; }
private static void EndCap_DomeHard(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, Transform3D normalTransform, TubeRingDome ring, double capHeight, bool isFirst) { // NOTE: There is one more than NumSegmentsPhi Point[] pointsPhi = ring.GetUnitPointsPhi(ring.NumSegmentsPhi); Point3D point; Vector3D normal; int zOffset = pointOffset; #region Triangles - Rings for (int phiCntr = 1; phiCntr < pointsPhi.Length - 1; phiCntr++) // The top cone will be added after this loop { for (int thetaCntr = 0; thetaCntr < pointsTheta.Length - 1; thetaCntr++) { // Phi points are going from bottom to equator <----------- NO????????? // Phi points are going from the equator to the top // pointsTheta are already the length they are supposed to be (not nessassarily a unit circle) #region Top/Left triangle point = new Point3D( pointsTheta[thetaCntr].X * pointsPhi[phiCntr].Y, pointsTheta[thetaCntr].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[thetaCntr].X * pointsPhi[phiCntr + 1].Y, pointsTheta[thetaCntr].Y * pointsPhi[phiCntr + 1].Y, capHeight * pointsPhi[phiCntr + 1].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[thetaCntr + 1].X * pointsPhi[phiCntr + 1].Y, pointsTheta[thetaCntr + 1].Y * pointsPhi[phiCntr + 1].Y, capHeight * pointsPhi[phiCntr + 1].X); geometry.Positions.Add(transform.Transform(point)); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); #endregion zOffset += 3; #region Bottom/Right triangle point = new Point3D( pointsTheta[thetaCntr].X * pointsPhi[phiCntr].Y, pointsTheta[thetaCntr].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[thetaCntr + 1].X * pointsPhi[phiCntr + 1].Y, pointsTheta[thetaCntr + 1].Y * pointsPhi[phiCntr + 1].Y, capHeight * pointsPhi[phiCntr + 1].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[thetaCntr + 1].X * pointsPhi[phiCntr].Y, pointsTheta[thetaCntr + 1].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); #endregion zOffset += 3; } // Connecting the last 2 points to the first 2 #region Top/Left triangle point = new Point3D( pointsTheta[pointsTheta.Length - 1].X * pointsPhi[phiCntr].Y, pointsTheta[pointsTheta.Length - 1].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[pointsTheta.Length - 1].X * pointsPhi[phiCntr + 1].Y, pointsTheta[pointsTheta.Length - 1].Y * pointsPhi[phiCntr + 1].Y, capHeight * pointsPhi[phiCntr + 1].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[0].X * pointsPhi[phiCntr + 1].Y, // wrapping theta back around pointsTheta[0].Y * pointsPhi[phiCntr + 1].Y, capHeight * pointsPhi[phiCntr + 1].X); geometry.Positions.Add(transform.Transform(point)); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); #endregion zOffset += 3; #region Bottom/Right triangle point = new Point3D( pointsTheta[pointsTheta.Length - 1].X * pointsPhi[phiCntr].Y, pointsTheta[pointsTheta.Length - 1].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[0].X * pointsPhi[phiCntr + 1].Y, pointsTheta[0].Y * pointsPhi[phiCntr + 1].Y, capHeight * pointsPhi[phiCntr + 1].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[0].X * pointsPhi[phiCntr].Y, pointsTheta[0].Y * pointsPhi[phiCntr].Y, capHeight * pointsPhi[phiCntr].X); geometry.Positions.Add(transform.Transform(point)); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); #endregion zOffset += 3; } #endregion #region Triangles - Cap // This is basically the same idea as EndCap_ConeHard, except for the extra phi bits Point3D topPoint = transform.Transform(new Point3D(0, 0, capHeight)); for (int thetaCntr = 0; thetaCntr < pointsTheta.Length - 1; thetaCntr++) { point = new Point3D( pointsTheta[thetaCntr].X * pointsPhi[1].Y, pointsTheta[thetaCntr].Y * pointsPhi[1].Y, capHeight * pointsPhi[1].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[thetaCntr + 1].X * pointsPhi[1].Y, pointsTheta[thetaCntr + 1].Y * pointsPhi[1].Y, capHeight * pointsPhi[1].X); geometry.Positions.Add(transform.Transform(point)); geometry.Positions.Add(topPoint); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); zOffset += 3; } // The last triangle links back to zero point = new Point3D( pointsTheta[pointsTheta.Length - 1].X * pointsPhi[1].Y, pointsTheta[pointsTheta.Length - 1].Y * pointsPhi[1].Y, capHeight * pointsPhi[1].X); geometry.Positions.Add(transform.Transform(point)); point = new Point3D( pointsTheta[0].X * pointsPhi[1].Y, pointsTheta[0].Y * pointsPhi[1].Y, capHeight * pointsPhi[1].X); geometry.Positions.Add(transform.Transform(point)); geometry.Positions.Add(topPoint); normal = GetNormal(geometry.Positions[zOffset + 0], geometry.Positions[zOffset + 1], geometry.Positions[zOffset + 2]); geometry.Normals.Add(normal); // the normals point straight out of the face geometry.Normals.Add(normal); geometry.Normals.Add(normal); geometry.TriangleIndices.Add(zOffset + 0); geometry.TriangleIndices.Add(zOffset + 1); geometry.TriangleIndices.Add(zOffset + 2); zOffset += 3; #endregion pointOffset = geometry.Positions.Count; }
private static void GetMeshSprtFace_OLD(ref int pointOffset, MeshGeometry3D mesh, Transform3D transform, double halfWidth, double halfHeight, double tip) { // Bottom mesh.Positions.Add(transform.Transform(new Point3D(-halfWidth, -halfHeight, 0))); // left bottom mesh.Positions.Add(transform.Transform(new Point3D(halfWidth, -halfHeight, 0))); // right bottom mesh.Positions.Add(transform.Transform(new Point3D(0, 0, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; // Right mesh.Positions.Add(transform.Transform(new Point3D(halfWidth, -halfHeight, 0))); // right bottom mesh.Positions.Add(transform.Transform(new Point3D(halfWidth, halfHeight, 0))); // right top mesh.Positions.Add(transform.Transform(new Point3D(0, 0, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; // Top mesh.Positions.Add(transform.Transform(new Point3D(halfWidth, halfHeight, 0))); // right top mesh.Positions.Add(transform.Transform(new Point3D(-halfWidth, halfHeight, 0))); // left top mesh.Positions.Add(transform.Transform(new Point3D(0, 0, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; // Left mesh.Positions.Add(transform.Transform(new Point3D(-halfWidth, halfHeight, 0))); // left top mesh.Positions.Add(transform.Transform(new Point3D(-halfWidth, -halfHeight, 0))); // left bottom mesh.Positions.Add(transform.Transform(new Point3D(0, 0, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; }
private static void EndCap_ConeSoft(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, Transform3D normalTransform, TubeRingPoint ring, double capHeight, bool isFirst) { #region Positions/Normals if (isFirst || !ring.MergeNormalWithPrevIfSoft) { for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++) { Point3D point = new Point3D(pointsTheta[thetaCntr].X, pointsTheta[thetaCntr].Y, 0d); geometry.Positions.Add(transform.Transform(point)); geometry.Normals.Add(normalTransform.Transform(point).ToVector().ToUnit()); // the normal is the same as the point for a sphere (but no tranlate transform) } } // Cone tip geometry.Positions.Add(transform.Transform(new Point3D(0, 0, capHeight))); geometry.Normals.Add(transform.Transform(new Vector3D(0, 0, capHeight < 0 ? -1 : 1))); // they can pass in a negative cap height #endregion #region Triangles int topIndex = geometry.Positions.Count - 1; for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++) { geometry.TriangleIndices.Add(pointOffset + cntr + 0); geometry.TriangleIndices.Add(pointOffset + cntr + 1); geometry.TriangleIndices.Add(topIndex); } // The last triangle links back to zero geometry.TriangleIndices.Add(pointOffset + pointsTheta.Length - 1 + 0); geometry.TriangleIndices.Add(pointOffset + 0); geometry.TriangleIndices.Add(topIndex); #endregion pointOffset = geometry.Positions.Count; }
private static void GetCylinder_AlongXSprtEndCap(ref int pointOffset, MeshGeometry3D geometry, Point[] points, Vector3D normal, double radiusX, double radiusY, double z, Transform3D transform) { //NOTE: This expects the cylinder's height to be along z, but will transform the points before commiting them to the geometry //TODO: This was copied from GetMultiRingedTubeSprtEndCap, make a good generic method #region Add points and normals for (int cntr = 0; cntr < points.Length; cntr++) { geometry.Positions.Add(transform.Transform(new Point3D(points[cntr].X * radiusX, points[cntr].Y * radiusY, z))); geometry.Normals.Add(transform.Transform(normal)); } #endregion #region Add the triangles // Start with 0,1,2 geometry.TriangleIndices.Add(pointOffset + 0); geometry.TriangleIndices.Add(pointOffset + 1); geometry.TriangleIndices.Add(pointOffset + 2); int lowerIndex = 2; int upperIndex = points.Length - 1; int lastUsedIndex = 0; bool shouldBumpLower = true; // Do the rest of the triangles while (lowerIndex < upperIndex) { geometry.TriangleIndices.Add(pointOffset + lowerIndex); geometry.TriangleIndices.Add(pointOffset + upperIndex); geometry.TriangleIndices.Add(pointOffset + lastUsedIndex); if (shouldBumpLower) { lastUsedIndex = lowerIndex; lowerIndex++; } else { lastUsedIndex = upperIndex; upperIndex--; } shouldBumpLower = !shouldBumpLower; } #endregion pointOffset += points.Length; }
private static void EndCap_PlateSoft(ref int pointOffset, ref double[] rotateAnglesForPerp, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, Transform3D normalTransform, TubeRingBase ring, bool isFirst) { #region Positions/Normals if (isFirst || !ring.MergeNormalWithPrevIfSoft) { for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++) { Point3D point = new Point3D(pointsTheta[thetaCntr].X, pointsTheta[thetaCntr].Y, 0d); geometry.Positions.Add(transform.Transform(point)); Vector3D normal; if (ring.MergeNormalWithPrevIfSoft) { //normal = point.ToVector(); // this isn't right throw new ApplicationException("finish this"); } else { normal = new Vector3D(0, 0, 1); } geometry.Normals.Add(normalTransform.Transform(normal).ToUnit()); } } #endregion #region Add the triangles // Start with 0,1,2 geometry.TriangleIndices.Add(pointOffset + 0); geometry.TriangleIndices.Add(pointOffset + 1); geometry.TriangleIndices.Add(pointOffset + 2); int lowerIndex = 2; int upperIndex = pointsTheta.Length - 1; int lastUsedIndex = 0; bool shouldBumpLower = true; // Do the rest of the triangles while (lowerIndex < upperIndex) { geometry.TriangleIndices.Add(pointOffset + lowerIndex); geometry.TriangleIndices.Add(pointOffset + upperIndex); geometry.TriangleIndices.Add(pointOffset + lastUsedIndex); if (shouldBumpLower) { lastUsedIndex = lowerIndex; lowerIndex++; } else { lastUsedIndex = upperIndex; upperIndex--; } shouldBumpLower = !shouldBumpLower; } #endregion pointOffset = geometry.Positions.Count; }
public static MeshGeometry3D GetRing(int numSides, double innerRadius, double outerRadius, double height, Transform3D transform = null, bool includeInnerRingFaces = true, bool includeOuterRingFaces = true) { MeshGeometry3D retVal = new MeshGeometry3D(); if (transform == null) { transform = Transform3D.Identity; } Point[] points = Math2D.GetCircle_Cached(numSides); double halfHeight = height * .5d; int pointOffset = 0; int zOffsetBottom, zOffsetTop; #region Outer Ring #region Positions/Normals for (int cntr = 0; cntr < numSides; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * outerRadius, points[cntr].Y * outerRadius, -halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X * outerRadius, points[cntr].Y * outerRadius, 0d).ToUnit())); // the normals point straight out of the side } for (int cntr = 0; cntr < numSides; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * outerRadius, points[cntr].Y * outerRadius, halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X * outerRadius, points[cntr].Y * outerRadius, 0d).ToUnit())); // the normals point straight out of the side } #endregion if (includeOuterRingFaces) { #region Triangles zOffsetBottom = pointOffset; zOffsetTop = zOffsetBottom + numSides; for (int cntr = 0; cntr < numSides - 1; cntr++) { // Top/Left triangle retVal.TriangleIndices.Add(zOffsetBottom + cntr + 0); retVal.TriangleIndices.Add(zOffsetTop + cntr + 1); retVal.TriangleIndices.Add(zOffsetTop + cntr + 0); // Bottom/Right triangle retVal.TriangleIndices.Add(zOffsetBottom + cntr + 0); retVal.TriangleIndices.Add(zOffsetBottom + cntr + 1); retVal.TriangleIndices.Add(zOffsetTop + cntr + 1); } // Connecting the last 2 points to the first 2 // Top/Left triangle retVal.TriangleIndices.Add(zOffsetBottom + (numSides - 1) + 0); retVal.TriangleIndices.Add(zOffsetTop); // wrapping back around retVal.TriangleIndices.Add(zOffsetTop + (numSides - 1) + 0); // Bottom/Right triangle retVal.TriangleIndices.Add(zOffsetBottom + (numSides - 1) + 0); retVal.TriangleIndices.Add(zOffsetBottom); retVal.TriangleIndices.Add(zOffsetTop); #endregion } pointOffset = retVal.Positions.Count; #endregion #region Inner Ring #region Positions/Normals for (int cntr = 0; cntr < numSides; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * innerRadius, points[cntr].Y * innerRadius, -halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X * innerRadius, points[cntr].Y * innerRadius, 0d).ToUnit() * -1d)); // the normals point straight in from the side } for (int cntr = 0; cntr < numSides; cntr++) { retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * innerRadius, points[cntr].Y * innerRadius, halfHeight))); retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X * innerRadius, points[cntr].Y * innerRadius, 0d).ToUnit() * -1d)); // the normals point straight in from the side } #endregion if (includeInnerRingFaces) { #region Triangles zOffsetBottom = pointOffset; zOffsetTop = zOffsetBottom + numSides; for (int cntr = 0; cntr < numSides - 1; cntr++) { // Top/Left triangle retVal.TriangleIndices.Add(zOffsetBottom + cntr + 0); retVal.TriangleIndices.Add(zOffsetTop + cntr + 0); retVal.TriangleIndices.Add(zOffsetTop + cntr + 1); // Bottom/Right triangle retVal.TriangleIndices.Add(zOffsetBottom + cntr + 0); retVal.TriangleIndices.Add(zOffsetTop + cntr + 1); retVal.TriangleIndices.Add(zOffsetBottom + cntr + 1); } // Connecting the last 2 points to the first 2 // Top/Left triangle retVal.TriangleIndices.Add(zOffsetBottom + (numSides - 1) + 0); retVal.TriangleIndices.Add(zOffsetTop + (numSides - 1) + 0); retVal.TriangleIndices.Add(zOffsetTop); // wrapping back around // Bottom/Right triangle retVal.TriangleIndices.Add(zOffsetBottom + (numSides - 1) + 0); retVal.TriangleIndices.Add(zOffsetTop); retVal.TriangleIndices.Add(zOffsetBottom); #endregion } pointOffset = retVal.Positions.Count; #endregion #region Top Cap Transform3DGroup capTransform = new Transform3DGroup(); capTransform.Children.Add(new TranslateTransform3D(0, 0, halfHeight)); capTransform.Children.Add(transform); GetRingSprtCap(ref pointOffset, retVal, capTransform, points, numSides, innerRadius, outerRadius); #endregion #region Bottom Cap capTransform = new Transform3DGroup(); capTransform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 180d))); capTransform.Children.Add(new TranslateTransform3D(0, 0, -halfHeight)); capTransform.Children.Add(transform); GetRingSprtCap(ref pointOffset, retVal, capTransform, points, numSides, innerRadius, outerRadius); #endregion // Exit Function return retVal; }
public static TruncatedIcosahedron GetTruncatedIcosahedron(double radius, Transform3D transform = null) { #region Points double t = (1d + Math.Sqrt(5d)) / 2d; double t2 = t * 2d; double t3 = t * 3d; double tA = 1d + (2d * t); double tB = 2d + t; // Length compare: // t3 4.8541019662496847 // tA 4.23606797749979 // tB 3.6180339887498949 // t2 3.23606797749979 // 2 2 // t 1.6180339887498949 // 1 1 // 0 0 Point3D[] points = new Point3D[] { //------------------------------------------------- X axis //(±3φ, 0, ±1) new Point3D(t3, 0, 1), // 0 new Point3D(-t3, 0, 1), new Point3D(t3, 0, -1), new Point3D(-t3, 0, -1), // 3 //(±(1+2φ), ±φ, ±2) new Point3D(tA, t, 2), // 4 new Point3D(tA, -t, 2), new Point3D(-tA, t, 2), new Point3D(-tA, -t, 2), new Point3D(tA, t, -2), new Point3D(tA, -t, -2), new Point3D(-tA, t, -2), new Point3D(-tA, -t, -2), // 11 //(±(2+φ), ±2φ, ±1) new Point3D(tB, t2, 1), // 12 new Point3D(tB, t2, -1), new Point3D(tB, -t2, 1), new Point3D(tB, -t2, -1), new Point3D(-tB, t2, 1), new Point3D(-tB, t2, -1), new Point3D(-tB, -t2, 1), new Point3D(-tB, -t2, -1), // 19 //------------------------------------------------- Y axis //(±1, ±3φ, 0) new Point3D(1, t3, 0), // 20 new Point3D(1, -t3, 0), new Point3D(-1, t3, 0), new Point3D(-1, -t3, 0), // 23 //(±2, ±(1+2φ), ±φ) new Point3D(2, tA, t), // 24 new Point3D(2, tA, -t), new Point3D(2, -tA, t), new Point3D(2, -tA, -t), new Point3D(-2, tA, t), new Point3D(-2, tA, -t), new Point3D(-2, -tA, t), new Point3D(-2, -tA, -t), // 31 //(±1, ±(2+φ), ±2φ) new Point3D(1, tB, t2), // 32 new Point3D(1, tB, -t2), new Point3D(1, -tB, t2), new Point3D(1, -tB, -t2), new Point3D(-1, tB, t2), new Point3D(-1, tB, -t2), new Point3D(-1, -tB, t2), new Point3D(-1, -tB, -t2), // 39 //------------------------------------------------- Z axis //(0, ±1, ±3φ) new Point3D(0, 1, t3), // 40 new Point3D(0, 1, -t3), new Point3D(0, -1, t3), new Point3D(0, -1, -t3), // 43 //(±φ, ±2, ±(1+2φ)) new Point3D(t, 2, tA), // 44 new Point3D(-t, 2, tA), new Point3D(t, 2, -tA), new Point3D(-t, 2, -tA), new Point3D(t, -2, tA), new Point3D(-t, -2, tA), new Point3D(t, -2, -tA), new Point3D(-t, -2, -tA), // 51 //(±2φ, ±1, ±(2+φ)) new Point3D(t2, 1, tB), // 52 new Point3D(t2, 1, -tB), new Point3D(t2, -1, tB), new Point3D(t2, -1, -tB), new Point3D(-t2, 1, tB), new Point3D(-t2, 1, -tB), new Point3D(-t2, -1, tB), new Point3D(-t2, -1, -tB), // 59 }; double maxLength = points[0].ToVector().Length; double ratio = radius / maxLength; points = points.Select(o => (o.ToVector() * ratio).ToPoint()).ToArray(); if (transform != null) { points = points.Select(o => transform.Transform(o)).ToArray(); } #endregion // Pentagons int[][] pentagonPolys = new int[][] { new int [] { 40, 44, 32, 36, 45 }, new int [] { 42, 49, 38, 34, 48 }, new int [] { 41, 47, 37, 33, 46 }, new int [] { 43, 50, 35, 39, 51 }, new int [] { 1, 7, 58, 56, 6 }, new int [] { 0, 4, 52, 54, 5 }, new int [] { 3, 10, 57, 59, 11 }, new int [] { 2, 9, 55, 53, 8 }, new int [] { 18, 19, 31, 23, 30 }, new int [] { 14, 26, 21, 27, 15 }, new int [] { 12, 13, 25, 20, 24 }, new int [] { 16, 28, 22, 29, 17 }, }; // Hexagons int[][] hexagonPolys = new int[][] { new int [] { 40, 45, 56, 58, 49, 42 }, new int [] { 40, 42, 48, 54, 52, 44 }, new int [] { 41, 43, 51, 59, 57, 47 }, new int [] { 41, 46, 53, 55, 50, 43 }, new int [] { 1, 6, 16, 17, 10, 3 }, new int [] { 1, 3, 11, 19, 18, 7 }, new int [] { 0, 2, 8, 13, 12, 4 }, new int [] { 0, 5, 14, 15, 9, 2 }, new int [] { 34, 26, 14, 5, 54, 48 }, new int [] { 32, 44, 52, 4, 12, 24 }, new int [] { 38, 49, 58, 7, 18, 30 }, new int [] { 33, 25, 13, 8, 53, 46 }, new int [] { 35, 50, 55, 9, 15, 27 }, new int [] { 36, 28, 16, 6, 56, 45 }, new int [] { 39, 31, 19, 11, 59, 51 }, new int [] { 37, 47, 57, 10, 17, 29 }, new int [] { 20, 25, 33, 37, 29, 22 }, new int [] { 20, 22, 28, 36, 32, 24 }, new int [] { 21, 26, 34, 38, 30, 23 }, new int [] { 21, 23, 31, 39, 35, 27 }, }; return new TruncatedIcosahedron(pentagonPolys, hexagonPolys, points); }
internal static void GetMeshFace(ref int pointOffset, MeshGeometry3D mesh, Transform3D transform, double halfWidth, double halfHeight, double tip, int numPyramids) { double faceWidth = halfWidth / numPyramids; double faceHeight = halfHeight / numPyramids; int to = numPyramids - 1; int from = to * -1; for (int x = from; x <= to; x += 2) { for (int y = from; y <= to; y += 2) { double offsetX = faceWidth * x; double offsetY = faceHeight * y; // Bottom mesh.Positions.Add(transform.Transform(new Point3D(offsetX - faceWidth, offsetY - faceHeight, 0))); // left bottom mesh.Positions.Add(transform.Transform(new Point3D(offsetX + faceWidth, offsetY - faceHeight, 0))); // right bottom mesh.Positions.Add(transform.Transform(new Point3D(offsetX, offsetY, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; // Right mesh.Positions.Add(transform.Transform(new Point3D(offsetX + faceWidth, offsetY - faceHeight, 0))); // right bottom mesh.Positions.Add(transform.Transform(new Point3D(offsetX + faceWidth, offsetY + faceHeight, 0))); // right top mesh.Positions.Add(transform.Transform(new Point3D(offsetX, offsetY, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; // Top mesh.Positions.Add(transform.Transform(new Point3D(offsetX + faceWidth, offsetY + faceHeight, 0))); // right top mesh.Positions.Add(transform.Transform(new Point3D(offsetX - faceWidth, offsetY + faceHeight, 0))); // left top mesh.Positions.Add(transform.Transform(new Point3D(offsetX, offsetY, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; // Left mesh.Positions.Add(transform.Transform(new Point3D(offsetX - faceWidth, offsetY + faceHeight, 0))); // left top mesh.Positions.Add(transform.Transform(new Point3D(offsetX - faceWidth, offsetY - faceHeight, 0))); // left bottom mesh.Positions.Add(transform.Transform(new Point3D(offsetX, offsetY, tip))); // tip mesh.TriangleIndices.Add(pointOffset + 0); mesh.TriangleIndices.Add(pointOffset + 1); mesh.TriangleIndices.Add(pointOffset + 2); pointOffset += 3; } } }
/// <summary> /// Volumes are calculated across axis where they are whole numbers (rounded to 0 decimal places). /// </summary> /// <param name="modelFile"></param> /// <param name="scaleMultiplyierX"></param> /// <param name="scaleMultiplyierY"></param> /// <param name="scaleMultiplyierZ"></param> /// <param name="transform"></param> /// <param name="traceType"></param> /// <param name="resetProgress"></param> /// <param name="incrementProgress"></param> /// <returns></returns> public static CubeType[][][] ReadModelVolmetic(string modelFile, double scaleMultiplyierX, double scaleMultiplyierY, double scaleMultiplyierZ, Transform3D transform, ModelTraceVoxel traceType, Action<double, double> resetProgress, Action incrementProgress) { var model = MeshHelper.Load(modelFile, ignoreErrors: true); // How far to check in from the proposed Volumetric edge. // This number is just made up, but small enough that it still represents the corner edge of the Volumetric space. // But still large enough that it isn't the exact corner. const double offset = 0.00000456f; if (scaleMultiplyierX > 0 && scaleMultiplyierY > 0 && scaleMultiplyierZ > 0 && scaleMultiplyierX != 1.0f && scaleMultiplyierY != 1.0f && scaleMultiplyierZ != 1.0f) { model.TransformScale(scaleMultiplyierX, scaleMultiplyierY, scaleMultiplyierZ); } var tbounds = model.Bounds; if (transform != null) tbounds = transform.TransformBounds(tbounds); var xMin = (int)Math.Floor(tbounds.X); var yMin = (int)Math.Floor(tbounds.Y); var zMin = (int)Math.Floor(tbounds.Z); var xMax = (int)Math.Ceiling(tbounds.X + tbounds.SizeX); var yMax = (int)Math.Ceiling(tbounds.Y + tbounds.SizeY); var zMax = (int)Math.Ceiling(tbounds.Z + tbounds.SizeZ); var xCount = xMax - xMin; var yCount = yMax - yMin; var zCount = zMax - zMin; var ccubic = ArrayHelper.Create<CubeType>(xCount, yCount, zCount); if (resetProgress != null) { double count = (from GeometryModel3D gm in model.Children select gm.Geometry as MeshGeometry3D).Aggregate<MeshGeometry3D, double>(0, (current, g) => current + (g.TriangleIndices.Count / 3)); if (traceType == ModelTraceVoxel.ThinSmoothed || traceType == ModelTraceVoxel.ThickSmoothedUp) { count += (xCount * yCount * zCount * 3); } resetProgress.Invoke(0, count); } #region basic ray trace of every individual triangle. foreach (var model3D in model.Children) { var gm = (GeometryModel3D)model3D; var g = gm.Geometry as MeshGeometry3D; var materials = gm.Material as MaterialGroup; System.Windows.Media.Color color = Colors.Transparent; if (materials != null) { var material = materials.Children.OfType<DiffuseMaterial>().FirstOrDefault(); if (material != null && material != null && material.Brush is SolidColorBrush) { color = ((SolidColorBrush)material.Brush).Color; } } for (var t = 0; t < g.TriangleIndices.Count; t += 3) { if (incrementProgress != null) { incrementProgress.Invoke(); } var p1 = g.Positions[g.TriangleIndices[t]]; var p2 = g.Positions[g.TriangleIndices[t + 1]]; var p3 = g.Positions[g.TriangleIndices[t + 2]]; if (transform != null) { p1 = transform.Transform(p1); p2 = transform.Transform(p2); p3 = transform.Transform(p3); } var minBound = MeshHelper.Min(p1, p2, p3).Floor(); var maxBound = MeshHelper.Max(p1, p2, p3).Ceiling(); Point3D[] rays; for (var y = minBound.Y; y < maxBound.Y; y++) { for (var z = minBound.Z; z < maxBound.Z; z++) { if (traceType == ModelTraceVoxel.Thin || traceType == ModelTraceVoxel.ThinSmoothed) { rays = new Point3D[] // 1 point ray trace in the center. { new Point3D(xMin, y + 0.5 + offset, z + 0.5 + offset), new Point3D(xMax, y + 0.5 + offset, z + 0.5 + offset) }; } else { rays = new Point3D[] // 4 point ray trace within each corner of the expected Volumetric cube. { new Point3D(xMin, y + offset, z + offset), new Point3D(xMax, y + offset, z + offset), new Point3D(xMin, y + 1 - offset, z + offset), new Point3D(xMax, y + 1 - offset, z + offset), new Point3D(xMin, y + offset, z + 1 - offset), new Point3D(xMax, y + offset, z + 1 - offset), new Point3D(xMin, y + 1 - offset, z + 1 - offset), new Point3D(xMax, y + 1 - offset, z + 1 - offset) }; } Point3D intersect; int normal; if (MeshHelper.RayIntersetTriangleRound(p1, p2, p3, rays, out intersect, out normal)) { ccubic[(int)Math.Floor(intersect.X) - xMin][(int)Math.Floor(intersect.Y) - yMin][(int)Math.Floor(intersect.Z) - zMin] = CubeType.Cube; } } } for (var x = minBound.X; x < maxBound.X; x++) { for (var z = minBound.Z; z < maxBound.Z; z++) { if (traceType == ModelTraceVoxel.Thin || traceType == ModelTraceVoxel.ThinSmoothed) { rays = new Point3D[] // 1 point ray trace in the center. { new Point3D(x + 0.5 + offset, yMin, z + 0.5 + offset), new Point3D(x + 0.5 + offset, yMax, z + 0.5 + offset) }; } else { rays = new Point3D[] // 4 point ray trace within each corner of the expected Volumetric cube. { new Point3D(x + offset, yMin, z + offset), new Point3D(x + offset, yMax, z + offset), new Point3D(x + 1 - offset, yMin, z + offset), new Point3D(x + 1 - offset, yMax, z + offset), new Point3D(x + offset, yMin, z + 1 - offset), new Point3D(x + offset, yMax, z + 1 - offset), new Point3D(x + 1 - offset, yMin, z + 1 - offset), new Point3D(x + 1 - offset, yMax, z + 1 - offset) }; } Point3D intersect; int normal; if (MeshHelper.RayIntersetTriangleRound(p1, p2, p3, rays, out intersect, out normal)) { ccubic[(int)Math.Floor(intersect.X) - xMin][(int)Math.Floor(intersect.Y) - yMin][(int)Math.Floor(intersect.Z) - zMin] = CubeType.Cube; } } } for (var x = minBound.X; x < maxBound.X; x++) { for (var y = minBound.Y; y < maxBound.Y; y++) { if (traceType == ModelTraceVoxel.Thin || traceType == ModelTraceVoxel.ThinSmoothed) { rays = new Point3D[] // 1 point ray trace in the center. { new Point3D(x + 0.5 + offset, y + 0.5 + offset, zMin), new Point3D(x + 0.5 + offset, y + 0.5 + offset, zMax), }; } else { rays = new Point3D[] // 4 point ray trace within each corner of the expected Volumetric cube. { new Point3D(x + offset, y + offset, zMin), new Point3D(x + offset, y + offset, zMax), new Point3D(x + 1 - offset, y + offset, zMin), new Point3D(x + 1 - offset, y + offset, zMax), new Point3D(x + offset, y + 1 - offset, zMin), new Point3D(x + offset, y + 1 - offset, zMax), new Point3D(x + 1 - offset, y + 1 - offset, zMin), new Point3D(x + 1 - offset, y + 1 - offset, zMax) }; } Point3D intersect; int normal; if (MeshHelper.RayIntersetTriangleRound(p1, p2, p3, rays, out intersect, out normal)) { ccubic[(int)Math.Floor(intersect.X) - xMin][(int)Math.Floor(intersect.Y) - yMin][(int)Math.Floor(intersect.Z) - zMin] = CubeType.Cube; } } } } } #endregion CrawlExterior(ccubic); if (traceType == ModelTraceVoxel.ThinSmoothed || traceType == ModelTraceVoxel.ThickSmoothedUp) { CalculateAddedInverseCorners(ccubic, incrementProgress); CalculateAddedSlopes(ccubic, incrementProgress); CalculateAddedCorners(ccubic, incrementProgress); } //if (traceType == ModelTraceVoxel.ThickSmoothedDown) //{ // CalculateSubtractedCorners(ccubic); // CalculateSubtractedSlopes(ccubic); // CalculateSubtractedInverseCorners(ccubic); //} return ccubic; }
public static TruncatedIcosidodecahedron GetTruncatedIcosidodecahedron(double radius, Transform3D transform = null) { //TODO: Currently, the points are hardcoded. All the polygons are regular. Take in a ratio for the length of side of the decagons. // 0 would make the decagons disappar, and the squares and hexagons would be it // 1 would make the squares disappear and the hexagons would become triangles // //The squares are the cornerstones. When calculating points, figure out what the centers of the various polygons are. Then adjust the //sizes of the squares. From that, find the rest of the points using the decagons. No need to find points for the hexagons, they have //no unique points #region Points double t = (1d + Math.Sqrt(5d)) / 2d; // φ double tS = t * t; // φ^2 double tI1 = 1d / t; // 1/φ double tI2 = 2d / t; // 2/φ double t2 = 2d * t; // 2φ double tA = 1d + (2d * t); // 1+2φ double tB = 2d + t; // 2+φ double tC = 3d + t; // 3+φ double tN1 = -1d + (3d * t); // -1+3φ double tN2 = -1d + (2d * t); // -1+2φ Point3D[] points = new Point3D[] { //(±1/φ, ±1/φ, ±(3+φ)) new Point3D(tI1, tI1, tC), new Point3D(tI1, tI1, -tC), new Point3D(tI1, -tI1, tC), new Point3D(tI1, -tI1, -tC), new Point3D(-tI1, tI1, tC), new Point3D(-tI1, tI1, -tC), new Point3D(-tI1, -tI1, tC), new Point3D(-tI1, -tI1, -tC), //(±2/φ, ±φ, ±(1+2φ)) new Point3D(tI2, t, tA), new Point3D(tI2, t, -tA), new Point3D(tI2, -t, tA), new Point3D(tI2, -t, -tA), new Point3D(-tI2, t, tA), new Point3D(-tI2, t, -tA), new Point3D(-tI2, -t, tA), new Point3D(-tI2, -t, -tA), //(±1/φ, ±φ^2, ±(-1+3φ)) new Point3D(tI1, tS, tN1), new Point3D(tI1, tS, -tN1), new Point3D(tI1, -tS, tN1), new Point3D(tI1, -tS, -tN1), new Point3D(-tI1, tS, tN1), new Point3D(-tI1, tS, -tN1), new Point3D(-tI1, -tS, tN1), new Point3D(-tI1, -tS, -tN1), //(±(-1+2φ), ±2, ±(2+φ)) new Point3D(tN2, 2, tB), new Point3D(tN2, 2, -tB), new Point3D(tN2, -2, tB), new Point3D(tN2, -2, -tB), new Point3D(-tN2, 2, tB), new Point3D(-tN2, 2, -tB), new Point3D(-tN2, -2, tB), new Point3D(-tN2, -2, -tB), //(±φ, ±3, ±2φ), new Point3D(t, 3, t2), new Point3D(t, 3, -t2), new Point3D(t, -3, t2), new Point3D(t, -3, -t2), new Point3D(-t, 3, t2), new Point3D(-t, 3, -t2), new Point3D(-t, -3, t2), new Point3D(-t, -3, -t2), }; points = points.Select(o => new Point3D[] { o, // orig new Point3D(o.Y, o.Z, o.X), // shift left new Point3D(o.Z, o.X, o.Y) // shift left twice }). SelectMany(o => o). ToArray(); double maxLength = points[0].ToVector().Length; double ratio = radius / maxLength; points = points.Select(o => (o.ToVector() * ratio).ToPoint()).ToArray(); if (transform != null) { points = points.Select(o => transform.Transform(o)).ToArray(); } #endregion int[][] decagonPolys = new int[][] { new int [] { 0, 6, 30, 78, 110, 62, 50, 98, 72, 24 }, new int [] { 14, 38, 86, 100, 52, 64, 112, 92, 44, 20 }, new int [] { 3, 27, 75, 104, 56, 68, 116, 81, 33, 9 }, new int [] { 15, 21, 45, 93, 119, 71, 59, 107, 87, 39 }, new int [] { 2, 8, 32, 80, 109, 61, 49, 97, 74, 26 }, new int [] { 1, 7, 31, 79, 108, 60, 48, 96, 73, 25 }, new int [] { 12, 36, 84, 101, 53, 65, 113, 90, 42, 18 }, new int [] { 4, 28, 76, 102, 54, 66, 114, 82, 34, 10 }, new int [] { 16, 22, 46, 94, 117, 69, 57, 105, 88, 40 }, new int [] { 17, 23, 47, 95, 118, 70, 58, 106, 89, 41 }, new int [] { 5, 29, 77, 103, 55, 67, 115, 83, 35, 11 }, new int [] { 13, 37, 85, 99, 51, 63, 111, 91, 43, 19 }, }; int[][] hexagonPolys = new int[][] { new int [] { 6, 18, 42, 66, 54, 30 }, new int [] { 82, 114, 90, 113, 89, 106 }, new int [] { 5, 17, 41, 65, 53, 29 }, new int [] { 77, 101, 84, 108, 79, 103 }, new int [] { 7, 19, 43, 67, 55, 31 }, new int [] { 83, 115, 91, 111, 87, 107 }, new int [] { 3, 15, 39, 63, 51, 27 }, new int [] { 0, 24, 48, 60, 36, 12 }, new int [] { 72, 98, 74, 97, 73, 96 }, new int [] { 1, 25, 49, 61, 37, 13 }, new int [] { 75, 99, 85, 109, 80, 104 }, new int [] { 76, 100, 86, 110, 78, 102 }, new int [] { 2, 26, 50, 62, 38, 14 }, new int [] { 8, 20, 44, 68, 56, 32 }, new int [] { 81, 116, 92, 112, 88, 105 }, new int [] { 9, 33, 57, 69, 45, 21 }, new int [] { 11, 35, 59, 71, 47, 23 }, new int [] { 93, 117, 94, 118, 95, 119 }, new int [] { 10, 34, 58, 70, 46, 22 }, new int [] { 4, 16, 40, 64, 52, 28 }, }; int[][] squarePolys = new int[][] { new int [] { 0, 12, 18, 6 }, new int [] { 36, 60, 108, 84 }, new int [] { 31, 55, 103, 79 }, new int [] { 43, 91, 115, 67 }, new int [] { 39, 87, 111, 63 }, new int [] { 3, 9, 21, 15 }, new int [] { 24, 72, 96, 48 }, new int [] { 25, 73, 97, 49 }, new int [] { 1, 13, 19, 7 }, new int [] { 37, 61, 109, 85 }, new int [] { 27, 51, 99, 75 }, new int [] { 33, 81, 105, 57 }, new int [] { 42, 90, 114, 66 }, new int [] { 41, 89, 113, 65 }, new int [] { 5, 11, 23, 17 }, new int [] { 35, 83, 107, 59 }, new int [] { 45, 69, 117, 93 }, new int [] { 29, 53, 101, 77 }, new int [] { 30, 54, 102, 78 }, new int [] { 28, 52, 100, 76 }, new int [] { 38, 62, 110, 86 }, new int [] { 26, 74, 98, 50 }, new int [] { 2, 14, 20, 8 }, new int [] { 32, 56, 104, 80 }, new int [] { 34, 82, 106, 58 }, new int [] { 46, 70, 118, 94 }, new int [] { 47, 71, 119, 95 }, new int [] { 4, 10, 22, 16 }, new int [] { 40, 88, 112, 64 }, new int [] { 44, 92, 116, 68 }, }; return new TruncatedIcosidodecahedron(decagonPolys, hexagonPolys, squarePolys, points); }