用可视化案例讲Rust编程5.用泛型和特性实现自适配绘制和颜色设置

上一节我们讲了用泛型实现返回结果,这一节我们来讲讲在函数签名里面使用泛型来对输入参数进行自适配。

先看UML设计图:

图片

好吧,看起来有点复杂,我们一个个来解释。

首先定义的是一个生成绘图元素需要的参数结构,并且定义个特性,就叫做构造绘图元素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>>>;
}

绘图元素的参数,定义了三个参数:

  • 第一个参数是输入一个几何要素集合,因为我们最起码有点线面三种几何要素,所以定义的是一个泛型变量G

  • 第二参数是一个颜色集合,这里也可以用泛型,不过我们不需要那么多种颜色定义,这里给了一个枚举型的输入颜色,枚举定义如下:

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

这里支持NameColor和Rgba两种颜色定义即可。

  • 第三个参数是一个size,用来控制点的大小、线的宽度和面要素的边框,当然你也可以设定更多的参数,我这里仅用来说明,就不搞那么麻烦了:

图片

接下去就可以写具体的实现了。

点要素的实现:

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}
}

线要素的实现:

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}
}

面数据的实现:

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}
}

里面三个方法都用了一个处理trace的方法,实现如下:

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!("")}}
}

这两个方法,几乎99%是想同的,只是输入的颜色类型不一样,这样就是静态语言的麻烦之处了,只要函数签名不一致,就相当于两个方法,看到这里,大家可能想问,上一节讲过的泛型,在这里能用么?答案当然可以,不过就算用泛型,最终编译出来的代码也会因为编译器的处理,而实现函数单态化,即编译器会针对具体情况,编译出多个静态函数出来。所以这里如果继续抽象,也不是不行,但是算做过度设计了。

之后,就可以写一个绘制函数,然后进行调用了:

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(),}
}//这个是一个内部函数,用来初始化构造制图参数的。
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),)
}

最后我们写一个测试调用方法,来绘制一下百度地图:

// 因为在Html里面绘制比较慢,所以我这里就仅画三个图层
#[test]
fn draw_bd_style(){let shp1 = "./data/shp/北京行政区划.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,所以网络访问上可能会有一些障碍,有可能需要科学上网……

打完收工。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/798594.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Security——09,解决跨域

解决跨域 一、SpringBoot配置二、配置SpringSecurity三、修改端口四、修改vue项目4.1 拿到token4.2 前端存储token4.3 前端请求头携带token 五、测试5.1 认证测试5.2 授权测试 一键三连有没有捏~~ 浏览器出于安全的考虑&#xff0c;使用 XMLHttpRequest对象发起 HTTP请求时必须…

day 74 js

js脚本 JS的作用&#xff1a; 描述显示的内容&#xff08;HTML&#xff09;修饰 HTML 标签&#xff08;CSS&#xff09;设置 HTML 标签的动作&#xff08;JS&#xff09;JS特点&#xff1a;基于对象的编程语言&#xff0c;通过浏览器解释执行作用&#xff1a;表单验证、改变标签…

使用阿里云服务器可以做什么?太多了

阿里云服务器可以干嘛&#xff1f;能干啥你还不知道么&#xff01;简单来讲可用来搭建网站、个人博客、企业官网、论坛、电子商务、AI、LLM大语言模型、测试环境等&#xff0c;阿里云百科aliyunbaike.com整理阿里云服务器的用途&#xff1a; 阿里云服务器活动 aliyunbaike.com…

LeetCode-热题100:763. 划分字母区间

题目描述 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。…

AcWing 4. 多重背包问题 I

解题思路 相关思路 import java.util.Scanner; public class Main {public static void main(String[] args){Scanner scanner new Scanner(System.in);int N scanner.nextInt();int V scanner.nextInt();int v[] new int[N1];int w[] new int[N1];int s[] new int[N1];…

揭秘AI幻觉:GPT-4V存在视觉编码漏洞,清华联合NUS提出LLaVA-UHD

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 GPT-4V 的推出引爆了多模态大模型的研究。GPT-4V 在包括多模态问答、推理、交互在内的多个领…

capter1:GPU 硬件与 CUDA 程序开发工具

GPU 硬件与 CUDA 程序开发工具 参考书籍&#xff1a;CUDA 编程 樊哲勇 代码地址&#xff1a;https://github.com/QINZHAOYU/CudaSteps GPU 硬件 在由 CPU 和 GPU 构成的异构计算平台中&#xff0c;通常将起控制作用的 CPU 称为 主机&#xff08;host&#xff09;&#xff0c;…

二. CUDA编程入门-双线性插值计算

目录 前言0. 简述1. 执行一下我们的第十个CUDA程序2. Bilinear interpolation3. 代码分析总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 Note&#xff1a;关于 CUDA 加速双线程插值的内容博主…

Linux下I2C设备驱动:i2c_driver 的注册示例代码

一. 简介 前面学习了 Linux下 I2C驱动框架分为&#xff1a;I2C总线驱动与I2C设备驱动两个部分。我们主要重点学习 I2C设备驱动&#xff0c;前一篇文章学习了I2C设备驱动相关的结构体与设备驱动注册与删除。文章如下&#xff1a; Linux下I2C驱动实验&#xff1a;I2C 设备驱动…

对象存储服务MinIO安装使用

对象存储服务MinIO安装使用 MinIO简介 MinIO基于Apache License v2.0开源协议的对象存储服务&#xff0c;可以做为云存储的解决方案用来保存海量的图片&#xff0c;视频&#xff0c;文档。由于采用Golang实现&#xff0c;服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置…

爬虫逆向非对称加密和对称加密案例

注意&#xff01;&#xff01;&#xff01;&#xff01;某XX网站逆向实例仅作为学习案例&#xff0c;禁止其他个人以及团体做谋利用途&#xff01;&#xff01;&#xff01; 案例--aHR0cHM6Ly9jcmVkaXQuaGxqLmdvdi5jbi94eWdzL3l6d2ZzeHF5bWQv 第一步&#xff1a;分析页面、请求…

CTF 之Zhuanxv

拿到题目进行目录遍历发现有一个/list文件 打开/list文件&#xff0c;发现是一个登录界面 尝试过爆破&#xff0c;毫无疑问不可能成功。 刷新页面&#xff0c;抓包&#xff0c;然后放一个包&#xff0c;发现又发了一个请求。 GET /loadimage?fileNameweb_login_bg.jpg HTTP/…

1995-2021年各省分品种能源产量和消费量数据

1995-2021年各省分品种能源产量和消费量数据 1、时间&#xff1a;1995-2021年 2、来源&#xff1a;能源统计年鉴、各省年鉴 3、指标&#xff1a;能源消费总量、煤炭消费量、焦炭消费量、原油消费量、汽油消费量、煤油消费量、柴油消费量、燃料油消费量、天然气消费量、电力消…

不开玩笑,你应该像「搬砖」一样写代码!斯坦福大学研究如是说

由于程序员不可避免要进行很多重复性的工作&#xff0c;并且工作强度很高&#xff0c;导致有一种自嘲的说法出现&#xff1a;程序员们自称自己每天都在搬砖&#xff08;实际上很多职场人都这么自嘲&#xff09;。我相信当我们说工作像「搬砖」的时候&#xff0c;只是在表达一种…

JSX 入门:React 开发者的必备技能指南

JSX 是 React 的一种语法扩展&#xff0c;用于描述 UI 组件的外观。在 React 中&#xff0c;JSX 可以与 JavaScript 一起使用&#xff0c;帮助您在应用程序中创建动态和可重用的组件。以下是 JSX 的语法、使用技巧和注意事项&#xff0c;以及一些示例代码。 JSX 基础语法 JSX…

非关系型数据库——三万字Redis数据库详解

目录 前言 一、Redis概述 1.主要特点 2.Redis优缺点 3.Redis为什么这么快 4.Redis那么快&#xff0c;为什么不用它做主数据库&#xff0c;只用它做缓存 5.线程模型 5.1单线程架构 5.2多线程IO处理&#xff08;Redis 6及以上&#xff09; 5.3线程模型的优化 6.作用 …

回归预测 | Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测

回归预测 | Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测 目录 回归预测 | Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测 1.Matlab实现…

系统设计取舍问题

在需求设计过程中&#xff0c;常常面临着取舍问题。由于资源和时间的限制&#xff0c;不可能满足所有的需求&#xff0c;因此需要进行取舍。以下是一些常见的需求设计取舍问题和应对方法&#xff1a; 优先级&#xff1a;对于不同的需求&#xff0c;可以根据其重要性和紧急程度来…

蓝桥杯考前复习二

1.快速幂 public static long qmi(long a, long b, long p) {long r 1;while (b ! 0) {if ((b & 1) 1) {r (r * a) % p;}b >> 1;a a * a % p;}return r;} 2.Java日期类 日期问题暂更 3.日期问题模板 考前更新 4.状态机DP 1.松散子序列 - 蓝桥云课 (lanqia…

LOOP AT内表循环事件块 程序实例

REPORT zdemo_0006. *声明一个结构 DATA: BEGIN OF gs_alv, va1 TYPE char2, va2 TYPE char2, va3 TYPE char2, va4 TYPE char2, END OF gs_alv. *声明内表 DATA: gt_alv LIKE TABLE OF gs_alv. *赋值宏 DEFINE append_va. gs_alv-va1…