午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

[Rust開發(fā)]用可視化案例講Rust編程5.用泛型和特性實(shí)現(xiàn)自適配繪制和顏色設(shè)置

 godxiasad 2024-01-24 發(fā)布于北京

想到就發(fā)了,反正大家也不看

上一節(jié)我們講了用泛型實(shí)現(xiàn)返回結(jié)果,這一節(jié)我們來講講在函數(shù)簽名里面使用泛型來對(duì)輸入?yún)?shù)進(jìn)行自適配。

先看UML設(shè)計(jì)圖:

好吧,看起來有點(diǎn)復(fù)雜,我們一個(gè)個(gè)來解釋。

首先定義的是一個(gè)生成繪圖元素需要的參數(shù)結(jié)構(gòu),并且定義個(gè)特性,就叫做構(gòu)造繪圖元素build_trace。

pub struct traceParam<G>{
pub geometrys:Vec<G>,
pub colors: Vec<inputColor>,
pub size: usize,
}

pub trait BuildTrace{
fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>>;
}

繪圖元素的參數(shù),定義了三個(gè)參數(shù):

  • 第一個(gè)參數(shù)是輸入一個(gè)幾何要素集合,因?yàn)槲覀冏钇鸫a有點(diǎn)線面三種幾何要素,所以定義的是一個(gè)泛型變量G

  • 第二參數(shù)是一個(gè)顏色集合,這里也可以用泛型,不過我們不需要那么多種顏色定義,這里給了一個(gè)枚舉型的輸入顏色,枚舉定義如下:

#[derive(Debug,Clone)]
pub enum inputColor {
NamedColor(NamedColor),
Rgba(Rgba),
}

這里支持NameColor和Rgba兩種顏色定義即可。

  • 第三個(gè)參數(shù)是一個(gè)size,用來控制點(diǎn)的大小、線的寬度和面要素的邊框,當(dāng)然你也可以設(shè)定更多的參數(shù),我這里僅用來說明,就不搞那么麻煩了:

接下去就可以寫具體的實(shí)現(xiàn)了。

點(diǎn)要素的實(shí)現(xiàn):

impl BuildTrace for traceParam<Point>{
fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>> {
let mut traces:Vec<Box<ScatterMapbox<f64,f64>>> = Vec::new();
for (pnt,color) in zip(&self.geometrys,&self.colors) {
let mut trace: Box<ScatterMapbox<f64, f64>> = ScatterMapbox::new(vec![pnt.y()], vec![pnt.x()]);
trace = match color {
inputColor::NamedColor(color) => {
MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Point)
},
inputColor::Rgba(color) => {
MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Point)
},
_ => panic!(""),
};
traces.push(trace);
}
traces
}
}

線要素的實(shí)現(xiàn):

impl BuildTrace for traceParam<LineString>{
fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>> {
let mut traces:Vec<Box<ScatterMapbox<f64,f64>>> = Vec::new();
for (line,color) in zip(&self.geometrys,&self.colors) {
let mut lat:Vec<f64>= Vec::new();
let mut lon:Vec<f64>= Vec::new();
for coord in line.coords(){
lat.push(coord.y);
lon.push(coord.x);
}
let mut trace: Box<ScatterMapbox<f64, f64>> = ScatterMapbox::new(lat, lon);
trace = match color {
inputColor::NamedColor(color) => {
MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Line)
},
inputColor::Rgba(color) => {
MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Line)
},
_ => panic!(""),
};
traces.push(trace);
}
traces
}
}

面數(shù)據(jù)的實(shí)現(xiàn):

impl BuildTrace for traceParam<Polygon>{
fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>> {
let mut traces:Vec<Box<ScatterMapbox<f64,f64>>> = Vec::new();
for (poly,color) in zip(&self.geometrys,&self.colors) {
let mut lat:Vec<f64>= Vec::new();
let mut lon:Vec<f64>= Vec::new();
for coord in poly.exterior(){
lat.push(coord.y);
lon.push(coord.x);
}
let mut trace: Box<ScatterMapbox<f64, f64>> = ScatterMapbox::new(lat, lon);
trace = match color {
inputColor::NamedColor(color) => {
MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Polygon)
},
inputColor::Rgba(color) => {
MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Polygon)
},
_ => panic!(""),
};
traces.push(trace);
for ipoly in poly.interiors(){
let mut ilat:Vec<f64>= Vec::new();
let mut ilon:Vec<f64>= Vec::new();
for coord in poly.exterior(){
ilat.push(coord.y);
ilon.push(coord.x);
}
trace = ScatterMapbox::new(ilat, ilon);
trace = MyTrace{color:NamedColor::White,size:self.size,trace:trace}.set_trace(geo_type::Polygon);
traces.push(trace);
}
}
traces
}
}

里面三個(gè)方法都用了一個(gè)處理trace的方法,實(shí)現(xiàn)如下:


struct MyTrace<T>{
color:T,
size:usize,
trace:Box<ScatterMapbox<f64,f64>>
}

enum geo_type{
Point,
Line,
Polygon,
}
trait SetTrace<T> {
fn set_trace(&self,geo_type:geo_type)->Box<ScatterMapbox<f64,f64>>;
}

impl SetTrace<NamedColor> for MyTrace<NamedColor>{
fn set_trace(&self,geo_type:geo_type)->Box<ScatterMapbox<f64,f64>> {
match geo_type{
geo_type::Point =>{
let t = *self.trace.to_owned()
.marker(Marker::new().color(self.color)).show_legend(false);
Box::new(t)
},

geo_type::Line =>{
let t = *self.trace.to_owned()
.line(Line::new().width(self.size as f64).color(self.color)).show_legend(false);
Box::new(t)
},

geo_type::Polygon=> {
let t = *self.trace.to_owned()
.fill(plotly::scatter_mapbox::Fill::ToSelf).fill_color(self.color).show_legend(false);
Box::new(t)
},
_ => panic!("")
}
}
}

impl SetTrace<Rgba> for MyTrace<Rgba>{
fn set_trace(&self,geo_type:geo_type)->Box<ScatterMapbox<f64,f64>> {
match geo_type{
geo_type::Point =>{
let t = *self.trace.to_owned()
.marker(Marker::new().color(self.color)).show_legend(false);
Box::new(t)
},

geo_type::Line =>{
let t = *self.trace.to_owned()
.line(Line::new().width(self.size as f64).color(self.color)).show_legend(false);
Box::new(t)
},

geo_type::Polygon=> {
let t = *self.trace.to_owned()
.fill(plotly::scatter_mapbox::Fill::ToSelf).fill_color(self.color).show_legend(false);
Box::new(t)
},
_ => panic!("")
}
}
}

這兩個(gè)方法,幾乎99%是想同的,只是輸入的顏色類型不一樣,這樣就是靜態(tài)語言的麻煩之處了,只要函數(shù)簽名不一致,就相當(dāng)于兩個(gè)方法,看到這里,大家可能想問,上一節(jié)講過的泛型,在這里能用么?答案當(dāng)然可以,不過就算用泛型,最終編譯出來的代碼也會(huì)因?yàn)榫幾g器的處理,而實(shí)現(xiàn)函數(shù)單態(tài)化,即編譯器會(huì)針對(duì)具體情況,編譯出多個(gè)靜態(tài)函數(shù)出來。所以這里如果繼續(xù)抽象,也不是不行,但是算做過度設(shè)計(jì)了。

之后,就可以寫一個(gè)繪制函數(shù),然后進(jìn)行調(diào)用了:

pub fn plot_draw_trace(traces:Vec<Box<ScatterMapbox<f64,f64>>>,outimg: Option<&str>){
let mut plot = Plot::new();
for t in traces{
plot.add_trace(t);
}
let layout = _get_layout(1024, 800, Center::new(39.9, 116.3),MapboxStyle::Dark);
plot.set_layout(layout);
match outimg {
Some(out) => plot.write_image(out, ImageFormat::PNG, 1200, 900, 1.0),
None => plot.show(),
}
}

//這個(gè)是一個(gè)內(nèi)部函數(shù),用來初始化構(gòu)造制圖參數(shù)的。
fn _get_layout(width:usize, height:usize,cnt:Center,ms:MapboxStyle) -> Layout{
Layout::new()
.drag_mode(DragMode::Zoom)
.margin(Margin::new().top(10).left(10).bottom(10).right(10))
.width(width)
.height(height)
.mapbox(
Mapbox::new()
.style(ms)
.access_token("pk.eyJ1IjoiYWxsZW5sdTIwMDgiLCJhIjoiY2xxZjNsaGtmMDd0ZTJqcWM1MzRmemx1NCJ9.TbiPQB6j1w9ilBP4pFHRRw")
.center(cnt)
.zoom(10),
)
}

最后我們寫一個(gè)測(cè)試調(diào)用方法,來繪制一下百度地圖:

// 因?yàn)樵贖tml里面繪制比較慢,所以我這里就僅畫三個(gè)圖層
#[test]
fn draw_bd_style(){
let shp1 = "./data/shp/北京行政區(qū)劃.shp";
let poly1:Vec<Polygon> = readShapefile::shp::read_shp(shp1);
let colors:Vec<inputColor> = (0..poly1.len())
.map(|x|inputColor::Rgba(Rgba::new(240,243,250,1.0))).collect();
let mut t1 = traceParam{geometrys:poly1,colors:colors,size:0}.build_trace();

let shp2 = "./data/shp/面狀水系.shp";
let poly2:Vec<Polygon> = readShapefile::shp::read_shp(&shp2);
let colors:Vec<inputColor> = (0..poly2.len())
.map(|x|inputColor::Rgba(Rgba::new(108,213,250,1.0))).collect();
let mut t2 = traceParam{geometrys:poly2,colors:colors,size:0}.build_trace();

let shp3 = "./data/shp/高速.shp";
let line1:Vec<LineString> = readShapefile::shp::read_shp(&shp3);
let colors:Vec<inputColor> = (0..line1.len())
.map(|x|inputColor::Rgba(Rgba::new(255,182,118,1.0))).collect();
let mut t3 = traceParam{geometrys:line1,colors:colors,size:1}.build_trace();

t1.append(&mut t2);
t1.append(&mut t3);
plot_draw_trace(t1,None);
}

繪制效果如下:

注意:plotly.rs的JS引用的是Mapbox,所以網(wǎng)絡(luò)訪問上可能會(huì)有一些障礙,有可能需要科學(xué)上網(wǎng)……

打完收工。

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多