上一節(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ù): #[derive(Debug,Clone)] pub enum inputColor { NamedColor(NamedColor), Rgba(Rgba), } 這里支持NameColor和Rgba兩種顏色定義即可。 接下去就可以寫具體的實(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è)測試調(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)……
打完收工。
|