[原]C#繪製等值線三 等值線標註

來源:互聯網
上載者:User

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

上文提到了等值線追蹤解決方案,在此基礎上,我們就可以把等值線畫出來了,但是只光禿禿的線條,沒有標註還是不行的,別人哪知道那條像蚯蚓一樣的線條代表什麼呢,本文我們就來討論下如何在等值線上進行標註。

感謝《等值線標註的一種演算法探討》一文的作者,我正在是使用這篇論文中的重要演算法指導了我的工作。

首先標註那些小的封閉式的等值線。

這裡我也沒有想出來好的方法,就使用方法,找出封閉式等值線中點座標X最小值,Y最小值,X最大值及最大值;如果XMax - XMin < 指定值以及YMax - YMin < 指定值,則在P((XMin + XMax) / 2,(YMin + YMax) / 2)處把等值線的值畫出來,如下代碼所示:

                            if (points[0].X == points[points.Count - 1].X && points[0].Y == points[points.Count - 1].Y)                            {                                float xMin = points.Min<VPoint>(p => p.X), xMax = points.Max<VPoint>(p => p.X), yMin = points.Min<VPoint>(p => p.Y), yMax = points.Max<VPoint>(p => p.Y);                                if (xMax - xMin < 25 && yMax - yMin < 25)                                {                                    g.DrawString(value.ToString(), font, brush, (xMax + xMin - sf.Width) / 2f, (yMax + yMin - sf.Height) / 2f);                                    continue;                                }                            }

效果中紅圈所示:

圖1

把過於小的封閉式等值線標註後,大點的封閉式和開放式等值線的標註方法就一樣了。

根據《等值線標註的一種演算法探討》一文中的指導思想,需要把曲線轉換為折線或是多邊形,啥意思咧,看所示:

如果我告訴你,現在如果每條線段的長度大於高程值的字串(value.ToString())所需的長度 - 空白長度,就在那裡畫一個標註應該就問題不大了吧,對於那些太小的線段,就不要去畫了,小到不像話的封閉式等值線,我們在上一步中已經處理過了。

那麼如何把一條曲線轉換為折線或是多邊形的呢?《等值線標註的一種演算法探討》一文中告訴我們(見論文2.2):“設一個dif參數,用來控制多邊形近似等值線的誤差,將曲線上的點從第0個開始,偶數點相連作為多邊形的邊,依次查看等值線上的3個點,如果中間的等值點(奇數點)到多邊形的邊的距離小於參數dif,捨棄中間的等值點,否則儲存中間的點。如此不斷迴圈,直到最後產生的多邊形的邊數不在(再 think8848注)減少為止。這樣就得到了等值線近似的多邊形。”dif越大,表明曲線越陡,dif越小,表明曲線越平緩。

演算法程式碼範例:

                            int n = (points[0].X != points[points.Count - 1].X && points[0].Y != points[points.Count - 1].Y) ? points.Count : points.Count - 1,                                minEdge = n + 1, k = n;                            float tolerance = 8f;                            var indexes = new List<int>(); for (int i = 0; i < points.Count; i++) { indexes.Add(i); }                            while (k < minEdge)                            {                                minEdge = k;                                var p = 0;                                while (p < minEdge - (n % 2 == 0 ? 3 : 2))                                {                                    float straight = this.GetPointToStraight(points[indexes[p + 1]], points[indexes[p]], points[indexes[p + 2]]);                                    if (Math.Abs(straight) < tolerance)                                    {                                        indexes[p + 1] = -1;                                        k -= 1;                                    }                                    p++; p++;                                }                                indexes = indexes.Where<int>(index => index != -1).ToList<int>();                            }

另附求點到直線的距離的方法,下列代表示例如何計算p點到直線p1p2最短距離

        private float GetPointToStraight(VPoint p, VPoint p1, VPoint p2)        {            if (p1.X == p2.X)            {                return (float)Math.Abs(p1.Y - p2.Y);            }            if (p1.Y == p2.Y)            {                return (float)Math.Abs(p1.X - p2.X);            }            double k = (p2.Y - p1.Y) / (p2.X - p1.X);            double c = (p2.X * p1.Y - p1.X * p2.Y) / (p2.X - p1.X);            return (float)((k * p.X - p.Y + c) / (Math.Sqrt(k * k + 1)));        }

最終indexes裡面儲存了在等值點列表中構成多邊形的點的索引。

在本文的最後,我們再來談談如果變音符號旋轉的問題,有一條線段作為基準,將畫布旋轉與線段傾斜角度相同度數應該不是一件難事,是的,.NET很容易就能做到,唯一的問題是如何線段的傾斜角度:

var alpha = (float)(Math.Atan((p2.Y - p1.Y) / (p2.X - p1.X)) * 180 / Math.PI);

就是這個角度了,三角函數已經忘了的兄弟可以到網上重新溫習下高中數學,呵呵。

                                    g.TranslateTransform(xOffset, yOffset);                                    g.RotateTransform(alpha);                                    g.DrawString(value.ToString(), font, brush, new PointF(0, 0));                                    g.RotateTransform(-alpha);                                    g.TranslateTransform(-xOffset, -yOffset);

變換座標系的原點到將要繪製標註的左上方位置,然後旋轉畫布,(注意,角度為正時為順時針,角度為負時為逆時針方向,好像和我們數學課中的方向不一致。)繪製完成後,再把座標系歸位,迴圈,直至將所有的標註都繪製完成。

至此,使用C#繪製等值線的工作基本完成。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.