2018年2月1日木曜日

C#で、SVGのpathの円弧データをデコードする

Fabool Laser Mini が参照している SVGデータ の要素(?)は、すべて「path」になっています。(の様です)

この内容を扱うには座標情報(?)をデコード(?)する必要があるのですが、円弧、、、
(円弧には、円、円弧、楕円、楕円弧が含まれます。のようです)

10分でわかるSVG 基礎編 (2/5)

なんだこれ・・・

中心座標が無いんだ。。。円弧と楕円弧の場合、角度情報も無いんだ。。。ほとんど暗号解析やんか?どうすんのこれ?

SVG pathの楕円を描くコマンドが使いにくい

先人がぼやいているし


2、3日悩みましたね。できるのかよー、って

できませんでした。ティへぺろ

そして、Svg.dll ってライブラリを、てかこれもドキュメントが見つけられなくて、2回くらいスルーしてましたががが。
変数名とかと型名を見ながらデバッグで状況を探った結果、
「System.Drawing.Drawing2D.GraphicsPath」を取得することに成功っっ

下のコードは、上記の後に、平坦化(直線群に変換)して、それの一覧を取得まで行っています。
「PathArcAnal」は自作の処理クラス、「PathArcItem」は自作のオブジェクトクラスです。


/// 円弧を変換する
private string[] ConvArc(string dValue, DValueTypes dValueType, SValueTypes sValueType)
{
    // 引数の確認
    if (string.IsNullOrEmpty(dValue) == true) { return null; }
    if (sValueType == SValueTypes.Delete) { return null; }   // 無いはず

    // 処理クラスの生成(と解析)
    PathArcAnal pathArcAnal = new PathArcAnal(dValue, dValueType);

    // 解析結果の確認
    if (pathArcAnal.Result == false) { return null; }

    // svg.dllの処理クラスの生成
    Svg.SvgPath sPath = new Svg.SvgPath();

    // 座標で回る
    PointF lastPos = pathArcAnal.StartPos;
    float minRadius = float.MaxValue;
    foreach (PathArcItem pathArcItem in pathArcAnal.PathArcItems)
    {
        // svg.dllの円弧要素の生成
        SvgArcSegment arcSegment = new SvgArcSegment(lastPos,
                                                        pathArcItem.Radius.X, pathArcItem.Radius.Y,
                                                        pathArcItem.Angle,
                                                        pathArcItem.Size,
                                                        pathArcItem.Sweep,
                                                        pathArcItem.Pos);

        // 追加する
        sPath.PathData.Add(arcSegment);

        // 座標の保存
        lastPos = pathArcItem.Pos;

        // 最小半径の保持
        if (pathArcItem.Radius.X < minRadius) { minRadius = pathArcItem.Radius.X; }
        if (pathArcItem.Radius.Y < minRadius) { minRadius = pathArcItem.Radius.Y; }
    }

    // マトリクス(変換を指示?)の生成
    System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix();

    // 平滑化(直線で細分化)する
    float coeff = (float)0.01;
    if (sValueType == SValueTypes.Smooth)
    {
        coeff = (float)0.001;
    }
    else if (sValueType == SValueTypes.Rough)
    {
        coeff = (float)0.1;
    }
    sPath.Path.Flatten(matrix, (float)(minRadius * coeff));

    // 戻り値の生成
    List<string> ret = new List<string>();

    // 座標群で回る
    PointF startPoint = PointF.Empty;
    PointF lastPoint = PointF.Empty;
    foreach (PointF p in sPath.Path.PathData.Points)
    {
        // 最初の座標の確認
        if (startPoint.IsEmpty || lastPoint.IsEmpty)
        {
            // 保持して抜ける
            startPoint = p;
            lastPoint = p;
            continue;
        }

        // 文字列を組み立てて追加する
        ret.Add("m " + lastPoint.X.ToString() + "," + lastPoint.Y.ToString() + " " + (p.X - lastPoint.X).ToString() + "," + (p.Y - lastPoint.Y).ToString());

        // 保持する
        lastPoint = p;
    }

    // 閉じる確認
    if (pathArcAnal.IsZ == true && startPoint.Equals(lastPoint) == false)
    {
        //-- 閉じる指定があり、実際には閉じていないとき
        // 文字列を組み立てて追加する
        ret.Add("m " + lastPoint.X.ToString() + "," + lastPoint.Y.ToString() + " " + (startPoint.X - lastPoint.X).ToString() + "," + (startPoint.Y - lastPoint.Y).ToString());
    }

    // 返す
    return ret.ToArray();
}


※動作しているコードの該当箇所をそのままコピーしました

0 件のコメント:

コメントを投稿