[原][osgearth]OE地形平整代碼解讀


在FlatteningLayer文件的createHeightField函數中:使用的github在2017年1月份的代碼

if (!geoms.getComponents().empty())
    {
        osg::ref_ptr<osg::HeightField> hf = HeightFieldUtils::createReferenceHeightField(
            ex,
            257, 257,           // base tile size for elevation data
            0u,                 // no border
            true);              // initialize to HAE (0.0) heights

        // Initialize to NO DATA.
        hf->getFloatArray()->assign(hf->getNumColumns()*hf->getNumRows(), NO_DATA_VALUE);

        // Create an elevation query envelope at the LOD we are creating
        osg::ref_ptr<ElevationEnvelope> envelope = _pool->createEnvelope(workingSRS, key.getLOD());

        // Resolve the buffering widths:
        double lineWidthLocal = lineWidth()->as(workingSRS->getUnits());
        double bufferWidthLocal = bufferWidth()->as(workingSRS->getUnits());
        
        if(integrate(key, hf, &geoms, workingSRS, lineWidthLocal, bufferWidthLocal, envelope, progress) || (progress && progress->isCanceled()))
        {
            //double t_create = OE_GET_TIMER(create);
            //OE_INFO << LC << key.str() << " : t=" << t_create << "s\n";

            // If integrate made any changes, return the new heightfield.
            // (Or if the operation was canceled...return it anyway and it 
            // will be discarded).
            return hf.release();
        }
    }

 

 

 創建一個高度場,長寬都是257,邊界為0,高度引用大地水平基准面。

   用默認值初始化高度場

   在自己創建的LOD中創建一個高程查詢信

   解決緩存寬度

   整合新高程

   如果高程有任何改變,返回新的高程圖,高度場。

 

這里integrate調用的函數,調用了integratePolygons函數來創建平整的高程圖,我們看看這里具體怎么操作的

我們來看integratePolygons函數:

 1 // Creates a heightfield that flattens an area intersecting the input polygon geometry.創建一個包含集合多邊形的高度場
 2     // The height of the area is found by sampling a point internal to the polygon.
 3     // bufferWidth = width of transition from flat area to natural terrain.
 4     bool integratePolygons(const TileKey& key, osg::HeightField* hf, const Geometry* geom, const SpatialReference* geomSRS,
 5                            double bufferWidth, ElevationEnvelope* envelope, ProgressCallback* progress)
 6     {
 7         bool wroteChanges = false;
 8 
 9         const GeoExtent& ex = key.getExtent();
10 
11         double col_interval = ex.width() / (double)(hf->getNumColumns()-1);
12         double row_interval = ex.height() / (double)(hf->getNumRows()-1);
13 
14         POINT Pex, P, internalP;
15 
16         bool needsTransform = ex.getSRS() != geomSRS;
17

循環遍歷長寬間隔獲取每個頂點坐標

18         for (unsigned col = 0; col < hf->getNumColumns(); ++col)
19         {
20             Pex.x() = ex.xMin() + (double)col * col_interval;
21 
22             for (unsigned row = 0; row < hf->getNumRows(); ++row)
23             {
24                 // check for cancelation periodically
25                 //if (progress && progress->isCanceled())
26                 //    return false;
27 
28                 Pex.y() = ex.yMin() + (double)row * row_interval;
29 
30                 if (needsTransform)
31                     ex.getSRS()->transform(Pex, geomSRS, P);
32                 else
33                     P = Pex;
34                 
35                 bool done = false;
36                 double minD2 = bufferWidth * bufferWidth; // minimum distance(squared) to closest polygon edge
37 
38                 const Polygon* bestPoly = 0L;
39 
40                 ConstGeometryIterator giter(geom, false);
41                 while (giter.hasMore() && !done)
42                 {
43                     const Polygon* polygon = dynamic_cast<const Polygon*>(giter.next());
44                     if (polygon)
45                     {
46                         // Does the point P fall within the polygon?
循環檢查這里是否有點在這些幾何形狀里
47 if (polygon->contains2D(P.x(), P.y())) 48 { 49 // yes, flatten it to the polygon's centroid elevation; 50 // and we're dont with this point.
如果這點就在幾何形狀范圍里,直接跳出檢查
51 done = true; 52 bestPoly = polygon; 53 minD2 = -1.0; 54 } 55 56 // If not in the polygon, how far to the closest edge?
如果沒在,計算距離邊緣最近的距離的平方
57                         else
58                         {
59                             double D2 = getDistanceSquaredToClosestEdge(P, polygon);
查看獲得值是否在緩存范圍內
60 if (D2 < minD2) 61 {
如果在范圍內,就設置好這個點在緩存內最近的位置,以便后面計算
62 minD2 = D2; 63 bestPoly = polygon; 64 } 65 } 66 } 67 } 68 69 if (bestPoly && minD2 != 0.0) 70 {

  判斷這些需要獲取的高程點,有沒有在需要關注的幾何圖形里或者緩沖區范圍內的,如果有就做以下工作,來抬高地形:

71                     float h;
72                     POINT internalP = getInternalPoint(bestPoly);
73                     float elevInternal = envelope->getElevation(internalP.x(), internalP.y());
74 
75                     if (minD2 < 0.0)
76                     {
77                         h = elevInternal;
78                     }
79                     else
80                     {
81                         float elevNatural = envelope->getElevation(P.x(), P.y());
82                         double blend = clamp(sqrt(minD2)/bufferWidth, 0.0, 1.0); // [0..1] 0=internal, 1=natural
83                         h = smoothstep(elevInternal, elevNatural, blend);
84                     }
85 
86                     hf->setHeight(col, row, h);
87                     wroteChanges = true;
88                 }
89 
90             }
91         }
92 
93         return wroteChanges;
94     }

 

真正平整的函數在:integrate函數

   進入FlatteningLayer文件的integratePolygons函數

      先獲取TileKey范圍

      獲取長寬的間隔分別是多大長度

      檢查是否要做SRS轉換,這里看是需要的

     

West -180  xMin    SRS-> -20037508.343

        East  0     xMax

        South -90  xMin    SRS-> -20037508.343

        North 90    yMax

 

循環遍歷長寬間隔獲取每個頂點坐標

      POINT P是這點的世界位置點

        循環檢查這些幾何形狀

              看看點是否在這些幾何形狀里

              如果不在,計算距離邊緣最近的距離的平方

                 查看獲得值是否在平整范圍內

如果在范圍內,就設置好這個點在范圍內最近的位置,以便后面計算

              如果點就在幾何形狀范圍里,直接跳出檢查

      直接點說

就是判斷這些需要獲取的高程點,有沒有在需要關注的幾何圖形里或者緩沖區范圍內的,如果有就做以下工作,來抬高地形:

      先找到幾何圖形內部的一個頂點(多為中心,質心等)

      通過ElevationEnvelope類的getElevation函數計算這個點的高程

      判斷這個要改變高程的點與幾何圖形的位置關系:

如果在幾何圖形內就設置這個點用剛才獲取的高程點(這個方式有待商榷)

         如果在緩沖區上,獲取這個點的現實高程值。獲取當前點在緩沖區上的范圍值,做smoothstep變換。

        然后將之前得到的高程按格子塞入高程圖。

           齊活!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM