예제 #1
0
const GeoExtent&
Feature::getExtent() const
{
    if ( !_cachedExtent.isValid() )
    {
        if ( getGeometry() && getSRS() )
        {
            if ( getSRS()->isGeographic() )
            {
                GeoExtent e( getSRS() );

                if ( _geoInterp.value() == GEOINTERP_GREAT_CIRCLE )
                {
                    const osg::EllipsoidModel* em = getSRS()->getEllipsoid();

                    // find the GC "cutting plane" with the greatest inclination.
                    ConstSegmentIterator i( getGeometry() );
                    while( i.hasMore() )
                    {
                        Segment s = i.next();

                        double minLat, maxLat;

                        GeoMath::greatCircleMinMaxLatitude( 
                            osg::DegreesToRadians(s.first.y()), osg::DegreesToRadians(s.first.x()),
                            osg::DegreesToRadians(s.second.y()), osg::DegreesToRadians(s.second.x()),
                            minLat, maxLat);

                        minLat = osg::RadiansToDegrees( minLat );
                        maxLat = osg::RadiansToDegrees( maxLat );

                        e.expandToInclude( s.first.x(), minLat );
                        e.expandToInclude( s.second.x(), maxLat );
                        //e.expandToInclude( e.getCentroid().x(), std::min(minLat, e.south()) );
                        //e.expandToInclude( e.getCentroid().x(), std::max(maxLat, e.north()) );
                    }
                }
                else // RHUMB_LINE
                {
                    ConstGeometryIterator i( getGeometry(), true );
                    while( i.hasMore() )
                    {
                        const Geometry* g = i.next();
                        for( Geometry::const_iterator v = g->begin(); v != g->end(); ++v )
                            e.expandToInclude( v->x(), v->y() );
                    }
                }

                const_cast<Feature*>(this)->_cachedExtent = e;
            }
            else
            {
                const_cast<Feature*>(this)->_cachedExtent = GeoExtent(getSRS(), getGeometry()->getBounds());
            }
        }
    }
    return _cachedExtent;
}
예제 #2
0
    void assemble_Surf2Vol(const Geometry& geo, Matrix& mat, const std::map<const Domain, Vertices> m_points) 
    {
        const double K = 1.0/(4.0*M_PI);

        unsigned size = 0; // total number of inside points
        for ( std::map<const Domain, Vertices>::const_iterator dvit = m_points.begin(); dvit != m_points.end(); ++dvit) {
            size += dvit->second.size();
        }

        mat = Matrix(size, (geo.size() - geo.outermost_interface().nb_triangles()));
        mat.set(0.0);

        for ( std::map<const Domain, Vertices>::const_iterator dvit = m_points.begin(); dvit != m_points.end(); ++dvit) {
            for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
                int orientation = dvit->first.mesh_orientation(*mit);
                if ( orientation != 0 ) {
                    operatorDinternal(*mit, mat, dvit->second, orientation * -1. * K);
                    if ( !mit->outermost() ) {
                        operatorSinternal(*mit, mat, dvit->second, orientation * K / geo.sigma(dvit->first));
                    }
                }
            }
        }
    }
예제 #3
0
void
KML_Geometry::parseStyle( xml_node<>* node, KMLContext& cx, Style& style )
{
    _extrude = getValue(node, "extrude") == "1";
    _tessellate = getValue(node, "tessellate") == "1";

    std::string am = getValue(node, "altitudemode");
    if ( am.empty() )
        am = "clampToGround"; // default.

    bool isPoly = _geom.valid() && _geom->getComponentType() == Geometry::TYPE_POLYGON;
    bool isLine = _geom.valid() && _geom->getComponentType() == Geometry::TYPE_LINESTRING;

    // Resolve the correct altitude symbol. CLAMP_TO_TERRAIN is the default, but the
    // technique will depend on the geometry's type and setup.
    AltitudeSymbol* alt = style.getOrCreate<AltitudeSymbol>();
    alt->clamping() = alt->CLAMP_TO_TERRAIN;


    // Compute some info about the geometry

    // Are all of the elevations zero?
    bool zeroElev = true;
    // Are all of the the elevations the same?
    bool sameElev = true;

    double maxElevation = -DBL_MAX;

    //if ( isPoly ) //compute maxElevation also for line strings for extrusion height
    {
        bool first = true;
        double e = 0.0;
        ConstGeometryIterator gi( _geom.get(), false );
        while(gi.hasMore() )
        {
            const Geometry* g = gi.next();
            for( Geometry::const_iterator ji = g->begin(); ji != g->end(); ++ji )
            {
                if ( !osg::equivalent(ji->z(), 0.0) )
                    zeroElev = false;

                if (first)
                {
                    first = false;
                    e = ji->z();
                }
                else
                {
                    if (!osg::equivalent(e, ji->z()))
                    {
                        sameElev = false;
                    }
                }

                if (ji->z() > maxElevation) maxElevation = ji->z();
            }
        }
    }

    // clamp to ground mode:
    if ( am == "clampToGround" )
    {
        if ( _extrude )
        {
            alt->technique() = alt->TECHNIQUE_MAP;
        }
        else if ( isPoly )
        {
            alt->technique() = alt->TECHNIQUE_DRAPE;
        }
        else if ( isLine)
        {
            alt->technique() = alt->TECHNIQUE_DRAPE; // or could be GPU.
        }
        else // line or point
        {
            alt->technique() = alt->TECHNIQUE_SCENE;
        }

        // extrusion is not compatible with clampToGround.
        _extrude = false;
    }

    // "relativeToGround" means the coordinates' Z values are relative to the Z of the
    // terrain at that point. NOTE: GE flattens rooftops in this mode when extrude=1,
    // which seems wrong..
    else if ( am == "relativeToGround" )
    {
        alt->clamping() = alt->CLAMP_RELATIVE_TO_TERRAIN;

        if (isPoly)
        {
            // If all of the verts have the same elevation then assume that it should be clamped at the centroid and not per vertex.
            if (sameElev)
            {
                alt->binding() = AltitudeSymbol::BINDING_CENTROID;
            }

            if ( _extrude )
            {
                alt->technique() = alt->TECHNIQUE_MAP;
            }
            else
            {
                alt->technique() = alt->TECHNIQUE_SCENE;

                if ( zeroElev )
                {
                    alt->clamping()  = alt->CLAMP_TO_TERRAIN;
                    alt->technique() = alt->TECHNIQUE_DRAPE;
                }
            }
        }
    }

    // "absolute" means to treat the Z values as-is
    else if ( am == "absolute" )
    {
        alt->clamping() = AltitudeSymbol::CLAMP_NONE;
    }

    if ( _extrude )
    {
        ExtrusionSymbol* es = style.getOrCreate<ExtrusionSymbol>();
        es->flatten() = false;
        if (*alt->clamping() == AltitudeSymbol::CLAMP_NONE)
        {
            // Set the height to the max elevation + the approx depth of the mariana trench so that it will extend low enough to be always go to the surface of the earth.
            // This lets us avoid clamping absolute absolute extruded polygons completely.
            es->height() = -(maxElevation + 11100.0);
        }
    }
    else
    {
        // remove polystyle since it doesn't apply to non-extruded lines and points
        if ( !isPoly )
        {
            style.remove<PolygonSymbol>();
        }
    }
}
예제 #4
0
    void assemble_cortical(const Geometry& geo, Matrix& mat, const Head2EEGMat& M, const std::string& domain_name, const unsigned gauss_order, double alpha, double beta, const std::string &filename)
    {
        // Following the article: M. Clerc, J. Kybic "Cortical mapping by Laplace–Cauchy transmission using a boundary element method".
        // Assumptions:
        // - domain_name: the domain containing the sources is an innermost domain (defined as the interior of only one interface (called Cortex)
        // - Cortex interface is composed of one mesh only (no shared vertices)
        // TODO check orders of MxM products for efficiency ... delete intermediate matrices
        const Domain& SourceDomain = geo.domain(domain_name);
        const Interface& Cortex    = SourceDomain.begin()->interface();
        const Mesh& cortex         = Cortex.begin()->mesh();
        // test the assumption
        assert(SourceDomain.size() == 1);
        assert(Cortex.size() == 1);
        // shape of the new matrix:
        unsigned Nl = geo.size()-geo.outermost_interface().nb_triangles()-Cortex.nb_vertices()-Cortex.nb_triangles();
        unsigned Nc = geo.size()-geo.outermost_interface().nb_triangles();
        std::fstream f(filename.c_str());
        Matrix P;
        if ( !f ) {
            // build the HeadMat:
            // The following is the same as assemble_HM except N_11, D_11 and S_11 are not computed.
            SymMatrix mat_temp(Nc);
            mat_temp.set(0.0);
            double K = 1.0 / (4.0 * M_PI);
            // We iterate over the meshes (or pair of domains) to fill the lower half of the HeadMat (since its symmetry)
            for ( Geometry::const_iterator mit1 = geo.begin(); mit1 != geo.end(); ++mit1) {
                for ( Geometry::const_iterator mit2 = geo.begin(); (mit2 != (mit1+1)); ++mit2) {
                    // if mit1 and mit2 communicate, i.e they are used for the definition of a common domain
                    const int orientation = geo.oriented(*mit1, *mit2); // equals  0, if they don't have any domains in common
                    // equals  1, if they are both oriented toward the same domain
                    // equals -1, if they are not
                    if ( orientation != 0) {
                        double Scoeff =   orientation * geo.sigma_inv(*mit1, *mit2) * K;
                        double Dcoeff = - orientation * geo.indicator(*mit1, *mit2) * K;
                        double Ncoeff;
                        if ( !(mit1->outermost() || mit2->outermost()) && ( (*mit1 != *mit2)||( *mit1 != cortex) ) ) {
                            // Computing S block first because it's needed for the corresponding N block
                            operatorS(*mit1, *mit2, mat_temp, Scoeff, gauss_order);
                            Ncoeff = geo.sigma(*mit1, *mit2)/geo.sigma_inv(*mit1, *mit2);
                        } else {
                            Ncoeff = orientation * geo.sigma(*mit1, *mit2) * K;
                        }
                        if ( !mit1->outermost() && (( (*mit1 != *mit2)||( *mit1 != cortex) )) ) {
                            // Computing D block
                            operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order);
                        }
                        if ( ( *mit1 != *mit2 ) && ( !mit2->outermost() ) ) {
                            // Computing D* block
                            operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order, true);
                        }
                        // Computing N block
                        if ( (*mit1 != *mit2)||( *mit1 != cortex) ) {
                            operatorN(*mit1, *mit2, mat_temp, Ncoeff, gauss_order);
                        }
                    }
                }
            }
            // Deflate the diagonal block (N33) of 'mat' : (in order to have a zero-mean potential for the outermost interface)
            const Interface i = geo.outermost_interface();
            unsigned i_first = (*i.begin()->mesh().vertex_begin())->index();
            deflat(mat_temp, i, mat_temp(i_first, i_first) / (geo.outermost_interface().nb_vertices()));

            mat = Matrix(Nl, Nc);
            mat.set(0.0);
            // copy mat_temp into mat except the lines for cortex vertices [i_vb_c, i_ve_c] and cortex triangles [i_tb_c, i_te_c].
            unsigned iNl = 0;
            unsigned i_vb_c = (*cortex.vertex_begin())->index();
            unsigned i_ve_c = (*cortex.vertex_rbegin())->index();
            unsigned i_tb_c = cortex.begin()->index();
            unsigned i_te_c = cortex.rbegin()->index();
            for ( unsigned i = 0; i < Nc; ++i) {
                if ( !(i_vb_c<=i && i<=i_ve_c) && !(i_tb_c<=i && i<=i_te_c) ) {
                    mat.setlin(iNl, mat_temp.getlin(i));
                    ++iNl;
                }
            }
            // ** Construct P: the null-space projector **
            Matrix W;
            {
                Matrix U, s;
                mat.svd(U, s, W);
            }

            SparseMatrix S(Nc,Nc);
            // we set S to 0 everywhere, except in the last part of the diag:
            for ( unsigned i = Nl; i < Nc; ++i) {
                S(i, i) = 1.0;
            }
            P = (W * S) * W.transpose(); // P is a projector: P^2 = P and mat*P*X = 0
            if ( filename.length() != 0 ) {
                std::cout << "Saving projector P (" << filename << ")." << std::endl;
                P.save(filename);
            }
        } else {
            std::cout << "Loading projector P (" << filename << ")." << std::endl;
            P.load(filename);
        }

        // ** Get the gradient of P1&P0 elements on the meshes **
        Matrix MM(M.transpose() * M);
        SymMatrix RR(Nc, Nc); RR.set(0.);
        for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
            mit->gradient_norm2(RR);
        }

        // ** Choose Regularization parameter **
        SparseMatrix alphas(Nc,Nc); // diagonal matrix
        Matrix Z;
        if ( alpha < 0 ) { // try an automatic method... TODO find better estimation
            double nRR_v = RR.submat(0, geo.nb_vertices(), 0, geo.nb_vertices()).frobenius_norm();
            alphas.set(0.);
            alpha = MM.frobenius_norm() / (1.e3*nRR_v);
            beta  = alpha * 50000.;
            for ( Vertices::const_iterator vit = geo.vertex_begin(); vit != geo.vertex_end(); ++vit) {
                alphas(vit->index(), vit->index()) = alpha;
            }
            for ( Meshes::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
                if ( !mit->outermost() ) {
                    for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) {
                        alphas(tit->index(), tit->index()) = beta;
                    }
                }
            }
            std::cout << "AUTOMATIC alphas = " << alpha << "\tbeta = " << beta << std::endl;
        } else {
            for ( Vertices::const_iterator vit = geo.vertex_begin(); vit != geo.vertex_end(); ++vit) {
                alphas(vit->index(), vit->index()) = alpha;
            }
            for ( Meshes::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
                if ( !mit->outermost() ) {
                    for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) {
                        alphas(tit->index(), tit->index()) = beta;
                    }
                }
            }
            std::cout << "alphas = " << alpha << "\tbeta = " << beta << std::endl;
        }
        Z = P.transpose() * (MM + alphas*RR) * P;

        // ** PseudoInverse and return **
        // X = P * { (M*P)' * (M*P) + (R*P)' * (R*P) }¡(-1) * (M*P)'m
        // X = P * { P'*M'*M*P + P'*R'*R*P }¡(-1) * P'*M'm
        // X = P * { P'*(MM + a*RR)*P }¡(-1) * P'*M'm
        // X = P * Z¡(-1) * P' * M'm
        Matrix rhs = P.transpose() * M.transpose();
        mat = P * Z.pinverse() * rhs;
    }
예제 #5
0
osg::Geode*
BuildGeometryFilter::processPoints(FeatureList& features, FilterContext& context)
{
    osg::Geode* geode = new osg::Geode();

    bool makeECEF = false;
    const SpatialReference* featureSRS = 0L;
    const SpatialReference* outputSRS = 0L;

    // set up referencing information:
    if ( context.isGeoreferenced() )
    {
        //makeECEF   = context.getSession()->getMapInfo().isGeocentric();
        featureSRS = context.extent()->getSRS();
        outputSRS  = context.getOutputSRS();
        makeECEF = outputSRS->isGeographic();
    }

    for( FeatureList::iterator f = features.begin(); f != features.end(); ++f )
    {
        Feature* input = f->get();

        GeometryIterator parts( input->getGeometry(), true );
        while( parts.hasMore() )
        {
            Geometry* part = parts.next();

            // extract the required point symbol; bail out if not found.
            const PointSymbol* point =
                input->style().isSet() && input->style()->has<PointSymbol>() ? input->style()->get<PointSymbol>() :
                _style.get<PointSymbol>();

            if ( !point )
                continue;

            // collect all the pre-transformation HAT (Z) values.
            osg::ref_ptr<osg::FloatArray> hats = new osg::FloatArray();
            hats->reserve( part->size() );
            for(Geometry::const_iterator i = part->begin(); i != part->end(); ++i )
                hats->push_back( i->z() );

            // resolve the color:
            osg::Vec4f primaryColor = point->fill()->color();
            
            osg::ref_ptr<osg::Geometry> osgGeom = new osg::Geometry();
            osgGeom->setUseVertexBufferObjects( true );
            osgGeom->setUseDisplayList( false );

            // embed the feature name if requested. Warning: blocks geometry merge optimization!
            if ( _featureNameExpr.isSet() )
            {
                const std::string& name = input->eval( _featureNameExpr.mutable_value(), &context );
                osgGeom->setName( name );
            }

            // build the geometry:
            osg::Vec3Array* allPoints = new osg::Vec3Array();

            transformAndLocalize( part->asVector(), featureSRS, allPoints, outputSRS, _world2local, makeECEF );

            osgGeom->addPrimitiveSet( new osg::DrawArrays(GL_POINTS, 0, allPoints->getNumElements()) );
            osgGeom->setVertexArray( allPoints );

            if ( input->style().isSet() )
            {
                //TODO: re-evaluate this. does it hinder geometry merging?
                applyPointSymbology( osgGeom->getOrCreateStateSet(), point );
            }

            // assign the primary color (PER_VERTEX required for later optimization)
            osg::Vec4Array* colors = new osg::Vec4Array;
            colors->assign( osgGeom->getVertexArray()->getNumElements(), primaryColor );
            osgGeom->setColorArray( colors );
            osgGeom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );

            geode->addDrawable( osgGeom );

            // record the geometry's primitive set(s) in the index:
            if ( context.featureIndex() )
                context.featureIndex()->tagDrawable( osgGeom, input );
        
            // install clamping attributes if necessary
            if (_style.has<AltitudeSymbol>() &&
                _style.get<AltitudeSymbol>()->technique() == AltitudeSymbol::TECHNIQUE_GPU)
            {            
                Clamping::applyDefaultClampingAttrs( osgGeom, input->getDouble("__oe_verticalOffset", 0.0) );
                Clamping::setHeights( osgGeom, hats.get() );
            }
        }
    }
    
    return geode;
}
예제 #6
0
osg::Geode*
BuildGeometryFilter::processLines(FeatureList& features, FilterContext& context)
{
    osg::Geode* geode = new osg::Geode();

    bool makeECEF = false;
    const SpatialReference* featureSRS = 0L;
    const SpatialReference* outputSRS = 0L;

    // set up referencing information:
    if ( context.isGeoreferenced() )
    {
        //makeECEF   = context.getSession()->getMapInfo().isGeocentric();
        featureSRS = context.extent()->getSRS();
        outputSRS  = context.getOutputSRS();
        makeECEF = outputSRS->isGeographic();
    }

    for( FeatureList::iterator f = features.begin(); f != features.end(); ++f )
    {
        Feature* input = f->get();

        // extract the required line symbol; bail out if not found.
        const LineSymbol* line = 
            input->style().isSet() && input->style()->has<LineSymbol>() ? input->style()->get<LineSymbol>() :
            _style.get<LineSymbol>();

        if ( !line )
            continue;

        // run a symbol script if present.
        if ( line->script().isSet() )
        {
            StringExpression temp( line->script().get() );
            input->eval( temp, &context );
        }

        GeometryIterator parts( input->getGeometry(), true );
        while( parts.hasMore() )
        {
            Geometry* part = parts.next();

            // skip invalid geometry for lines.
            if ( part->size() < 2 )
                continue;

            // collect all the pre-transformation HAT (Z) values.
            osg::ref_ptr<osg::FloatArray> hats = new osg::FloatArray();
            hats->reserve( part->size() );
            for(Geometry::const_iterator i = part->begin(); i != part->end(); ++i )
                hats->push_back( i->z() );

            // if the underlying geometry is a ring (or a polygon), use a line loop; otherwise
            // use a line strip.
            GLenum primMode = dynamic_cast<Ring*>(part) ? GL_LINE_LOOP : GL_LINE_STRIP;

            // resolve the color:
            osg::Vec4f primaryColor = line->stroke()->color();
            
            osg::ref_ptr<osg::Geometry> osgGeom = new osg::Geometry();
            osgGeom->setUseVertexBufferObjects( true );
            osgGeom->setUseDisplayList( false );

            // embed the feature name if requested. Warning: blocks geometry merge optimization!
            if ( _featureNameExpr.isSet() )
            {
                const std::string& name = input->eval( _featureNameExpr.mutable_value(), &context );
                osgGeom->setName( name );
            }

            // build the geometry:
            osg::Vec3Array* allPoints = new osg::Vec3Array();

            transformAndLocalize( part->asVector(), featureSRS, allPoints, outputSRS, _world2local, makeECEF );

            osgGeom->addPrimitiveSet( new osg::DrawArrays(primMode, 0, allPoints->getNumElements()) );
            osgGeom->setVertexArray( allPoints );

            if ( input->style().isSet() )
            {
                //TODO: re-evaluate this. does it hinder geometry merging?
                applyLineSymbology( osgGeom->getOrCreateStateSet(), line );
            }
            
            // subdivide the mesh if necessary to conform to an ECEF globe;
            // but if the tessellation is set to zero, or if the style specifies a
            // tessellation size, skip this step.
            if ( makeECEF && !line->tessellation().isSetTo(0) && !line->tessellationSize().isSet() )
            {
                double threshold = osg::DegreesToRadians( *_maxAngle_deg );
                OE_DEBUG << "Running mesh subdivider with threshold " << *_maxAngle_deg << std::endl;

                MeshSubdivider ms( _world2local, _local2world );
                //ms.setMaxElementsPerEBO( INT_MAX );
                if ( input->geoInterp().isSet() )
                    ms.run( *osgGeom, threshold, *input->geoInterp() );
                else
                    ms.run( *osgGeom, threshold, *_geoInterp );
            }

            // assign the primary color (PER_VERTEX required for later optimization)
            osg::Vec4Array* colors = new osg::Vec4Array;
            colors->assign( osgGeom->getVertexArray()->getNumElements(), primaryColor );
            osgGeom->setColorArray( colors );
            osgGeom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );

            geode->addDrawable( osgGeom );

            // record the geometry's primitive set(s) in the index:
            if ( context.featureIndex() )
                context.featureIndex()->tagDrawable( osgGeom, input );
        
            // install clamping attributes if necessary
            if (_style.has<AltitudeSymbol>() &&
                _style.get<AltitudeSymbol>()->technique() == AltitudeSymbol::TECHNIQUE_GPU)
            {
                Clamping::applyDefaultClampingAttrs( osgGeom, input->getDouble("__oe_verticalOffset", 0.0) );
                Clamping::setHeights( osgGeom, hats.get() );
            }
        }
    }
    
    return geode;
}
예제 #7
0
osg::Geode*
BuildGeometryFilter::processPolygonizedLines(FeatureList&   features, 
                                             bool           twosided,
                                             FilterContext& context)
{
    osg::Geode* geode = new osg::Geode();

    // establish some referencing
    bool                    makeECEF   = false;
    const SpatialReference* featureSRS = 0L;
    const SpatialReference* outputSRS  = 0L;

    if ( context.isGeoreferenced() )
    {
        //makeECEF   = context.getSession()->getMapInfo().isGeocentric();
        featureSRS = context.extent()->getSRS();
        outputSRS = context.getOutputSRS();
        makeECEF = outputSRS->isGeographic();
        //mapSRS     = context.getSession()->getMapInfo().getProfile()->getSRS();
    }

    // iterate over all features.
    for( FeatureList::iterator i = features.begin(); i != features.end(); ++i )
    {
        Feature* input = i->get();
        // extract the required line symbol; bail out if not found.
        const LineSymbol* line =
            input->style().isSet() && input->style()->has<LineSymbol>() ? input->style()->get<LineSymbol>() :
            _style.get<LineSymbol>();

        if ( !line )
            continue;

        // run a symbol script if present.
        if ( line->script().isSet() )
        {
            StringExpression temp( line->script().get() );
            input->eval( temp, &context );
        }

        // The operator we'll use to make lines into polygons.
        PolygonizeLinesOperator polygonizer( *line->stroke() );

        // iterate over all the feature's geometry parts. We will treat
        // them as lines strings.
        GeometryIterator parts( input->getGeometry(), true );
        while( parts.hasMore() )
        {
            Geometry* part = parts.next();

            // if the underlying geometry is a ring (or a polygon), close it so the
            // polygonizer will generate a closed loop.
            Ring* ring = dynamic_cast<Ring*>(part);
            if ( ring )
                ring->close();

            // skip invalid geometry
            if ( part->size() < 2 )
                continue;

            // collect all the pre-transformation HAT (Z) values.
            osg::ref_ptr<osg::FloatArray> hats = new osg::FloatArray();
            hats->reserve( part->size() );
            for(Geometry::const_iterator i = part->begin(); i != part->end(); ++i )
                hats->push_back( i->z() );

            // transform the geometry into the target SRS and localize it about 
            // a local reference point.
            osg::ref_ptr<osg::Vec3Array> verts   = new osg::Vec3Array();
            osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array();
            transformAndLocalize( part->asVector(), featureSRS, verts.get(), normals.get(), outputSRS, _world2local, makeECEF );

            // turn the lines into polygons.
            osg::Geometry* geom = polygonizer( verts.get(), normals.get(), twosided );
            if ( geom )
            {
                geode->addDrawable( geom );
            }

            // record the geometry's primitive set(s) in the index:
            if ( context.featureIndex() )
                context.featureIndex()->tagDrawable( geom, input );
        
            // install clamping attributes if necessary
            if (_style.has<AltitudeSymbol>() &&
                _style.get<AltitudeSymbol>()->technique() == AltitudeSymbol::TECHNIQUE_GPU)
            {
                Clamping::applyDefaultClampingAttrs( geom, input->getDouble("__oe_verticalOffset", 0.0) );
                Clamping::setHeights( geom, hats.get() );
            }
        }

        polygonizer.installShaders( geode );
    }
    return geode;
}
예제 #8
0
osg::Geode*
BuildGeometryFilter::processPolygons(FeatureList& features, FilterContext& context)
{
    osg::Geode* geode = new osg::Geode();

    bool makeECEF = false;
    const SpatialReference* featureSRS = 0L;
    //const SpatialReference* mapSRS = 0L;
    const SpatialReference* outputSRS = 0L;

    // set up the reference system info:
    if ( context.isGeoreferenced() )
    {
        //makeECEF   = context.getSession()->getMapInfo().isGeocentric();
        featureSRS = context.extent()->getSRS();
        outputSRS  = context.getOutputSRS(); //getSession()->getMapInfo().getProfile()->getSRS();
        makeECEF   = context.getOutputSRS()->isGeographic();
    }

    for( FeatureList::iterator f = features.begin(); f != features.end(); ++f )
    {
        Feature* input = f->get();

        // access the polygon symbol, and bail out if there isn't one
        const PolygonSymbol* poly =
            input->style().isSet() && input->style()->has<PolygonSymbol>() ? input->style()->get<PolygonSymbol>() :
            _style.get<PolygonSymbol>();

        if ( !poly ) {
            OE_TEST << LC << "Discarding feature with no poly symbol\n";
            continue;
        }

        // run a symbol script if present.
        if ( poly->script().isSet() )
        {
            StringExpression temp( poly->script().get() );
            input->eval( temp, &context );
        }

        GeometryIterator parts( input->getGeometry(), false );
        while( parts.hasMore() )
        {
            Geometry* part = parts.next();

            part->removeDuplicates();

            // skip geometry that is invalid for a polygon
            if ( part->size() < 3 ) {
                OE_TEST << LC << "Discarding illegal part (less than 3 verts)\n";
                continue;
            }

            // resolve the color:
            osg::Vec4f primaryColor = poly->fill()->color();
            
            osg::ref_ptr<osg::Geometry> osgGeom = new osg::Geometry();
            osgGeom->setUseVertexBufferObjects( true );
            osgGeom->setUseDisplayList( false );

            // are we embedding a feature name?
            if ( _featureNameExpr.isSet() )
            {
                const std::string& name = input->eval( _featureNameExpr.mutable_value(), &context );
                osgGeom->setName( name );
            }


            // compute localizing matrices or use globals
            osg::Matrixd w2l, l2w;
            if (makeECEF)
            {
                osgEarth::GeoExtent featureExtent(featureSRS);
                featureExtent.expandToInclude(part->getBounds());

                computeLocalizers(context, featureExtent, w2l, l2w);
            }
            else
            {
                w2l = _world2local;
                l2w = _local2world;
            }

            // collect all the pre-transformation HAT (Z) values.
            osg::ref_ptr<osg::FloatArray> hats = new osg::FloatArray();
            hats->reserve( part->size() );
            for(Geometry::const_iterator i = part->begin(); i != part->end(); ++i )
                hats->push_back( i->z() );

            // build the geometry:
            tileAndBuildPolygon(part, featureSRS, outputSRS, makeECEF, true, osgGeom, w2l);
            //buildPolygon(part, featureSRS, mapSRS, makeECEF, true, osgGeom, w2l);

            osg::Vec3Array* allPoints = static_cast<osg::Vec3Array*>(osgGeom->getVertexArray());
            if (allPoints && allPoints->size() > 0)
            {
                // subdivide the mesh if necessary to conform to an ECEF globe:
                if ( makeECEF )
                {
                    //convert back to world coords
                    for( osg::Vec3Array::iterator i = allPoints->begin(); i != allPoints->end(); ++i )
                    {
                        osg::Vec3d v(*i);
                        v = v * l2w;
                        v = v * _world2local;

                        (*i)._v[0] = v[0];
                        (*i)._v[1] = v[1];
                        (*i)._v[2] = v[2];
                    }

                    double threshold = osg::DegreesToRadians( *_maxAngle_deg );
                    OE_TEST << "Running mesh subdivider with threshold " << *_maxAngle_deg << std::endl;

                    MeshSubdivider ms( _world2local, _local2world );
                    if ( input->geoInterp().isSet() )
                        ms.run( *osgGeom, threshold, *input->geoInterp() );
                    else
                        ms.run( *osgGeom, threshold, *_geoInterp );
                }

                // assign the primary color array. PER_VERTEX required in order to support
                // vertex optimization later
                unsigned count = osgGeom->getVertexArray()->getNumElements();
                osg::Vec4Array* colors = new osg::Vec4Array;
                colors->assign( count, primaryColor );
                osgGeom->setColorArray( colors );
                osgGeom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );

                geode->addDrawable( osgGeom );

                // record the geometry's primitive set(s) in the index:
                if ( context.featureIndex() )
                    context.featureIndex()->tagDrawable( osgGeom, input );
        
                // install clamping attributes if necessary
                if (_style.has<AltitudeSymbol>() &&
                    _style.get<AltitudeSymbol>()->technique() == AltitudeSymbol::TECHNIQUE_GPU)
                {
                    Clamping::applyDefaultClampingAttrs( osgGeom, input->getDouble("__oe_verticalOffset", 0.0) );
                }
            }
            else
            {
                OE_TEST << LC << "Oh no. buildAndTilePolygon returned nothing.\n";
            }
        }
    }
    
    OE_TEST << LC << "Num drawables = " << geode->getNumDrawables() << "\n";
    return geode;
}
예제 #9
0
    void assemble_cortical2(const Geometry& geo, Matrix& mat, const Head2EEGMat& M, const std::string& domain_name, const unsigned gauss_order, double gamma, const std::string &filename)
    {
        // Re-writting of the optimization problem in M. Clerc, J. Kybic "Cortical mapping by Laplace–Cauchy transmission using a boundary element method".
        // with a Lagrangian formulation as in see http://www.math.uh.edu/~rohop/fall_06/Chapter3.pdf eq3.3
        // find argmin(norm(gradient(X)) under constraints: 
        // H * X = 0 and M * X = m
        // let G be the gradient norm matrix, l1, l2 the lagrange parameters
        // 
        // [ G  H' M'] [   X    ]   [ 0 ]
        // | H  0    | |   l1   | = | 0 |
        // [ M     0 ] [   l2   ]   [ m ]
        //
        // {----,----}
        //      K
        // we want a submat of the inverse of K (using blockwise inversion, (TODO maybe iterative solution better ?)).
        // Assumptions:
        // - domain_name: the domain containing the sources is an innermost domain (defined as the interior of only one interface (called Cortex)
        // - Cortex interface is composed of one mesh only (no shared vertices)

        const Domain& SourceDomain = geo.domain(domain_name);
        const Interface& Cortex    = SourceDomain.begin()->interface();
        const Mesh& cortex         = Cortex.begin()->mesh();
        
        om_error(SourceDomain.size()==1);
        om_error(Cortex.size()==1);

        // shape of the new matrix:
        unsigned Nl = geo.size()-geo.nb_current_barrier_triangles()-Cortex.nb_vertices()-Cortex.nb_triangles();
        unsigned Nc = geo.size()-geo.nb_current_barrier_triangles();
        std::fstream f(filename.c_str());
        Matrix H;
        if ( !f ) {
            // build the HeadMat:
            // The following is the same as assemble_HM except N_11, D_11 and S_11 are not computed.
            SymMatrix mat_temp(Nc);
            mat_temp.set(0.0);
            double K = 1.0 / (4.0 * M_PI);
            // We iterate over the meshes (or pair of domains) to fill the lower half of the HeadMat (since its symmetry)
            for ( Geometry::const_iterator mit1 = geo.begin(); mit1 != geo.end(); ++mit1) {
                for ( Geometry::const_iterator mit2 = geo.begin(); (mit2 != (mit1+1)); ++mit2) {
                    // if mit1 and mit2 communicate, i.e they are used for the definition of a common domain
                    const int orientation = geo.oriented(*mit1, *mit2); // equals  0, if they don't have any domains in common
                    // equals  1, if they are both oriented toward the same domain
                    // equals -1, if they are not
                    if ( orientation != 0) {
                        double Scoeff =   orientation * geo.sigma_inv(*mit1, *mit2) * K;
                        double Dcoeff = - orientation * geo.indicator(*mit1, *mit2) * K;
                        double Ncoeff;
                        if ( !(mit1->current_barrier() || mit2->current_barrier()) && ( (*mit1 != *mit2)||( *mit1 != cortex) ) ) {
                            // Computing S block first because it's needed for the corresponding N block
                            operatorS(*mit1, *mit2, mat_temp, Scoeff, gauss_order);
                            Ncoeff = geo.sigma(*mit1, *mit2)/geo.sigma_inv(*mit1, *mit2);
                        } else {
                            Ncoeff = orientation * geo.sigma(*mit1, *mit2) * K;
                        }
                        if ( !mit1->current_barrier() && (( (*mit1 != *mit2)||( *mit1 != cortex) )) ) {
                            // Computing D block
                            operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order);
                        }
                        if ( ( *mit1 != *mit2 ) && ( !mit2->current_barrier() ) ) {
                            // Computing D* block
                            operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order, true);
                        }
                        // Computing N block
                        if ( (*mit1 != *mit2)||( *mit1 != cortex) ) {
                            operatorN(*mit1, *mit2, mat_temp, Ncoeff, gauss_order);
                        }
                    }
                }
            }
            // Deflate all current barriers as one
            deflat(mat_temp,geo);

            H = Matrix(Nl + M.nlin(), Nc);
            H.set(0.0);
            // copy mat_temp into H except the lines for cortex vertices [i_vb_c, i_ve_c] and cortex triangles [i_tb_c, i_te_c].
            unsigned iNl = 0;
            for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
                if ( *mit != cortex ) {
                    for ( Mesh::const_vertex_iterator vit = mit->vertex_begin(); vit != mit->vertex_end(); ++vit) {
                        H.setlin(iNl, mat_temp.getlin((*vit)->index()));
                        ++iNl;
                    }
                    if ( !mit->current_barrier() ) {
                        for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) {
                            H.setlin(iNl, mat_temp.getlin(tit->index()));
                            ++iNl;
                        }
                    }
                }
            }
            if ( filename.length() != 0 ) {
                std::cout << "Saving matrix H (" << filename << ")." << std::endl;
                H.save(filename);
            }
        } else {
            std::cout << "Loading matrix H (" << filename << ")." << std::endl;
            H.load(filename);
        }

        // concat M to H
        for ( unsigned i = Nl; i < Nl + M.nlin(); ++i) {
            for ( unsigned j = 0; j < Nc; ++j) {
                H(i, j) = M(i-Nl, j);
            }
        }

        // ** Get the gradient of P1&P0 elements on the meshes **
        SymMatrix G(Nc);
        G.set(0.);
        for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
            mit->gradient_norm2(G);
        }
        // multiply by gamma the submat of current gradient norm2
        for ( Meshes::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) {
            if ( !mit->current_barrier() ) {
                for ( Mesh::const_iterator tit1 = mit->begin(); tit1 != mit->end(); ++tit1) {
                    for ( Mesh::const_iterator tit2 = mit->begin(); tit2 != mit->end(); ++tit2) {
                        G(tit1->index(), tit2->index()) *= gamma;
                    }
                }
            }
        }
        std::cout << "gamma = " << gamma << std::endl;
        
        G.invert();
        mat = (G * H.transpose() * (H * G * H.transpose()).inverse()).submat(0, Nc, Nl, M.nlin());
    }
예제 #10
0
void 
KML_Placemark::build( const Config& conf, KMLContext& cx )
{
    Style masterStyle;

    if ( conf.hasValue("styleurl") )
    {
        // process a "stylesheet" style
        const Style* ref_style = cx._sheet->getStyle( conf.value("styleurl"), false );
        if ( ref_style )
            masterStyle = *ref_style;
    }
    else if ( conf.hasChild("style") )
    {
        // process an "inline" style
        KML_Style kmlStyle;
        kmlStyle.scan( conf.child("style"), cx );
        masterStyle = cx._activeStyle;
    }

    // parse the geometry. the placemark must have geometry to be valid. The 
    // geometry parse may optionally specify an altitude mode as well.
    KML_Geometry geometry;
    geometry.build(conf, cx, masterStyle);

    Geometry* allGeom = geometry._geom.get();
    if ( allGeom )
    {
        GeometryIterator giter( allGeom, false );
        while( giter.hasMore() )
        {
            Geometry* geom = giter.next();
            Style style = masterStyle;

            // KML's default altitude mode is clampToGround.
            AltitudeMode altMode = ALTMODE_RELATIVE;

            AltitudeSymbol* altSym = style.get<AltitudeSymbol>();
            if ( !altSym )
            {
                altSym = style.getOrCreate<AltitudeSymbol>();
                altSym->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
                altSym->technique() = AltitudeSymbol::TECHNIQUE_SCENE;
            }
            else if ( !altSym->clamping().isSetTo(AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN) )
            {
                altMode = ALTMODE_ABSOLUTE;
            }
            
            if ( geom && geom->getTotalPointCount() > 0 )
            {
                GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode);

                bool isPoly = geom->getComponentType() == Geometry::TYPE_POLYGON;
                bool isPoint = geom->getComponentType() == Geometry::TYPE_POINTSET;

                // check for symbols.
                ModelSymbol*    model = style.get<ModelSymbol>();
                IconSymbol*     icon  = style.get<IconSymbol>();
                TextSymbol*     text  = style.get<TextSymbol>();

                if ( !text && cx._options->defaultTextSymbol().valid() )
                    text = cx._options->defaultTextSymbol().get();

                // the annotation name:
                std::string name = conf.hasValue("name") ? conf.value("name") : "";
                if ( text && !name.empty() )
                {
                    text->content()->setLiteral( name );
                }

                AnnotationNode* featureNode = 0L;
                AnnotationNode* iconNode    = 0L;
                AnnotationNode* modelNode   = 0L;

                // one coordinate? It's a place marker or a label.
                if ( model || icon || text || geom->getTotalPointCount() == 1 )
                {
                    // load up the default icon if there we don't have one.
                    if ( !model && !icon )
                    {
                        icon = cx._options->defaultIconSymbol().get();
                        if ( icon )
                            style.add( icon );
                    }

                    // if there's a model, render that - models do NOT get labels.
                    if ( model )
                    {
                        ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions );
                        node->setPosition( position );

                        if ( cx._options->modelScale() != 1.0f )
                        {
                            float s = *cx._options->modelScale();
                            node->setScale( osg::Vec3f(s,s,s) );
                        }

                        if ( !cx._options->modelRotation()->zeroRotation() )
                        {
                            node->setLocalRotation( *cx._options->modelRotation() );
                        }

                        modelNode = node;
                    }

                    else if ( !text && !name.empty() )
                    {
                        text = style.getOrCreate<TextSymbol>();
                        text->content()->setLiteral( name );
                    }

                    if ( icon )
                    {
                        iconNode = new PlaceNode( cx._mapNode, position, style, cx._dbOptions );
                    }

                    else if ( !model && text && !name.empty() )
                    {
                        // note: models do not get labels.
                        iconNode = new LabelNode( cx._mapNode, position, style );
                    }
                }

                // multiple coords? feature:
                if ( geom->getTotalPointCount() > 1 )
                {
                    ExtrusionSymbol* extruded = style.get<ExtrusionSymbol>();
                    AltitudeSymbol*  altitude = style.get<AltitudeSymbol>();

                    // Remove symbols that we have already processed so the geometry
                    // compiler doesn't get confused.
                    if ( model )
                        style.removeSymbol( model );
                    if ( icon )
                        style.removeSymbol( icon );
                    if ( text )
                        style.removeSymbol( text );

                    // analyze the data; if the Z coords are all 0.0, enable draping.
                    if ( /*isPoly &&*/ !extruded && altitude && altitude->clamping() != AltitudeSymbol::CLAMP_TO_TERRAIN )
                    {
                        bool zeroElev = true;
                        ConstGeometryIterator gi( geom, false );
                        while( zeroElev == true && gi.hasMore() )
                        {
                            const Geometry* g = gi.next();
                            for( Geometry::const_iterator ji = g->begin(); ji != g->end() && zeroElev == true; ++ji )
                            {
                                if ( !osg::equivalent(ji->z(), 0.0) )
                                    zeroElev = false;
                            }
                        }
                        if ( zeroElev )
                        {
                            altitude->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN;
                            altitude->technique() = AltitudeSymbol::TECHNIQUE_GPU;
                        }
                    }

                    // Make a feature node; drape if we're not extruding.
                    bool draped =
                        isPoly    && 
                        !extruded &&
                        (!altitude || altitude->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN);

                    if ( draped && style.get<LineSymbol>() && !style.get<PolygonSymbol>() )
                    {
                        draped = false;
                    }

                    // turn off the clamping if we're draping.
                    if ( draped && altitude )
                    {
                        altitude->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;
                    }

                    GeometryCompilerOptions compilerOptions;

                    // Check for point-model substitution:
                    if ( style.has<ModelSymbol>() )
                    {
                        compilerOptions.instancing() = true;
                    }

                    Feature* feature = new Feature(geom, cx._srs.get(), style);
                    featureNode = new FeatureNode( cx._mapNode, feature, draped, compilerOptions );
                }


                // assemble the results:
                if ( (iconNode || modelNode) && featureNode )
                {
                    osg::Group* group = new osg::Group();
                    group->addChild( featureNode );
                    if ( iconNode )
                        group->addChild( iconNode );
                    if ( modelNode )
                        group->addChild( modelNode );

                    cx._groupStack.top()->addChild( group );

                    if ( iconNode && cx._options->declutter() == true )
                        Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true );

                    if ( iconNode )
                        KML_Feature::build( conf, cx, iconNode );
                    if ( modelNode )
                        KML_Feature::build( conf, cx, modelNode );
                    if ( featureNode )
                        KML_Feature::build( conf, cx, featureNode );
                }

                else
                {
                    if ( iconNode )
                    {
                        if ( cx._options->iconAndLabelGroup().valid() )
                        {
                            cx._options->iconAndLabelGroup()->addChild( iconNode );
                        }
                        else
                        {
                            cx._groupStack.top()->addChild( iconNode );
                            if ( cx._options->declutter() == true )
                                Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true );
                        }
                        KML_Feature::build( conf, cx, iconNode );
                    }
                    if ( modelNode )
                    {
                        cx._groupStack.top()->addChild( modelNode );
                        KML_Feature::build( conf, cx, modelNode );
                    }
                    if ( featureNode )
                    {
                        cx._groupStack.top()->addChild( featureNode );
                        KML_Feature::build( conf, cx, featureNode );
                    }
                }
            }
        }
    }
}