基於ArcGIS Engine + C#實現使用者自訂動態電力符號
華立電網北京研發中心 阿文
ArcGIS Engine二次開發一般需要通過案頭產品來製作這些符號,然後通過專門的轉換工具轉換以後供AE使用。電力GIS應用當中,電力裝置種類繁多,裝置狀態比較複雜,需要用不同的符號來表現電力裝置的不通狀態,此外電力技術的更新速度很快,新裝置種類也不斷推陳出新,使用者往往要求提供符號定義工具以滿足這些需求。本文以配電變壓器為例,介紹一種使用ArcGIS Engine + C#二次開發模式下,可以讓使用者自己定義裝置符號的一種方法。
一、符號定義
配電變壓器符號如所示:
此主題相關圖片如下:
可以將這個符號分解成四個圖元,兩段線段,兩個圓(圓弧)。用以下結構來描述圖元:
public struct MetaData
{
public int Typ; // 圖形類型 3:圓弧,0:線段
public double Scale; // 縮放
public int OffsX ; // 位移(x)
public int OffsY; // 位移(y)
public double Angle; // 旋轉
public int x1; // 圖元的第一點位置(x)
public int y1; // 圖元的第一點位置(y)
public int x2; // 圖元的第二點位置(x)
public int y2; // 圖元的第二點位置(y)
public int x3; // 圖元的第三點位置(x)
public int y3; // 圖元的第三點位置(y)
public int x4; // 圖元的第四點位置(x)
public int y4; // 圖元的第四點位置(y)
}
// 線段:第一點:起點座標, 第二點:終點座標, 第三點, 第四點為空白
// 圓弧:第一點:圓弧所在圓所屬矩形的左上方,
// 第二點:圓弧所在圓所屬矩形的左右下角,
// 第三點:圓弧起點
// 第四點:圓弧終點
// 圓弧方向為逆時針,對於圓x3,y3,x4,y4重合
各圖元的座標如下:
|
Typ |
x1 |
y1 |
X2 |
Y2 |
x3 |
Y3 |
X4 |
Y4 |
第一點 |
3 |
20 |
-70 |
160 |
70 |
90 |
-70 |
90 |
-70 |
第二點 |
3 |
100 |
-70 |
240 |
70 |
100 |
0 |
100 |
0 |
第三點 |
0 |
0 |
0 |
20 |
0 |
0 |
0 |
0 |
0 |
第四點 |
0 |
240 |
0 |
260 |
0 |
0 |
0 |
0 |
0 |
可以編寫一個繪製簡單圖元的繪圖工具,方便使用者繪製這些圖元,繪製好的圖元存成以上格式,存入到資料庫中,以方便系統讀入。
2樓
tanhw 發表於:2007-3-8 10:49:00
一、自訂、實現符號類MyMarkerSymbol:
1.類的定義:
自訂符號需要實現以下四個介面:
IMarkerSymbol
ISymbol
IClone
IpersistVariant
MyMarkerSymbol類定義為:
public class MyMarkerSymbol :IMarkerSymbol,ISymbol,IClone,IPersistVariant
{
public MyMarkerSymbol()
{
//base.New();
Class_Initialize_Renamed();
}
}
建構函式,需將符號的角度傳入。
public MyMarkerSymbol(double ange)
{
//base.New();
Class_Initialize_Renamed();
m_Angle = ange;
}
//成員變數
private int m_lPen;
private int m_lOldPen;
private int m_lHDC;
private double m_Angle;
private int m_SymbolIndex;
private ESRI.ArcGIS.Display.IDisplayTransformation m_pDispTrans;
private int m_lSize;
2.介面函數的實現:
要實現自訂符號需要實現這四個介面的多個函數,最重要的是ImarkerSymbol的三個函數:SetupDC,Draw和ResetDC。
SetupDC用於設定畫筆畫刷、顏色等資訊。
public void SetupDC(int hDC, ITransformation transformation)
{
// TODO: 添加 MyMarkerSymbol.SetupDC 實現
m_lPen = CreatePen(0, 2, System.Convert.ToInt32(m_pColor.RGB));
m_lOldPen = SelectObject(hDC, m_lPen);
m_lHDC = hDC;
m_pDispTrans = (IDisplayTransformation)transformation;
}
hDC為畫布控制代碼。
ResetDC函數,繪製完成後,進行資源釋放和狀態回複。
public void ResetDC()
{
// TODO: 添加 MyMarkerSymbol.ResetDC 實現
SelectObject(m_lHDC, m_lOldPen);
DeleteObject(m_lPen);
m_pDispTrans = null;
m_lHDC = 0;
}
Draw函數實現符號的繪製工作:
public void Draw(IGeometry Geometry)
{
// TODO: 添加 MyMarkerSymbol.Draw 實現
if (Geometry == null)
{
return;
}
ESRI.ArcGIS.Geometry.IPoint pPt;
pPt = (IPoint)Geometry;
int x;
int y;
if (m_pDispTrans == null)
{
x = (int)pPt.X;
y = (int)pPt.Y;
}
else
{
m_pDispTrans.FromMapPoint(pPt, out x, out y);
}
DrawMetas(x,y);
}
3.DrawMetas實現:
需要在畫布上繪製兩條直線合兩個圓,可以通過調用Windows API函數來實現:
[System.Runtime.InteropServices.DllImport("gdi32")]
private static extern bool LineTo (int hdc,int x,int y );
[System.Runtime.InteropServices.DllImport("gdi32")]
public static extern bool MoveToEx(int hdc,int x,int y,LPPOINT lpPoint);
[System.Runtime.InteropServices.DllImport("gdi32")]
public static extern bool Arc
(int hdc,int X1,int Y1, int X2,int Y2,int X3, int Y3,int X4,int Y4);
3樓
tanhw 發表於:2007-3-8 10:53:00
4.圖元旋轉
自訂符號需要按指定角度進行旋轉,直線旋轉的方法比較簡單,以下介紹圓弧的旋轉方法:
以圓弧所在圓所屬矩形的左上方為例:
此主題相關圖片如下:
旋轉前的座標為(x0,y0),旋轉後的座標為(x1,y1),計算出旋轉半徑r,alpha,則:
x1 = r*Math.Cos( alpha - mAngle );
y1 = r*Math.Sin( alpha - mAngle );
其他各定點也可以用同樣方法計算。
計算出各頂點後調用以下方法繪製圓弧即可:
Arc(m_lHDC,(int)(x1),(int)(y1),(int)(x2),(int)(y2), (int)(x3),(int)(y3),(int)(x4),(int)(y4));
對於直線段可以用以下方法繪製即可:
LPPOINT prePos=new LPPOINT();
MoveToEx(m_lHDC,(int)x1,(int)y1,prePos);
LineTo(m_lHDC,(int)x2,(int)y2);
三、調用符號
1. 使用IsimpleRenderer介面渲染:
//定義render
IsimpleRenderer pSimpleRenderer = new SimpleRendererClass();
//定義自訂符號
MyMarkerSymbol mMyMarkerSymbol = new MyMarkerSymbol();
//渲染
IGeoFeatureLayer m_pGeoFeatureLayer;
pSimpleRenderer.Symbol = (ISymbol) mMyMarkerSymbol;
m_pGeoFeatureLayer = (IGeoFeatureLayer)ly;
m_pGeoFeatureLayer.Renderer = (IFeatureRenderer)pSimpleRenderer;
2. 使用IUniqueValueRenderer介面渲染:
IuniqueValueRenderer pRender = new UniqueValueRendererClass();
iAngleField = pFields.FindField("ANGLE");
for (int i=0;i< pFeatCls.FeatureCount(pQueryFilter) ;i++)
{
pFeat = pFeatCursor.NextFeature();
string x = null;
x = pFeat.get_Value(iField).ToString() ;
dAngle = (double)pFeat.get_Value(iAngleField);
SymbolIndex = int.Parse(pFeat.get_Value(iSymIndexField).ToString());
MyMarkerSymbol sym = new MyMarkerSymbol(dAngle);
pRender.AddValue( x,x, (ISymbol)msy);
}
pLyr.Renderer = (IFeatureRenderer)pRender;
以上介紹只能實現比較簡單的動態符號,但只要完善其中的函數,就可以實現各種複雜的電力符號,應用到Arcgis Engine應用開發中,實現使用者自訂裝置符號,系統自動渲染。如有更好方法請賜教(hongwu.tan@hotmail.com)