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 &current = 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(
                    &currentDescriptor->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;
}
예제 #2
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
예제 #3
0
      /* 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()'
예제 #4
0
      /* 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()'