MFC から SVG の基本図形（1/2）

## MFCとSVGの基本図形の違い
MFC の環境では GDI 描画と GDI+ の描画を選択できますが、処理速度の関係から GDI+ を使っていることが多いかと思います。
他のグラフィックライブラリも利用できますが、本稿は MFC の基本描画を対象にしたベクタ画像を扱うため、ここでは主に GDI+ と SVG の基本図形について記載します。

GDI+ の line や polyline、polygon の描画は SVG での描画方法と大きな違いはありません。
基本図形で違いが出るのは GDI+ に ellipse （楕円）しかなく、SVG の基本図形で宣言されている circle が存在しないことです。

## ライン
MFC と SVG の両方で (x1, y1) から (x2, y2) まで線を描画するという指定がされています。
描画方法に大きな差分がないため、ここでは SvgImage クラスにそのまま AddLine 関数を追加します。

```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddLine(double dX1, double dY1, double dX2, double dY2, int nDepth = 0);
}
```
```cpp:SvgImage.cpp
void SvgImage::AddLine(double dX1, double dY1, double dX2, double dY2, int nDepth)
{
	SvgTag *svgLine = new mdSvgTag();
	svgLine->m_strName = L"line";
	svgLine->m_nDepth = nDepth + 1;
	svgLine->m_bOne = TRUE;

	CString csStr;
	csStr.Format(_T("%lf"), dX1 - m_rectAll.left);
	svgLine->m_arrAttr.Add(L"x1");
	svgLine->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), m_rectAll.bottom - dY1);
	svgLine->m_arrAttr.Add(L"y1");
	svgLine->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), dX2 - m_rectAll.left);
	svgLine->m_arrAttr.Add(L"x2");
	svgLine->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), m_rectAll.bottom - dY2);
	svgLine->m_arrAttr.Add(L"y2");
	svgLine->m_arrAttrValue.Add(csStr);

	m_arrayTag.Add(svgLine);
}
```

SVG 画像は左上のポイントが原点のため、 m_rectAll の left と bottom の値を使いながら座標の上下反転と平行移動を行います。
この操作はすべての図形出力関数で繰り返し行われる操作となります。

x 座標：
- dX1(入力 X 座標) - m_rectAll.left

y 座標：
- m_rectAll.bottom - dY1(入力 y 座標)

```cpp
	CString csStr;
	csStr.Format(_T("%lf"), dX1 - m_rectAll.left);
	svgLine->m_arrAttr.Add(L"x1");
	svgLine->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%lf"), m_rectAll.bottom - dY1);
	svgLine->m_arrAttr.Add(L"y1");
	svgLine->m_arrAttrValue.Add(csStr);
```

## 接続された複数のライン
MFC は複数のポイントの座標とポイントの数を指定することで描画されます。
SVG は複数のポイントを属性 points に記載することで描画されます。
 SvgImage クラスに追加する AddLines 関数は MFC の GDI+ の描画関数に合わせて宣言を行います。

```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddLines(CPoint* lpPos, int nSize, int nDepth = 0);
}
```
```cpp:SvgImage.cpp
void SvgImage::AddLines(CPoint* lpPos, int nSize, int nDepth)
{
	// 2点以上なければ処理しない
	if (nSize < 2) return;

	SvgTag *svgLine = new SvgTag();
	svgLine->m_strName = L"polyline";
	svgLine->m_nDepth = nDepth + 1;
	svgLine->m_bOne = TRUE;

	// pathを作る
	CString csStr;
	CString csPath = L"";
	for (int i = 0; i < nSize; i++)
	{
		CPoint mPos = lpPos[i];
		csStr = L"";
		double dLeft = mPos.x - m_rectAll.left;
		double dTop = m_rectAll.bottom - mPos.y;
		if (i == 0)
		{
			csStr.Format(_T("%lf %lf"), dLeft, dTop);
		}
		else {
			csStr.Format(_T(", %lf %lf"), dLeft, dTop);
		}
		csPath += csStr;
	}
	svgLine->m_arrAttr.Add(L"points");
	svgLine->m_arrAttrValue.Add(csPath);

	m_arrayTag.Add(svgLine);
}
```

polyline タグの座標指定属性の points のフォーマットは１つのポイントをカンマ区切りで、他の座標の区切りは空白区切りで行います。

```
points = "x1,y1 x2,y2 x3,y3"
```

このため、座標のポイントの数だけ繰り返し座標を追加していく形となります。

## 多角形
MCF と SVG のどちらも接続された複数のラインと同じ形式の描画方法となります。

```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddPolygon(CPoint* lpPos, int nSize, int nDepth = 0);
}
```
```cpp:SvgImage.cpp

void SvgImage::AddPolygon(CPoint* lpPos, int nSize, BYTE byLineType, int nDepth)
{
	SvgTag* svgPath = new SvgTag();
	svgPath->m_strName = L"polygon";
	svgPath->m_nDepth = nDepth + 1;
	svgPath->m_bOne = TRUE;

	// pathを作る
	CString csStr;
	CString csPath = L"";
	for (int i = 0; i < nSize; i++)
	{
		CPoint mPos = lpPos[i];
		csStr = L"";
		double dLeft = mPos.x - m_rectAll.left;
		double dTop = m_rectAll.bottom - mPos.y;
		if (i == 0)
		{
			csStr.Format(_T("%lf %lf"), dLeft, dTop);
		}
		else {
			csStr.Format(_T(", %lf %lf"), dLeft, dTop);
		}
		csPath += csStr;
	}
	svgPath->m_arrAttr.Add(L"points");
	svgPath->m_arrAttrValue.Add(csPath);

	m_arrayTag.Add(svgPath);
}
```

MFCとSVGの基本図形(2/2)につづく