[原]C#繪製等值線二 等值線追蹤

來源:互聯網
上載者:User

轉載請註明作者及出處,謝謝

上文提到了繪製等值線的一些基本原理及構建三角網的思路,本文將著重介紹等值線追蹤方法。

在我一開始的想法中,繪製等值線肯定就是把所有具有相同值的點串連起來就OK了,一想那不是一個蜘蛛網嘛,不同高程值的等值線都交叉了,那還叫什麼等值線?瞭解到使用三角網剖分方法來產生等值線後,又是以為三角形延著三個點來遊走就能得到等值線,又一想不行,因為如果值恰好在某一個點上時,那到底向哪條邊遊走呢?最重要的是,如果我要繪製照度為500的等值線,如果三角網中所有的點上的值沒有500怎麼辦?那豈不是很滑稽:有600,有400,但是沒有500這條線,這就好比有爺爺,也有孫子,但是沒有兒子,那孫子是從哪兒來的呢?這才發現原來人家早提出方案了,使用插值法,更重要一點是論文中還特意使用等值線不從三角網上的點通過,為什嗎?因為從點上過的話,等值線的方向不好計算。

知道了等值線都是與三角形的邊交叉後(當然,除了三角網的邊框),這裡還需要對等值線的另一個特性有個瞭解,即等值線按照其類型可以分為開放式和封閉式。所謂開放式是指,等值線的兩個端點都在三角網的邊框上,所謂封閉式是指,等值線是一個閉環,起點同時也是終點。

假定我們需要繪製高程值為500的等值線,那麼在三角網中追蹤等值線的基本思路是:先尋找所有開放式等值線,然後再尋找封閉式等值線。開放式等值線的具體作法為:

1. 將所有至少兩個邊都包含500這個值的三角形找出來放到一個列表valTrangles中,判斷一個邊上是否包含500這個值的點的方法:

圖1

            //為了避免邊的兩個端點的值正好等於指定值,從而造成難以判斷等值線方向            //因此當端點值正好等於指定值時給端點值減去一個很小的正數,使指定值所            //在的點和兩個端點不重合            decimal tolerance = 0.000001M;            decimal value1 = edge.P1.Value, value2 = edge.P2.Value;            if (value1 == value) { value1 -= tolerance; }            if (value2 == value) { value2 -= tolerance; }            return (value1 - value) * (value2 - value) <= 0;

從圖1和上面的代碼中我們可以清楚的看到,如果V點介於V1和V2的話,那麼value1 - value和value2 - value中必然有一個是負數,從而使代碼傳回值是true。

2. 從valTrangle中任意一個三角網邊框邊的三角形開始,判斷這個邊上是否具有500這個點,如果有,記錄當前三角形以及當前邊,並將該點添加到等值線構成點列表(var Contour = new List<VPoint>())中,開始在這個三角形剩下的兩個邊上尋找“出路”,(My Code沒有處理剩餘的兩條邊上同時具有指定高程值的情況,但是直至目前沒有出現不合理的等值線。)。這裡有一個問題:知道一個邊上有某個點,那麼這個點的座標是多少呢?因為我們的三角形的邊長度比較小,所以我們可以利用兩個點,通過線性關係得到指定值所在的座標:

                var factor = (float)((value - edge.P1.Value) / (edge.P2.Value - edge.P1.Value));                result.X = edge.P1.X + factor * (edge.P2.X - edge.P1.X);                result.Y = edge.P1.Y + factor * (edge.P2.Y - edge.P1.Y);

3. 找到第一個“出口”點後,將該點添加到Contour中,並將當前三角形標記為-1,即臨時已使用。然後使用當前邊為“出口”點所在的邊,使當前三角形為當前邊的另一個所屬三角形,還記得我們Edge類型中的Trangle1和Trangle2的定義吧。

  currentTrangle = currentTrangle == currentEdge.Triangle1 ? currentEdge.Triangle2 : currentEdge.Triangle1;

4.在得到當前三角形,當前邊後迴圈調用第3步,又會得到第3個等值線的點,依照這個方法,最終會有兩種可能,a:某個邊只有屬於一個三角形(到達三角網的邊框了);b:到達的三角形的UsedStatus為-1(這個三角形已經被前面的步驟使用過了)。這時退出迴圈。

這個時候,對於某個值的開放式的等值線就已經尋找完了,這裡使用一個邊所屬的兩個三角形這種方法,可以在很大程度上降低使用點陣擷取三角形和邊的麻煩,那種方法雖然談不上非常困難,但是一大堆的索引值足以使你心煩意亂。

尋找封閉式等值的方法和開放式基本上沒有區別,所不同的只是允出準則為找到的出口和等值線第一點的座標相同而已。

這裡給出核心代碼(同時包含開放式和封閉式):

        private IList<VPoint> GetContour(IList<Triangle> triangles, Edge currentEdge, decimal value)        {            IList<VPoint> result = new List<VPoint>();            var firstEdge = currentEdge;            var currentTrangle = currentEdge.Triangle1;            var currentPoint = this.TryGetContourPoints(currentEdge, value);            result.Add(currentPoint);            while (true)            {                currentTrangle.UsedStatus = -1;                var edges = currentTrangle.Get2OtherEdge(currentEdge);                currentPoint = this.TryGetContourPoints(edges[0], value);                int useEdge = 0;                if (currentPoint == null)                {                    currentPoint = this.TryGetContourPoints(edges[1], value);                    useEdge = 1;                }                result.Add(currentPoint);                currentEdge = edges[useEdge];                currentTrangle = currentTrangle == currentEdge.Triangle1 ? currentEdge.Triangle2 : currentEdge.Triangle1;                if (currentTrangle == null || currentTrangle.UsedStatus == -1 || currentTrangle.UsedStatus == 1)                {                    int usedStatus = 0;                    //開放式等值線                     if ((firstEdge.IsBorder && currentEdge.IsBorder && result.Count >= 2) ||                        //封閉式等值線                        (firstEdge.IsBorder == false && currentTrangle != null && currentTrangle.UsedStatus == -1 && result.Count >= 6 && currentEdge == firstEdge))                    {                        usedStatus = 1;                        this.CompleteContour(triangles, usedStatus);                    }                    else                    {                        this.CompleteContour(triangles, usedStatus);                        result = null;                    }                    break;                }            }            return result;        }

當尋找結束後,如果等值線合法,即開放式到達了邊框,封閉式到達了起點,則“提交”一下候選的三角形,使用從臨時使用狀態回退到未使用狀態1,不再參與下次尋找,反之,則“復原”一下候選三角形,使用從臨時使用狀態回退到未使用狀態0。這裡還有一個“保險”,開放式的等值線,一定是大於等於2個點,封閉式的等值線,一定是大於等於6個點。

至此,三角形追蹤完成,稍事休息,接下來講等值線標註。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.