Exemple #1
0
void
decimatePart( GeoPointList& input, double threshold, int min_points, GeoPartList& output )
{
    GeoPointList new_part;
    GeoPoint last_point;
    double t2 = threshold * threshold;

    if ( input.size() >= min_points )
    {
        for( GeoPointList::iterator i = input.begin(); i != input.end(); i++ )
        {
            if ( i == input.begin() )// || i == input.end()-1 )
            {
                last_point = *i;
                new_part.push_back( *i );
            }
            else
            {
                double d2 = (*i - last_point).length2();
                if ( d2 > t2 )
                {
                    new_part.push_back( *i );
                    last_point = *i;
                }
            }
        }

        if ( new_part.size() >= min_points )
        {
            output.push_back( new_part );
        }
    }
}
Exemple #2
0
bool
cropPointPart( const GeoPointList& part, const GeoExtent& extent, GeoPartList& output )
{
    GeoPointList new_part;
    for( UINT i=0; i<part.size(); i++ )
    {
        if ( extent.contains( part[i] ) )
            new_part.push_back( part[i] );
    }
    output.push_back( new_part );
    return true;
}
Exemple #3
0
static OGRGeometryH
encodePart( const GeoPointList& part, OGRwkbGeometryType part_type )
{
    OGRGeometryH part_handle = OGR_G_CreateGeometry( part_type );

    for( int v = part.size()-1; v >= 0; v-- )
    {
        const GeoPoint& p = part[v];
        if ( p.getDim() > 2 )
            OGR_G_AddPoint( part_handle, p.x(), p.y(), p.z() );
        else
            OGR_G_AddPoint_2D( part_handle, p.x(), p.y() );
    }

    return part_handle;
}
Exemple #4
0
bool
findIsectSegmentAndPoint(const GeoPoint& p1,
                         const GeoPoint& p2,
                         const GeoPointList& input,
                         const UINT start_i,
                         int&      out_seg_i,
                         GeoPoint& out_isect_p )
{
    for( UINT i=0; i<input.size()-1; i++ )
    {
        // ignore the segments preceding and following the start index
        if ( (input.size()+start_i-1)%input.size() <= i && i <= (input.size()+start_i+1)%input.size() )
            continue;

        const GeoPoint& p3 = input[i];
        const GeoPoint& p4 = input[i+1];

        double denom = (p4.y()-p3.y())*(p2.x()-p1.x()) - (p4.x()-p3.x())*(p2.y()-p1.y());
        if ( denom != 0.0 )
        {
            double ua_num = (p4.x()-p3.x())*(p1.y()-p3.y()) - (p4.y()-p3.y())*(p1.x()-p3.x());
            double ub_num = (p2.x()-p1.x())*(p1.y()-p3.y()) - (p2.y()-p1.y())*(p1.x()-p3.x());

            double ua = ua_num/denom;
            double ub = ub_num/denom;

            if ( ua <= 1.0 ) {
                //osgGIS::notify( osg::WARN ) 
                //    << " [" 
                //    << i << "] "
                //    << "isect point was found at on source segment (ua=" << ua << ")" 
                //    << std::endl
                //    << "  source segment = (" << p1.toString() << " => " << p2.toString() << "), "
                //    << "  target segment = (" << p3.toString() << " => " << p4.toString() << ")"
                //    << std::endl;
            }

            else if ( ub < 0.0 || ub > 1.0 ) 
            {
                //osgGIS::notify( osg::WARN ) 
                //    << " [" 
                //    << i << "] "
                //    << "isect point was not found on target segment (ub=" << ub << ")" 
                //    << std::endl
                //    << "  source segment = (" << p1.toString() << " => " << p2.toString() << "), "
                //    << "  target segment = (" << p3.toString() << " => " << p4.toString() << ")"
                //    << std::endl;
            }
            else
            {
                double isect_x = p1.x() + ua*(p2.x()-p1.x());
                double isect_y = p1.y() + ua*(p2.y()-p1.y());
                out_seg_i = i;
                out_isect_p = p1.getDim() == 2?
                    GeoPoint( isect_x, isect_y, p4.getSRS() ) :
                    GeoPoint( isect_x, isect_y, p4.z(), p4.getSRS() );
                return true;
            }
        }
    }
    return false;
}
Exemple #5
0
// poly clipping algorithm Aug 2007
bool
cropPolygonPart( const GeoPointList& initial_input, const GeoExtent& window, GeoPartList& final_outputs )
{
    // trivial rejection for a non-polygon:
    if ( initial_input.size() < 3 )
    {
        return false;
    }

    // check for trivial acceptance.
    if ( window.contains( initial_input ) )
    {
        final_outputs.push_back( initial_input );
        return true;
    }

    // prepare the list of input parts to process.
    GeoPartList inputs;
    inputs.push_back( initial_input );

    // run the algorithm against all four sides of the window in succession.
    for( UINT stage = 0; stage < 4; stage++ )
    {
        GeoPoint s1, s2;
        switch( stage )
        {
            case STAGE_SOUTH: s1 = window.getSouthwest(), s2 = window.getSoutheast(); break;
            case STAGE_EAST:  s1 = window.getSoutheast(), s2 = window.getNortheast(); break;
            case STAGE_NORTH: s1 = window.getNortheast(), s2 = window.getNorthwest(); break;
            case STAGE_WEST:  s1 = window.getNorthwest(), s2 = window.getSouthwest(); break;
        }

        // output parts to send to the next stage (or to return).
        GeoPartList outputs;

        // run against each input part.
        for( GeoPartList::iterator i = inputs.begin(); i != inputs.end(); i++ )
        {
            //GeoPointList& input = *i;
            GeoPointList input = *i;
            scrubPart( input );

            // trivially reject a degenerate part (should never happen ;)
            if ( input.size() < 3 )
            {
                continue;
            }
            
            // trivially accept if the window contains the entire extent of the part:
            GeoExtent input_extent;
            input_extent.expandToInclude( input );

            // trivially accept when the part lies entirely within the line:
            if ( extentInsideOrOnLine( input_extent, s1, s2 ) )
            {
                outputs.push_back( input );
                continue;
            }

            // trivially reject when there's no overlap:
            if ( !window.intersects( input_extent ) || extentInsideOrOnLine( input_extent, s2, s1 ) )
            {
                continue;
            }                

            // close the part in preparation for cropping. The cropping process with undo
            // this automatically.
            input.push_back( input.front() );

            // 1a. Traverse the part and find all intersections. Insert them into the input shape.
            // 1b. Create a traversal-order list, ordering the isect points in the order in which they are encountered.
            // 1c. Create a spatial-order list, ordering the isect points along the boundary segment in the direction of the segment.
            GeoPointList working;
            UINTList traversal_order;
            UINTList spatial_order;
            GeoPoint prev_p;
            bool was_inside = true;

            for( UINT input_i = 0; input_i < input.size(); input_i++ )
            {
                const GeoPoint& p = input[ input_i ];
                bool is_inside = pointInsideOrOnLine( p, s1, s2 );

                if ( input_i > 0 )
                {
                    if ( was_inside != is_inside ) // entering or exiting
                    {
                        GeoPoint isect_p;
                        if ( getIsectPoint( prev_p, p, s1, s2, /*out*/ isect_p ) )
                        {
                            working.push_back( isect_p );
                            traversal_order.push_back( working.size()-1 );
                            spatialInsert( spatial_order, working.size()-1, stage, working );
                        }
                        else
                        {
                            osgGIS::notify( osg::WARN ) 
                                << "getIsectPoint failed" << std::endl;
                        }
                    }
                }

                working.push_back( p );
                prev_p = p;
                was_inside = is_inside;
            }

            if ( spatial_order.size() == 0 )
            {
                outputs.push_back( input );
                continue;
            }

            // 2. Start at the point preceding the first isect point (in spatial order). This will be the first
            //    outside point (since the first isect point is always an ENTRY.
            UINT overall_start_ptr = spatial_order[0];
            UINT shape_ptr = overall_start_ptr;

            // initialize the isect traversal pointer to start at the spatial order's first isect point:
            UINT trav_ptr = findIndexOf( traversal_order, spatial_order[0] );
            UINT traversals = 0;

            std::stack<DeferredPart> part_stack;
            GeoPointList current_part;

            // Process until we make it all the way around.
            while( traversals < traversal_order.size() )
            {
                // 4. We are outside. Find the next ENTRY point and either start a NEW part, or RESUME
                //    a previously deferred part that is on top of the stack.
                shape_ptr = traversal_order[trav_ptr]; // next ENTRY
                trav_ptr = (trav_ptr + 1) % traversal_order.size();
                traversals++;

                UINT part_start_ptr = shape_ptr;

                if ( part_stack.size() > 0 && part_stack.top().waiting_on_ptr == part_start_ptr )
                {
                    // time to resume a part that we deferred earlier.
                    DeferredPart& top = part_stack.top();
                    current_part = top.part;
                    part_start_ptr = top.part_start_ptr;
                    part_stack.pop();
                }
                else
                {
                    // start a new part
                    current_part = GeoPointList();
                }

                // 5. Traverse to the next EXIT, adding all points along the way. 
                //    Then check the spatial order of the EXIT against the part's starting point. If the former
                //    is ONE MORE than the latter, close out the part.
                for( bool part_done = false; !part_done && traversals < traversal_order.size(); )
                {
                    UINT next_exit_ptr = traversal_order[trav_ptr];
                    trav_ptr = (trav_ptr + 1) % traversal_order.size();
                    traversals++;
                
                    for( ; shape_ptr != next_exit_ptr; shape_ptr = (shape_ptr+1)%working.size() )
                    {
                        current_part.push_back( working[shape_ptr] );
                    }

                    // record the exit point:
                    current_part.push_back( working[next_exit_ptr] );

                    UINT part_start_order = findIndexOf( spatial_order, part_start_ptr );
                    UINT next_exit_order = findIndexOf( spatial_order, next_exit_ptr );
                    if ( next_exit_order - part_start_order == 1 )
                    {
                        outputs.push_back( current_part );
                        part_done = true;
                        continue;
                    }

                    // 6. Find the next ENTRY. If the spatial order of the ENTRY is one less than the 
                    //    spatial ordering of the preceding EXIT, continue on with the part.
                    UINT next_entry_ptr = traversal_order[trav_ptr];
                    trav_ptr = (trav_ptr + 1) % traversal_order.size();
                    traversals++;

                    // check whether we are back at the beginning:
                    if ( traversals >= traversal_order.size() )
                    {
                        current_part.push_back( working[next_entry_ptr] );
                        continue;
                    }

                    // check whether we are continuing the current part:
                    UINT next_entry_order = findIndexOf( spatial_order, next_entry_ptr );
                    if ( next_exit_order - next_entry_order == 1 )
                    {
                        shape_ptr = next_entry_ptr; // skip ahead to the entry point
                        continue;
                    }

                    // 7. We encountered an out-of-order traversal, so need to push the current part onto
                    //    the deferral stack until later, and start a new part.
                    part_stack.push( DeferredPart(
                        current_part,
                        part_start_ptr,
                        spatial_order[next_exit_order-1] ) );

                    current_part = GeoPointList();
                    //current_part.push_back( working[next_entry_ptr] );
                    part_start_ptr = next_entry_ptr;
                    shape_ptr = next_entry_ptr;
                }
            }

            // pop any parts left on the stack (they're complete now)
            while( part_stack.size() > 0 )
            {
                GeoPointList& part = part_stack.top().part;
                part.push_back( working[part_stack.top().waiting_on_ptr] );
                outputs.push_back( part );
                part_stack.pop();
            }
        }

        // set up for next iteration
        outputs.swap( inputs );
    }

    // go through and make sure no polys are "closed" (probably unnecessary).
    //for( GeoPartList::iterator k = inputs.begin(); k != inputs.end(); k++ )
    //{
    //    while ( k->size() > 3 && k->front() == k->back() )
    //        k->erase( k->end()-1 );
    //}

    final_outputs.swap( inputs );
    return true;
}
Exemple #6
0
static void
scrubPart( GeoPointList& part )
{
    while( part.size() >= 0 && part.front() == part.back() )
        part.erase( part.end()-1 );
}