wxThread::ExitCode HaloRenderingThread::Entry() { wxCommandEvent evt(wxEVT_HALO_RENDERING_THREAD_NOTIFY, wxID_ANY); setupStruct.resultValid = false; setupStruct.imageBuffer = 0; setupStruct.rayPaths = new map<RayPathId, RayPathDescriptor>; if (setupStruct.crystals.size() == 0) { evt.SetString(wxT("No crystal population set up.")); evt.SetInt(1); setupStruct.notifee->AddPendingEvent(evt); return 0; } // Cast rays on crystals and refracted rays will form a pixel. int crystalTypeIndex = 0; CrystalDescriptor *currentDescriptor = &setupStruct.crystals[0]; const int N_CRYSTAL_TYPES = setupStruct.crystals.size(); int crystalsRemaining = currentDescriptor->populationWeight; Mesh currentMesh; size_t percentStep = setupStruct.crystalCount / 100; if (percentStep < 1) percentStep = 1; Vector3 sunPos(0, 0, -100000); rotate2d(sunPos.y, sunPos.z, setupStruct.solarAltitude * 3.14159265636 / 180.0); // Two prependicular vector Vector3 prepX = sunPos % Vector3(0, 1, 0); // FIXME: Sun on the zenith Vector3 prepY = sunPos % prepX; prepX /= ~prepX; prepY /= ~prepY; setupStruct.deleteBuffer = freeBuffer; setupStruct.deleteMap = freeMap; size_t size = setupStruct.imageSize; setupStruct.imageBuffer = new uint32_t[size * size * 6]; memset(setupStruct.imageBuffer, 0, size * size * 6 * sizeof(uint32_t)); uint32_t *leftPlane = setupStruct.imageBuffer; // 0th plane uint32_t *rightPlane = setupStruct.imageBuffer + size * size; // 1st plane uint32_t *topPlane = setupStruct.imageBuffer + 2 * size * size; // 2nd plane uint32_t *bottomPlane = setupStruct.imageBuffer + 3 * size * size; // 3rd plane uint32_t *backPlane = setupStruct.imageBuffer + 4 * size * size; // 4th plane uint32_t *frontPlane = setupStruct.imageBuffer + 5 * size * size; // 5th plane double halfImageSize = size * 0.5; int maxRays = (setupStruct.maxRayCastInfoSize * 1000000) / (sizeof(RayPathDescriptor) + sizeof(RayPathId)); if (maxRays == 0) maxRays = 1; int recordRayModulus = setupStruct.crystalCount / maxRays; if (!recordRayModulus) recordRayModulus = 1; struct RefractionColor { int rgb; double refractionIndex; }; RefractionColor colors[] = { { 0x0000FF, 1.3072 }, { 0x0080FF, 1.3094 }, { 0x00FFFF, 1.31 }, { 0x00FF80, 1.3107 }, { 0x00FF00, 1.3114 }, { 0x80FF00, 1.3125 }, { 0xFFFF00, 1.3136 }, { 0xFF8000, 1.3147 }, { 0xFF0000, 1.3158 }, { 0xFF0040, 1.3172 }, { 0xFF0080, 1.32 }, }; const int N_COLORS = sizeof(colors) / sizeof(colors[0]); // Cast many rays. for (size_t i = 0; i < setupStruct.crystalCount; i++) { if (setupStruct.cancelled) { // If the user shut the rendering down... delete[] setupStruct.imageBuffer; setupStruct.imageBuffer = 0; return 0; } if (!crystalsRemaining) { // We iterate through the crystals based on their population weights. crystalTypeIndex++; if (crystalTypeIndex >= N_CRYSTAL_TYPES) crystalTypeIndex = 0; currentDescriptor = &setupStruct.crystals[crystalTypeIndex]; crystalsRemaining = currentDescriptor->populationWeight; } // Get the raw mesh currentMesh = currentDescriptor->mesh; // Rotate it according to the orientation. Matrix orientationMatrix = getOrientationMatrix(currentDescriptor->orientation); // Apply wobbliness Vector3 wobbleRotationAxis(1, 0, 0); rotate2d(wobbleRotationAxis.x, wobbleRotationAxis.z, randFloat(0, 3.1415)); double wobblinessLimit = currentDescriptor->wobbliness * 3.1415 / 180.0; Matrix wobbleMatrix = createRotationMatrix( wobbleRotationAxis, randFloatNormal( 0, wobblinessLimit ) ); Matrix transformation = orientationMatrix % wobbleMatrix; transformMesh(currentMesh, transformation); // Crystal created, now cast a ray on it. Vector3 offset = prepX * randFloat(-1, 1) + prepY * randFloat(-1, 1); vector<RayPath> rayPaths; // Compute color here double colorCode = randFloat(0, N_COLORS - 1); RefractionColor prev = colors[(int)(floor(colorCode))]; RefractionColor next = colors[(int)(ceil(colorCode))]; double kColor = colorCode - floor(colorCode); RefractionColor currentColor; currentColor.rgb = prev.rgb; currentColor.refractionIndex = (1 - kColor) * prev.refractionIndex + kColor * next.refractionIndex; // Compute real poisition of the ray (Sun is a disk) Vector3 realSunPos = sunPos; Vector3 rayRotVector; double rayRotVectorLength; do { rayRotVector = realSunPos % getRandomVector(); rayRotVectorLength = ~rayRotVector; } while (rayRotVectorLength == 0); rayRotVector /= rayRotVectorLength; realSunPos = transformVector( createRotationMatrix( rayRotVector, randFloat( 0, setupStruct.solarDiskRadius * 3.1415926536 / 180.0 ) ), realSunPos ); computeRayPathInGlassMesh(currentMesh, currentColor.refractionIndex, realSunPos + offset, -realSunPos, 0.01, rayPaths); /* Project rays on the six planes. */ for (size_t j = 0; j < rayPaths.size(); j++) { RayPath ¤t = rayPaths[j]; size_t pathLength = current.size(); Vector3 exitDir = current[pathLength - 1].first - current[pathLength - 2].first; Vector3 projectionDir = -exitDir; double xPos, yPos; // select the plane to project on. uint32_t *plane; double xm = 1, ym = 1; int planeId; if ((fabs(projectionDir.x) > fabs(projectionDir.y)) && (fabs(projectionDir.x) > fabs(projectionDir.z))) { if (projectionDir.x < 0) { plane = leftPlane; planeId = 0; xm = -1; } else { plane = rightPlane; planeId = 1; } xPos = xm * projectionDir.z / fabs(projectionDir.x) * halfImageSize + halfImageSize; yPos = -ym * projectionDir.y / fabs(projectionDir.x) * halfImageSize + halfImageSize; } if ((fabs(projectionDir.y) > fabs(projectionDir.x)) && (fabs(projectionDir.y) > fabs(projectionDir.z))) { if (projectionDir.y < 0) { plane = bottomPlane; planeId = 3; ym = -1; } else { plane = topPlane; planeId = 2; } xPos = xm * projectionDir.x / fabs(projectionDir.y) * halfImageSize + halfImageSize; yPos = -ym * projectionDir.z / fabs(projectionDir.y) * halfImageSize + halfImageSize; } if ((fabs(projectionDir.z) > fabs(projectionDir.x)) && (fabs(projectionDir.z) > fabs(projectionDir.y))) { if (projectionDir.z < 0) { plane = frontPlane; planeId = 5; } else { plane = backPlane; planeId = 4; xm = -1; } xPos = xm * projectionDir.x / fabs(projectionDir.z) * halfImageSize + halfImageSize; yPos = -ym * projectionDir.y / fabs(projectionDir.z) * halfImageSize + halfImageSize; } // Calculate the new intensity of the pixel. xPos = clampInInt(xPos, 0, size - 1); yPos = clampInInt(yPos, 0, size - 1); int prevPixel = plane[(int)(yPos) * size + (int)(xPos)]; int nextPixel = 0; double intensity = current[pathLength - 2].second * 20; for (int j = 0; j < 3; j++) { int currentSaturation = (prevPixel >> (8 * j)) & 0xFF; int toAdd = (int)(((currentColor.rgb >> (8 * j)) & 0xFF) * intensity) >> 8; int nextSaturation; if (currentSaturation + toAdd > 255) nextSaturation = 255; else nextSaturation = currentSaturation + toAdd; nextPixel += (1 << (8 * j)) * nextSaturation * setupStruct.pixelIntensity; } plane[(int)(yPos) * size + (int)(xPos)] = nextPixel; // Record the ray if needed if (!(i % recordRayModulus)) { RayPathId pixelId(planeId, (int)xPos, (int)yPos); RayPathDescriptor theDescriptor( ¤tDescriptor->mesh, transformation, realSunPos + offset, -realSunPos, intensity ); map<RayPathId, RayPathDescriptor>::iterator it = setupStruct.rayPaths->find(pixelId); if (it == setupStruct.rayPaths->end()) { // If not found, insert it as new setupStruct.rayPaths->insert( make_pair( pixelId, theDescriptor ) ); } else if (it->second.intensity < intensity) { // If found, update it if the current ray is more intense it->second = theDescriptor; } } } if (i % percentStep == 0) { sendNotifyString(wxString::Format(wxT("Casting rays: %d%%"), i / percentStep)); } crystalsRemaining--; } evt.SetString(wxT("Completed.")); evt.SetInt(1); //< 1 means the operation is finished. setupStruct.resultValid = true; setupStruct.notifee->AddPendingEvent(evt); return 0; }
/* Returns the effect of solid Earth tides (meters) at the given * position and epoch, in the Up-East-Down (UEN) reference frame. * * @param[in] t Epoch to look up * @param[in] p Position of interest * * @return a Triple with the solid tidal effect, in meters and in * the UED reference frame. * * @throw InvalidRequest If the request can not be completed for any * reason, this is thrown. The text may have additional information * as to why the request failed. */ Triple SolidTides::getSolidTide(const CommonTime& t, const Position& p) const throw(InvalidRequest) { // We will store here the results Triple res; // Objects to compute Sun and Moon positions SunPosition sunPosition; MoonPosition moonPosition; try { // Variables to hold Sun and Moon positions Triple sunPos(sunPosition.getPosition(t)); Triple moonPos(moonPosition.getPosition(t)); // Compute the factors for the Sun double rpRs( p.X()*sunPos.theArray[0] + p.Y()*sunPos.theArray[1] + p.Z()*sunPos.theArray[2]); double Rs2(sunPos.theArray[0]*sunPos.theArray[0] + sunPos.theArray[1]*sunPos.theArray[1] + sunPos.theArray[2]*sunPos.theArray[2]); double rp2( p.X()*p.X() + p.Y()*p.Y() + p.Z()*p.Z() ); double xy2p( p.X()*p.X() + p.Y()*p.Y() ); double sqxy2p( std::sqrt(xy2p) ); double sqRs2(std::sqrt(Rs2)); double fac_s( 3.0*MU_SUN*rp2/(sqRs2*sqRs2*sqRs2*sqRs2*sqRs2) ); double g1sun( fac_s*(rpRs*rpRs/2.0 - rp2*Rs2/6.0) ); double g2sun( fac_s * rpRs * (sunPos.theArray[1]*p.X() - sunPos.theArray[0]*p.Y()) * std::sqrt(rp2)/sqxy2p ); double g3sun( fac_s * rpRs * ( sqxy2p* sunPos.theArray[2] - p.Z()/sqxy2p * (p.X()*sunPos.theArray[0] + p.Y()*sunPos.theArray[1]) ) ); // Compute the factors for the Moon double rpRm( p.X()*moonPos.theArray[0] + p.Y()*moonPos.theArray[1] + p.Z()*moonPos.theArray[2]); double Rm2(moonPos.theArray[0]*moonPos.theArray[0] + moonPos.theArray[1]*moonPos.theArray[1] + moonPos.theArray[2]*moonPos.theArray[2]); double sqRm2(std::sqrt(Rm2)); double fac_m( 3.0*MU_MOON*rp2/(sqRm2*sqRm2*sqRm2*sqRm2*sqRm2) ); double g1moon( fac_m*(rpRm*rpRm/2.0 - rp2*Rm2/6.0) ); double g2moon( fac_m * rpRm * (moonPos.theArray[1]*p.X() - moonPos.theArray[0]*p.Y()) * std::sqrt(rp2)/sqxy2p ); double g3moon( fac_m * rpRm * ( sqxy2p* moonPos.theArray[2] - p.Z()/sqxy2p * (p.X()*moonPos.theArray[0] + p.Y()*moonPos.theArray[1]) ) ); // Effects due to the Sun double delta_sun1(H_LOVE*g1sun); double delta_sun2(L_LOVE*g2sun); double delta_sun3(L_LOVE*g3sun); // Effects due to the Moon double delta_moon1(H_LOVE*g1moon); double delta_moon2(L_LOVE*g2moon); double delta_moon3(L_LOVE*g3moon); // Combined effect res.theArray[0] = delta_sun1 + delta_moon1; res.theArray[1] = delta_sun2 + delta_moon2; res.theArray[2] = delta_sun3 + delta_moon3; } // End of try block catch(InvalidRequest& ir) { GPSTK_RETHROW(ir); } return res; } // End SolidTides::getSolidTide
/* Returns a satTypeValueMap object, adding the new data generated when * calling this object. * * @param time Epoch corresponding to the data. * @param gData Data object holding the data. */ satTypeValueMap& ComputeSatPCenter::Process(const DayTime& time, satTypeValueMap& gData) throw(ProcessingException) { try { // Compute Sun position at this epoch SunPosition sunPosition; Triple sunPos(sunPosition.getPosition(time)); // Define a Triple that will hold satellite position, in ECEF Triple svPos(0.0, 0.0, 0.0); SatIDSet satRejectedSet; // Loop through all the satellites satTypeValueMap::iterator it; for (it = gData.begin(); it != gData.end(); ++it) { // Use ephemeris if satellite position is not already computed if( ( (*it).second.find(TypeID::satX) == (*it).second.end() ) || ( (*it).second.find(TypeID::satY) == (*it).second.end() ) || ( (*it).second.find(TypeID::satZ) == (*it).second.end() ) ) { if(pEphemeris==NULL) { // If ephemeris is missing, then remove all satellites satRejectedSet.insert( (*it).first ); continue; } else { // Try to get satellite position // if it is not already computed try { // For our purposes, position at receive time // is fine enough Xvt svPosVel(pEphemeris->getXvt( (*it).first, time )); // If everything is OK, then continue processing. svPos[0] = svPosVel.x.theArray[0]; svPos[1] = svPosVel.x.theArray[1]; svPos[2] = svPosVel.x.theArray[2]; } catch(...) { // If satellite is missing, then schedule it // for removal satRejectedSet.insert( (*it).first ); continue; } } } else { // Get satellite position out of GDS svPos[0] = (*it).second[TypeID::satX]; svPos[1] = (*it).second[TypeID::satY]; svPos[2] = (*it).second[TypeID::satZ]; } // End of 'if( ( (*it).second.find(TypeID::satX) == ...' // Let's get the satellite antenna phase correction value in // meters, and insert it in the GNSS data structure. (*it).second[TypeID::satPCenter] = getSatPCenter((*it).first, time, svPos, sunPos); } // End of 'for (it = gData.begin(); it != gData.end(); ++it)' // Remove satellites with missing data gData.removeSatID(satRejectedSet); return gData; } catch(Exception& u) { // Throw an exception if something unexpected happens ProcessingException e( getClassName() + ":" + StringUtils::asString( getIndex() ) + ":" + u.what() ); GPSTK_THROW(e); } } // End of method 'ComputeSatPCenter::Process()'
/* Returns a satTypeValueMap object, adding the new data generated * when calling this object. * * @param epoch Time of observations. * @param gData Data object holding the data. */ satTypeValueMap& EclipsedSatFilter::Process( const CommonTime& epoch, satTypeValueMap& gData ) throw(ProcessingException) { try { SatIDSet satRejectedSet; // Set the threshold to declare that satellites are in eclipse // threshold = cos(180 - coneAngle/2) double threshold( std::cos(PI - coneAngle/2.0*DEG_TO_RAD) ); // Compute Sun position at this epoch, and store it in a Triple SunPosition sunPosition; Triple sunPos(sunPosition.getPosition(epoch)); // Define a Triple that will hold satellite position, in ECEF Triple svPos(0.0, 0.0, 0.0); // Loop through all the satellites satTypeValueMap::iterator it; for (it = gData.begin(); it != gData.end(); ++it) { // Check if satellite position is not already computed if( ( (*it).second.find(TypeID::satX) == (*it).second.end() ) || ( (*it).second.find(TypeID::satY) == (*it).second.end() ) || ( (*it).second.find(TypeID::satZ) == (*it).second.end() ) ) { // If satellite position is missing, then schedule this // satellite for removal satRejectedSet.insert( (*it).first ); continue; } else { // Get satellite position out of GDS svPos[0] = (*it).second[TypeID::satX]; svPos[1] = (*it).second[TypeID::satY]; svPos[2] = (*it).second[TypeID::satZ]; } // Unitary vector from Earth mass center to satellite Triple rk( svPos.unitVector() ); // Unitary vector from Earth mass center to Sun Triple ri( sunPos.unitVector() ); // Get dot product between unitary vectors = cosine(angle) double cosAngle(ri.dot(rk)); // Check if satellite is within shadow if(cosAngle <= threshold) { // If satellite is eclipsed, then schedule it for removal satRejectedSet.insert( (*it).first ); // Keep track of last known epoch the satellite was in eclipse shadowEpoch[(*it).first] = epoch; continue; } else { // Maybe the satellite is out fo shadow, but it was recently // in eclipse. Check also that. if( shadowEpoch.find( (*it).first ) != shadowEpoch.end() ) { // If satellite was recently in eclipse, check if elapsed // time is less or equal than postShadowPeriod if( std::abs( ( epoch - shadowEpoch[(*it).first] ) ) <= postShadowPeriod ) { // Satellite left shadow, but too recently. Delete it satRejectedSet.insert( (*it).first ); } else { // If satellite left shadow a long time ago, set it free shadowEpoch.erase( (*it).first ); } } } } // Remove satellites with missing data gData.removeSatID(satRejectedSet); return gData; } catch(Exception& u) { // Throw an exception if something unexpected happens ProcessingException e( getClassName() + ":" + u.what() ); GPSTK_THROW(e); } } // End of 'EclipsedSatFilter::Process()'