private static Vector3D PerformDrag3DRight(DragData dragData, Vector3D lookFrom) { // The view vector magnitude. double abs = lookFrom.Abs(); Vector3D newLookFrom = lookFrom; // Increment it. abs += 5 * abs * dragData.YPercent; newLookFrom.Normalize(); newLookFrom *= abs; double smallestRadius = .02; if (newLookFrom.Abs() < smallestRadius) { newLookFrom.Normalize(); newLookFrom *= smallestRadius; } double largestRadius = 100.0; if (newLookFrom.Abs() > largestRadius) { newLookFrom.Normalize(); newLookFrom *= largestRadius; } return(newLookFrom); }
public double ProjectedArea(Vector3D viewDir) { Vector3D vectord = this.Max - this.Min; Vector3D v = new Vector3D(vectord.Y, vectord.Z, vectord.X) * new Vector3D(vectord.Z, vectord.X, vectord.Y); return(Vector3D.Abs(viewDir).Dot(v)); }
public static Vector3D EdgeToPlane(Geometry g, H3.Cell.Edge edge) { if (g != Geometry.Hyperbolic) { throw new System.NotImplementedException(); } Vector3D b1, b2; H3Models.Ball.GeodesicIdealEndpoints(edge.Start, edge.End, out b1, out b2); if (((b2 + b1) / 2).IsOrigin) { Vector3D lineNormal = b2 - b1; lineNormal.RotateXY(Math.PI / 2); lineNormal.Normalize(); return(new Vector3D(lineNormal.X, lineNormal.Y, lineNormal.Z, 0)); } Vector3D center, normal; double radius, angleTot; H3Models.Ball.Geodesic(edge.Start, edge.End, out center, out radius, out normal, out angleTot); Vector3D closest = H3Models.Ball.ClosestToOrigin(new Circle3D() { Center = center, Radius = radius, Normal = normal }); Vector3D closestKlein = HyperbolicModels.PoincareToKlein(closest); center.Normalize(); return(new Vector3D(center.X, center.Y, center.Z, closestKlein.Abs())); }
/// <summary> /// Builds a segment going through the box (if we cross it). /// </summary> private static Segment BuildSegment(CircleNE c) { Vector3D[] iPoints = Box.GetIntersectionPoints(c); if (2 != iPoints.Length) { return(null); } if (c.IsLine) { return(Segment.Line(iPoints[0], iPoints[1])); } // Find the midpoint. Probably a better way. Vector3D t1 = iPoints[0] - c.Center; Vector3D t2 = iPoints[1] - c.Center; double angle1 = Euclidean2D.AngleToCounterClock(t1, t2); double angle2 = Euclidean2D.AngleToClock(t1, t2); Vector3D mid1 = t1, mid2 = t1; mid1.RotateXY(angle1 / 2); mid2.RotateXY(-angle2 / 2); mid1 += c.Center; mid2 += c.Center; Vector3D mid = mid1; if (mid2.Abs() < mid1.Abs()) { mid = mid2; } return(Segment.Arc(iPoints[0], mid, iPoints[1])); }
internal static Sphere SphereFuncBall(Geometry g, Vector3D v, bool simple = true) { //bool simple = true; if (simple) { double size = 125; double thickCen = 2.0 / size; //double thickEdge = .7 / size; double thickEdge = 1.0 / size; double thick = thickCen - v.Abs() * (thickCen - thickEdge); return(new Sphere() { Center = v, Radius = thick }); } else { double thick = .1; //double minRad = 0.8 / 100; double minRad = 1.0 / 125; Vector3D c; double r; H3Models.Ball.DupinCyclideSphere(v, thick / 2, g, out c, out r); return(new Sphere() { Center = c, Radius = Math.Max(r, minRad) }); } }
public double ProjectedArea(Vector3D viewDir) { Vector3D span = Max - Min; Vector3D size = new Vector3D(span.Y, span.Z, span.X) * new Vector3D(span.Z, span.X, span.Y); return(Vector3D.Abs(viewDir).Dot(size)); }
/// <summary> Рисует гирлянду из сфер. </summary> private void DrawSpheres() { Glu.GLUquadric quad = Glu.gluNewQuadric(); for (int i = 0; i < 50; i++) { Vector3D position = new Vector3D((float)((2.0 + 3.0 * i / 50.0) * Math.Sin(i)), (float)((2.0 + 3.0 * i / 50.0) * Math.Cos(i)), (float)(-4.0 + 9.0 * i / 50.0)); Gl.glPushMatrix(); Gl.glTranslatef(position.X * (float)(Math.Sin(time / 100.0)), position.Y * (float)(Math.Cos(time / 100.0)), position.Z * (float)(0.5 + 0.5 * Math.Sin(time / 100.0))); Gl.glColor3fv(Vector3D.Abs(position / 5.0f).ToArray()); Glu.gluSphere(quad, 0.3f, 20, 20); Gl.glPopMatrix(); } Glu.gluDeleteQuadric(quad); }
/// <summary> /// Returns a stereographically sphere representing us. /// </summary> public Sphere ToSphere() { // Equatorial sphere? if (Pole == new Vector3D(0, 0, 0, 1)) { return(new Sphere()); } // A plane? Vector3D poleR3 = Sterographic.S3toR3(Pole); if (Tolerance.Equal(poleR3.Abs(), 1)) { return(Sphere.Plane(poleR3)); } // Get 4 points on the sphere. Vector3D e1 = new Vector3D(1, 0, 0, 0); Vector3D e2 = new Vector3D(0, 1, 0, 0); Vector3D e3 = new Vector3D(0, 0, 1, 0); Vector3D e4 = new Vector3D(0, 0, 0, 1); System.Func <Vector3D, Vector3D> one = v => { v = Euclidean3D.ProjectOntoPlane(Pole, new Vector3D(), v); v.Normalize(); return(Sterographic.S3toR3(v)); }; return(Sphere.From4Points(one(e1), one(e2), one(e3), one(e4))); }
public bool Equals(SurfaceVertex v1, SurfaceVertex v2) { double threshold = 0.001; if (v1.Vertex.Compare(v2.Vertex, threshold)) { return(true); } foreach (Puzzle.Translation trans in m_translations) { Vector3D offset = trans.m_translation; if (Tolerance.Zero(offset.Abs(), threshold)) { continue; } Vector3D test = v1.Vertex + offset; if (test.Compare(v2.Vertex, threshold)) { return(true); } } return(false); }
/// <summary> /// Offsets a vector by a hyperbolic distance. /// </summary> public static Vector3D Offset( Vector3D v, double hDist ) { double mag = v.Abs(); mag = DonHatch.h2eNorm( DonHatch.e2hNorm( mag ) + hDist ); v.Normalize(); v *= mag; return v; }
public static double DistancePointPlane( Vector3D normalVector, Vector3D planePoint, Vector3D point ) { // Check to make sure that plane is not degenerate. if( Tolerance.Zero( normalVector.MagSquared() ) ) return double.NaN; // Here is the distance (signed depending on which side of the plane we are on). return ( point - planePoint ).Dot( normalVector ) / normalVector.Abs(); }
public static double DistancePointLine( Vector3D n1, Vector3D p1, Vector3D point ) { // Check to make sure that n1 is not degenerate. if( Tolerance.Zero( n1.MagSquared() ) ) return double.NaN; // ZZZ - Can we make this a signed distance? return ( ( point - p1 ).Cross( n1 ) ).Abs() / n1.Abs(); }
public static bool IsInfinite( Vector3D input ) { // XXX - ugly hack I'd like to improve. return IsInfinite( input.X ) || IsInfinite( input.Y ) || IsInfinite( input.Z ) || IsInfinite( input.W ) || input.Abs() > InfiniteScale; }
/// <summary> /// A simple thickening. This is not accurate, but meant to save cost by minimizing wall thickness everywhere. /// The input vector should live on normal. /// </summary> private static System.Tuple <Vector3D, Vector3D> ThickenSimple(Vector3D v, Sphere normal) { double size = 125; double thickCen = 2.0 / size; //double thickEdge = .7 / size; double thickEdge = 1.0 / size; double thick = thickCen - v.Abs() * (thickCen - thickEdge); Vector3D direction = v - normal.Center; return(ThickenSimple(v, direction, thick)); }
/// <summary> /// For a point outside the unit ball, get the ideal circle associate to the dual plane. /// </summary> public static Circle3D GetCircle(Vector3D p) { Sphere ball = new Sphere(); // Our point defines an orthogonal cone to the unit ball. double d = p.Abs(); double radius = Math.Sqrt(d * d - 1); Sphere s = new Sphere(p, radius); return(ball.Intersection(s)); }
/// <summary> /// Evaluates the configured flux function (see /// <see cref="BoundaryConditionSourceFromINonlinearFlux.BoundaryConditionSourceFromINonlinearFlux(CNSControl, ISpeciesMap, BoundaryCondition, INonlinearFlux)"/> /// using the present flow state <paramref name="U"/> and the boundary /// value provided by the configured boundary condition. /// </summary> /// <param name="time"></param> /// <param name="x"></param> /// <param name="U"></param> /// <param name="IndexOffset"></param> /// <param name="FirstCellInd"></param> /// <param name="Lenght"></param> /// <param name="Output"></param> public void Source(double time, MultidimensionalArray x, MultidimensionalArray[] U, int IndexOffset, int FirstCellInd, int Lenght, MultidimensionalArray Output) { int D = CNSEnvironment.NumberOfDimensions; int noOfNodes = x.GetLength(1); int noOfVariables = D + 2; MultidimensionalArray normal = MultidimensionalArray.Create(Lenght, noOfNodes, D); MultidimensionalArray[] Uout = new MultidimensionalArray[noOfVariables]; for (int i = 0; i < noOfVariables; i++) { Uout[i] = MultidimensionalArray.Create(Lenght, noOfNodes); } double[] xLocal = new double[D]; Material material = speciesMap.GetMaterial(double.NaN); for (int i = 0; i < Lenght; i++) { for (int j = 0; j < noOfNodes; j++) { StateVector stateIn = new StateVector(material, U, i, j); Vector3D levelSetNormal = new Vector3D(); int offset = CNSEnvironment.NumberOfDimensions + 2; for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++) { levelSetNormal[d] = U[offset + d][i + IndexOffset, j]; } levelSetNormal.Normalize(); Debug.Assert(Math.Abs(levelSetNormal.Abs() - 1.0) < 1e-13, "Abnormal normal vector"); for (int d = 0; d < D; d++) { xLocal[d] = x[i + IndexOffset, j, d]; normal[i, j, d] = levelSetNormal[d]; } StateVector stateOut = boundaryCondition.GetBoundaryState(time, xLocal, levelSetNormal, stateIn); Debug.Assert(stateOut.IsValid, "Invalid boundary state"); Uout[0][i, j] = stateOut.Density; for (int d = 0; d < D; d++) { Uout[d + 1][i, j] = stateOut.Momentum[d]; } Uout[D + 1][i, j] = stateOut.Energy; } } fluxFunction.InnerEdgeFlux(time, -1, x, normal, U, Uout, IndexOffset, Lenght, Output); }
public override float GetVolume(ref Vector3D voxelPosition) { if (base.m_inverseIsDirty) { base.m_inverse = MatrixD.Invert(base.m_transformation); base.m_inverseIsDirty = false; } voxelPosition = Vector3D.Transform(voxelPosition, base.m_inverse); Vector3D vectord = Vector3D.Abs(voxelPosition) - this.Boundaries.HalfExtents; double num = Vector3D.Dot(voxelPosition, this.RampNormal) + this.RampNormalW; return(base.SignedDistanceToDensity((float)Math.Max(vectord.Max(), -num))); }
public void Vector3AbsTest() { Vector3D v1 = new Vector3D(-2.5f, 2.0f, 0.5f); Vector3D v3 = Vector3D.Abs(new Vector3D(0.0f, double.NegativeInfinity, double.NaN)); Vector3D v = Vector3D.Abs(v1); Assert.AreEqual(2.5f, v.X); Assert.AreEqual(2.0f, v.Y); Assert.AreEqual(0.5f, v.Z); Assert.AreEqual(0.0f, v3.X); Assert.AreEqual(double.PositiveInfinity, v3.Y); Assert.AreEqual(double.NaN, v3.Z); }
public override float GetVolume(ref Vector3D voxelPosition) { if (base.m_inverseIsDirty) { base.m_inverse = MatrixD.Invert(base.m_transformation); base.m_inverseIsDirty = false; } voxelPosition = Vector3D.Transform(voxelPosition, base.m_inverse); Vector3D center = this.Boundaries.Center; Vector3D vectord2 = Vector3D.Abs(voxelPosition - center) - (center - this.Boundaries.Min); return(base.SignedDistanceToDensity((float)vectord2.Max())); }
public void Vector3AbsTest() { Vector3D <float> v1 = new Vector3D <float>(-2.5f, 2.0f, 0.5f); Vector3D <float> v3 = Vector3D.Abs(new Vector3D <float>(0.0f, float.NegativeInfinity, float.NaN)); Vector3D <float> v = Vector3D.Abs(v1); Assert.Equal(2.5f, v.X); Assert.Equal(2.0f, v.Y); Assert.Equal(0.5f, v.Z); Assert.Equal(0.0f, v3.X); Assert.Equal(float.PositiveInfinity, v3.Y); Assert.Equal(float.NaN, v3.Z); }
/** * Find the appropriate face for the projection of a point. */ public static int FindCubeFace(ref Vector3D localPos) { Vector3D abs; Vector3D.Abs(ref localPos, out abs); if (abs.X > abs.Y) { if (abs.X > abs.Z) { if (localPos.X > 0.0f) { return((int)Direction.Right); } else { return((int)Direction.Left); } } else if (localPos.Z > 0.0f) { return((int)Direction.Backward); } else { return((int)Direction.Forward); } } else if (abs.Y > abs.Z) { if (localPos.Y > 0.0f) { return((int)Direction.Up); } else { return((int)Direction.Down); } } else if (localPos.Z > 0.0f) { return((int)Direction.Backward); } else { return((int)Direction.Forward); } }
private static string FormatSphereNoMaterialOffset(Sphere sphere, bool invert, bool includeClosingBracket = true) { bool microOffset = true; double microOff = 0.00001; //microOff = 0.000001; // Don't offset unless drawn!!! //microOff = -0.00005; if (invert) { microOff *= -1; } if (sphere.IsPlane) { Vector3D offsetOnNormal = Euclidean2D.ProjectOntoLine(sphere.Offset, new Vector3D(), sphere.Normal); double offset = offsetOnNormal.Abs(); if (offsetOnNormal.Dot(sphere.Normal) < 0) { offset *= -1; } if (microOffset) { offset -= microOff; } return(string.Format("plane {{ {0}, {1:G6}{2} {3}", FormatVec(sphere.Normal), offset, invert ? " inverse" : string.Empty, includeClosingBracket ? "}" : string.Empty)); } else { double radius = sphere.Radius; if (microOffset) { if (radius < 20) { radius -= microOff; } else { radius *= (1 - microOff); } } return(string.Format("sphere {{ {0}, {1:G6}{2} {3}", FormatVec(sphere.Center), radius, invert ? " inverse" : string.Empty, includeClosingBracket ? "}" : string.Empty)); } }
/** * Project the position to local space for a provided face. */ public static void ProjectForFace(ref Vector3D localPos, int face, out Vector2D normalCoord) { Vector3D abs; Vector3D.Abs(ref localPos, out abs); switch ((Direction)face) { case Direction.Forward: localPos /= abs.Z; normalCoord.X = -localPos.X; normalCoord.Y = localPos.Y; break; case Direction.Backward: localPos /= abs.Z; normalCoord.X = localPos.X; normalCoord.Y = localPos.Y; break; case Direction.Left: localPos /= abs.X; normalCoord.X = localPos.Z; normalCoord.Y = localPos.Y; break; case Direction.Right: localPos /= abs.X; normalCoord.X = -localPos.Z; normalCoord.Y = localPos.Y; break; case Direction.Up: localPos /= abs.Y; normalCoord.X = localPos.Z; normalCoord.Y = localPos.X; break; case Direction.Down: localPos /= abs.Y; normalCoord.X = -localPos.Z; normalCoord.Y = localPos.X; break; default: Debug.Fail("Bad face number!!!!!"); normalCoord = Vector2D.Zero; break; } }
private static string H3Facet(Sphere sphere) { if (sphere.IsPlane) { Vector3D offsetOnNormal = Euclidean2D.ProjectOntoLine(sphere.Offset, new Vector3D(), sphere.Normal); return(string.Format("plane {{ {0}, {1:G6} material {{ sphereMat }} clipped_by {{ ball }} }}", FormatVec(sphere.Normal), offsetOnNormal.Abs())); } else { return(string.Format("sphere {{ {0}, {1:G6} material {{ sphereMat }} clipped_by {{ ball }} }}", FormatVec(sphere.Center), sphere.Radius)); } }
private static string FormatSphereNoMaterial(Sphere sphere, bool invert, bool includeClosingBracket = true) { if (sphere.IsPlane) { Vector3D offsetOnNormal = Euclidean2D.ProjectOntoLine(sphere.Offset, new Vector3D(), sphere.Normal); return(string.Format("plane {{ {0}, {1:G6}{2} {3}", FormatVec(sphere.Normal), offsetOnNormal.Abs(), invert ? " inverse" : string.Empty, includeClosingBracket ? "}" : string.Empty)); } else { return(string.Format("sphere {{ {0}, {1:G6}{2} {3}", FormatVec(sphere.Center), sphere.Radius, invert ? " inverse" : string.Empty, includeClosingBracket ? "}" : string.Empty)); } }
public Ray ExecuteTransform(Ray r) { Point3D o = ExecuteTransform(r.Origin, out Vector3D oError); Vector3D d = ExecuteTransform(r.Direction); // Offset ray origin to edge of error bounds and compute _tMax_ double lengthSquared = d.LengthSquared(); double tMax = r.TMax; if (lengthSquared > 0) { double dt = d.Abs().Dot(oError) / lengthSquared; o += d.ToPoint3D() * dt; tMax -= dt; } return(new Ray(o, d, tMax, r.Time, r.Medium)); }
public Vector3D GetPow(Vector3D ThrVec, bool max = false) { var res = new Vector3D { X = ThrVec.X > 0 ? myThr.RightThrusters.EffectivePow : -myThr.LeftThrusters.EffectivePow, Y = ThrVec.Y > 0 ? myThr.UpThrusters.EffectivePow : -myThr.DownThrusters.EffectivePow, Z = ThrVec.Z > 0 ? myThr.BackwardThrusters.EffectivePow : -myThr.ForwardThrusters.EffectivePow }; if (!max) { var c = ThrVec / Vector3D.Abs(ThrVec).Sum; c /= c.AbsMax(); res *= c; } return(res); }
public H3.Cell.Edge[] Helicoid() { List <H3.Cell.Edge> fiberList = new List <H3.Cell.Edge>(); // These two params affect each other (changing numFibers will affect rotation rate). double rotationRate = Math.PI / 78.5; int numFibers = 1000; // Note: we need to increment a constant hyperbolic distance each step. int count = 0; double max = DonHatch.e2hNorm(0.998); double offset = max * 2 / (numFibers - 1); for (double z_h = -max; z_h <= max; z_h += offset) { double z = DonHatch.h2eNorm(z_h); Sphere s = H3Models.Ball.OrthogonalSphereInterior(new Vector3D(0, 0, z)); Circle3D c = H3Models.Ball.IdealCircle(s); // Two endpoints of our fiber. Vector3D v1 = new Vector3D(c.Radius, 0, c.Center.Z); Vector3D v2 = new Vector3D(-c.Radius, 0, c.Center.Z); v1.RotateXY(rotationRate * count); v2.RotateXY(rotationRate * count); v1 = Transform(v1); v2 = Transform(v2); Vector3D t = Transform(new Vector3D(0, 0, z)); double cutoff = 0.995; if (t.Abs() > cutoff) { continue; } fiberList.Add(new H3.Cell.Edge(v1, v2, order: false)); count++; } return(fiberList.ToArray()); }
public static Circle3D GeodesicFrom2Points(Vector3D a, Vector3D b) { if (a == b || a == -b) { throw new System.Exception("Geodesic not unique"); } System.Func <Vector3D, Circle3D> lineFunc = p => { Circle3D circ = new Circle3D(); circ.Radius = double.PositiveInfinity; p.Normalize(); circ.Normal = p; // Hacky representation of a line. return(circ); }; if (a.IsOrigin || b.IsOrigin) { Vector3D p = a.IsOrigin ? b : a; return(lineFunc(p)); } double mag1 = a.Abs(), mag2 = b.Abs(); if (Tolerance.Equal(mag1, 1) && Tolerance.Equal(mag2, 1)) { return(new Circle3D(a, b, a * -1)); } // The antipode in S^3 of a or b will give us a 3rd point. Vector3D antipode = Sterographic.S3toR3(Sterographic.R3toS3(a) * -1); // If the antipode is also an an antipode in R3, the points are colinear // (or they are on the equatorial 2-sphere, but that is checked above). if (a == antipode * -1) { return(lineFunc(a)); } return(new Circle3D(a, b, antipode)); }
public static Circle3D GetCircleForBallPoint(Vector3D p) { Sphere ball = new Sphere(); p = SphericalModels.GnomonicToStereo(p); if (Tolerance.GreaterThanOrEqual(p.Abs(), 1)) { return(null); } Sphere t = H3Models.Ball.OrthogonalSphereInterior(p); //return H3Models.Ball.IdealCircle( t ); // Get the corresponding point on the exterior (our inversion). p = HyperbolicModels.PoincareToKlein(p); p = HyperbolicModels.PoincareToKlein(p); p = ball.ReflectPoint(p); return(GetCircle(p)); }
// grid coordinates, not world coordinates public void calculateMaxThrust() { pos_maxThrustWorld = Vector3D.Zero; neg_maxThrustWorld = Vector3D.Zero; pos_maxThrust = Vector3D.Zero; neg_maxThrust = Vector3D.Zero; foreach(IMyThrust thruster in thrusters) { Vector3D engineDir = thruster.Orientation.Forward.GetVector(); Vector3D engineForce = engineDir * thruster.MaxEffectiveThrust; Vector3D engineForceWorld = engineForce.TransformNormal(grid.WorldMatrix); // split into positive and negative Vector3D positive = (engineForce + engineForce.Abs())/2; pos_maxThrust += positive; neg_maxThrust += engineForce - positive; // and for world space too positive = (engineForceWorld + engineForceWorld.Abs())/2; pos_maxThrustWorld += positive; neg_maxThrustWorld += engineForceWorld - positive; } }
private void PerformDrag3D(DragData dragData) { switch (dragData.Button) { case MouseButtons.Left: { // The spherical coordinate radius. double radius = m_viewLookFrom3D.Abs(); if (!Tolerance.Zero(radius)) { Vector3D newLookFrom = m_viewLookFrom3D; Vector3D newUp = m_up3D; Vector3D rotationAxis = newUp.Cross(newLookFrom); rotationAxis.Normalize(); double angle = System.Math.Atan2(dragData.XDiff, dragData.YDiff); rotationAxis.RotateAboutAxis(newLookFrom, angle); double magnitude = -System.Math.Sqrt(dragData.XDiff * dragData.XDiff + dragData.YDiff * dragData.YDiff) / 100; newLookFrom.RotateAboutAxis(rotationAxis, magnitude); newUp.RotateAboutAxis(rotationAxis, magnitude); m_viewLookFrom3D = newLookFrom; m_up3D = newUp; } break; } case MouseButtons.Right: { m_viewLookFrom3D = PerformDrag3DRight(dragData, m_viewLookFrom3D); break; } } }
private void DrawCylinders() { Glu.GLUquadric quad = Glu.gluNewQuadric(); for (int i = 1; i < 12; i++) { Vector3D position = new Vector3D((float)(6.5 * Math.Sin(i * time / 50.0)), (float)(6.5 * Math.Cos(i * time / 50.0)), -5.0f); Gl.glPushMatrix(); Gl.glTranslatef(position.X, position.Y, position.Z); Gl.glColor3fv(Vector3D.Abs(Vector3D.Sin(time * position / 100.0f)).ToArray()); Glu.gluCylinder(quad, 0.5f, 0.0f, 1.5f, 20, 20); Gl.glPopMatrix(); } Glu.gluDeleteQuadric(quad); }
/// <summary> /// LOD /// </summary> public static void LOD_Finite( Vector3D e1, Vector3D e2, out int div1, out int div2, H3.Settings settings ) { //if( settings.Halfspace ) // throw new System.NotImplementedException(); int maxHit = 15; int hit = (int)( Math.Max( e1.Abs(), e2.Abs() ) * maxHit ); div1 = 11; div2 = 30 - hit; /* lasercrystal int maxHit = 8; int hit = (int)( Math.Max( e1.Abs(), e2.Abs() ) * maxHit ); div1 = 6; div2 = 20 - hit;*/ }
private static Vector3D HalfTo( Vector3D v ) { double distHyperbolic = DonHatch.e2hNorm( v.Abs() ); double halfDistEuclidean = DonHatch.h2eNorm( distHyperbolic / 3 ); Vector3D result = v; result.Normalize( halfDistEuclidean ); return result; }
/// <summary> /// Given two points (in the UHS model), find the endpoints /// of the associated geodesic that lie on the z=0 plane. /// </summary> public static void GeodesicIdealEndpoints( Vector3D v1, Vector3D v2, out Vector3D z1, out Vector3D z2 ) { // We have to special case when geodesic is vertical (parallel to z axis). Vector3D diff = v2 - v1; Vector3D diffFlat = new Vector3D( diff.X, diff.Y ); if( Tolerance.Zero( diffFlat.Abs() ) ) // Vertical { Vector3D basePoint = new Vector3D( v1.X, v1.Y ); z1 = diff.Z > 0 ? basePoint : Infinity.InfinityVector; z2 = diff.Z < 0 ? basePoint : Infinity.InfinityVector; } else { if( Tolerance.Zero( v1.Z ) && Tolerance.Zero( v2.Z ) ) { z1 = v1; z2 = v2; return; } // If one point is ideal, we need to not reflect that one! bool swapped = false; if( Tolerance.Zero( v1.Z ) ) { Utils.SwapPoints( ref v1, ref v2 ); swapped = true; } Vector3D v1_reflected = v1; v1_reflected.Z *= -1; Circle3D c = new Circle3D( v1_reflected, v1, v2 ); Vector3D radial = v1 - c.Center; radial.Z = 0; if( !radial.Normalize() ) { radial = v2 - c.Center; radial.Z = 0; if( !radial.Normalize() ) System.Diagnostics.Debugger.Break(); } radial *= c.Radius; z1 = c.Center + radial; z2 = c.Center - radial; // Make sure the order will be right. // (z1 closest to v1 along arc). if( v1.Dist( z1 ) > v2.Dist( z1 ) ) Utils.SwapPoints( ref z1, ref z2 ); if( swapped ) Utils.SwapPoints( ref z1, ref z2 ); } }
// x,y,z -> r,theta,phi public static Vector3D CartesianToSpherical( Vector3D v ) { double r = v.Abs(); if( Tolerance.Zero( r ) ) return new Vector3D(); return new Vector3D( r, Math.Acos( v.Z / r ), Math.Atan2( v.Y, v.X ) ); }
// r,theta,phi -> x,y,z public static Vector3D SphericalToCartesian( Vector3D v ) { if( Tolerance.Zero( v.Abs() ) ) return new Vector3D(); return new Vector3D( v.X * Math.Sin( v.Y ) * Math.Cos( v.Z ), v.X * Math.Sin( v.Y ) * Math.Sin( v.Z ), v.X * Math.Cos( v.Y ) ); }
/// <summary> /// Helper that works in all geometries. /// center: http://www.wolframalpha.com/input/?i=%28+%28+%28+r+%2B+p+%29+%2F+%28+1+-+r*p+%29+%29+%2B+%28+%28+-r+%2B+p+%29+%2F+%28+1+%2B+r*p+%29+%29++%29+%2F+2 /// radius: http://www.wolframalpha.com/input/?i=%28+%28+%28+r+%2B+p+%29+%2F+%28+1+-+r*p+%29+%29+-+%28+%28+-r+%2B+p+%29+%2F+%28+1+%2B+r*p+%29+%29++%29+%2F+2 /// </summary> public static void DupinCyclideSphere( Vector3D vNonEuclidean, double radiusEuclideanOrigin, Geometry g, out Vector3D centerEuclidean, out double radiusEuclidean ) { if( g == Geometry.Euclidean ) { centerEuclidean = vNonEuclidean; radiusEuclidean = radiusEuclideanOrigin; return; } double p = vNonEuclidean.Abs(); if( !vNonEuclidean.Normalize() ) { // We are at the origin. centerEuclidean = vNonEuclidean; radiusEuclidean = radiusEuclideanOrigin; return; } double r = radiusEuclideanOrigin; double numeratorCenter = g == Geometry.Hyperbolic ? ( 1 - r * r ) : ( 1 + r * r ); double numeratorRadius = g == Geometry.Hyperbolic ? ( 1 - p * p ) : ( 1 + p * p ); double center = p * numeratorCenter / ( 1 - p * p * r * r ); radiusEuclidean = r * numeratorRadius / ( 1 - p * p * r * r ); centerEuclidean = vNonEuclidean * center; /* // Alternate impl, in this case for spherical. Mobius m = new Mobius(); m.Isometry( Geometry.Spherical, 0, p1 ); Vector3D t1 = m.Apply( new Vector3D( mag, 0, 0 ) ); Vector3D t2 = m.Apply( new Vector3D( -mag, 0, 0 ) ); center = ( t1 + t2 ) / 2; radius = t1.Dist( t2 ) / 2; */ }
/// <summary> /// Calculate points along a geodesic segment from v1 to v2. /// </summary> public static Vector3D[] GeodesicPoints( Vector3D v1, Vector3D v2, int div ) { Vector3D center, normal; double radius, angleTot; Geodesic( v1, v2, out center, out radius, out normal, out angleTot ); if( Infinity.IsInfinite( radius ) || Tolerance.Zero( v1.Abs() ) || Tolerance.Zero( v2.Abs() ) ) // HACK! radius should be infinite, something wrong with geodesic func { Segment seg = Segment.Line( v1, v2 ); return seg.Subdivide( div ); //return new Vector3D[] { v1, v2 }; } else return Shapeways.CalcArcPoints( center, radius, v1, normal, angleTot, div ); }
/// <summary> /// Find an orthogonal sphere defined by a single interior point. /// This point is the unique point on the sphere that is furthest from the ball boundary. /// (equivalently, closest to the origin) /// </summary> public static Sphere OrthogonalSphereInterior( Vector3D v ) { // r = radius of sphere // c = distance from origin to passed in point // http://www.wolframalpha.com/input/?i=%28c%2Br%29%5E2+%3D+1+%2B+r%5E2%2C+solve+for+r double c = v.Abs(); double r = -(c * c - 1) / (2 * c); v.Normalize(); return new Sphere() { Center = v * ( c + r ), Radius = r }; }
/// <summary> /// Calculate the cosine of the angle between two vectors. /// </summary> private static double CosAngle( Vector3D p1, Vector3D p2 ) { double cosA = p1.Dot( p2 ) / (p1.Abs() * p2.Abs()); return Clamp( cosA ); }
/// <summary> /// Given 2 points in the interior of the ball, calculate the center and radius of the orthogonal circle. /// One point may optionally be on the boundary, but one shoudl be in the interior. /// If both points are on the boundary, we'll fall back on our other method. /// </summary> public static void OrthogonalCircleInterior( Vector3D v1, Vector3D v2, out Circle3D circle ) { if( Tolerance.Equal( v1.Abs(), 1 ) && Tolerance.Equal( v2.Abs(), 1 ) ) { circle = OrthogonalCircle( v1, v2 ); return; } // http://www.math.washington.edu/~king/coursedir/m445w06/ortho/01-07-ortho-to3.html // http://www.youtube.com/watch?v=Bkvo09KE1zo Vector3D interior = Tolerance.Equal( v1.Abs(), 1 ) ? v2 : v1; Sphere ball = new Sphere(); Vector3D reflected = ball.ReflectPoint( interior ); circle = new Circle3D( reflected, v1, v2 ); }
/// <summary> /// Calculate the sine of the angle between two vectors. /// </summary> private static double SinAngle( Vector3D p1, Vector3D p2 ) { double sinA = (p1.Cross( p2 )).Abs() / (p1.Abs() * p2.Abs()); return Clamp( sinA ); }
public static PerspectiveCamera CreateFromBounds(AxisAlignedBox3D bounds, Viewport3D viewport, float fieldOfView, float yaw = 0.0f, float pitch = 0.0f, float zoom = 1.0f) { // Calculate initial guess at camera settings. Matrix3D transform = Matrix3D.CreateFromYawPitchRoll(yaw, pitch, 0); Vector3D cameraDirection = Vector3D.Normalize(transform.Transform(Vector3D.Forward)); PerspectiveCamera initialGuess = new PerspectiveCamera { FieldOfView = fieldOfView, NearPlaneDistance = 1.0f, FarPlaneDistance = bounds.Size.Length() * 10, Position = bounds.Center - cameraDirection * bounds.Size.Length() * 2, LookDirection = cameraDirection, UpDirection = Vector3D.Up }; Matrix3D projection = initialGuess.GetProjectionMatrix(viewport.AspectRatio); Matrix3D view = initialGuess.GetViewMatrix(); // Project bounding box corners onto screen, and calculate screen bounds. float closestZ = float.MaxValue; Box2D?screenBounds = null; Point3D[] corners = bounds.GetCorners(); foreach (Point3D corner in corners) { Point3D screenPoint = viewport.Project(corner, projection, view, Matrix3D.Identity); if (screenPoint.Z < closestZ) { closestZ = screenPoint.Z; } IntPoint2D intScreenPoint = new IntPoint2D((int)screenPoint.X, (int)screenPoint.Y); if (screenBounds == null) { screenBounds = new Box2D(intScreenPoint, intScreenPoint); } else { Box2D value = screenBounds.Value; value.Expand(intScreenPoint); screenBounds = value; } } // Now project back from screen bounds into scene, setting Z to the minimum bounding box Z value. IntPoint2D minScreen = screenBounds.Value.Min; IntPoint2D maxScreen = screenBounds.Value.Max; Point3D min = viewport.Unproject(new Point3D(minScreen.X, minScreen.Y, closestZ), projection, view, Matrix3D.Identity); Point3D max = viewport.Unproject(new Point3D(maxScreen.X, maxScreen.Y, closestZ), projection, view, Matrix3D.Identity); // Use these new values to calculate the distance the camera should be from the AABB centre. Vector3D size = Vector3D.Abs(max - min); float radius = size.Length(); float dist = radius / (2 * MathUtility.Tan(fieldOfView * viewport.AspectRatio / 2)); Point3D closestBoundsCenter = (min + (max - min) / 2); Point3D position = closestBoundsCenter - cameraDirection * dist * (1 / zoom); return(new PerspectiveCamera { FieldOfView = fieldOfView, NearPlaneDistance = 1.0f, FarPlaneDistance = dist * 10, Position = position, LookDirection = cameraDirection, UpDirection = Vector3D.Up }); }