public static void HopfOrbit() { List <Vector3D> s2Points = new List <Vector3D>(); for (double theta = Math.PI * .1; theta <= Math.PI * .9; theta += Math.PI * .2) { for (double lon = -Math.PI; lon <= Math.PI; lon += Math.PI / 10) { s2Points.Add(SphericalCoords.SphericalToCartesian(new Vector3D(1.0, theta, lon))); } } using (StreamWriter sw = File.CreateText(@".\out.pov")) { System.Func <Vector3D, Sphere> sizeFunc = v => new Sphere() { Center = v, Radius = 0.01 }; foreach (Vector3D s2Point in s2Points) { Vector3D[] circlePoints = OneHopfCircle(s2Point); //for( int i = 0; i < circlePoints.Length; i++ ) // circlePoints[i] = circlePoints[i].ProjectTo3DSafe( 1.0 ); // Note: effectively orthogonal projects here because EdgeSphereSweep doesn't write W coord. string circleString = PovRay.EdgeSphereSweep(circlePoints, sizeFunc); sw.WriteLine(circleString); } } }
public static Vector3 GetVecWithoutYRot(Vector3 coords) { SphericalCoords sphCoords = CartesianToSpherical(coords); sphCoords.theta = 0; return(sphCoords.ToCartesian()); }
public static Vector3D SinusoidalToStereo(Vector3D v) { double lat = Math.PI / 2 * (1 - v.Y); Vector3D spherical = new Vector3D(1, lat, Math.PI * v.X / Math.Cos(lat - Math.PI / 2)); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(Sterographic.SphereToPlane(onBall)); }
public static Vector3 SphericalToCartesian(SphericalCoords coords) { float rSinPhi = coords.radius * Mathf.Sin(coords.phi); float x = rSinPhi * Mathf.Cos(coords.theta); float y = coords.radius * Mathf.Cos(coords.phi); float z = rSinPhi * Mathf.Sin(coords.theta); return(new Vector3(x, y, z)); }
/// <summary> /// 2-dimensional function. /// http://archive.bridgesmathart.org/2013/bridges2013-217.pdf /// </summary> public static Vector3D MercatorToStereo(Vector3D v) { v *= Math.PI; // Input is [-1,1] double lat = 2 * Math.Atan(Math.Exp(v.Y)) - Math.PI / 2; double inclination = lat + Math.PI / 2; Vector3D spherical = new Vector3D(1, inclination, v.X); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(Sterographic.SphereToPlane(onBall)); }
public static Vector3D EquirectangularToStereo(Vector3D v) { // http://mathworld.wolfram.com/EquirectangularProjection.html // y is the latitude // x is the longitude // Assume inputs go from -1 to 1. Vector3D spherical = new Vector3D(1, Math.PI / 2 * (1 - v.Y), v.X * Math.PI); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(Sterographic.SphereToPlane(onBall)); }
/// <summary> /// https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection /// </summary> private static double EqualAreaToStereo(double dist) { if (dist > 1) { throw new System.ArgumentException(); } // We have dist normalized between 0 and 1, so this formula is slightly // different than on Wikipedia, where dist ranges up to 2. Vector3D v = new Vector3D(1, 2 * Math.Acos(dist), 0); v = Sterographic.SphereToPlane(SphericalCoords.SphericalToCartesian(v)); return(v.Abs()); }
public static void GenPolyhedron() { Tiling tiling; int p = 3; int q = 6; GetAssociatedTiling(p, q, 5000, out tiling); double overallScale = 12.5; // 2.5 cm = 1 in diameter Shapeways mesh = new Shapeways(); foreach (Tile tile in tiling.Tiles) { foreach (Segment seg in tile.Boundary.Segments) { double tilingScale = 0.75; seg.Scale(new Vector3D(), tilingScale); Vector3D v1 = Sterographic.PlaneToSphereSafe(seg.P1); Vector3D v2 = Sterographic.PlaneToSphereSafe(seg.P2); //if( v1.Dist( v2 ) < 0.01 ) // continue; if (SphericalCoords.CartesianToSpherical(v1).Y < Math.PI / 12 && SphericalCoords.CartesianToSpherical(v2).Y < Math.PI / 12) { continue; } double dist = v1.Dist(v2); int divisions = 2 + (int)(dist * 20); Vector3D[] points = seg.Subdivide(divisions); points = points.Select(v => Sterographic.PlaneToSphereSafe(v)).ToArray(); mesh.AddCurve(points, v => SizeFunc(v, overallScale)); } } mesh.Mesh.Scale(overallScale); string outputFileName = @"d:\temp\" + p + q + ".stl"; STL.SaveMeshToSTL(mesh.Mesh, outputFileName); }
private static double SizeFunc(Vector3D v, double overallScale) { //return .6 / 2 / overallScale; // Silver min wall is 0.6 // Silver min wire is 0.8 (supported) or 1.0 (unsupported). double min = 0.55 / 2; double max = 1.5 / 2; // for caps //double min = 0.71 / 2; //double max = 0.5 / 2; // 36 //double max = 0.35 / 2; // 63 Vector3D s = SphericalCoords.CartesianToSpherical(v); double angle = s.Y / Math.PI; // angle 0 to 1 double result = min + (max - min) * angle; return(result / overallScale); }
public static void RLD_Surface() { RLD_outputs outputs; Mesh mesh = new Mesh(); SurfaceInternal(out outputs); double scale = m_params.Scale; // Now add in all the catenoids. double mInc = Math.PI * 2 / m_params.M; for (int k = 1; k < outputs.x_i.Length; k++) { for (int m = 0; m < m_params.M; m++) { Vector3D loc = SphericalCoords.SphericalToCartesian(new Vector3D(1, Math.PI / 2 - outputs.x_i[k], m * mInc)); mesh.Append(Catenoid(scale, loc, outputs.phi_i[k], outputs.t_i[k])); } } PovRay.WriteMesh(mesh, "RLD.pov"); }
/// <summary> /// This allows us to change the model we have on the plane. /// We usually want UHS, but for Pov-Ray mapping these images to a sphere, we need to have it be an equirectangular projection /// NOTE: The bounds should be set to 1.0 for this to work! v.X and v.Y must be in-between -1 and 1. (also, don't rotate simplex mirrors, for POV-Ray anyway) /// </summary> private Vector3D PlaneModelToBall(Vector3D v, double t = 0.0) { bool equirectangular = false; if (!equirectangular) { // Normal UHS (sterographic projection). return(H3Models.UHSToBall(v)); } else { // If you want output to have twice the width. double xScale = 2; v.X /= xScale; // http://mathworld.wolfram.com/EquirectangularProjection.html // y is the latitude // x is the longitude // Assume inputs go from -1 to 1. Vector3D spherical = new Vector3D(1, Math.PI / 2 * (1 - v.Y), v.X * Math.PI); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(ApplyTransformationToSphere(onBall, t)); } }
private void FillKNNTrees(KNNBone rootBone, bool ignoreRotation, bool bothHandsInFeatureVec, string headBoneName, string rHandBoneName, string lHandBoneName, float slidingWindowSizeInMS, float slidingWindowOffsetInMS, float pollingRate, List <int> lHandTreeNodes, List <int> rHandTreeNodes, List <float[]> lHandTreePoints, List <float[]> rHandTreePoints) { float sourceFrameTime = bvhParser.frameTime; float targetFrameTime = 1.0f / pollingRate; float totalTime = bvhParser.frames * sourceFrameTime; int totalNewFrames = (int)(totalTime / targetFrameTime); float slidingWindowOffset = slidingWindowOffsetInMS / 1000.0f; float slidingWindowSize = slidingWindowSizeInMS / 1000.0f; int totalWindows = (int)((totalTime - (slidingWindowSize)) / (slidingWindowOffset)); int framesPerWindow = (int)((slidingWindowSize) / targetFrameTime); int nrOfFeatures = bothHandsInFeatureVec ? 18 : 9; int featureVecLength = nrOfFeatures * framesPerWindow; setToFrame(0, true, true, true); for (int currentWindow = 0; currentWindow < totalWindows; currentWindow++) { float[] lHandPoints = new float[featureVecLength]; float[] rHandPoints = new float[featureVecLength]; for (int currFrame = 0; currFrame < framesPerWindow; currFrame++) { float startTime = slidingWindowOffset * (float)currentWindow; float sourceFrame = getSourceFrameFromTargetTime(sourceFrameTime, startTime + (float)currFrame * targetFrameTime); setToFrame(sourceFrame, true, true, true); Vector3 rHandPosition = root.Find(rHandBoneName).position; Vector3 lHandPosition = root.Find(lHandBoneName).position; if (sourceFrame >= 1.0f) { setToFrame(sourceFrame - 1.0f, true, true, true); } Vector3 prevRHandPosition = root.Find(rHandBoneName).position; Vector3 prevLHandPosition = root.Find(lHandBoneName).position; if (sourceFrame >= 2.0f) { setToFrame(sourceFrame - 2.0f, true, true, true); } Vector3 prevPrevRHandPosition = root.Find(rHandBoneName).position; Vector3 prevPrevLHandPosition = root.Find(lHandBoneName).position; Vector3 lHandVelocity = (lHandPosition - prevLHandPosition) / sourceFrameTime; Vector3 rHandVelocity = (rHandPosition - prevRHandPosition) / sourceFrameTime; Vector3 prevLHandVelocity = (prevLHandPosition - prevPrevLHandPosition) / sourceFrameTime; Vector3 prevRHandVelocity = (prevRHandPosition - prevPrevRHandPosition) / sourceFrameTime; Vector3 lHandAcceleration = (lHandVelocity - prevLHandVelocity) / sourceFrameTime; Vector3 rHandAcceleration = (rHandVelocity - prevRHandVelocity) / sourceFrameTime; if (ignoreRotation) { SphericalCoords rHandSpPosition = SphericalCoords.CartesianToSpherical(rHandPosition); SphericalCoords lHandSpPosition = SphericalCoords.CartesianToSpherical(lHandPosition); float rHandAngle = rHandSpPosition.theta * Mathf.Rad2Deg; float lHandAngle = lHandSpPosition.theta * Mathf.Rad2Deg; //rotate velocity and acceleration angle around "theta" lHandVelocity = Quaternion.AngleAxis(lHandAngle, Vector3.up) * lHandVelocity; rHandVelocity = Quaternion.AngleAxis(rHandAngle, Vector3.up) * rHandVelocity; lHandAcceleration = Quaternion.AngleAxis(lHandAngle, Vector3.up) * lHandAcceleration; rHandAcceleration = Quaternion.AngleAxis(rHandAngle, Vector3.up) * rHandAcceleration; rHandSpPosition.theta = 0; lHandSpPosition.theta = 0; rHandPosition = rHandSpPosition.ToCartesian(); lHandPosition = lHandSpPosition.ToCartesian(); } int pointOffset = currFrame * nrOfFeatures; lHandPoints[pointOffset] = lHandPosition.x; lHandPoints[pointOffset + 1] = lHandPosition.y; lHandPoints[pointOffset + 2] = lHandPosition.z; lHandPoints[pointOffset + 3] = lHandVelocity.x; lHandPoints[pointOffset + 4] = lHandVelocity.y; lHandPoints[pointOffset + 5] = lHandVelocity.z; lHandPoints[pointOffset + 6] = lHandAcceleration.x; lHandPoints[pointOffset + 7] = lHandAcceleration.y; lHandPoints[pointOffset + 8] = lHandAcceleration.z; rHandPoints[pointOffset] = rHandPosition.x; rHandPoints[pointOffset + 1] = rHandPosition.y; rHandPoints[pointOffset + 2] = rHandPosition.z; rHandPoints[pointOffset + 3] = rHandVelocity.x; rHandPoints[pointOffset + 4] = rHandVelocity.y; rHandPoints[pointOffset + 5] = rHandVelocity.z; rHandPoints[pointOffset + 6] = rHandAcceleration.x; rHandPoints[pointOffset + 7] = rHandAcceleration.y; rHandPoints[pointOffset + 8] = rHandAcceleration.z; if (bothHandsInFeatureVec) { lHandPoints[pointOffset + 9] = rHandPosition.x; lHandPoints[pointOffset + 10] = rHandPosition.y; lHandPoints[pointOffset + 11] = rHandPosition.z; lHandPoints[pointOffset + 12] = rHandVelocity.x; lHandPoints[pointOffset + 13] = rHandVelocity.y; lHandPoints[pointOffset + 14] = rHandVelocity.z; lHandPoints[pointOffset + 15] = rHandAcceleration.x; lHandPoints[pointOffset + 16] = rHandAcceleration.y; lHandPoints[pointOffset + 17] = rHandAcceleration.z; rHandPoints[pointOffset + 9] = lHandPosition.x; rHandPoints[pointOffset + 10] = lHandPosition.y; rHandPoints[pointOffset + 11] = lHandPosition.z; rHandPoints[pointOffset + 12] = lHandVelocity.x; rHandPoints[pointOffset + 13] = lHandVelocity.y; rHandPoints[pointOffset + 14] = lHandVelocity.z; rHandPoints[pointOffset + 15] = lHandAcceleration.x; rHandPoints[pointOffset + 16] = lHandAcceleration.y; rHandPoints[pointOffset + 17] = lHandAcceleration.z; } } int lastPositionSourceIndex = (int)((currentWindow * slidingWindowOffset + slidingWindowSize) / sourceFrameTime); setToFrame(lastPositionSourceIndex, true, true, true); rootBone.AddRotationsFromTransform(root); lHandTreePoints.Add(lHandPoints); lHandTreeNodes.Add(lHandTreeNodes.Count); rHandTreePoints.Add(rHandPoints); rHandTreeNodes.Add(rHandTreeNodes.Count); } }
public static void CatenoidBasedSurface() { RLD_outputs outputs; SurfaceInternal(out outputs); double scale = m_params.Scale; // Map a point for a given k/m from the hemihypersphere to the complex plane. // You can also pass in -1 for k to get a point on the equator of the hemihypersphere. double mInc = Math.PI * 2 / m_params.M; Func <RLD_outputs, int, int, Vector3D> onPlane = (o, k, m) => { double theta = k == -1 ? 0 : outputs.x_i[k]; theta += Math.PI / 2; return (Sterographic.SphereToPlane( SphericalCoords.SphericalToCartesian( new Vector3D(1, theta, m * mInc) ) )); }; // Setup texture coords on fundamental triangle. // We'll use a fundamental triangle in the southern hemisphere, // with stereographically projected coords at (0,0), (1,0), and CCW on the unit circle depending on M. Polygon p = new Polygon(); p.Segments.Add(Segment.Line(new Vector3D(), new Vector3D(1, 0))); p.Segments.Add(Segment.Arc(new Vector3D(1, 0), onPlane(outputs, 1, 1), onPlane(outputs, -1, 1))); p.Segments.Add(Segment.Line(onPlane(outputs, -1, 1), new Vector3D())); int levels = 9; TextureHelper.SetLevels(levels); Vector3D[] coords = TextureHelper.TextureCoords(p, Geometry.Spherical, doGeodesicDome: true); int[] elementIndices = TextureHelper.TextureElements(1, levels); // Setup a nearTree for the catenoid locations (on the plane). NearTree nearTree = new NearTree(Metric.Spherical); for (int k = 1; k < outputs.x_i.Length; k++) { for (int m = 0; m <= 1; m++) { Vector3D loc = onPlane(outputs, k, m); nearTree.InsertObject(new NearTreeObject() { ID = k, Location = loc }); } } // Given a point on the plane, find the nearest catenoid center and calculate the height of the surface based on that. // This also calculates the locking of the point. Func <Vector3D, Tuple <double, Vector3D, Vector3D> > heightAndLocking = coord => { NearTreeObject closest; if (!nearTree.FindNearestNeighbor(out closest, coord, double.MaxValue)) { throw new System.Exception(); } Vector3D locked = new Vector3D(); if (p.Segments[0].IsPointOn(coord) || p.Segments[2].IsPointOn(coord)) { locked = new Vector3D(1, 1, 0, 0); } //if( p.Segments[1].IsPointOn( v ) ) // Not working right for some reason, but line below will work. if (Tolerance.Equal(coord.Abs(), 1)) { locked = new Vector3D(1, 1, 1, 0); } Vector3D vSphere = Sterographic.PlaneToSphere(coord); Vector3D cSphere = Sterographic.PlaneToSphere(closest.Location); double dist = vSphere.AngleTo(cSphere); int k = (int)closest.ID; double waist = outputs.t_i[k]; double rld_height = outputs.phi_i[k]; double h = waist * 3.5 * 2; // height where catenoid will meet rld_height. double factor = scale * rld_height * 2 / h; // Artifical scaling so we can see things. dist /= factor; double z = double.NaN; if (dist >= waist) { z = waist * DonHatch.acosh(dist / waist); } else if (dist >= 0.7 * waist) { z = 0; // Move the coord to the thinnest waist circle. Mobius m = new Mobius(); m.Hyperbolic(Geometry.Spherical, coord.ToComplex(), waist / dist); coord = m.Apply(coord); } if (dist < waist * 20) { locked = new Vector3D(1, 1, 1, 1); } return(new Tuple <double, Vector3D, Vector3D>(z * factor, locked, coord)); }; // Calculate all the coordinates. Vector3D[] locks = new Vector3D[coords.Length]; for (int i = 0; i < coords.Length; i++) { Vector3D coord = coords[i]; var hl = heightAndLocking(coord); locks[i] = hl.Item2; coord = hl.Item3; coords[i] = Normal(Sterographic.PlaneToSphere(coord), (double)hl.Item1); } // Relax it. Relax(coords, elementIndices, locks); Mesh mesh = new Mesh(); Sphere s = new Sphere(); for (int i = 0; i < elementIndices.Length; i += 3) { Vector3D a = coords[elementIndices[i]]; Vector3D b = coords[elementIndices[i + 1]]; Vector3D c = coords[elementIndices[i + 2]]; if (a.DNE || b.DNE || c.DNE) { continue; } for (int m = 0; m <= 0; m++) { mesh.Triangles.Add(new Mesh.Triangle(a, b, c)); mesh.Triangles.Add(new Mesh.Triangle( s.ReflectPoint(a), s.ReflectPoint(b), s.ReflectPoint(c))); a.RotateXY(mInc); b.RotateXY(mInc); c.RotateXY(mInc); } } PovRay.WriteMesh(mesh, "RLD.pov"); }
/// <summary> /// Converts to cartesian coordinates. /// </summary> public Vector3 ToCartesian() { return(SphericalCoords.SphericalToCartesian(this)); }
public void SetSkeletonFromHandPos(KDTree <float, int> tree, LinkedList <FeatureItem> features, string handName, int k) { float[] featureVec = new float[featureVectorLength]; Transform headTransform = rootBone.transform.Find("LowerBack/Spine/Spine1/Neck/Neck1/Head"); Transform neckTransform = rootBone.transform.Find("LowerBack/Spine/Spine1/Neck/Neck1/Head"); rootBone.transform.position -= headTransform.position; float handTargetSpPositionAngle = SphericalCoords.GetYRotFromVec(features.Last().position) * Mathf.Rad2Deg; var currFeatureContainer = features.Last; Debug.Assert(featureVectorLength % 9 == 0); for (int i = 0; i < featureVectorLength / 9; i++) { FeatureItem currFeatureItem = currFeatureContainer.Value; Vector3 handPos = currFeatureItem.position; Vector3 handVel = currFeatureItem.velocity; Vector3 handAcc = currFeatureItem.acceleration; if (ignoreRotation) { float handYRotValue = SphericalCoords.GetYRotFromVec(handPos) * Mathf.Rad2Deg; SphericalCoords sphCoords = SphericalCoords.CartesianToSpherical(handPos); sphCoords.theta = 0; Vector3 outVec = sphCoords.ToCartesian(); handPos = Quaternion.AngleAxis(handYRotValue, Vector3.up) * handPos; handVel = Quaternion.AngleAxis(handYRotValue, Vector3.up) * handVel; handAcc = Quaternion.AngleAxis(handYRotValue, Vector3.up) * handAcc; } int startIndex = 9 * i; featureVec[startIndex] = handPos.x; featureVec[startIndex + 1] = handPos.y; featureVec[startIndex + 2] = handPos.z; featureVec[startIndex + 3] = handVel.x; featureVec[startIndex + 4] = handVel.y; featureVec[startIndex + 5] = handVel.z; featureVec[startIndex + 6] = handAcc.x; featureVec[startIndex + 7] = handAcc.y; featureVec[startIndex + 8] = handAcc.z; if (currFeatureContainer.Previous != null) { currFeatureContainer = currFeatureContainer.Previous; } } Tuple <float[], int>[] poseIndices = tree.NearestNeighbors(featureVec, k); int index = poseIndices[0].Item2; RotationIndex[] rotations = new RotationIndex[poseIndices.Length]; for (int i = 0; i < poseIndices.Length; i++) { double distance = Metrics.WeightedL2Norm(poseIndices[i].Item1, featureVec); RotationIndex currIdx = new RotationIndex(poseIndices[i].Item2, (float)(1.0 / distance)); rotations[i] = currIdx; } rootBone.SetToRotations(rotations); //rootBone.SetToRotation(index); Transform handTransform = rootBone.transform.Find(handName); SphericalCoords handTransformSpPosition = SphericalCoords.CartesianToSpherical(handTransform.position - headTransform.position); float handTransformSpPositionAngle = handTransformSpPosition.theta * Mathf.Rad2Deg; rootBone.transform.localRotation *= Quaternion.Euler(0, -handTargetSpPositionAngle + handTransformSpPositionAngle, 0); }