private int FindHelper(kdnode node, Point3D pt) { if (node == null) { return -1; } else if (Math.Abs(pt.X - node.Pt.X) < mEpsilon && Math.Abs(pt.Y - node.Pt.Y) < mEpsilon && Math.Abs(pt.Z - node.Pt.Z) < mEpsilon) { return node.Idx; } else if (pt.X < node.Pt.X - mEpsilon) { return FindHelper(node.Left, new Point3D(pt.Y, pt.Z, pt.X)); } else if (pt.X > node.Pt.X + mEpsilon) { return FindHelper(node.Right, new Point3D(pt.Y, pt.Z, pt.X)); } else { int leftresult = FindHelper(node.Left, new Point3D(pt.Y, pt.Z, pt.X)); if (leftresult != -1) return leftresult; return FindHelper(node.Right, new Point3D(pt.Y, pt.Z, pt.X)); } }
public static void ConvexHull(ref Surface surf) { if (surf.NumPoints < 4) return; //add the middle point to make a tetrahedron for some numerical stability Point3D Middle = new Point3D(); for (int i = 0; i < surf.NumPoints; i++) { Middle += surf.Point(i); } Middle /= surf.NumPoints; int mid = surf.AddPoint(Middle); //clean out the faces, and add faces of a tetrahedron using the first 3 pts and the middle. Point3D inside = (surf.Point(0) + surf.Point(1) + surf.Point(2) + surf.Point(mid)) / 4.0; while (surf.NumFaces > 0) surf.RemoveFace(0); surf.AddFace(0, 1, 2, inside); surf.AddFace(0, 1, mid, inside); surf.AddFace(0, 2, mid, inside); surf.AddFace(1, 2, mid, inside); // add in points one at a time, remove and replace faces as necessary for (int i = 3; i < surf.NumPoints; i++) { List<Edge> Edges = new List<Edge>(); //for the ith point... //go through the each existing face, for (int j = surf.NumFaces - 1; j >= 0; j--) { //if a triangle is facing our new point, remove the face, add its edges to a list. double tmp = Point3D.Dot(surf.FaceNormal(j), surf.Point(i) - surf.Point(surf.Face(j).I)); if (Point3D.Dot(surf.FaceNormal(j), (surf.Point(i) - surf.Point(surf.Face(j).I)).Normalized) > -DMS.EPSILON) { Edges.Add(new Edge(surf.Face(j).I, surf.Face(j).J)); Edges.Add(new Edge(surf.Face(j).J, surf.Face(j).K)); Edges.Add(new Edge(surf.Face(j).K, surf.Face(j).I)); surf.RemoveFace(j); } } //now add a triangle using any non duplicated edges together with our new point. Edges.Sort(Edge.Comparison); for (int j = 0; j < Edges.Count(); j++) { if (j != Edges.Count() - 1 && Edges[j] == Edges[j + 1]) { //this edge is a duplicate, do nothing. j++; //we'll skip the next one which is a duplicate too. continue; } surf.AddFace(Edges[j].I, Edges[j].J, i, inside); } } }
public Rotation(double Angle, Point3D Axis) { Axis.Normalize(); mQ0 = Math.Cos(Angle / 2.0); Axis.Scale(Math.Sin(Angle / 2.0)); mQX = Axis.X; mQY = Axis.Y; mQZ = Axis.Z; Normalize(); }
public Color GetSpherePixel(Point3D point) { //look up theta and phi "directly" from X, Y. double X = point.Theta / DMS.TAU; double Y = point.Phi / DMS.HALFTAU; //but really 0 is at the north pole. if (X < 0.0) X += 1.0; return GetPixel( (int)(X * m_Size.Width), (int)(Y * m_Size.Height) ); }
//constructors; public OctahedronUnit(Size size, DMSImage Source, Point3D center, Point3D topRight) : base(size, Source) { O = center.Normalized; F = Point3D.Cross(center, topRight).Normalized; A = Point3D.Cross(F, O); H = -A; C = -F; B = (O + A + C).ScaledTo(2.0 / Math.Sqrt(3.0)); E = (O + C + H).ScaledTo(2.0 / Math.Sqrt(3.0)); G = (O + F + H).ScaledTo(2.0 / Math.Sqrt(3.0)); D = (O + F + A).ScaledTo(2.0 / Math.Sqrt(3.0)); }
public Cylinder(Point3D Center, Point3D Direction, double Height, double Radius, int nPoints) { //create cylinder centered at 0, along z axis, with given length and radius. for (int i = 0; i < nPoints; i++) { AddPoint(Point3D.FromCylindricalCoords(Radius, Height / 2.0, Math.PI * 2.0 * ((double)i / nPoints))); AddPoint(Point3D.FromCylindricalCoords(Radius, -Height / 2.0, Math.PI * 2.0 * ((double)i / nPoints))); } AddPoint(new Point3D(0, 0, Height / 2.0)); AddPoint(new Point3D(0, 0, -Height / 2.0)); //add faces for (int i = 0; i < nPoints; i++) { int next = (i + 1) % nPoints; AddFace(nPoints, i * 2, next * 2, Point3D.Origin); AddFace(nPoints + 1, i * 2 + 1, next * 2 + 1, Point3D.Origin); AddFace(next * 2, i * 2 + 1, i * 2, Point3D.Origin); AddFace(next * 2, i * 2 + 1, next * 2 + 1, Point3D.Origin); } if (Radius < 0) { foreach (Triangle tri in mFaces) tri.Reverse(); } //transform points if (Direction.R > DMS.EPSILON && Direction.Phi > DMS.EPSILON) { Rotation rot = new Rotation(Direction.Normalized.Phi, new Point3D(-Direction.Y, Direction.X, 0)); for (int i = 0; i < mPts.Count(); i++) { mPts[i] = rot.Rotate(mPts[i]); } } //add offset for (int i = 0; i < mPts.Count(); i++) { mPts[i] += Center; } }
public override Color GetPixel(int x, int y) { Point3D Q; if (m_bOrthographic) { //if outside circle if ((new Point2D(x, y) - m_center).R > m_radius) { return m_Blank; } double u = (double)(x - m_radius) / m_radius; double v = (double)(y - m_radius) / m_radius; double w = Math.Sqrt(Math.Max(1.0 - u * u - v * v, 0.0)); Q = new Point3D(u, v, w); Q = m_sphereRot.Rotate(Q); } else { double u = (double)(x) / (double)(m_Size.Width) * DMS.TAU; double v = (double)(y) / (double)(m_Size.Height) * DMS.HALFTAU; Q = Point3D.FromSphericalCoords(1.0, v, u); } if( m_Source != null ) { return m_Source.GetPixel( new Point2D( DMS.FixAnglePositive(-Q.Theta) / DMS.TAU, Q.Phi / DMS.HALFTAU) ); } RelativePosition RP = m_Skeleton.NearestSegmentOnSphere( Q ); Segment S = RP.Segment; int nIdx = m_Skeleton.IndexOf(S); //draw skeleton line if( RP.Distance < 0.4 * DMS.TAU/360.0 ) return Color.Black; return Globemaker.colorFromRandomIndex(nIdx); }
public override Color GetPixel(int x, int y) { //convert x,y to 0 to 1 double remapX = (double)x / (double)Size.Width; double remapY = (double)y / (double)Size.Width; if (remapX + remapY > 1.5 || remapX + remapY < 0.5 || remapX - remapY < -0.5 || remapX - remapY > 0.5) { return m_Blank; } Point3D O = new Point3D(2, 1, 0); Point3D U = new Point3D(-2, 0, 2); Point3D V = new Point3D(-2, 0, -2); Point3D src = O + remapX*U + remapY*V; return m_Source.GetSpherePixel(src); }
private bool InsertHelper(ref kdnode node, Point3D pt, int idx) { if (node == null) { node = new kdnode(pt, idx); return true; } else if( Math.Abs(pt.X - node.Pt.X) < mEpsilon && Math.Abs(pt.Y - node.Pt.Y) < mEpsilon && Math.Abs(pt.Z - node.Pt.Z) < mEpsilon ) { return false; } else { if (pt.X < node.Pt.X) return InsertHelper(ref node.Left, new Point3D(pt.Y, pt.Z, pt.X), idx); else return InsertHelper(ref node.Right, new Point3D(pt.Y, pt.Z, pt.X), idx); } }
private Segment m_Segment; //which segment we're talking about #endregion Fields #region Constructors //point on sphere public RelativePosition( Point3D p, Segment seg ) { m_Segment = seg; Point3D PosOnSphere = m_Segment.Arot.Inverse.Rotate( p ); //we think of our segment starting at z and rotating towards x; double fAngle = DMS.FixAnglePositive(Math.Atan2(PosOnSphere.X, PosOnSphere.Z)); //test if closest orthoganally if( fAngle < m_Segment.Length ) { m_fTheta = PosOnSphere.Y > 0 ? DMS.QUARTERTAU : -DMS.QUARTERTAU; m_fClosestPt = fAngle; m_fDistance = Math.Abs(Math.Asin( PosOnSphere.Y )); } /* if */ //angle to A (z-axis) is TWO_PI-fAngle, angle to B (end of rot.) is fAngle-length // test if point on sphere is closer to z axis then to end of rot. else if( (DMS.TAU - fAngle) < (fAngle - m_Segment.Length) ) { m_fTheta = PosOnSphere.Theta; m_fClosestPt = 0.0; m_fDistance = PosOnSphere.Phi; } /* else if */ // otherwise point on sphere is closer to end of rotation then to z axis else { //rotate posonsphere about y (from x to z) by grSegments[dtCurrent.nIdx].length PosOnSphere = new Point3D( Math.Sin(Math.Atan2(PosOnSphere.X, PosOnSphere.Z)-m_Segment.Length) * Math.Sqrt(1.0-PosOnSphere.Y*PosOnSphere.Y), PosOnSphere.Y, Math.Cos(Math.Atan2(PosOnSphere.X, PosOnSphere.Z)-m_Segment.Length) * Math.Sqrt(1.0-PosOnSphere.Y*PosOnSphere.Y) ); //now it's same as before except for fClosestPt m_fTheta = PosOnSphere.Theta; m_fClosestPt = m_Segment.Length; m_fDistance = PosOnSphere.Phi; } /* else if */ }
private void AddCity() { Point3D city; double greyval; while(true) { city = new Point3D( m_rand.NextDouble()-0.5, m_rand.NextDouble() - 0.5, m_rand.NextDouble() - 0.5); if( city.R > 0.5 ) continue; //go from uniform random cube to uniform random random sphere. greyval = GetGreyValue(city); m_totalareacount++; if( greyval < 0.0 ) //don't add cities to empty spaces { m_emptyareacount++; continue; } if( m_rand.NextDouble() * greyval * greyval > 0.01 ) continue; break; } m_SumGreyValues += greyval; city.Normalize(); m_Cities.Add(city); }
public RelativePosition NearestSegmentOnSphere(Point3D pos) { RelativePosition result = null; foreach( Segment seg in m_Segments ) { RelativePosition current = new RelativePosition(pos, seg); if( result == null || current.Distance * current.Segment.Strength + DMS.EPSILON < result.Distance * result.Segment.Strength ) { result = current; } /* if */ } /* foreach */ return result; }
private Point2D coordsInFundDomain(Point3D p) { //want baricentric coords (u,v) st. B + u*(A-B) + v*(C-B) = p' //where p' is p projected to X=1.0 plane. p.Scale(1.0 / p.X); Point3D A = domainCorner(0); Point3D B = domainCorner(1); Point3D C = domainCorner(2); Point2D v0 = new Point2D(A.Y - B.Y, A.Z - B.Z); Point2D v1 = new Point2D(C.Y - B.Y, C.Z - B.Z); Point2D v2 = new Point2D(p.Y - B.Y, p.Z - B.Z); double dot00 = Point2D.Dot(v0, v0); double dot01 = Point2D.Dot(v0, v1); double dot02 = Point2D.Dot(v0, v2); double dot11 = Point2D.Dot(v1, v1); double dot12 = Point2D.Dot(v1, v2); double invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01); return new Point2D( (dot11 * dot02 - dot01 * dot12) * invDenom, (dot00 * dot12 - dot01 * dot02) * invDenom); }
public PixelInfo(int u, int v, Point3D color) { _U = u; _V = v; _color = color; Up = Down = Left = Right = 0; }
private double MinWeightedDist(Point3D a, Point3D b) { double greyvalueA = GetGreyValue(a); double greyvalueB = GetGreyValue(b); double result = Math.Acos(Point3D.Dot(a, b)); result -= m_GlobalRadius * GetGreyValue(a); result -= m_GlobalRadius * GetGreyValue(b); return result / Math.Max(greyvalueA, greyvalueB); }
private bool IsInThirt(Point3D pt) { Point3D[] thirt = new Point3D[] { new Point3D(-3.662782754263035300e-01, 7.559006998770361200e-01, 5.426364868640331000e-01), new Point3D(-9.408369689587646700e-01, 3.266601753606225300e-01, -9.010509238579085500e-02), new Point3D(2.949031158172585300e-01, -6.086014011689210300e-01, -7.366386405670685100e-01), new Point3D(-7.408675404485654300e-20, 1.131011890285944400e-19, 1.000000000000000000e+00), new Point3D(-7.559006998770361200e-01, -3.662782754263035300e-01, 5.426364868640331000e-01), new Point3D(-3.266601753606225300e-01, -9.408369689587646700e-01, -9.010509238579085500e-02), new Point3D(6.086014011689210300e-01, 2.949031158172585300e-01, -7.366386405670685100e-01), new Point3D(3.662782754263035300e-01, -7.559006998770361200e-01, 5.426364868640331000e-01), new Point3D(9.408369689587646700e-01, -3.266601753606225300e-01, -9.010509238579085500e-02), new Point3D(-2.949031158172585300e-01, 6.086014011689210300e-01, -7.366386405670685100e-01), new Point3D(7.559006998770361200e-01, 3.662782754263035300e-01, 5.426364868640331000e-01), new Point3D(3.266601753606225300e-01, 9.408369689587646700e-01, -9.010509238579085500e-02), new Point3D(-6.086014011689210300e-01, -2.949031158172585300e-01, -7.366386405670685100e-01) }; for (int i = 0; i < 13; i++) { if (Math.Acos(Point3D.Dot(thirt[i], pt.Normalized)) < 57.1367031 / 2.0 * Math.PI / 180.0) { return true; } } return false; }
private List<Point3D> Interpolate(int idx, int pieces, bool bSpline) { List<Point3D> result = new List<Point3D>(); if (!bSpline) { //line segment Point3D dir = (m_Cities[(idx + 1) % m_Cities.Count] - m_Cities[idx]) / (double)pieces; for (int i = 0; i <= pieces; i++) { result.Add(m_Cities[idx] + dir * i); } } else { //spline Point3D p4 = m_Cities[idx]; Point3D p3 = m_Cities[(idx - 1 + m_Cities.Count) % m_Cities.Count]; Point3D p2 = m_Cities[(idx - 2 + m_Cities.Count) % m_Cities.Count]; Point3D p1 = m_Cities[(idx - 3 + m_Cities.Count) % m_Cities.Count]; double[] a = new double[5]; double[] b = new double[5]; Point3D[] A = new Point3D[5]; A[0] = (-p1 + 3.0 * p2 - 3.0 * p3 + p4) / 6.0; A[1] = (3.0 * p1 - 6.0 * p2 + 3.0 * p3) / 6.0; A[2] = (-3.0 * p1 + 3.0 * p3) / 6.0; A[3] = (p1 + 4 * p2 + p3) / 6.0; for (int i = 0; i <= pieces; i++) { float t = (float)i / pieces; result.Add((A[2] + t * (A[1] + t * A[0])) * t + A[3]); } } return result; }
private double Dist( Point3D a, Point3D b ) { double result = Math.Acos(Point3D.Dot(a, b)); result -= m_GlobalRadius * GetGreyValue(a); result -= m_GlobalRadius * GetGreyValue(b); return result; }
private double GetGreyValue(Point3D pt) { if (m_Source == null) { #if false if( IsInThirt( pt ) ) return 0.1; //dark else return -1.0; //so light it's not there. #elif true if( IsInCox53( pt ) ) return 0.1; //dark else return -1.0; //so light it's not there. #else return 1.0; #endif } double result; lock (m_Source) { result = m_Source.GetSpherePixel(pt).GetBrightness(); } if (result == 1.0) return -1.0; return (0.1 + 0.9 * result); }
public static Point3D Cross( Point3D A, Point3D B ) { return new Point3D( A.Y*B.Z - A.Z*B.Y, A.Z*B.X - A.X*B.Z, A.X*B.Y - A.Y*B.X ); }
private bool IsInCox53(Point3D pt) { bool result = true; Point3D[] planenorms = new Point3D[] { new Point3D(0,0,1), new Point3D(0,1,0), new Point3D(0.309016994,-0.809016994,-0.5), new Point3D(0.309016994,-0.809016994,0.5), new Point3D(0.309016994,0.809016994,-0.5), new Point3D(0.309016994,0.809016994,0.5), new Point3D(0.5,-0.309016994,-0.809016994), new Point3D(0.5,-0.309016994,0.809016994), new Point3D(0.5,0.309016994,-0.809016994), new Point3D(0.5,0.309016994,0.809016994), new Point3D(0.809016994,-0.5,-0.309016994), new Point3D(0.809016994,-0.5,0.309016994), new Point3D(0.809016994,0.5,-0.309016994), new Point3D(0.809016994,0.5,0.309016994), new Point3D(1,0,0) }; for (int i = 0; i < 15; i++) { if (Point3D.Dot(planenorms[i], pt.Normalized) < 0.0) { result = !result; } } return result; }
/// <summary> /// returns the angle between /// the plane containing points ABO and /// the plane containing points CBO /// where O is the origin /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <param name="C"></param> /// <returns></returns> public static double DihedralAngle(Point3D A, Point3D B, Point3D C) { double result = -1.0; try { Point3D normal1 = Point3D.Cross(A - B, B ); Point3D normal2 = Point3D.Cross(C - B, B); result = Point3D.Angle(normal1, Point3D.Origin, normal2); } catch {} return result; }
private Point3D JitterPt(Point3D pt) { double oneminuscosjitterradius = 1.0 - Math.Cos(m_JitterRadius * GetGreyValue(pt)); //First we get a random point within spherical cap centered at (0,0,1) with a radius of max Point3D jitteredpt = Point3D.FromSphericalCoords(1.0, Math.Acos(1.0 - m_rand.NextDouble() * oneminuscosjitterradius), m_rand.NextDouble() * 2.0 * Math.PI ); Rotation ToPt = new Rotation(pt.Theta, pt.Phi, 0); return ToPt.Rotate( jitteredpt ); }
public static double Dot(Point3D A, Point3D B) { return A.X*B.X + A.Y*B.Y + A.Z*B.Z; }
private double SetAvgColour(PixelInfo pixel) { Point3D NewColor = new Point3D(); Point3D tmp; int count = 0; pixel.SetNeighbors(m_Source, m_resolution); if (pixel.Up != 0) { tmp = GetPixelHelper(pixel.U, pixel.V - pixel.Up); if (tmp != null) { NewColor += tmp; count++; } } if (pixel.Down != 0) { tmp = GetPixelHelper(pixel.U, pixel.V + pixel.Down); if (tmp != null) { NewColor += tmp; count++; } } if (pixel.Left != 0) { tmp = GetPixelHelper(pixel.U - pixel.Left, pixel.V); if (tmp != null) { NewColor += tmp; count++; } } if (pixel.Up != 0) { tmp = GetPixelHelper(pixel.U + pixel.Right, pixel.V); if (tmp != null) { NewColor += tmp; count++; } } if (count == 0) NewColor = new Point3D(128, 128, 128); else NewColor /= (double)count; double Result = (pixel.color - NewColor).R; pixel.color = NewColor; return Result; }
public Point3D(Point3D A) : this(A.X, A.Y, A.Z) { }
public override Color GetPixel(int x, int y) { Point3D result = GetPixelHelper(x, y); if (result == null) { int u = x - (x % m_resolution); int v = y - (y % m_resolution); Point3D A = GetPixelHelper(u, v); Point3D B = GetPixelHelper(u, v + m_resolution); Point3D C = GetPixelHelper(u + m_resolution, v); Point3D D = GetPixelHelper(u + m_resolution, v + m_resolution); double U = (double)(x - u) / m_resolution; double V = (double)(y - v) / m_resolution; result = new Point3D(); double count = 0.0; if (A != null) { result += (1.0 - U) * (1.0 - V) * A; count += (1.0 - U) * (1.0 - V); } if (B != null) { result += (1.0 - U) * V * B; count += (1.0 - U) * V; } if (C != null) { result += U * (1.0 - V) * C; count += U * (1.0 - V); } if (D != null) { result += U * V * D; count += U * V; } if (count == 0.0) result = new Point3D(128, 128, 128); else result /= count; } if (result.X < 0.0) result.X = 0.0; if (result.Y < 0.0) result.Y = 0.0; if (result.Z < 0.0) result.Z = 0.0; if (result.X > 255.0) result.X = 255.0; if (result.Y > 255.0) result.Y = 255.0; if (result.Z > 255.0) result.Z = 255.0; // we add a dither return Color.FromArgb(Dither(result.X), Dither(result.Y), Dither(result.Z)); }
public Point3D ScaledTo(double newLength ) { Point3D result = new Point3D(this); result.R = newLength; return result; }
public Color GetSpherePixel(Point3D point) { if (mSourceType == DMSImageType.Equirectangular) { //latitude and longitude are pulled straight from spherical coordinates of the 3d pooint double longitude = point.Theta / DMS.TAU; double latitude = point.Phi / DMS.HALFTAU; //but really 0 is at the north pole. if (longitude < 0.0 ) longitude += 1.0; Point2D EquirectangularLocation = new Point2D( longitude, latitude ); return GetPixel(EquirectangularLocation); } else { // we can get the location on a mirror ball image from the spherical coordinates by taking the sin of phi. Point2D MirrorBallLocation = Point2D.FromPolar(Math.Sin(point.Phi/2.0), point.Theta); //the coordinates are from -1 to 1, we need to convert them to 0 to 1 MirrorBallLocation += new Point2D(1, 1); MirrorBallLocation.Scale(0.5); return GetPixel(MirrorBallLocation); } }
public bool bNearerSegmentOnSphereExists( Point3D pos, double fCriteria ) { if( m_LastCloserSegment != null && RelativePosition.IsNearerOnSphere( pos, m_LastCloserSegment, fCriteria ) ) { return true; } foreach( Segment seg in m_Segments ) { if (RelativePosition.IsNearerOnSphere(pos, seg, fCriteria)) { m_LastCloserSegment = seg; return true; } } return false; }