Rust-builds-TIN-triangulation-with-kiss3D
1.TIN三角网简介
三角网是由一系列连续三角形构成的网状的平面控制图形,是三角测量中布设连续三角形的两种主要扩展形式,同时向各方向扩展而构成网状,优点为点位分布均匀、各点之间互相牵制、图形强度较高,缺点是扩展较缓慢。
三角网是实现地形三维可视化,数字地面模型(Digital Terrain Model,简称 DTM)是一种很有效的途径。DTM 主要是由栅格和不规则三角网(Triangulated Irregular Network,简称 TIN )两种数据格式来表示,相比于栅格 TIN 具有许多优点,几乎能适用于任何复杂的地形,所以 TIN 是 DTM 常采用的一种格式。
2.实现逻辑
st=>start: 生成随机数据
op1=>operation: 遍历-三点确定圆,内部不含第四个点
op2=>operation: 每一次遍历三个点集合,选出最小角最大的三角形
op3=>operation: 过滤掉重复点的集合
e=>end: 绘制三角形
st->op1->op2->op3->e
3.具体代码
cargo.toml
[dependencies]
nalgebra = "0.31.0"
kiss3d = "0.31.0"
rand="*"
libm="*"
point.rs
坐标点相关操作
extern crate rand;
use libm::acos;
use rand::Rng;
use std::f32::consts::PI;
#[derive(Clone, Copy, Debug)]
pub struct Point {
pub x: f64,
pub y: f64,
}
#[derive(Clone, Copy, Debug)]
pub struct Circle {
pub x: f64,
pub y: f64,
pub r: f64,
}
#[derive(Clone, Copy, Debug)]
pub struct CirclePoint {
pub point1: usize,
pub point2: usize,
pub point3: usize,
}
#[derive(Clone, Debug)]
pub struct RenderPoint {
pub render: Vec<Point>,
}
//判断三个点是否在一条直线上
pub fn is_line(point1: Point, point2: Point, point3: Point) -> bool {
let a = (point1.x - point2.x) / (point1.y - point2.y);
let b = (point1.x - point3.x) / (point1.y - point3.y);
if a == b {
true
} else {
false
}
}
//三点确定一个圆
pub fn round(point1: Point, point2: Point, point3: Point) -> Circle {
let a = point1.x - point2.x;
let b = point1.y - point2.y;
let c = point1.x - point3.x;
let d = point1.y - point3.y;
let e = ((point1.x.powi(2) - point2.x.powi(2)) - (point2.y.powi(2) - point1.y.powi(2))) / 2.0;
let f = ((point1.x.powi(2) - point3.x.powi(2)) - (point3.y.powi(2) - point1.y.powi(2))) / 2.0;
let x = -(d * e - b * f) / (b * c - a * d);
let y = -(a * f - c * e) / (b * c - a * d);
let r = ((x - point1.x).powi(2) + (y - point1.y).powi(2)).sqrt();
Circle { x, y, r }
}
pub fn rand_data() -> f64 {
let mut rng = rand::thread_rng();
let n1 = rng.gen::<f64>();
n1 * 600.0 - 300.0
}
pub fn rand_point() -> Vec<Point> {
//生成随机数据
let mut data = Vec::new();
for _i in 0..10 {
let x = rand_data();
let y = rand_data();
data.push(Point { x, y })
}
data
}
pub fn min_angle(point_a: Point, point_b: Point, point_c: Point) -> f64 {
//返回三角形最小的角
let ab = ((point_a.x - point_b.x).powi(2) + (point_a.y - point_b.y).powi(2)).sqrt();
let ac = ((point_a.x - point_c.x).powi(2) + (point_a.y - point_c.y).powi(2)).sqrt();
let cb = ((point_c.x - point_b.x).powi(2) + (point_c.y - point_b.y).powi(2)).sqrt();
let cos_a = (ab * ab + ac * ac - cb * cb) / (2.0 * ab * ac);
let cos_b = (ab * ab + cb * cb - ac * ac) / (2.0 * ab * cb);
let cos_c = (cb * cb + ac * ac - ab * ab) / (2.0 * cb * ac);
let angle_a = acos(cos_a);
let angle_b = acos(cos_b);
let angle_c = acos(cos_c);
let mut min = angle_a;
if min > angle_b {
min = angle_b;
};
if min > angle_c {
min = angle_c;
};
min / (PI as f64) * 180.0
}
pub fn get_max_index(data: &Vec<f64>) -> usize {
let mut max = data[0];
let mut index = 0;
for i in 0..data.len() {
if max < data[i] {
max = data[i];
index = i;
};
}
index
}
pub fn remove_duplicate(data: Vec<CirclePoint>) -> Vec<CirclePoint> {
//除去重复元素
let mut new_data = Vec::new();
let mut data_cp = Vec::new();
for k in 0..data.len() {
let mut tem = vec![data[k].point1, data[k].point2, data[k].point3];
tem.sort();
data_cp.push(CirclePoint {
point1: tem[0],
point2: tem[1],
point3: tem[2],
});
}
let num = data.len();
new_data.push(data_cp[0]);
'one: for i in 0..num {
let mut flag = false;
for j in 0..new_data.len() {
if (data_cp[i].point1 == new_data[j].point1)
&& (data_cp[i].point2 == new_data[j].point2)
&& (data_cp[i].point3 == new_data[j].point3)
{
flag = false;
continue 'one;
} else {
flag = true;
};
}
if flag {
new_data.push(data_cp[i]);
}
}
new_data
}
pub fn tin_data(point_data: Vec<Point>) -> Vec<RenderPoint> {
//处理数据,返回最终结果
let data_cp = point_data.clone();
let data_num = data_cp.len();
let mut render_data = Vec::new();
for i in 0..data_num {
for j in 0..data_num {
if i == j {
continue;
} else {
let mut angle = Vec::new();
let mut circle_points = Vec::new();
'three: for k in 0..data_num {
if k == j || k == i {
continue;
} else {
let a = data_cp[i];
let b = data_cp[j];
let c = data_cp[k];
let circle = round(a, b, c);
let mut flag: bool = false;
'four: for n in 0..data_num {
if n == j || n == i || n == k {
continue 'four;
} else {
let x = data_cp[n].x;
let y = data_cp[n].y;
let r = ((x - circle.x).powi(2) + (y - circle.y).powi(2)).sqrt();
if r < circle.r {
flag = false;
continue 'three;
} else {
flag = true;
};
};
}
if flag {
circle_points.push(CirclePoint {
point1: i,
point2: j,
point3: k,
});
angle.push(min_angle(data_cp[i], data_cp[j], data_cp[k]));
};
};
let index = get_max_index(&angle);
render_data.push(circle_points[index])
}
}
}
}
let tem = remove_duplicate(render_data);
let mut render_point = Vec::new();
for i in tem {
let mut render = Vec::new();
render.push(point_data[i.point1]);
render.push(data_cp[i.point2]);
render.push(data_cp[i.point3]);
render_point.push(RenderPoint { render });
}
render_point
}
draw.rs
绘制三角形
use crate::point::RenderPoint;
extern crate kiss3d;
extern crate nalgebra as na;
use kiss3d::light::Light;
use kiss3d::nalgebra::{Point2, Point3};
use kiss3d::window::Window;
pub fn line_2_d(render_point: Vec<RenderPoint>) {
let mut window = Window::new("TIN 三角图");
window.set_light(Light::StickToCamera);
while window.render() {
for i in 0..render_point.len() {
let a = render_point[i].render[0];
let b = render_point[i].render[1];
let c = render_point[i].render[2];
let point1 = Point2::new(a.x as f32, a.y as f32);
let point2 = Point2::new(b.x as f32, b.y as f32);
let point3 = Point2::new(c.x as f32, c.y as f32);
window.draw_planar_line(&point1, &point2, &Point3::new(1.0, 0.0, 0.0));
window.draw_planar_line(&point2, &point3, &Point3::new(0.0, 1.0, 0.0));
window.draw_planar_line(&point3, &point1, &Point3::new(0.0, 0.0, 1.0));
}
}
}
main.rs
主程序
mod point;
mod draw;
use point::{rand_point, tin_data};
use draw::line_2_d;
fn main() {
let data = rand_point();
let data = tin_data(data);
line_2_d(data);
}
4.成果
在 point.rs 中的 rand_point()调整生成点的数量
最后修改: 2022-08-21T00:21:41
版权声明:署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
comment 评论