public void FindAnyPerpendicular_GivenNullVector_ReturnsUndefinedVector() { var v = new Vector3D(0, 0, 0); var p = v.FindAnyPerpendicular(); Assert.IsTrue(p.IsUndefined()); Assert.AreEqual(new Vector3D(0, 0, 0), v); // check that the input vector is unchanged }
public void FindAnyPerpendicular_GivenLargeVector_ReturnsUnitZ() { var v = new Vector3D(1e-100, 1e100, 0); var p = v.FindAnyPerpendicular(); Assert.AreEqual(new Vector3D(0, 0, 1), p); Assert.AreEqual(new Vector3D(1e-100, 1e100, 0), v); // check that the input vector is unchanged }
private void AddBranch(MeshBuilder mesh, Point3D p0, Vector3D direction, int p) { double angle = GetAngleBetween(direction, UpVector); bool isStem = angle < 10; double h = isStem ? 2.5 : 2; double r = (Level+1-p)*0.1; mesh.AddCone(p0, direction, r, r * 0.8, h, false, false, 12); var p1 = p0 + direction*h; if (p == Level) return; if (isStem) { var rightVector=direction.FindAnyPerpendicular(); var t0 = new RotateTransform3D(new AxisAngleRotation3D(rightVector, GetRandom(3))); AddBranch(mesh, p1, t0.Transform(direction), p + 1); var t1 = new RotateTransform3D(new AxisAngleRotation3D(rightVector, 95 + GetRandom(5))); var d1 = t1.Transform(direction); int nBranches = 5+GetRandom(2); for (int i = 0; i < nBranches; i++) { double a = 360.0 * i / nBranches + GetRandom(25); var t2 = new RotateTransform3D(new AxisAngleRotation3D(UpVector, a)); AddBranch(mesh, p1, t2.Transform(d1), p + 1); } } else { var rightVector=Vector3D.CrossProduct(direction, UpVector); var t1 = new RotateTransform3D(new AxisAngleRotation3D(rightVector, -5 + GetRandom(5))); var t2 = new RotateTransform3D(new AxisAngleRotation3D(UpVector, 45+GetRandom(10))); var t3 = new RotateTransform3D(new AxisAngleRotation3D(UpVector, -45 + GetRandom(10))); var d1 = t1.Transform(direction); AddBranch(mesh, p1, d1, p + 1); AddBranch(mesh, p1, t2.Transform(d1), p + 1); AddBranch(mesh, p1, t3.Transform(d1), p + 1); } }
private static Transform3D CreateBodyTransform(Point3D p, Vector3D z) { double length = z.Length; z.Normalize(); var x = z.FindAnyPerpendicular(); x.Normalize(); var y = Vector3D.CrossProduct(z, x); var mat = new Matrix3D(x.X, x.Y, x.Z, 0, y.X, y.Y, y.Z, 0, z.X*length, z.Y*length, z.Z*length, 0, p.X, p.Y, p.Z, 1); return new MatrixTransform3D(mat); }
private static Transform3D CreateHeadTransform(Point3D p, Vector3D z) { z.Normalize(); var x = z.FindAnyPerpendicular(); x.Normalize(); var y = Vector3D.CrossProduct(z, x); var mat = new Matrix3D( x.X, x.Y, x.Z, 0, y.X, y.Y, y.Z, 0, z.X, z.Y, z.Z, 0, p.X, p.Y, p.Z, 1); return new MatrixTransform3D(mat); }
/// <summary> /// Adds a surface of revolution. /// </summary> /// <param name="origin">The origin.</param> /// <param name="axis">The axis.</param> /// <param name="section">The points defining the curve to revolve.</param> /// <param name="sectionIndices">The indices of the line segments of the section.</param> /// <param name="thetaDiv">The number of divisions.</param> /// <param name="textureValues">The texture values.</param> public void AddSurfaceOfRevolution( Point3D origin, Vector3D axis, IList<Point> section, IList<int> sectionIndices, int thetaDiv = 37, IList<double> textureValues = null) { if (this.textureCoordinates != null && textureValues == null) { throw new ArgumentNullException("textureValues"); } if (textureValues != null && textureValues.Count != section.Count) { throw new InvalidOperationException(WrongNumberOfTextureCoordinates); } axis.Normalize(); // Find two unit vectors orthogonal to the specified direction var u = axis.FindAnyPerpendicular(); var v = Vector3D.CrossProduct(axis, u); var circle = GetCircle(thetaDiv); int n = section.Count; int index0 = this.positions.Count; for (int i = 0; i < thetaDiv; i++) { var w = (v * circle[i].X) + (u * circle[i].Y); for (int j = 0; j < n; j++) { var q1 = origin + (axis * section[j].Y) + (w * section[j].X); this.positions.Add(q1); if (this.normals != null) { double tx = section[j + 1].X - section[j].X; double ty = section[j + 1].Y - section[j].Y; var normal = (-axis * ty) + (w * tx); normal.Normalize(); this.normals.Add(normal); } if (this.textureCoordinates != null) { this.textureCoordinates.Add(new Point((double)i / (thetaDiv - 1), textureValues == null ? (double)j / (n - 1) : textureValues[j])); } } } for (int i = 0; i < thetaDiv; i++) { var ii = (i + 1) % thetaDiv; for (int j = 0; j + 1 < sectionIndices.Count; j += 2) { var j0 = sectionIndices[j]; var j1 = sectionIndices[j + 1]; int i0 = index0 + (i * n) + j0; int i1 = index0 + (ii * n) + j0; int i2 = index0 + (i * n) + j1; int i3 = index0 + (ii * n) + j1; this.triangleIndices.Add(i0); this.triangleIndices.Add(i1); this.triangleIndices.Add(i3); this.triangleIndices.Add(i3); this.triangleIndices.Add(i2); this.triangleIndices.Add(i0); } } }
/// <summary> /// Adds a surface of revolution. /// </summary> /// <param name="points">The points (x coordinates are distance from the origin along the axis of revolution, y coordinates are radius, )</param> /// <param name="textureValues">The v texture coordinates, one for each point in the <paramref name="points" /> list.</param> /// <param name="origin">The origin of the revolution axis.</param> /// <param name="direction">The direction of the revolution axis.</param> /// <param name="thetaDiv">The number of divisions around the mesh.</param> /// <remarks> /// See http://en.wikipedia.org/wiki/Surface_of_revolution. /// </remarks> public void AddRevolvedGeometry(IList<Point> points, IList<double> textureValues, Point3D origin, Vector3D direction, int thetaDiv) { direction.Normalize(); // Find two unit vectors orthogonal to the specified direction var u = direction.FindAnyPerpendicular(); var v = Vector3D.CrossProduct(direction, u); u.Normalize(); v.Normalize(); var circle = GetCircle(thetaDiv); int index0 = this.positions.Count; int n = points.Count; int totalNodes = (points.Count - 1) * 2 * thetaDiv; int rowNodes = (points.Count - 1) * 2; for (int i = 0; i < thetaDiv; i++) { var w = (v * circle[i].X) + (u * circle[i].Y); for (int j = 0; j + 1 < n; j++) { // Add segment var q1 = origin + (direction * points[j].X) + (w * points[j].Y); var q2 = origin + (direction * points[j + 1].X) + (w * points[j + 1].Y); // TODO: should not add segment if q1==q2 (corner point) // const double eps = 1e-6; // if (Point3D.Subtract(q1, q2).LengthSquared < eps) // continue; this.positions.Add(q1); this.positions.Add(q2); if (this.normals != null) { double tx = points[j + 1].X - points[j].X; double ty = points[j + 1].Y - points[j].Y; var normal = (-direction * ty) + (w * tx); normal.Normalize(); this.normals.Add(normal); this.normals.Add(normal); } if (this.textureCoordinates != null) { this.textureCoordinates.Add(new Point((double)i / (thetaDiv - 1), textureValues == null ? (double)j / (n - 1) : textureValues[j])); this.textureCoordinates.Add(new Point((double)i / (thetaDiv - 1), textureValues == null ? (double)(j + 1) / (n - 1) : textureValues[j + 1])); } int i0 = index0 + (i * rowNodes) + (j * 2); int i1 = i0 + 1; int i2 = index0 + ((((i + 1) * rowNodes) + (j * 2)) % totalNodes); int i3 = i2 + 1; this.triangleIndices.Add(i1); this.triangleIndices.Add(i0); this.triangleIndices.Add(i2); this.triangleIndices.Add(i1); this.triangleIndices.Add(i2); this.triangleIndices.Add(i3); } } }
/// <summary> /// Add a surface of revolution /// http://en.wikipedia.org/wiki/Surface_of_revolution /// </summary> /// <param name="points">The points.</param> /// <param name="origin">The origin.</param> /// <param name="direction">The direction.</param> /// <param name="thetaDiv">The theta div.</param> public void AddRevolvedGeometry(PointCollection points, Point3D origin, Vector3D direction, int thetaDiv) { direction.Normalize(); // Find two unit vectors orthogonal to the specified direction var u = direction.FindAnyPerpendicular(); var v = Vector3D.CrossProduct(direction, u); u.Normalize(); v.Normalize(); var circle = GetCircle(thetaDiv); int index0 = positions.Count; int nPoints = points.Count; int totalNodes = (points.Count - 1) * 2 * thetaDiv; int rowNodes = (points.Count - 1) * 2; for (int i = 0; i < thetaDiv; i++) { Vector3D w = v * circle[i].X + u * circle[i].Y; for (int j = 0; j + 1 < nPoints; j++) { // Add segment var q1 = origin + direction * points[j].X + w * points[j].Y; var q2 = origin + direction * points[j + 1].X + w * points[j + 1].Y; // todo:should not add segment if q1==q2 (corner point) // const double eps = 1e-6; // if (Point3D.Subtract(q1, q2).LengthSquared < eps) // continue; double tx = points[j + 1].X - points[j].X; double ty = points[j + 1].Y - points[j].Y; var normal = -direction * ty + w * tx; normal.Normalize(); positions.Add(q1); positions.Add(q2); if (normals != null) { normals.Add(normal); normals.Add(normal); } if (textureCoordinates != null) { textureCoordinates.Add(new Point((double)i / (thetaDiv - 1), (double)j / (nPoints - 1))); textureCoordinates.Add(new Point((double)i / (thetaDiv - 1), (double)(j + 1) / (nPoints - 1))); } int i0 = index0 + i * rowNodes + j * 2; int i1 = i0 + 1; int i2 = index0 + ((i + 1) * rowNodes + j * 2) % totalNodes; int i3 = i2 + 1; triangleIndices.Add(i1); triangleIndices.Add(i2); triangleIndices.Add(i0); triangleIndices.Add(i1); triangleIndices.Add(i3); triangleIndices.Add(i2); } } }