Exemplo n.º 1
0
FilterContext
ScaleFilter::push( FeatureList& input, FilterContext& cx )
{
    for( FeatureList::iterator i = input.begin(); i != input.end(); ++i )
    {
        Feature* input = i->get();
        if ( input && input->getGeometry() )
        {
            Bounds envelope = input->getGeometry()->getBounds();

            // now scale and shift everything
            GeometryIterator scale_iter( input->getGeometry() );
            while( scale_iter.hasMore() )
            {
                Geometry* geom = scale_iter.next();
                for( osg::Vec3dArray::iterator v = geom->begin(); v != geom->end(); v++ )
                {
                    double xr = (v->x() - envelope.xMin()) / envelope.width();
                    v->x() += (xr - 0.5) * _scale;

                    double yr = (v->y() - envelope.yMin()) / envelope.height();
                    v->y() += (yr - 0.5) * _scale;
                }
            }
        }
    }

    return cx;
}
Exemplo n.º 2
0
    // Returns true if these Bounds share any area in common with another.
    bool overlaps(const Bounds& other, bool force2d = false) const
    {
        Point otherMid(other.mid());

        return
            std::abs(m_mid.x - otherMid.x) <=
                width() / 2.0 + other.width() / 2.0 &&
            std::abs(m_mid.y - otherMid.y) <=
                depth() / 2.0 + other.depth() / 2.0 &&
            (force2d || std::abs(m_mid.z - otherMid.z) <=
                height() / 2.0 + other.height() / 2.0);
    }
/**
 * Tiles the Geometry into the given number of columns and rows
 */
void tileGeometry(Geometry* geometry, const SpatialReference* featureSRS, unsigned int numCols, unsigned int numRows, GeometryCollection& out)
{
    // Clear the output list.
    out.clear();

    Bounds b = geometry->getBounds();
    double tw = b.width() / (double)numCols;
    double th = b.height() / (double)numRows;

    // Get the average Z, since GEOS will set teh Z of new verts to that of the cropping polygon,
    // which is stupid but that's how it is.
    double z = 0.0;
    for(unsigned i=0; i<geometry->size(); ++i)
        z += geometry->at(i).z();
    z /= geometry->size();

    osg::ref_ptr<Polygon> poly = new Polygon;
    poly->resize( 4 );        

    for(int x=0; x<(int)numCols; ++x)
    {
        for(int y=0; y<(int)numRows; ++y)
        {
            (*poly)[0].set( b.xMin() + tw*(double)x,     b.yMin() + th*(double)y,     z );
            (*poly)[1].set( b.xMin() + tw*(double)(x+1), b.yMin() + th*(double)y,     z );
            (*poly)[2].set( b.xMin() + tw*(double)(x+1), b.yMin() + th*(double)(y+1), z );
            (*poly)[3].set( b.xMin() + tw*(double)x,     b.yMin() + th*(double)(y+1), z );

            osg::ref_ptr<Geometry> ringTile;
            if ( geometry->crop(poly.get(), ringTile) )
            {
                // Use an iterator since crop could return a multi-polygon
                GeometryIterator gi( ringTile.get(), false );
                while( gi.hasMore() )
                {
                    Geometry* geom = gi.next();
                    out.push_back( geom );                                                
                }
            }
        }
    }
}
Exemplo n.º 4
0
bool
ExtrudeGeometryFilter::buildStructure(const Geometry*         input,
                                      double                  height,
                                      double                  heightOffset,
                                      bool                    flatten,
                                      const SkinResource*     wallSkin,
                                      const SkinResource*     roofSkin,
                                      Structure&              structure,
                                      FilterContext&          cx )
{
    bool  makeECEF                 = false;
    const SpatialReference* srs    = 0L;
    const SpatialReference* mapSRS = 0L;

    if ( cx.isGeoreferenced() )
    {
       srs      = cx.extent()->getSRS();
       makeECEF = cx.getSession()->getMapInfo().isGeocentric();
       mapSRS   = cx.getSession()->getMapInfo().getProfile()->getSRS();
    }

    // whether this is a closed polygon structure.
    structure.isPolygon = (input->getComponentType() == Geometry::TYPE_POLYGON);

    // extrusion working variables
    double     targetLen = -DBL_MAX;
    osg::Vec3d minLoc(DBL_MAX, DBL_MAX, DBL_MAX);
    double     minLoc_len = DBL_MAX;
    osg::Vec3d maxLoc(0,0,0);
    double     maxLoc_len = 0;

    // Initial pass over the geometry does two things:
    // 1: Calculate the minimum Z across all parts.
    // 2: Establish a "target length" for extrusion
    double absHeight = fabs(height);

    ConstGeometryIterator zfinder( input );
    while( zfinder.hasMore() )
    {
        const Geometry* geom = zfinder.next();
        for( Geometry::const_iterator m = geom->begin(); m != geom->end(); ++m )
        {
            osg::Vec3d m_point = *m;

            if ( m_point.z() + absHeight > targetLen )
                targetLen = m_point.z() + absHeight;

            if (m_point.z() < minLoc.z())
                minLoc = m_point;

            if (m_point.z() > maxLoc.z())
                maxLoc = m_point;
        }
    }

    // apply the height offsets
    height    -= heightOffset;
    targetLen -= heightOffset;
    
    float   roofRotation  = 0.0f;
    Bounds  roofBounds;
    float   sinR = 0.0f, cosR = 0.0f;
    double  roofTexSpanX = 0.0, roofTexSpanY = 0.0;
    osg::ref_ptr<const SpatialReference> roofProjSRS;

    if ( roofSkin )
    {
        roofBounds = input->getBounds();

        // if our data is lat/long, we need to reproject the geometry and the bounds into a projected
        // coordinate system in order to properly generate tex coords.
        if ( srs && srs->isGeographic() )
        {
            osg::Vec2d geogCenter = roofBounds.center2d();
            roofProjSRS = srs->createUTMFromLonLat( Angle(geogCenter.x()), Angle(geogCenter.y()) );
            if ( roofProjSRS.valid() )
            {
                roofBounds.transform( srs, roofProjSRS.get() );
                osg::ref_ptr<Geometry> projectedInput = input->clone();
                srs->transform( projectedInput->asVector(), roofProjSRS.get() );
                roofRotation = getApparentRotation( projectedInput.get() );
            }
        }
        else
        {
            roofRotation = getApparentRotation( input );
        }
            
        sinR = sin(roofRotation);
        cosR = cos(roofRotation);

        if ( !roofSkin->isTiled().value() )
        {
            //note: non-tiled roofs don't really work atm.
            roofTexSpanX = cosR*roofBounds.width() - sinR*roofBounds.height();
            roofTexSpanY = sinR*roofBounds.width() + cosR*roofBounds.height();
        }
        else
        {
            roofTexSpanX = roofSkin->imageWidth().isSet() ? *roofSkin->imageWidth() : roofSkin->imageHeight().isSet() ? *roofSkin->imageHeight() : 10.0;
            if ( roofTexSpanX <= 0.0 ) roofTexSpanX = 10.0;
            roofTexSpanY = roofSkin->imageHeight().isSet() ? *roofSkin->imageHeight() : roofSkin->imageWidth().isSet() ? *roofSkin->imageWidth() : 10.0;
            if ( roofTexSpanY <= 0.0 ) roofTexSpanY = 10.0;
        }
    }

    // prep for wall texture coordinate generation.
    double texWidthM  = wallSkin ? *wallSkin->imageWidth() : 0.0;
    double texHeightM = wallSkin ? *wallSkin->imageHeight() : 1.0;

    ConstGeometryIterator iter( input );
    while( iter.hasMore() )
    {
        const Geometry* part = iter.next();

        // skip a part that's too small
        if (part->size() < 2)
            continue;

        // add a new wall.
        structure.elevations.push_back(Elevation());
        Elevation& elevation = structure.elevations.back();

        double maxHeight = targetLen - minLoc.z();

        // Adjust the texture height so it is a multiple of the maximum height
        double div = osg::round(maxHeight / texHeightM);
        elevation.texHeightAdjustedM = div > 0.0 ? maxHeight / div : maxHeight;

        // Step 1 - Create the real corners and transform them into our target SRS.
        Corners corners;
        for(Geometry::const_iterator m = part->begin(); m != part->end(); ++m)
        {
            Corners::iterator corner = corners.insert(corners.end(), Corner());
            
            // mark as "from source", as opposed to being inserted by the algorithm.
            corner->isFromSource = true;
            corner->base = *m;

            // extrude:
            if ( height >= 0 ) // extrude up
            {
                if ( flatten )
                    corner->roof.set( corner->base.x(), corner->base.y(), targetLen );
                else
                    corner->roof.set( corner->base.x(), corner->base.y(), corner->base.z() + height );
            }
            else // height < 0 .. extrude down
            {
                corner->roof = *m;
                corner->base.z() += height;
            }
            
            // figure out the rooftop texture coords before doing any transformation:
            if ( roofSkin && srs )
            {
                double xr, yr;

                if ( srs && srs->isGeographic() && roofProjSRS )
                {
                    osg::Vec3d projRoofPt;
                    srs->transform( corner->roof, roofProjSRS.get(), projRoofPt );
                    xr = (projRoofPt.x() - roofBounds.xMin());
                    yr = (projRoofPt.y() - roofBounds.yMin());
                }
                else
                {
                    xr = (corner->roof.x() - roofBounds.xMin());
                    yr = (corner->roof.y() - roofBounds.yMin());
                }

                corner->roofTexU = (cosR*xr - sinR*yr) / roofTexSpanX;
                corner->roofTexV = (sinR*xr + cosR*yr) / roofTexSpanY;
            }
            
            // transform into target SRS.
            transformAndLocalize( corner->base, srs, corner->base, mapSRS, _world2local, makeECEF );
            transformAndLocalize( corner->roof, srs, corner->roof, mapSRS, _world2local, makeECEF );
        }

        // Step 2 - Insert intermediate Corners as needed to satify texturing
        // requirements (if necessary) and record each corner offset (horizontal distance
        // from the beginning of the part geometry to the corner.)
        double cornerOffset    = 0.0;
        double nextTexBoundary = texWidthM;

        for(Corners::iterator c = corners.begin(); c != corners.end(); ++c)
        {
            Corners::iterator this_corner = c;

            Corners::iterator next_corner = c;
            if ( ++next_corner == corners.end() )
                next_corner = corners.begin();

            osg::Vec3d base_vec = next_corner->base - this_corner->base;
            double span = base_vec.length();

            this_corner->offsetX = cornerOffset;

            if (wallSkin)
            {
                base_vec /= span; // normalize
                osg::Vec3d roof_vec = next_corner->roof - this_corner->roof;
                roof_vec.normalize();

                while(nextTexBoundary < cornerOffset+span)
                {
                    // insert a new fake corner.
                    Corners::iterator new_corner = corners.insert(next_corner, Corner());
                    new_corner->isFromSource = false;
                    double advance = nextTexBoundary-cornerOffset;
                    new_corner->base = this_corner->base + base_vec*advance;
                    new_corner->roof = this_corner->roof + roof_vec*advance;
                    new_corner->offsetX = cornerOffset + advance;
                    nextTexBoundary += texWidthM;

                    // advance the main iterator
                    c = new_corner;
                }
            }

            cornerOffset += span;
        }

        // Step 3 - Calculate the angle of each corner.
        osg::Vec3d prev_vec;
        for(Corners::iterator c = corners.begin(); c != corners.end(); ++c)
        {
            Corners::const_iterator this_corner = c;

            Corners::const_iterator next_corner = c;
            if ( ++next_corner == corners.end() )
                next_corner = corners.begin();

            if ( this_corner == corners.begin() )
            {
                Corners::const_iterator prev_corner = corners.end();
                --prev_corner;
                prev_vec = this_corner->roof - prev_corner->roof;
                prev_vec.normalize();
            }

            osg::Vec3d this_vec = next_corner->roof - this_corner->roof;
            this_vec.normalize();
            if ( c != corners.begin() )
            {
                c->cosAngle = prev_vec * this_vec;
            }
        }

        // Step 4 - Create faces connecting each pair of Posts.
        Faces& faces = elevation.faces;
        for(Corners::const_iterator c = corners.begin(); c != corners.end(); ++c)
        {
            Corners::const_iterator this_corner = c;

            Corners::const_iterator next_corner = c;
            if ( ++next_corner == corners.end() )
                next_corner = corners.begin();
            
            // only close the shape for polygons.
            if (next_corner != corners.begin() || structure.isPolygon)
            {
                faces.push_back(Face());
                Face& face = faces.back();
                face.left  = *this_corner;
                face.right = *next_corner;

                // recalculate the final offset on the last face
                if ( next_corner == corners.begin() )
                {
                    osg::Vec3d vec = next_corner->roof - this_corner->roof;
                    face.right.offsetX = face.left.offsetX + vec.length();
                }

                face.widthM = next_corner->offsetX - this_corner->offsetX;
            }
        }
    }

    return true;
}
Exemplo n.º 5
0
bool
ExtrudeGeometryFilter::extrudeGeometry(const Geometry*         input,
                                       double                  height,
                                       double                  heightOffset,
                                       bool                    flatten,
                                       osg::Geometry*          walls,
                                       osg::Geometry*          roof,
                                       osg::Geometry*          base,
                                       osg::Geometry*          outline,
                                       const osg::Vec4&        wallColor,
                                       const osg::Vec4&        wallBaseColor,
                                       const osg::Vec4&        roofColor,
                                       const osg::Vec4&        outlineColor,
                                       const SkinResource*     wallSkin,
                                       const SkinResource*     roofSkin,
                                       FilterContext&          cx )
{
    bool makeECEF = false;
    const SpatialReference* srs = 0L;
    const SpatialReference* mapSRS = 0L;

    if ( cx.isGeoreferenced() )
    {
       srs = cx.extent()->getSRS();
       makeECEF = cx.getSession()->getMapInfo().isGeocentric();
       mapSRS = cx.getSession()->getMapInfo().getProfile()->getSRS();
    }

    bool made_geom = false;

    double tex_width_m   = wallSkin ? *wallSkin->imageWidth() : 1.0;
    double tex_height_m  = wallSkin ? *wallSkin->imageHeight() : 1.0;
    bool   tex_repeats_y = wallSkin ? *wallSkin->isTiled() : false;
    bool   useColor      = (!wallSkin || wallSkin->texEnvMode() != osg::TexEnv::DECAL) && !_makeStencilVolume;

    bool isPolygon = input->getComponentType() == Geometry::TYPE_POLYGON;

    unsigned pointCount = input->getTotalPointCount();
    
    // If we are extruding a polygon, and applying a wall texture, we need an extra
    // point in the geometry in order to close the polygon and generate a unique
    // texture coordinate for that final point.
    bool isSkinnedPolygon = isPolygon && wallSkin != 0L;

    // Total number of verts. Add 2 to close a polygon (necessary so the first and last
    // points can have unique texture coordinates)
    unsigned numWallVerts = 2 * pointCount + (isSkinnedPolygon? (2 * input->getNumGeometries()) : 0);

    // create all the OSG geometry components
    osg::Vec3Array* verts = new osg::Vec3Array( numWallVerts );
    walls->setVertexArray( verts );

    osg::Vec2Array* wallTexcoords = 0L;
    if ( wallSkin )
    { 
        wallTexcoords = new osg::Vec2Array( numWallVerts );
        walls->setTexCoordArray( 0, wallTexcoords );
    }

    osg::Vec4Array* colors = 0L;
    if ( useColor )
    {
        // per-vertex colors are necessary if we are going to use the MeshConsolidator -gw
        colors = new osg::Vec4Array();
        colors->reserve( numWallVerts );
        colors->assign( numWallVerts, wallColor );
        walls->setColorArray( colors );
        walls->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
    }

    // set up rooftop tessellation and texturing, if necessary:
    osg::Vec3Array* roofVerts     = 0L;
    osg::Vec2Array* roofTexcoords = 0L;
    float           roofRotation  = 0.0f;
    Bounds          roofBounds;
    float           sinR = 0.0f, cosR = 0.0f;
    double          roofTexSpanX = 0.0, roofTexSpanY = 0.0;
    osg::ref_ptr<const SpatialReference> roofProjSRS;

    if ( roof )
    {
        roofVerts = new osg::Vec3Array( pointCount );
        roof->setVertexArray( roofVerts );

        // per-vertex colors are necessary if we are going to use the MeshConsolidator -gw
        if ( useColor )
        {
            osg::Vec4Array* roofColors = new osg::Vec4Array();
            roofColors->reserve( pointCount );
            roofColors->assign( pointCount, roofColor );
            roof->setColorArray( roofColors );
            roof->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
        }

        if ( roofSkin )
        {
            roofTexcoords = new osg::Vec2Array( pointCount );
            roof->setTexCoordArray( 0, roofTexcoords );

            // Get the orientation of the geometry. This is a hueristic that will help 
            // us align the roof skin texture properly. TODO: make this optional? It makes
            // sense for buildings and such, but perhaps not for all extruded shapes.
            roofRotation = getApparentRotation( input );

            roofBounds = input->getBounds();

            // if our data is lat/long, we need to reproject the geometry and the bounds into a projected
            // coordinate system in order to properly generate tex coords.
            if ( srs && srs->isGeographic() )
            {
                osg::Vec2d geogCenter = roofBounds.center2d();
                roofProjSRS = srs->createUTMFromLonLat( Angular(geogCenter.x()), Angular(geogCenter.y()) );
                roofBounds.transform( srs, roofProjSRS.get() );
                osg::ref_ptr<Geometry> projectedInput = input->clone();
                srs->transform( projectedInput->asVector(), roofProjSRS.get() );
                roofRotation = getApparentRotation( projectedInput.get() );
            }
            else
            {
                roofRotation = getApparentRotation( input );
            }
            
            sinR = sin(roofRotation);
            cosR = cos(roofRotation);

            if ( !roofSkin->isTiled().value() )
            {
                //note: doesn't really work
                roofTexSpanX = cosR*roofBounds.width() - sinR*roofBounds.height();
                roofTexSpanY = sinR*roofBounds.width() + cosR*roofBounds.height();
            }
            else
            {
                roofTexSpanX = roofSkin->imageWidth().isSet() ? *roofSkin->imageWidth() : roofSkin->imageHeight().isSet() ? *roofSkin->imageHeight() : 10.0;
                if ( roofTexSpanX <= 0.0 ) roofTexSpanX = 10.0;
                roofTexSpanY = roofSkin->imageHeight().isSet() ? *roofSkin->imageHeight() : roofSkin->imageWidth().isSet() ? *roofSkin->imageWidth() : 10.0;
                if ( roofTexSpanY <= 0.0 ) roofTexSpanY = 10.0;
            }
        }
    }

    osg::Vec3Array* baseVerts = NULL;
    if ( base )
    {
        baseVerts = new osg::Vec3Array( pointCount );
        base->setVertexArray( baseVerts );
    }

    osg::Vec3Array* outlineVerts = 0L;
    osg::Vec3Array* outlineNormals = 0L;
    if ( outline )
    {
        outlineVerts = new osg::Vec3Array( numWallVerts );
        outline->setVertexArray( outlineVerts );

        osg::Vec4Array* outlineColors = new osg::Vec4Array();
        outlineColors->reserve( numWallVerts );
        outlineColors->assign( numWallVerts, outlineColor );
        outline->setColorArray( outlineColors );
        outline->setColorBinding( osg::Geometry::BIND_PER_VERTEX );

        // cop out, just point all the outline normals up. fix this later.
        outlineNormals = new osg::Vec3Array();
        outlineNormals->reserve( numWallVerts );
        outlineNormals->assign( numWallVerts, osg::Vec3(0,0,1) );
        outline->setNormalArray( outlineNormals );
    }

    unsigned wallVertPtr    = 0;
    unsigned roofVertPtr    = 0;
    unsigned baseVertPtr    = 0;

    double     targetLen = -DBL_MAX;
    osg::Vec3d minLoc(DBL_MAX, DBL_MAX, DBL_MAX);
    double     minLoc_len = DBL_MAX;
    osg::Vec3d maxLoc(0,0,0);
    double     maxLoc_len = 0;

    // Initial pass over the geometry does two things:
    // 1: Calculate the minimum Z across all parts.
    // 2: Establish a "target length" for extrusion

    double absHeight = fabs(height);

    ConstGeometryIterator zfinder( input );
    while( zfinder.hasMore() )
    {
        const Geometry* geom = zfinder.next();
        for( Geometry::const_iterator m = geom->begin(); m != geom->end(); ++m )
        {
            osg::Vec3d m_point = *m;

            if ( m_point.z() + absHeight > targetLen )
                targetLen = m_point.z() + absHeight;

            if (m_point.z() < minLoc.z())
                minLoc = m_point;

            if (m_point.z() > maxLoc.z())
                maxLoc = m_point;
        }
    }

    // apply the height offsets
    height    -= heightOffset;
    targetLen -= heightOffset;

    // now generate the extruded geometry.
    ConstGeometryIterator iter( input );
    while( iter.hasMore() )
    {
        const Geometry* part = iter.next();

        double tex_height_m_adj = tex_height_m;

        unsigned wallPartPtr = wallVertPtr;
        unsigned roofPartPtr = roofVertPtr;
        unsigned basePartPtr = baseVertPtr;
        double   partLen     = 0.0;
        double   maxHeight   = 0.0;

        maxHeight = targetLen - minLoc.z();

        // Adjust the texture height so it is a multiple of the maximum height
        double div = osg::round(maxHeight / tex_height_m);
        if (div == 0) div = 1; //Prevent divide by zero
        tex_height_m_adj = maxHeight / div;

        //osg::DrawElementsUShort* idx = new osg::DrawElementsUShort( GL_TRIANGLES );
        osg::DrawElementsUInt* idx = new osg::DrawElementsUInt( GL_TRIANGLES );

        for( Geometry::const_iterator m = part->begin(); m != part->end(); ++m )
        {
            osg::Vec3d basePt = *m;
            osg::Vec3d roofPt;

            if ( height >= 0 )
            {
                if ( flatten )
                    roofPt.set( basePt.x(), basePt.y(), targetLen );
                else
                    roofPt.set( basePt.x(), basePt.y(), basePt.z() + height );
            }
            else // height < 0
            {
                roofPt = *m;
                basePt.z() += height;
            }

            // add to the approprate vertex lists:
            int p = wallVertPtr;

            // figure out the rooftop texture coordinates before doing any
            // transformations:
            if ( roofSkin && roofProjSRS && srs )
            {
                double xr, yr;

                if ( srs && srs->isGeographic() )
                {
                    osg::Vec3d projRoofPt;
                    srs->transform( roofPt, roofProjSRS.get(), projRoofPt );
                    xr = (projRoofPt.x() - roofBounds.xMin());
                    yr = (projRoofPt.y() - roofBounds.yMin());
                }
                else
                {
                    xr = (roofPt.x() - roofBounds.xMin());
                    yr = (roofPt.y() - roofBounds.yMin());
                }

                float u = (cosR*xr - sinR*yr) / roofTexSpanX;
                float v = (sinR*xr + cosR*yr) / roofTexSpanY;

                (*roofTexcoords)[roofVertPtr].set( u, v );
            }

            transformAndLocalize( basePt, srs, basePt, mapSRS, _world2local, makeECEF );
            transformAndLocalize( roofPt, srs, roofPt, mapSRS, _world2local, makeECEF );


            if ( base )
            {
                (*baseVerts)[baseVertPtr] = basePt;
            }

            if ( roof )
            {
                (*roofVerts)[roofVertPtr] = roofPt;
            }

            baseVertPtr++;
            roofVertPtr++;

            (*verts)[p] = roofPt;
            (*verts)[p+1] = basePt;

            if ( useColor )
            {
                (*colors)[p+1] = wallBaseColor;
            }

            if ( outline )
            {
                (*outlineVerts)[p] = roofPt;
                (*outlineVerts)[p+1] = basePt;
            }
            
            partLen += wallVertPtr > wallPartPtr ? ((*verts)[p] - (*verts)[p-2]).length() : 0.0;
            double h = tex_repeats_y ? -((*verts)[p] - (*verts)[p+1]).length() : -tex_height_m_adj;

            if ( wallSkin )
            {
                (*wallTexcoords)[p].set( partLen/tex_width_m, 0.0f );
                (*wallTexcoords)[p+1].set( partLen/tex_width_m, h/tex_height_m_adj );
            }

            // form the 2 triangles
            if ( (m+1) == part->end() )
            {
                if ( isPolygon )
                {
                    // end of the wall; loop around to close it off.
                    if ( isSkinnedPolygon )
                    {
                        // if we requested an extra geometry point, that means we are generating
                        // a polygon-closing line so we can have a unique texcoord for it. 
                        idx->push_back(wallVertPtr);
                        idx->push_back(wallVertPtr+1);
                        idx->push_back(wallVertPtr+2);

                        idx->push_back(wallVertPtr+1);
                        idx->push_back(wallVertPtr+3);
                        idx->push_back(wallVertPtr+2);

                        (*verts)[p+2] = (*verts)[wallPartPtr];
                        (*verts)[p+3] = (*verts)[wallPartPtr+1];

                        if ( wallSkin )
                        {
                            partLen += ((*verts)[p+2] - (*verts)[p]).length();
                            double h = tex_repeats_y ? -((*verts)[p+2] - (*verts)[p+3]).length() : -tex_height_m_adj;
                            (*wallTexcoords)[p+2].set( partLen/tex_width_m, 0.0f );
                            (*wallTexcoords)[p+3].set( partLen/tex_width_m, h/tex_height_m_adj );
                        }

                        wallVertPtr += 2;
                    }
                    else
                    {
                        // either not a poly, or no wall skin, so we can share the polygon-closing
                        // loop point.
                        idx->push_back(wallVertPtr); 
                        idx->push_back(wallVertPtr+1);
                        idx->push_back(wallPartPtr);

                        idx->push_back(wallVertPtr+1);
                        idx->push_back(wallPartPtr+1);
                        idx->push_back(wallPartPtr);
                    }
                }
                else
                {
                    //nop - no elements required at the end of a line
                }
            }
            else
            {
                idx->push_back(wallVertPtr); 
                idx->push_back(wallVertPtr+1);
                idx->push_back(wallVertPtr+2); 

                idx->push_back(wallVertPtr+1);
                idx->push_back(wallVertPtr+3);
                idx->push_back(wallVertPtr+2);
            }

            wallVertPtr += 2;
            made_geom = true;
        }

        walls->addPrimitiveSet( idx );

        if ( roof )
        {
            roof->addPrimitiveSet( new osg::DrawArrays(
                osg::PrimitiveSet::LINE_LOOP,
                roofPartPtr, roofVertPtr - roofPartPtr ) );
        }

        if ( base )
        {
            // reverse the base verts:
            int len = baseVertPtr - basePartPtr;
            for( int i=basePartPtr; i<len/2; i++ )
                std::swap( (*baseVerts)[i], (*baseVerts)[basePartPtr+(len-1)-i] );

            base->addPrimitiveSet( new osg::DrawArrays(
                osg::PrimitiveSet::LINE_LOOP,
                basePartPtr, baseVertPtr - basePartPtr ) );
        }

        if ( outline )
        {
            unsigned len = baseVertPtr - basePartPtr;

            GLenum roofLineMode = isPolygon ? GL_LINE_LOOP : GL_LINE_STRIP;
            osg::DrawElementsUInt* roofLine = new osg::DrawElementsUInt( roofLineMode );
            roofLine->reserveElements( len );
            for( unsigned i=0; i<len; ++i )
                roofLine->addElement( basePartPtr + i*2 );
            outline->addPrimitiveSet( roofLine );

            // if the outline is tessellated, we only want outlines on the original 
            // points (not the inserted points)
            unsigned step = std::max( 1u, 
                _outlineSymbol->tessellation().isSet() ? *_outlineSymbol->tessellation() : 1u );

            osg::DrawElementsUInt* wallLines = new osg::DrawElementsUInt( GL_LINES );
            wallLines->reserve( len*2 );
            for( unsigned i=0; i<len; i+=step )
            {
                wallLines->push_back( basePartPtr + i*2 );
                wallLines->push_back( basePartPtr + i*2 + 1 );
            }
            outline->addPrimitiveSet( wallLines );

            applyLineSymbology( outline->getOrCreateStateSet(), _outlineSymbol.get() );
        }
    }

    return made_geom;
}
Exemplo n.º 6
0
void
ScatterFilter::polyScatter(const Geometry*         input,
                           const SpatialReference* inputSRS,
                           const FilterContext&    context,
                           PointSet*               output )
{
    Bounds bounds;
    double areaSqKm = 0.0;

    ConstGeometryIterator iter( input, false );
    while( iter.hasMore() )
    {
        const Polygon* polygon = dynamic_cast<const Polygon*>( iter.next() );
        if ( !polygon )
            continue;

        if ( /*context.isGeocentric() ||*/ context.profile()->getSRS()->isGeographic() )
        {
            bounds = polygon->getBounds();

            double avglat = bounds.yMin() + 0.5*bounds.height();
            double h = bounds.height() * 111.32;
            double w = bounds.width() * 111.32 * sin( 1.57079633 + osg::DegreesToRadians(avglat) );

            areaSqKm = w * h;
        }

        else if ( context.profile()->getSRS()->isProjected() )
        {
            bounds = polygon->getBounds();
            areaSqKm = (0.001*bounds.width()) * (0.001*bounds.height());
        }

        double zMin = 0.0;
        unsigned numInstancesInBoundingRect = (unsigned)(areaSqKm * (double)osg::clampAbove( 0.1f, _density ));
        if ( numInstancesInBoundingRect == 0 )
            continue;

        if ( _random )
        {
            // Random scattering. Note, we try to place as many instances as would
            // fit in the bounding rectangle; The real placed number will be less since
            // we only place models inside the actual polygon. But the density will 
            // be correct.
            for( unsigned j=0; j<numInstancesInBoundingRect; ++j )
            {
                double x = bounds.xMin() + _prng.next() * bounds.width();
                double y = bounds.yMin() + _prng.next() * bounds.height();

                bool include = true;

                if ( include && polygon->contains2D( x, y ) )
                    output->push_back( osg::Vec3d(x, y, zMin) );
            }
        }

        else
        {
            // regular interval scattering:
            double numInst1D = sqrt((double)numInstancesInBoundingRect);
            double ar = bounds.width() / bounds.height();
            unsigned cols = (unsigned)( numInst1D * ar );
            unsigned rows = (unsigned)( numInst1D / ar );
            double colInterval = bounds.width() / (double)(cols-1);
            double rowInterval = bounds.height() / (double)(rows-1);
            double interval = 0.5*(colInterval+rowInterval);

            for( double cy=bounds.yMin(); cy<=bounds.yMax(); cy += interval )
            {
                for( double cx = bounds.xMin(); cx <= bounds.xMax(); cx += interval )
                {
                    bool include = true;

                    if ( include && polygon->contains2D( cx, cy ) )
                        output->push_back( osg::Vec3d(cx, cy, zMin) );
                }
            }
        }
    }
}