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; }
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)); } } } } }
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>(); } } }
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; }
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; }
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; }
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; }
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; }
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()); }
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 ); } } } } } }