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

分享

[Rust開發(fā)]用可視化案例講Rust編程3:函數(shù)分解與參數(shù)傳遞

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

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

上一節(jié)我們在繪制面要素的時(shí)候,發(fā)現(xiàn)了函數(shù)功能體是三個(gè)不同步驟組成的:

  1. 讀取文件獲得geometry

  2. 把geometry轉(zhuǎn)變?yōu)槔L圖元素trace

  3. 把繪圖元素繪制到地圖上

像我們上一節(jié)那樣,把所有的功能都寫在一個(gè)函數(shù)里面,這樣的函數(shù)靈活性太差,例如我們要讀取和繪制若干個(gè)點(diǎn)、線、面,那么如果不去修改,那么每讀一個(gè)shapefile就要重復(fù)去寫一個(gè)方法,那就太繁瑣了,我們重構(gòu)的第一步,就是要把各種功能盡量的切分出來,形成一個(gè)個(gè)能夠獨(dú)立運(yùn)行和維護(hù)的模塊,所以今天我們就把昨天那個(gè)代碼給切分成多個(gè)函數(shù),增加重用,減少冗余。

首先是第一個(gè)函數(shù),用于讀取shapefile,輸入的參數(shù)就是shapefile的路徑,輸出是解析好的集合:(下面是的注釋是寫個(gè)沒有學(xué)習(xí)過Rust的同學(xué)的,了解過的同學(xué)就可以略過了)

//Rust通過fn定義函數(shù),函數(shù)里面的參數(shù)有兩種模式
//帶`&`符號的的是標(biāo)識傳遞進(jìn)去的是一個(gè)引用(不懂引用的同學(xué),暫時(shí)可以先跳過)
//如果不帶&則標(biāo)識輸入的是一個(gè)具體的值。
//函數(shù)后面的 -> 表示函數(shù)的返回值的類型,這里是一個(gè)Polygon類型的vec
fn read_polygon(shapefile: &str) ->Vec<Polygon>{
let shp = shapefile::read_as::<_,
shapefile::Polygon, shapefile::dbase::Record>(
shapefile,
).expect("Could not open polygon-shapefile");

//構(gòu)建輸入?yún)?shù)
let mut polygons:Vec<Polygon> = Vec::new();
//shapefile讀取文件默認(rèn)得到的是一個(gè)MultiPolygon
//
for (polygon, polygon_record) in shp {
let geo_mpolygon: geo_types::MultiPolygon<f64> = polygon.into();
for poly in geo_mpolygon.iter(){
polygons.push(poly.to_owned());
}
}
//Rust中,如果語句后面沒有分號`;`則表示這是一個(gè)表達(dá)式,會返回一個(gè)結(jié)果
//如果這個(gè)表達(dá)式出現(xiàn)在函數(shù)最后,則等同于return polygons的功能
polygons
}

然后就是第二個(gè)函數(shù),把解析出來的polygon集合,轉(zhuǎn)換為plotly的繪圖元素trace:

//輸入兩個(gè)參數(shù),上面輸入的polygons的幾何,和一個(gè)顏色參數(shù)。
//polygon會有
fn build_polygon(polygons: &Vec<Polygon>,color:Rgba)->Vec<Box<ScatterMapbox<f64,f64>>>{
let mut trace_vec = Vec::new();
for ps in polygons{
let mut lon:Vec<f64> = Vec::new();
let mut lat:Vec<f64> = Vec::new();
for p in ps.exterior(){
lon.push(p.x);
lat.push(p.y);
}
let trace = ScatterMapbox::new(lat, lon).mode(Mode::None)
.fill(plotly::scatter_mapbox::Fill::ToSelf)
.fill_color(color);
trace_vec.push(trace);
}
trace_vec
}

第三個(gè)函數(shù),就是把trace繪制成圖了:

//這里直接就繪制出來了,所以沒有返回值
fn draw_trace(traces:&Vec<Box<ScatterMapbox<f64,f64>>>){
let mut plot = Plot::new();
let layout = Layout::new()
.drag_mode(DragMode::Zoom)
.margin(Margin::new().top(10).left(10).bottom(10).right(10))
.width(1024)
.height(700)
.mapbox(
Mapbox::new()
.style(MapboxStyle::WhiteBg)
.center(Center::new(39.9, 116.3))
.zoom(9),
);
plot.set_layout(layout);

for t in traces.iter(){
plot.add_trace(t.to_owned());
}
plot.show();
}

有這三個(gè)函數(shù)之后,我們調(diào)用就很方便了:

#[test]
fn test_draw_2(){
let poly1 = "./data/shp/北京行政區(qū)劃.shp";
let t1 = build_polygon(
&read_polygon(poly1), Rgba::new(240,243,250,1.0));
draw_trace(&t1);
}

效果如下: 

如果我們要繪制兩個(gè)圖層,例如再這個(gè)圖層上,在繪制一個(gè)面狀水系,就很省事了:

#[test]
fn test_draw_2(){
let poly1 = "./data/shp/北京行政區(qū)劃.shp";
let mut t1 = build_polygon(
&read_polygon(poly1), Rgba::new(240,243,250,1.0));

let poly2 = "./data/shp/面狀水系.shp";
let mut t2 = build_polygon(
&read_polygon(poly2), Rgba::new(108,213,250,1.0));

t1.append(&mut t2);
draw_trace(&t1);
}

效果如下: 

但是現(xiàn)在帶來了一個(gè)問題,如果我們要輸入的是線要素呢?那不是有得重新寫一個(gè)讀取線要素的方法么?當(dāng)然,這么寫是一點(diǎn)問題都沒有的,如下所示:

fn read_line(shapefile: &str) ->Vec<LineString>{
let shp = shapefile::read_as::<_,
shapefile::Polyline, shapefile::dbase::Record>(
shapefile,
).expect(&format!("Could not open polyline-shapefile, error: {}", shapefile));

let mut linestrings:Vec<LineString> = Vec::new();
for (pline, pline_record) in shp {
let geo_mline: geo_types::MultiLineString<f64> = pline.into();
for line in geo_mline.iter(){
linestrings.push(line.to_owned());
}
}
linestrings
}
  • 從代碼中可以看見,除了讀取部分稍有不同,線要素與面要素的處理原則大致是差不多的。如果是動(dòng)態(tài)類型的語言,可以直接寫成一個(gè)方法也沒問題,但是Rust是靜態(tài)類型,也就是你需要在編譯之前,就固定下類型來的,這個(gè)問題,我們明天再說。

同樣的,讀取了線要素,還要把線要素轉(zhuǎn)換成線類型的繪圖要素,如下:

fn build_line(lines: &Vec<LineString>,colors:Vec<Rgba>)->Vec<Box<ScatterMapbox<f64,f64>>>{
let mut trace_vec = Vec::new();
for (line,color) in zip(lines,colors){
let mut lon:Vec<f64> = Vec::new();
let mut lat:Vec<f64> = Vec::new();
for p in line.coords(){
lon.push(p.x);
lat.push(p.y);
}
let trace = ScatterMapbox::new(lat, lon)
.mode(Mode::Lines)
.marker(Marker::new().color(color));
trace_vec.push(trace);
}
trace_vec
}

這樣就得到了一個(gè)和面要素轉(zhuǎn)換的繪圖要素是一樣的,然后我們就可以用同一個(gè)方法來解決了,如下:

  #[test]
fn test_draw_2(){
let poly1 = "./data/shp/北京行政區(qū)劃.shp";
let mut t1 = build_polygon(
&read_polygon(poly1), Rgba::new(240,243,250,1.0));

let poly2 = "./data/shp/面狀水系.shp";
let mut t2 = build_polygon(
&read_polygon(poly2), Rgba::new(108,213,250,1.0));

let line1 = "./data/shp/高速.shp";
let line1 = read_line(line1);
let line1_color:Vec<Rgba> = (0..line1.len()).map(|x|Rgba::new(255,182,118,1.0)).collect();
let mut t3 = build_line(&line1,line1_color);

//把三個(gè)trace合并成一個(gè),傳遞到繪圖函數(shù)里面即可
t1.append(&mut t2);
t1.append(&mut t3);
draw_trace(&t1);
}

效果如下: 

以此推類,如果有點(diǎn)要素,照樣處理就行。

看到這里,有同學(xué)會問,我們有多少種類型,就一定要寫多少個(gè)方法,這個(gè)可以理解,每個(gè)方法都用不同的名稱來調(diào)用,讓調(diào)用的人也太難記了,有沒有一種方法,就調(diào)用一個(gè)方法,根據(jù)輸入的類型,自動(dòng)去匹配邏輯處理能力行不行?

當(dāng)然是沒有問題,所以下一節(jié),我們來解決這個(gè)問題。

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多