Rustとsvg

#Rustをsvg形式で書き出す。

Rust 3 Advent Calendar 2020 22日目の記事です。

Qiita初投稿です。
Rustを使ってクレート開発とsvg形式で書き出したという話です。

こんな感じの画像を書き出します。

![testPolygon1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672574/2d02737e-2535-f37c-0d8f-c1c012e19f00.png)

**Qiitaではsvg形式は貼り付けられないのでpng形式です。リポジトリにはsvg形式の画像もあります。**

なおこの記事ではsvgとは何か?と言うような説明はしません。

### リポジトリ

すべてGithubにおいています。

[Rust version](https://github.com/HosodaMath/creative_to_svg/tree/main/Rust/draw_svg)

[Python version](https://github.com/HosodaMath/ExternalLibraly/tree/master/StudyNote/Data/Python/PythonSVG)

**Python versionのほうが開発は進んでいます**

## 開発目的

1.Rustの勉強
2.svgの勉強
3.イラスト制作のため

以上この3つです。

##polygonの実装

svgにはいくつものタグが存在しますがpolygonタグ1つに絞って実装しました。


```rust
pub mod polygon {
    use crate::point::point::Point;
    use crate::convert_str::convert_str::*;
    ///# Polygonを表す構造体
    pub struct Polygon {

        data: Vec<Point>,
    }

    impl Polygon {
        /// ## 変数の初期化を行う(コンストラクタ)
       /// ### variable
       /// init_data : Vec<Point> ポリゴンデータの初期化
       /// ### Example
       /// let polygon1 = Polygon::new(0.0, 0.0)
       ///
        pub fn new(init_data: Vec<Point>) -> Polygon {

            Polygon { data: init_data }
        }
    }


    impl Polygon {
        /// ## ポリゴンタグデータの取得
        /// 設定パラメータ fill fill-opacity
        /// fill_color: fill
        /// fill_opacity: fill-opacity
        ///
        pub fn render_polygon1(self, fill_color: String, fill_opacity: f64) -> String{
            let str_data = format_one(self.data);
            let start = "<polygon";
            let location_data = format!("points=\"{}\"", str_data);
            let fill_set = format!("fill=\"{}\" fill-opacity=\"{}\"",
                                   fill_color, fill_opacity);
            let end = "/>\n";
            let poly1 = format!("{} {} {} {}", start, location_data, fill_set, end);

            return poly1;
        }
    }

    impl Polygon {
        /// ## ポリゴンタグデータの取得
        /// 設定パラメータ fill fill-opacity stroke stroke-width stroke-opacity
        /// fill_color: String fill
        /// fill_opacity: f64 fill-opacity
        /// stroke_color: String stroke
        /// stroke_width: f64 stroke-width
        /// stroke_opacity: f64 stroke-opacity
        ///
        pub fn render_polygon2(self, fill_color: String, fill_opacity: f64,
                               stroke_color: String, stroke_width: f64, stroke_opacity: f64) -> String{
            let str_data = format_one(self.data);
            let start = "<polygon";
            let location_data = format!("points=\"{}\"", str_data);
            let fill_set = format!("fill=\"{}\" fill-opacity=\"{}\"",
                                   fill_color, fill_opacity);
            let stroke_set = format!("stroke=\"{}\" stroke-width=\"{}\" stroke-opacity=\"{}\"",
                                     stroke_color, stroke_width, stroke_opacity);
            let end = "/>\n";
            let poly2 = format!("{} {} {} {} {}", start, location_data, fill_set, stroke_set, end);

            return poly2;
        }
    }

    impl Polygon {
        /// ## ポリゴンタグデータの取得
        /// 設定パラメータ stroke stroke-width stroke-opacity
        /// stroke_color: String stroke
        /// stroke_width: f64 stroke-width
        /// stroke_opacity: f64 stroke-opacity
        pub fn render_polygon3(self, stroke_color: String, stroke_width: f64, stroke_opacity: f64) -> String{
            let str_data = format_one(self.data);
            let start = "<polygon";
            let location_data = format!("points=\"{}\"", str_data);
            let fill_set = format!("fill=\"transparent\"");
            let stroke_set = format!("stroke=\"{}\" stroke-width=\"{}\" stroke-opacity=\"{}\"",
                                     stroke_color, stroke_width, stroke_opacity);
            let end = "/>\n";
            let poly3 = format!("{} {} {} {} {}", start, location_data, fill_set, stroke_set, end);

            return poly3;
        }
    }
}
```
1つ注意点なのはpolygonタグでの座標データの取り扱いは1つの文字列にまとめていかないといけないということです。

それほど難しくないですがsvgの仕様を知らないとうまく出力されてもsvg側でエラーが出てしまうので注意が必要です。

ソースコードにある

```rust
format_one(self.data);
```

は複数のデータを1つにまとめているユーリティ関数です。

## 三角形の描画

三角形の描画するコードの1部です

```rust
pub mod triangle {
    use crate::point::point::Point;
    /// # 三角形の作成
    /// 大きさはsvg画像サイズに依存する。
    pub struct Triangle {
        width: f64,
        height: f64,
    }

    impl Triangle {
        /// ## 変数の初期化を行う(コンストラクタ)
        /// ### variable
        /// init_width: f64 画像サイズ 横幅
        /// init_height: f64 画像サイズ 高さ
        pub fn new(init_width: f64, init_height: f64) -> Triangle {

            Triangle { width:init_width, height: init_height }
        }
    }

    impl Triangle {
        pub fn triangle1(&self) -> Vec<Point> {
            let mut data: Vec<Point> = vec![];
            let x = [0.0, self.width / 2.0, self.width];
            let y = [self.height, 0.0, self.height];
            if x.len() == y.len() {
                for count in 0..3 {
                    let tmp = Point::new(x[count], y[count]);
                    data.push(tmp);
                }
            }

            return data
        }
    }
}
```

[三角形を描画するコード](https://github.com/HosodaMath/ExternalLibraly/blob/master/StudyNote/Data/Rust/RustSVG/src/triangle.rs)

### まとめと反省点

1. main.rsとlib.rsが同じ階層に有る。
2. ディレクトリによる分別と管理を行う。
3. lib.rsに何か書かれている。
4. svgとしてしっかり?出力されている。

など上げたらきりがないのでここまでとします。

クレート開発とsvgの勉強をし直してきます。

### アップデート情報

2020/12/27 Githubリンクの修正とrect lineの追加