private PixelInformation getIlluminationDirectionPerRenderingPixel(SpacecraftState sc, uint x, uint y) { PixelInformation PixelOut = new PixelInformation(); Vector3D c_pos = sc.getPosition(); // STEP 1: Visibility Test Vector3D rayDirection = (sc.getPOVDirection() + (((1 + Convert.ToDouble(this._height) - (2 * Convert.ToDouble(y))) / (2 * Convert.ToDouble(this._height))) * sc.getPOVUp()) - (((1 + Convert.ToDouble(this._width) - (2 * Convert.ToDouble(x))) / (2 * Convert.ToDouble(this._width))) * sc.getPOVRight())).unit(); double discriminant = 4 * Math.Pow(c_pos * rayDirection, 2) - 4 * (rayDirection * rayDirection) * (c_pos * c_pos) + 4 * (rayDirection * rayDirection) * Math.Pow(_moon_radius, 2); bool encounter = false; Vector3D p_surf = new Vector3D(); if (discriminant < 0) { // no encounter } else if (discriminant == 0) { // one intersection encounter = true; double t = (-2 * (c_pos * rayDirection)) / (2 * (rayDirection * rayDirection)); p_surf = c_pos + rayDirection * t; } else { // two intersections encounter = true; double t1 = (-2 * (c_pos * rayDirection) + Math.Sqrt(discriminant)) / (2 * (rayDirection * rayDirection)); double t2 = (-2 * (c_pos * rayDirection) - Math.Sqrt(discriminant)) / (2 * (rayDirection * rayDirection)); Vector3D ray_point1 = c_pos + rayDirection * t1; Vector3D ray_point2 = c_pos + rayDirection * t2; double ray_norm1 = (ray_point1 - c_pos).norm(); double ray_norm2 = (ray_point2 - c_pos).norm(); if (ray_norm1 < ray_norm2) { p_surf = ray_point1; } else { p_surf = ray_point2; } } if (encounter) { /* Pixel shows the Moon's surface: Continue with executing steps 2 - 8. */ double x1 = Convert.ToDouble(x); double y1 = Convert.ToDouble(y); // STEP 2: Obtaining the Surface Hit Point PixelOut.lat = tools.rad2deg((Math.PI / 2) - Math.Acos(p_surf.z() / _moon_radius)); PixelOut.lon = tools.rad2deg(Math.Atan2(p_surf.y(), p_surf.x())); // STEP 3: Calculation of the Sun's direction Vector3D hat_p_surf = p_surf.unit(); Vector3D hat_d_sun = (sc.getSunPosition() - p_surf).unit(); // STEP 4: Derivation of the Local Tangent Plane of the Surface Hit Point (nothing to do here) // STEP 5: Determination of a Subsurface Point of the Solar Illumination Direction on the Local Tangent Plane double lambda_5 = -(1000 * (hat_d_sun.x() * hat_p_surf.x() + hat_d_sun.y() * hat_p_surf.y() + hat_d_sun.z() * hat_p_surf.z())) / (hat_p_surf.x() * hat_p_surf.x() + hat_p_surf.y() * hat_p_surf.y() + hat_p_surf.z() * hat_p_surf.z()); Vector3D p_local = p_surf + 1000 * hat_d_sun + lambda_5 * hat_p_surf; // STEP 6: Local Illumination Direction Vector3D hat_d_local = (p_local - c_pos).unit(); /// STEP 7: Projection of the Local Illumination Point to the Image Plane Vector3D k = c_pos + sc.getPOVDirection(); Vector3D c_up = sc.getPOVUp(); Vector3D c_right = sc.getPOVRight(); double w = Convert.ToDouble(this._width); double h = Convert.ToDouble(this._height); double x2 = ( -2 * w * c_pos.y() * c_up.z() * hat_d_local.x() - c_right.y() * c_up.z() * hat_d_local.x() - w * c_right.y() * c_up.z() * hat_d_local.x() + 2 * w * c_pos.x() * c_up.z() * hat_d_local.y() + c_right.x() * c_up.z() * hat_d_local.y() + w * c_right.x() * c_up.z() * hat_d_local.y() + 2 * w * c_pos.z() * (c_up.y() * hat_d_local.x() - c_up.x() * hat_d_local.y()) + (1 + w) * c_right.z() * (c_up.y() * hat_d_local.x() - c_up.x() * hat_d_local.y()) + 2 * w * c_pos.y() * c_up.x() * hat_d_local.z() + c_right.y() * c_up.x() * hat_d_local.z() + w * c_right.y() * c_up.x() * hat_d_local.z() - 2 * w * c_pos.x() * c_up.y() * hat_d_local.z() - c_right.x() * c_up.y() * hat_d_local.z() - w * c_right.x() * c_up.y() * hat_d_local.z() - 2 * w * c_up.z() * hat_d_local.y() * k.x() + 2 * w * c_up.y() * hat_d_local.z() * k.x() + 2 * w * c_up.z() * hat_d_local.x() * k.y() - 2 * w * c_up.x() * hat_d_local.z() * k.y() - 2 * w * c_up.y() * hat_d_local.x() * k.z() + 2 * w * c_up.x() * hat_d_local.y() * k.z() )/( 2 * (c_right.z() * (c_up.y() * hat_d_local.x() - c_up.x() * hat_d_local.y()) + c_right.y() * (-c_up.z() * hat_d_local.x() + c_up.x() * hat_d_local.z()) + c_right.x() * (c_up.z() * hat_d_local.y() - c_up.y() * hat_d_local.z())) ); double y2 = ( -c_right.z() * c_up.y() * hat_d_local.x() - h * c_right.z() * c_up.y() * hat_d_local.x() + c_right.y() * c_up.z() * hat_d_local.x() + h * c_right.y() * c_up.z() * hat_d_local.x() - 2 * h * c_pos.x() * c_right.z() * hat_d_local.y() + c_right.z() * c_up.x() * hat_d_local.y() + h * c_right.z() * c_up.x() * hat_d_local.y() - c_right.x() * c_up.z() * hat_d_local.y() - h * c_right.x() * c_up.z() * hat_d_local.y() + c_pos.z() * (-2 * h * c_right.y() * hat_d_local.x() + 2 * h * c_right.x() * hat_d_local.y()) + 2 * h * c_pos.x() * c_right.y() * hat_d_local.z() - c_right.y() * c_up.x() * hat_d_local.z() - h * c_right.y() * c_up.x() * hat_d_local.z() + c_right.x() * c_up.y() * hat_d_local.z() + h * c_right.x() * c_up.y() * hat_d_local.z() + 2 * h * c_pos.y() * (c_right.z() * hat_d_local.x() - c_right.x() * hat_d_local.z()) + 2 * h * c_right.z() * hat_d_local.y() * k.x() - 2 * h * c_right.y() * hat_d_local.z() * k.x() - 2 * h * c_right.z() * hat_d_local.x() * k.y() + 2 * h * c_right.x() * hat_d_local.z() * k.y() + 2 * h * c_right.y() * hat_d_local.x() * k.z() - 2 * h * c_right.x() * hat_d_local.y() * k.z() )/( 2 * (c_right.z() * (-c_up.y() * hat_d_local.x() + c_up.x() * hat_d_local.y()) + c_right.y() * (c_up.z() * hat_d_local.x() - c_up.x() * hat_d_local.z()) + c_right.x() * (-c_up.z() * hat_d_local.y() + c_up.y() * hat_d_local.z())) ); // STEP 8: The Local Solar Illumination Angle Vector2D v1 = new Vector2D(0, 1000); Vector2D v2 = new Vector2D(x2-x1, y2-y1); if (v2.x() > 0) { PixelOut.IlluminationAngle = tools.rad2deg(Math.Acos((v1 * v2) / (v1.norm() * v2.norm()))); } else { PixelOut.IlluminationAngle = tools.rad2deg(2 * Math.PI - Math.Acos((v1 * v2) / (v1.norm() * v2.norm()))); } PixelOut.exists = true; return PixelOut; } else { // next grid sample point return PixelOut; } }
private void generatePOVRayFile(SpacecraftState sc, string filename) { ArrayList filetext = new ArrayList(); Vector3D scPos = sc.getPosition(); Vector3D sunPos = sc.getSunPosition(); /* POV-Ray file */ /* ============ */ filetext.Add("#version 3.7;"); filetext.Add(""); filetext.Add("#declare Orange = rgb <1,0.5,0>;"); filetext.Add("#declare Red = rgb <1,0,0>;"); filetext.Add("#declare Yellow = rgb <1,1,0>;"); filetext.Add("#declare moon = texture"); filetext.Add(" {"); filetext.Add(" pigment { color rgb<0.8, 0.8, 0.8> }"); filetext.Add(" finish"); filetext.Add(" {"); filetext.Add(" ambient 0.0"); filetext.Add(" diffuse 0.8"); filetext.Add(" }"); filetext.Add(" }"); filetext.Add(""); filetext.Add("global_settings"); filetext.Add("{"); filetext.Add(" charset utf8"); filetext.Add(" assumed_gamma 1.0"); filetext.Add("}"); filetext.Add(""); filetext.Add("camera"); filetext.Add("{"); filetext.Add(" perspective"); filetext.Add(" location <" + scPos.x()/1000 + ", " + scPos.y()/1000 + ", " + scPos.z()/1000 + ">"); filetext.Add(" right <" + sc.getPOVRight().x().ToString("0.0000000") + ", " + sc.getPOVRight().y().ToString("0.0000000") + ", " + sc.getPOVRight().z().ToString("0.0000000") + ">"); filetext.Add(" up <" + sc.getPOVUp().x().ToString("0.0000000") + ", " + sc.getPOVUp().y().ToString("0.0000000") + ", " + sc.getPOVUp().z().ToString("0.0000000") + ">"); filetext.Add(" direction <" + sc.getPOVDirection().x().ToString("0.0000000") + ", " + sc.getPOVDirection().y().ToString("0.0000000") + ", " + sc.getPOVDirection().z().ToString("0.0000000") + ">"); filetext.Add("}"); filetext.Add(""); if (!Program.ignoreSun) { filetext.Add("light_source"); filetext.Add("{"); filetext.Add(" <" + sunPos.x() / 1000 + ", " + sunPos.y() / 1000 + ", " + sunPos.z() / 1000 + ">"); filetext.Add(" color rgb<1, 1, 1>"); filetext.Add(" looks_like"); filetext.Add(" {"); filetext.Add(" sphere"); filetext.Add(" {"); filetext.Add(" 0, 1000"); filetext.Add(" pigment { rgbt 1 }"); filetext.Add(" hollow"); filetext.Add(" interior"); filetext.Add(" {"); filetext.Add(" media"); filetext.Add(" {"); filetext.Add(" emission 1"); filetext.Add(" density"); filetext.Add(" {"); filetext.Add(" spherical"); filetext.Add(" density_map"); filetext.Add(" {"); filetext.Add(" [0 rgb 0]"); filetext.Add(" [60 Orange]"); filetext.Add(" [80 Red]"); filetext.Add(" [100 Yellow]"); filetext.Add(" }"); filetext.Add(" scale 1000"); filetext.Add(" }"); filetext.Add(" }"); filetext.Add(" }"); filetext.Add(" }"); filetext.Add(" }"); filetext.Add("}"); } else { filetext.Add("light_source"); filetext.Add("{"); filetext.Add(" <" + scPos.x() / 1000 + ", " + scPos.y() / 1000 + ", " + scPos.z() / 1000 + ">"); filetext.Add(" color rgb<1, 1, 1>"); filetext.Add("}"); } filetext.Add(""); // Dynamical Surface Pattern Selection Algorithm (DSPSA) ArrayList pattern = new ArrayList(); for (double y = 1; y <= this._height; y++) { for (double x = 1; x <= this._width; x++) { Vector3D rayDirection = sc.getPOVDirection() + (((1 + this._height - (2 * y)) / (2 * this._height)) * sc.getPOVUp()) - (((1 + this._width - (2 * x)) / (2 * this._width)) * sc.getPOVRight()); this.DSPSA(rayDirection, scPos, pattern); } } foreach (string str in pattern) { filetext.Add("#include \"" + this._pattern_repos + this._res + "\\pattern_LDEM_" + this._res + str + ".inc\""); } /* FOR DEBUG: diplay three dots as axis marker filetext.Add("sphere { <1800,0,0>, 100 pigment { color rgb <1.0, 0.0, 0.0> } finish { ambient 1.0 diffuse 1.0 } no_shadow }"); filetext.Add("sphere { <0,1800,0>, 100 pigment { color rgb <1.0, 1.0, 0.0> } finish { ambient 1.0 diffuse 1.0 } no_shadow }"); filetext.Add("sphere { <0,0,1800>, 100 pigment { color rgb <0.0, 1.0, 0.0> } finish { ambient 1.0 diffuse 1.0 } no_shadow }"); */ filetext.Add(""); filetext.Add("//-------------------------DEBUG INFORMATION-------------------------------------------------------------------------------------------------------"); filetext.Add("// MSISF Version: " + Program.VERSION); filetext.Add("// Config:"); filetext.Add("// SimTime: " + sc.getTime().ToString(Program.scientificFormat)); filetext.Add("// s/c position: [" + scPos.x().ToString(Program.scientificFormat) + "," + scPos.y().ToString(Program.scientificFormat) + "," + scPos.z().ToString(Program.scientificFormat) + "]"); filetext.Add("// s/c orientation: [" + sc.getOrientation().v().x().ToString(Program.scientificFormat) + "," + sc.getOrientation().v().y().ToString(Program.scientificFormat) + "," + sc.getOrientation().v().z().ToString(Program.scientificFormat) + "," + sc.getOrientation().r().ToString(Program.scientificFormat) + "]"); filetext.Add("//-----------------------END DEBUG INFORMATION------------------------------------------------------------------------------------------------------"); TextWriter file = new System.IO.StreamWriter(filename + ".pov", false); foreach (string line in filetext) { file.WriteLine(line); } file.Close(); string md5 = tools.md5File(filename + ".pov"); file = new System.IO.StreamWriter(filename + ".pov", true); file.WriteLine("// " + md5); file.Close(); /* META INFORMATION FILE (XML FILE) */ /* ================================ */ filetext = new ArrayList(); filetext.Add("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"); filetext.Add("<!DOCTYPE MSISRendering SYSTEM \"../lib/MSISRendering.dtd\">"); filetext.Add("<MSISRendering>"); // GENERAL INFORMATION filetext.Add(" <GeneralInformation>"); filetext.Add(" <SimulationTime>"); filetext.Add(" <MJD>" + sc.getTime().ToString(Program.scientificFormat) + "</MJD>"); filetext.Add(" <UTC>" + tools.MJDtoUTC(sc.getTime()).ToString("s") + "Z</UTC>"); filetext.Add(" </SimulationTime>"); filetext.Add(" <CameraPosition unit=\"m\">"); filetext.Add(" <Vector3D x=\"" + sc.getPosition().x().ToString(Program.scientificFormat) + "\" y=\"" + sc.getPosition().y().ToString(Program.scientificFormat) + "\" z=\"" + sc.getPosition().z().ToString(Program.scientificFormat) + "\" />"); filetext.Add(" </CameraPosition>"); filetext.Add(" <CameraOrientation>"); filetext.Add(" <Quaternion r=\"" + sc.getOrientation().r().ToString(Program.scientificFormat) + "\" x=\"" + sc.getOrientation().v().x().ToString(Program.scientificFormat) + "\" y=\"" + sc.getOrientation().v().y().ToString(Program.scientificFormat) + "\" z=\"" + sc.getOrientation().v().z().ToString(Program.scientificFormat) + "\" />"); filetext.Add(" </CameraOrientation>"); filetext.Add(" <SunPosition unit=\"m\">"); filetext.Add(" <Vector3D x=\"" + sc.getSunPosition().x().ToString(Program.scientificFormat) + "\" y=\"" + sc.getSunPosition().y().ToString(Program.scientificFormat) + "\" z=\"" + sc.getSunPosition().z().ToString(Program.scientificFormat) + "\" />"); filetext.Add(" </SunPosition>"); filetext.Add(" <FlightAltitude unit=\"m\">" + (sc.getPosition().norm() - 1.73715E6).ToString(Program.scientificFormat) + "</FlightAltitude>"); filetext.Add(" <SurfaceResolution unit=\"px/deg\">" + this._res.ToString() + "</SurfaceResolution>"); filetext.Add(" <FOV unit=\"deg\">" + this._FOV.ToString() + "</FOV>"); filetext.Add(" <MSISVersion>" + Program.VERSION + "</MSISVersion>"); filetext.Add(" <CommandLine>" + Program.commandLineString +"</CommandLine>"); filetext.Add(" </GeneralInformation>"); // PIXEL INFORMATION filetext.Add(" <PixelInformation>"); for(uint y = this.gridV; y <= this._height; y += this.gridV) { for(uint x = this.gridH; x <= this._width; x += this.gridH) { PixelInformation PixelMetaData = new PixelInformation(); // if getIlluminationDirectionPerRenderingPixel() returns false, the Moon's // surface has not been hit (the respective pixel shows the space background) PixelMetaData = getIlluminationDirectionPerRenderingPixel(sc, x, y); if (PixelMetaData.exists) { filetext.Add(" <Pixel h=\"" + x.ToString() + "\" v=\"" + y.ToString() + "\">"); filetext.Add(" <SelenographicCoordinates lat=\"" + PixelMetaData.lat.ToString(Program.scientificFormat) + "\" lon=\"" + PixelMetaData.lon.ToString(Program.scientificFormat) + "\" units=\"deg\" />"); filetext.Add(" <IlluminationDirection unit=\"deg\">" + PixelMetaData.IlluminationAngle.ToString(Program.scientificFormat) + "</IlluminationDirection>"); filetext.Add(" </Pixel>"); sc.PixelInfo.Add(new Vector2D(Convert.ToDouble(x), Convert.ToDouble(y)), PixelMetaData); } } } filetext.Add(" </PixelInformation>"); filetext.Add("</MSISRendering>"); file = new System.IO.StreamWriter(filename + ".xml", false); foreach (string line in filetext) { file.WriteLine(line); } file.Close(); }