/// <summary> /// Reflect a point in us. /// </summary> public Vector3D ReflectPoint(Vector3D p) { if (IsPlane) { // We used to call ProjectOntoPlane, but optimized it away. // This is faster because we already know our normal is normalized, // and it avoids some extra Vector3D operations. double dist = Euclidean3D.DistancePointPlane(this.Normal, this.Offset, p); Vector3D offset = this.Normal * dist * -2; return(p + offset); } else { if (p == Center) { return(Infinity.InfinityVector); } if (Infinity.IsInfinite(p)) { return(Center); } Vector3D v = p - Center; double d = v.Abs(); v.Normalize(); return(Center + v * (Radius * Radius / d)); } }
/// <summary> /// Reflect a point in us. /// </summary> public Vector3D ReflectPoint(Vector3D p) { if (IsPlane) { //Debug.Assert( !Infinity.IsInfinite( p ) ); Vector3D v = Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, p); v = p + (v - p) * 2; return(v); } else { if (p == Center) { return(Infinity.InfinityVector); } if (Infinity.IsInfinite(p)) { return(Center); } Vector3D v = p - Center; double d = v.Abs(); v.Normalize(); return(Center + v * (Radius * Radius / d)); } }
public bool IsPointOn(Vector3D test) { if (IsPlane) { double dist = Euclidean3D.DistancePointPlane(this.Normal, this.Offset, test); return(Tolerance.Zero(dist)); } return(Tolerance.Equal((test - Center).Abs(), Radius)); }
/// <summary> /// Calculate a normal after a transformation function is applied /// to the points of the polygon. /// </summary> public Vector3D NormalAfterTransform(System.Func <Vector3D, Vector3D> transform) { if (this.NumSides < 1) { return(new Vector3D(0, 0, 1)); } return(Euclidean3D.NormalFrom3Points( this.Segments[0].P1, this.Segments[0].P2, this.Center, transform)); }
public static void TranslateSphere(Sphere s, Vector3D t) { if (s.IsPlane) { Vector3D offsetAlongNormal = Euclidean3D.ProjectOntoLine(s.Normal, new Vector3D(), t); s.Offset += offsetAlongNormal; } else { s.Center += t; } }
/// <summary> /// Radially project a point onto our surface. /// </summary> public Vector3D ProjectToSurface(Vector3D p) { if (this.IsPlane) { return(Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, p)); } Vector3D direction = p - Center; direction.Normalize(); direction *= Radius; return(Center + direction); }
/// <summary> /// Reflect ourselves about another sphere. /// </summary> public void Reflect(Sphere sphere) { // An interior point used to calculate whether we get inverted. Vector3D interiorPoint; if (IsPlane) { Debug.Assert(!this.Normal.IsOrigin); interiorPoint = this.Offset - this.Normal; } else { // We don't want it to be the center, because that will reflect to infinity. interiorPoint = (this.Center + new Vector3D(this.Radius / 2, 0)); } if (Invert) { interiorPoint = ReflectPoint(interiorPoint); } Debug.Assert(IsPointInside(interiorPoint)); interiorPoint = sphere.ReflectPoint(interiorPoint); Debug.Assert(!interiorPoint.DNE); if (this.Equals(sphere)) { if (IsPlane) { //this.Center = -this.Center; // Same as inverting, but we need to do it this way because of Pov-Ray this.Invert = !this.Invert; } else { this.Invert = !this.Invert; } Debug.Assert(this.IsPointInside(interiorPoint)); return; } // Both planes? if (IsPlane && sphere.IsPlane) { // XXX - not general, but I know the planes I'll be dealing with go through the origin. //if( !sphere.Offset.IsOrigin ) // throw new System.NotImplementedException(); /*Vector3D p1 = this.Normal.Cross( sphere.Normal ); * if( !p1.Normalize() ) * { * this.Center *= -1; * return; * } * * Vector3D p2 = p1.Cross( this.Normal ); * p2.Normalize(); * p1 = sphere.ReflectPoint( p1 ); * p2 = sphere.ReflectPoint( p2 ); * Vector3D newNormal = p2.Cross( p1 ); * if( !newNormal.Normalize() ) * throw new System.Exception( "Reflection impl" ); * this.Center = newNormal;*/ // Reflect the normal relative to the plane (conjugate with sphere.Offset). Vector3D newNormal = this.Normal + sphere.Offset; newNormal = sphere.ReflectPoint(newNormal); newNormal -= sphere.Offset; newNormal.Normalize(); this.Center = newNormal; // Calc the new offset (so far we have considered planes through origin). this.Offset = sphere.ReflectPoint(this.Offset); //Debug.Assert( Offset.IsOrigin ); // XXX - should handle more generality. Debug.Assert(this.IsPointInside(interiorPoint)); return; } // We are a plane and reflecting in a sphere. if (IsPlane) { // Think of 2D case here (circle and line)... Vector3D projected = Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, sphere.Center); Vector3D p = sphere.ReflectPoint(projected); if (Infinity.IsInfinite(p)) { // This can happen if we go through sphere.Center. // This reflection does not change our orientation (does not invert us). return; } Center = sphere.Center + (p - sphere.Center) / 2; Radius = Center.Dist(sphere.Center); // Did this invert us? if (!this.IsPointInside(interiorPoint)) { Invert = !Invert; } return; } // Is mirror a plane? if (sphere.IsPlane) { Vector3D projected = Euclidean3D.ProjectOntoPlane(sphere.Normal, sphere.Offset, Center); Vector3D diff = Center - projected; Center -= 2 * diff; // Radius remains unchanged. // NOTE: This does not invert us. Debug.Assert(this.IsPointInside(interiorPoint)); return; } // // Now sphere reflecting in a sphere. // // Reflecting to a plane? if (IsPointOn(sphere.Center)) { // Concentric spheres? if (Center == sphere.Center) { throw new System.Exception(); } // Center Vector3D center = Center - sphere.Center; // Offset Vector3D direction = center; direction.Normalize(); Vector3D offset = direction * Radius * 2; offset = sphere.ReflectPoint(offset); // We are a line now. Center = center; //Offset = offset; // Not working?? Caused issues in old generation code for 435. Radius = double.PositiveInfinity; // Did this invert us? if (!this.IsPointInside(interiorPoint)) { this.Invert = !this.Invert; } Debug.Assert(this.IsPointInside(interiorPoint)); return; } // XXX - Could try to share code below with Circle class. // NOTE: We can't just reflect the center. // See http://mathworld.wolfram.com/Inversion.html double a = Radius; double k = sphere.Radius; Vector3D v = Center - sphere.Center; double s = k * k / (v.MagSquared() - a * a); Center = sphere.Center + v * s; Radius = Math.Abs(s) * a; // Did this invert us? if (!this.IsPointInside(interiorPoint)) { Invert = !Invert; } }