コード例 #1
0
ファイル: GreatCircles.cpp プロジェクト: TopPano/hugin_lite
GreatCircleArc::GreatCircleArc(double startLat, double startLong,
                       double endLat, double endLong,
                       VisualizationState & visualizationState)

{
    m_visualizationState = &visualizationState;
    // get the output projection
    const HuginBase::PanoramaOptions & options = *(visualizationState.GetOptions());
    // make an image to transform spherical coordinates into the output projection
    HuginBase::SrcPanoImage equirectangularImage;
    equirectangularImage.setProjection(HuginBase::SrcPanoImage::EQUIRECTANGULAR);
    equirectangularImage.setHFOV(360.0);
    equirectangularImage.setSize(vigra::Size2D(360.0, 180.0));
    
    // make a transformation from spherical coordinates to the output projection
    HuginBase::PTools::Transform transform;
    transform.createInvTransform(equirectangularImage, options);
    
	m_xscale = visualizationState.GetScale();

    /**Handle case where the points are opposite sides of the sphere
     * (i.e. The angle startLat is -endLat and startLong is -endLong.)
     * There are infinetly many great circles in this case, we pick one going
     * through (180, 90), by splitting the problem in two.
     */
    if (startLat == 360.0 - endLat && startLong == 180.0 - endLong)
    {
        // we should probably check to see if we already go through (180, 90).
        if (startLat == 180.0 && startLong == 90.0)
        {
            // foiled again: pick one going through (180, 0) instead.
            *this = GreatCircleArc(startLat, startLong, 180.0, 0.0, visualizationState);
            GreatCircleArc other(180.0, 0.0, endLat, endLong, visualizationState);
            m_lines.insert(m_lines.end(), other.m_lines.begin(), other.m_lines.end());
            return;
        }
        *this = GreatCircleArc(startLat, startLong, 180.0, 90.0, visualizationState);
        GreatCircleArc other(180.0, 90.0, endLat, endLong, visualizationState);
        m_lines.insert(m_lines.end(), other.m_lines.begin(), other.m_lines.end());
        return;
    }
    
    // convert start and end positions so that they don't go across the +/-180
    // degree seam
    if (startLat < 90.0 && endLat > 270.0)
    {
        endLat -= 360.0;
    }
    // convert to radians
    startLat *= (M_PI / 180.0);
    startLong *= (M_PI / 180.0);
    endLat *= (M_PI / 180.0);
    endLong *= (M_PI / 180.0);
    
    // find sines and cosines, they are used multiple times.
    double sineStartLat = std::sin(startLat);
    double sineStartLong = std::sin(startLong);
    double sineEndLat = std::sin(endLat);
    double sineEndLong = std::sin(endLong);
    double cosineStartLat = std::cos(startLat);
    double cosineStartLong = std::cos(startLong);
    double cosineEndLat = std::cos(endLat);
    double cosineEndLong = std::cos(endLong);
    
    /* to get points on the great circle, we linearly interpolate between the
     * two 3D coordinates for the given spherical coordinates, then normalise
     * the vector to get back on the sphere. This works everywhere except exact
     * opposite points, where we'll get the original points repeated several
     * times (and if we are even more unlucky we will hit the origin where the
     * normal isn't defined.)
     */
    // convert locations to 3d coordinates.
    double p1[3] = {cosineStartLat * sineStartLong, sineStartLat * sineStartLong, cosineStartLong};
    double p2[3] = {cosineEndLat * sineEndLong, sineEndLat * sineEndLong, cosineEndLong};
    
    ///@todo don't check the +/- 180 degree boundary when projection does not break there.
    bool hasSeam = true;
    // draw a line strip and transform the coordinates as we go.
    double b1 = 0.0;
    double b2 = 1.0;
    const double bDifference = 1.0 / double(segments);
    // for discontinuity detection.
    int lastSegment = 1;
    // The last processed vertex's position.
    hugin_utils::FDiff2D last_vertex;
    /* true if we shouldn't use last_vertex to make a line segment
     * i.e. We just crossed a discontinuity. */
    bool skip = true;
    for (unsigned int segment_index = 0; segment_index < segments;
         segment_index++, b1 += bDifference, b2 -= bDifference)
    {
        // linearly interpolate positions
        double v[3] = {p1[0] * b1 + p2[0] * b2, p1[1] * b1 + p2[1] * b2, p1[2] * b1 + p2[2] * b2};
        // normalise
        double length = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
        v[0] /= length;
        v[1] /= length;
        v[2] /= length;
        /*double longitude = atan2(numerator,
                                 cosineStartLong * (c1 * std::sin(latitude) -
                                                    c2 * std::cos(latitude)));*/
        double longitude = std::acos(v[2]);
        // acos returns values between 0 and M_PI. The other
        // latitudes are on the back of the sphere, so check y coordinate (v1)
        double latitude = std::acos(v[0] / std::sin(longitude));
        if (v[1] < 0.0)
        {
            // on the back.
            latitude = -latitude + 2 * M_PI;
        }
        
        double vx, vy;
        bool infront =  transform.transformImgCoord(vx,
                                                    vy,
                                                    latitude  * 180.0 / M_PI,
                                                    longitude  * 180.0 / M_PI);
        // don't draw across +/- 180 degree seems.
        if (hasSeam)
        {
            // we divide the width of the panorama into 3 segments. If we jump
            // across the middle section, we split the line into two.
            int newSegment = vx / (options.getWidth() / 3);
            if ((newSegment < 1 && lastSegment > 1) ||
                (newSegment > 1 && lastSegment < 1))
            {
                skip = true;
            }
            lastSegment = newSegment;
        }
        if (infront)
        {
            if (!skip)
            {
                LineSegment line;
                line.vertices[0] = last_vertex;
                line.vertices[1] = hugin_utils::FDiff2D(vx, vy);
                m_lines.push_back(line);
            }
            // The next line segment should be a valid one.
            last_vertex = hugin_utils::FDiff2D(vx, vy);
            skip = false;
        } else {
            skip = true;
        }
    }
}
コード例 #2
0
void PreviewLayoutLinesTool::updateLineInformation()
{
    m_lines.clear();
    const HuginBase::Panorama & pano = *(helper->GetPanoramaPtr());
    unsigned int numberOfImages = pano.getNrOfImages();
    HuginBase::UIntSet active_images = pano.getActiveImages();
    // make a line for every image pair, but set the unneeded ones as dud.
    // This is for constant look up times when we scan control points.
    m_lines.resize(numberOfImages * numberOfImages);
    unsigned int numberOfControlPoints = pano.getNrOfCtrlPoints();
    // loop over all control points to count them and get error statistics.
    for (unsigned int cpi = 0 ; cpi < numberOfControlPoints ; cpi++)
    {
        const HuginBase::ControlPoint & cp = pano.getCtrlPoint(cpi);
        unsigned int low_index, high_index;
        if (cp.image1Nr < cp.image2Nr)
        {
            low_index = cp.image1Nr;
            high_index = cp.image2Nr;
        } else {
            low_index = cp.image2Nr;
            high_index = cp.image1Nr;
        }
        // find the line.
        // We use the formula in the line below to record image numbers to each
        // line later.
        LineDetails & line = m_lines[low_index * numberOfImages + high_index];
        // update control point count.
        line.numberOfControlPoints++;
        // update error statistics
        line.totalError += cp.error;
        if (cp.error > line.worstError)
        {
            line.worstError = cp.error;
        }
    }
    
    /* Find some locations of the images. We will test if they overlap using
     *  these locations. We don't need the last image as we can always take the
     * smallest numbered image as the source of points.
     */
    /** @todo Check both ways around.
     * This only checks if points from the smallest numbered image are
     * within the largest numbered image. If the first image is huge compared to
     * the second, then it many points will miss and we might not reach the
     * target even if the second image is contained within the first.
     */
    std::vector<PosMap>  positions(pano.getNrOfImages() - 1);
    for (unsigned int i = 0; i < numberOfImages - 1; i++)
    {
        const HuginBase::SrcPanoImage & img = pano.getImage(i);
        for (unsigned int x = 0; x < SAMPLE_FREQUENCY; x++)
        {
            for (unsigned int y = 0; y < SAMPLE_FREQUENCY; y++)
            {
                // scale (x, y) so it is always within the cropped region of the
                // image.
                vigra::Rect2D c = img.getCropRect();
                /** @todo Use only points inside the circle when circular crop
                 * is used.
                 */
                double xc = double (x) / double (SAMPLE_FREQUENCY)
                                        * double(c.width()) + c.left();
                double yc = double (y) / double (SAMPLE_FREQUENCY)
                                        * double(c.height()) + c.top();
                // now look up (xc, yc) in the image, find where in the panorama
                // it ends up.
                m_transforms[i]->transformImgCoord  (
                            positions[i][x][y].x, positions[i][x][y].y,
                            xc, yc                  );
            }
        }
    }
    
    // write other line data.
    for (unsigned int i = 0; i < numberOfImages; i++)
    {
        for (unsigned int j = 0; j < numberOfImages; j++)
        {
            LineDetails & line = m_lines[i * numberOfImages + j];
            line.image1 = i;
            line.image2 = j;
            /// test if the line should be visible.
            if (!(set_contains(active_images, i) &&
                  set_contains(active_images, j)))
            {
                // At least one of the images is hidden, so don't show the line.
                line.dud = true;
            }
            else if (line.numberOfControlPoints > 0)
            {
                line.dud = false;
            } else if (i >= j) {
                // We only use lines where image1 is the lowest numbered image.
                // We don't bother with lines from one image to the same one.
                line.dud = true;
            } else {
                // test overlapping regions.
                HuginBase::PTools::Transform transform;
                ViewState & viewState = *helper->GetViewStatePtr();
                HuginBase::SrcPanoImage & src = *viewState.GetSrcImage(j);
                transform.createTransform(src, *(viewState.GetOptions()));
                unsigned int overlapingSamples = 0;
                for (unsigned int x = 0; x < SAMPLE_FREQUENCY; x++)
                {
                    for (unsigned int y = 0; y < SAMPLE_FREQUENCY; y++)
                    {
                        // check if mapping a point that was found earilier to
                        // be inside an image in panorama space is inside the
                        // other image when transformed from panorama to image.
                        double dx, dy;
                        transform.transformImgCoord (
                                        dx, dy,
                                        positions[i][x][y].x,
                                        positions[i][x][y].y
                                                    );
                        if (src.isInside(vigra::Point2D((int) dx, (int) dy)))
                        {
                            // they overlap
                            overlapingSamples++;
                        }
                    }
                }
                // If the overlap isn't big enough, the line isn't used.
                line.dud = (overlapingSamples < MIN_SAMPLE_OVERLAPS);
            }
            
            if (!line.dud)
            {
                line.arc = GreatCircleArc(m_imageCentresSpherical[i].x,
                                          m_imageCentresSpherical[i].y,
                                          m_imageCentresSpherical[j].x,
                                          m_imageCentresSpherical[j].y,
                                          *(helper->GetVisualizationStatePtr()));
            }
        }
    }
}
コード例 #3
0
ファイル: GreatCircles.cpp プロジェクト: TopPano/hugin_lite
void GreatCircles::drawLineFromSpherical(double startLat, double startLong,
                                         double endLat, double endLong, double width)
{
    DEBUG_ASSERT(m_visualizationState); 
    GreatCircleArc(startLat, startLong, endLat, endLong, *m_visualizationState).draw(true, width);
}