【Cesium开发实战】电子围栏功能的实现,可自定义高度

Cesium有很多很强大的功能,可以在地球上实现很多炫酷的3D效果。今天给大家分享一个可自定义高度的电子围栏。

1.话不多说,先展示。

电子围栏

2.设计思路

点击绘制,在地图上可绘制多个点位,双击结束绘制,可对电子围栏起名称以及自定义电子围栏高度,并以列表形式展示,可同时绘制多个电子围栏,点击列表可飞行至对应的电子围栏,也可删除对应的电子围栏。

3.具体代码

<template>
	<div class="page">
		<el-button @click="draw">绘制</el-button>
		<el-table :data="dataList" border @row-click="rowClick">
			<el-table-column prop="name" label="名称" align="center" />
			<el-table-column prop="action" label="操作" align="center">
				<template #default="scope">
					<el-button link type="primary" size="small" @click="delEntity(scope.row, scope.$index)"
						><el-icon :size="16"><ele-Delete /> </el-icon
					></el-button>
				</template>
			</el-table-column>
		</el-table>
	</div>
	<el-dialog v-model="dialogFormVisible" title="配置" width="500" :close-on-press-escape="false" :close-on-click-modal="false" :show-close="false">
		<el-form ref="formRef" :model="form" label-width="auto" :rules="rules">
			<el-form-item label="电子围栏名称" prop="title">
				<el-input v-model="form.title" placeholder="请输入" />
			</el-form-item>
			<el-form-item label="电子围栏高度">
				<el-input-number :min="0" v-model="form.height" placeholder="请输入" />
			</el-form-item>
		</el-form>

		<template #footer>
			<div class="dialog-footer">
				<el-button type="primary" @click="submitForm(formRef)"> 确定 </el-button>
			</div>
		</template>
	</el-dialog>
</template>

<script setup lang="ts">
import { Cesium } from '/@/utils/cesium';
import { onMounted, onUnmounted, reactive, ref } from 'vue';
import { debounce } from 'lodash';

const props = defineProps(['viewer']);

const dialogFormVisible = ref(false);

var handler: any = null;

const formRef = ref();

const rules = {
	title: { required: true, message: '请输入电子围栏名称', trigger: 'blur' },
};

// 视点名称
const form = reactive({
	title: '',
	height: 100,
});

var flyOption = {
	offset: {
		heading: Cesium.Math.toRadians(1.0114629015290062),
		pitch: Cesium.Math.toRadians(-23.53661660731824),
		roll: Cesium.Math.toRadians(0.00324596311071617),
	},
};
/**
 * 添加电子围栏
 */
var addElectronicFence = (name: string, positions: any) => {
	let material = getCustomMaterialWall({
		image: '/src/assets/cesium/wall.png',
		freely: 'vertical',
		direction: '+',
		count: 2,
		color: Cesium.Color.RED,
		duration: 2000,
	});

	var geometry = props.viewer.entities.add({
		id: new Date().getTime(),
		name: name,
		wall: {
			positions: Cesium.Cartesian3.fromDegreesArrayHeights(positions),
			material: material,
		},
	});

	entities.push(geometry);
	dataList.push({
		id: geometry.id,
		name: geometry.name,
		positions: positions,
	});
};

var getCustomMaterialWall = (options: any) => {
	if (props.viewer && options && options.image) {
		return _initWallCustomMaterialProperty(options);
	}
};

// 动态初始化材质线
var _initWallCustomMaterialProperty = (options: any) => {
	var Color = Cesium.Color,
		defaultValue = Cesium.defaultValue,
		defined = Cesium.defined,
		defineProperties = Object.defineProperties,
		Event = Cesium.Event,
		createPropertyDescriptor = Cesium.createPropertyDescriptor,
		Property = Cesium.Property,
		Material = Cesium.Material,
		MaterialType = options.MaterialType || 'wallType' + parseInt(Math.random() * 1000);

	function WallLinkCustomMaterialProperty(options) {
		options = defaultValue(options, defaultValue.EMPTY_OBJECT);
		this._definitionChanged = new Event();
		this._color = undefined;
		this._colorSubscription = undefined;
		this.color = options.color || Color.BLUE;
		this.duration = options.duration || 3000;
		this._time = new Date().getTime();
	}

	defineProperties(WallLinkCustomMaterialProperty.prototype, {
		isvarant: {
			get: function () {
				return false;
			},
		},
		definitionChanged: {
			get: function () {
				return this._definitionChanged;
			},
		},
		color: createPropertyDescriptor('color'),
	});
	WallLinkCustomMaterialProperty.prototype.getType = function (time) {
		return MaterialType;
	};
	WallLinkCustomMaterialProperty.prototype.getValue = function (time, result) {
		if (!defined(result)) {
			result = {};
		}
		result.color = Property.getValueOrClonedDefault(this._color, time, Color.WHITE, result.color);
		result.image = options.image;
		result.time = ((new Date().getTime() - this._time) % this.duration) / this.duration;
		return result;
	};
	WallLinkCustomMaterialProperty.prototype.equals = function (other) {
		return this === other || (other instanceof WallLinkCustomMaterialProperty && Property.equals(this._color, other._color));
	};
	//动态墙
	Material._materialCache.addMaterial(MaterialType, {
		fabric: {
			type: MaterialType,
			uniforms: {
				color: new Color(1.0, 0.0, 0.0, 0.5),
				image: options.image,
				time: 0,
			},
			source: _getDirectionWallShader({
				get: true,
				count: options.count,
				freely: options.freely,
				direction: options.direction,
			}),
		},
		translucent: function (material) {
			return true;
		},
	});

	return new WallLinkCustomMaterialProperty(options);
};

var _getDirectionWallShader = (options: any) => {
	if (options && options.get) {
		var materail =
			'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
                    {\n\
                    czm_material material = czm_getDefaultMaterial(materialInput);\n\
                    vec2 st = materialInput.st;\n\
                    \n\ ';
		if (options.freely == 'vertical') {
			//(由下到上)

			materail += 'vec4 colorImage = texture2D(image, vec2(fract(float(' + options.count + ')*st.t ' + options.direction + ' time), fract(st.s)));\n\ ';
		} else {
			//(逆时针)

			materail += 'vec4 colorImage = texture2D(image, vec2(fract(float(' + options.count + ')*st.s ' + options.direction + ' time), fract(st.t)));\n\ ';
		}
		//泛光
		materail +=
			'vec4 fragColor;\n\
                    fragColor.rgb = (colorImage.rgb+color.rgb) / 1.0;\n\
                    fragColor = czm_gammaCorrect(fragColor);\n\ ';

		materail +=
			' material.diffuse = colorImage.rgb;\n\
                    material.alpha = colorImage.a;\n\
                    material.emission = fragColor.rgb;\n\
                    \n\
                    return material;\n\
                    }\n\
                    ';

		return materail;
	}
};

const drawing = ref(false);

// 电子围栏列表数据
const dataList: any = reactive([]);

// 电子围栏实体列表
var entities: any = [];

// 电子围栏point实体列表
var pointEntities: any = [];

// 当前选中实体索引
var geometryIndex: any = null;

/**
 * 点击绘制按钮
 */
const draw = () => {
	drawing.value = true;
};

/**
 * 点击表格一行
 */
const rowClick = (row: any, column: any, event: Event) => {
	if (column && column.property) {
		let index = dataList.findIndex((v: any) => v.id === row.id);
		if (index !== -1) {
			geometryIndex = index;
			props.viewer.flyTo(entities[index], flyOption);
		}
	}
};

/**
 * 删除已绘制的图形
 */
const delEntity = (item: any, index: number) => {
	props.viewer.entities.remove(entities[index]);
	entities.splice(index, 1);
	dataList.splice(index, 1);
};

/**
 * 点击确定绘制
 */
const submitForm = async (formEl: any) => {
	const valid = await formEl.validate();
	if (valid) {
		var pointList: any = [];
		pointEntities.forEach((entity: any) => {
			var { longitude, latitude } = getPosition(entity);
			pointList.push(longitude, latitude, form.height);
			props.viewer.entities.remove(entity);
		});
		var { longitude, latitude } = getPosition(pointEntities[0]);
		pointList.push(longitude, latitude, form.height);
		pointEntities = [];
		addElectronicFence(form.title, pointList);
		dialogFormVisible.value = false;
		formEl.resetFields();
	}
};

/**
 * 添加鼠标事件
 */
const addClickHandler = () => {
	handler = new Cesium.ScreenSpaceEventHandler(props.viewer.scene.canvas);
	// 单击绘制
	handler.setInputAction((event: any) => {
		leftClickHandler(event);
	}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

	// 双击结束point绘制,开始围栏绘制
	handler.setInputAction((event: any) => {
		if (drawing.value) {
			drawing.value = false;
		}

		if (pointEntities.length) {
			dialogFormVisible.value = true;
		}
	}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
};

/**
 * 单击左键
 */
const leftClickHandler = debounce((event: any) => {
	if (drawing.value) {
		let cartesian = props.viewer.scene.pickPosition(event.position);
		let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
		let coordinate = {
			longitude: Cesium.Math.toDegrees(cartographic.longitude),
			latitude: Cesium.Math.toDegrees(cartographic.latitude),
			height: cartographic.height + 1,
		};
		var pointGeometry = new Cesium.Entity({
			name: 'Sample Label',
			position: Cesium.Cartesian3.fromDegrees(coordinate.longitude, coordinate.latitude, coordinate.height),
			point: {
				// 实体是一个点
				pixelSize: 10, // 点的大小
				color: Cesium.Color.RED, // 点的颜色
			},
		});
		props.viewer.entities.add(pointGeometry);
		pointEntities.push(pointGeometry);
	}
}, 100);

/**
 * 获取实体的经纬度
 */
const getPosition = (entity: any) => {
	// 获取点实体的位置
	var position = entity.position.getValue(Cesium.JulianDate.now());
	// 转换Cartesian3到经纬度
	var cartographic = Cesium.Cartographic.fromCartesian(position, props.viewer.scene.globe.ellipsoid);
	var longitude = Cesium.Math.toDegrees(cartographic.longitude);
	var latitude = Cesium.Math.toDegrees(cartographic.latitude);
	return {
		longitude,
		latitude,
	};
};

onMounted(() => {
	addClickHandler();
});

onUnmounted(() => {
	entities.forEach((entity: any) => {
		props.viewer.entities.remove(entity);
	});
	handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
	handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
});
</script>

<style scoped>
.page {
	position: absolute;
	right: 10px;
	top: 10px;
	color: #fff;
	background: #fff;
	padding: 10px;
	border-radius: 5px;
	width: 300px;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Elasticsearch】开源搜索技术的演进与选择:Elasticsearch 与 OpenSearch

开源搜索技术的演进与选择&#xff1a;Elasticsearch 与 OpenSearch 1.历史发展2.OpenSearch 与 Elasticsearch 相同点3.OpenSearch 与 Elasticsearch 不同点3.1 版本大不同3.2 许可证不同3.3 社区不同3.4 功能不同3.5 安全性不同3.6 性能不同3.7 价格不同3.8 两者可相互导入 4…

LLM- 注意力机制

一&#xff1a;什么是注意力机制&#xff0c;以及产生背景&#xff1f; &#xff08;1&#xff09;&#xff1a;RNN模型[RNN模型]的缺点&#xff1a;下图是例如RNN模型解决机器翻译的例子&#xff0c;从这个例子可以看到Encoder最后一个向量&#xff08;eos&#xff09;送给了…

Open3D 从体素网格构建八叉树

目录 一、概述 1.1体素网格 1.2八叉树构建 1.3应用 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 3.1原始点云 3.2体素网格 3.3八叉树 3.4体素网格 一、概述 八叉树&#xff08;Octree&#xff09;是一种树状数据结构&#xff0c;用于递归地将三维空间划分为…

极客天成RDMA分布式存储加速自动驾驶仿真建模

01 自动驾驶汽车行业发展现状 随着全球5G技术的应用与发展&#xff0c;人工智能产业的逐步推进&#xff0c;无人驾驶汽车行业市场规模显著增长。中商产业研究院发布的《2024-2029全球与中国无人驾驶列车系统市场现状及未来发展趋势》显示&#xff0c;2023年全球无人驾驶汽车行…

AutoMQ 生态集成 Kafdrop-ui

Kafdrop [1] 是一个为 Kafka 设计的简洁、直观且功能强大的Web UI 工具。它允许开发者和管理员轻松地查看和管理 Kafka 集群的关键元数据&#xff0c;包括主题、分区、消费者组以及他们的偏移量等。通过提供一个用户友好的界面&#xff0c;Kafdrop 大大简化了 Kafka 集群的监控…

【Ubuntu】windows和Linux文件互传、共享

【Ubuntu】windows和Linux文件互传、共享 一、FTP、SAMBA、NFS简介 FTP: File Transfer Protocol&#xff08;文件传输协议) SAMBA: 基于SMB(Server Message Block服务器消息块)协议的软件实现 NFS: Network File System&#xff08;网络文件系统&#xff09; 二、Linux 共享文…

QT案例-通过QCustomPlot库绘制Window系统CPU温度实时折线图

之前项目中涉及到了获取硬件信息内容&#xff0c;对CPU的温度监控有点兴趣&#xff0c;观察和百度发现鲁大师和驱动人生的CPU温度监控貌似是用驱动实现的&#xff0c;有点太高大上了&#xff0c;搞不懂。后面经过到处查找资料终于找到了Qt在Windows 环境下监控CPU等硬件温度/运…

android文本长按复制

android文本长按复制 &#x1f4d6;1. 长按直接复制✅步骤一&#xff1a;定义一个TextView✅步骤二&#xff1a;为TextView注册长按事件✅步骤三&#xff1a;弹出系统复制功能 &#x1f4d6;2. 长按弹框确认复制✅步骤一&#xff1a;定义一个TextView✅步骤二&#xff1a;封装P…

vue详解

目录 ​编辑 常用指令 v-for v-bind v-if & v-show v-if v-show v-on v-model Vue生命周期 ​编辑 Axios Axios使用步骤 Axios-请求方式别名 Vue简单案例 常用指令 指令:HTML标签上带有 v-前缀的特殊属性&#xff0c;不同的指令具有不同的含义&#xff0c;可…

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片(Form_Vision部分代码)

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片(Form_Vision部分代码) 1 目标效果视频 CamManager 2 增加一个class IMG_BUFFER 用来管理采集的图片 // <summary> /// IMG_BUFFER 用来管理内存图片的抓取队列 /// </summary> public class IMG_BUFF…

imx6ull/linux应用编程学习(14) MQTT基础知识

什么是mqtt&#xff1f; 与HTTP 协议一样&#xff0c; MQTT 协议也是应用层协议&#xff0c;工作在 TCP/IP 四层模型中的最上层&#xff08;应用层&#xff09;&#xff0c;构建于 TCP/IP协议上。 MQTT 最大优点在于&#xff0c;可以以极少的代码和有限的带宽&#xff0c;为连接…

electron在VSCode和IDEA及webStrom等编辑器控制台打印日志乱码

window10环境下设置 1.打开Windows设置 2.打开时间和语言&#xff0c;选择语言菜单、如何点击管理语言设置 3.打开之后选择管理&#xff0c;选择更改系统区域设置&#xff0c;把Beta版&#xff1a;使用Unicode UTF-8提供全球语言支持 勾上&#xff0c;点击确定&#xff0c;…

后端学习(一)

添加数据库包&#xff1a; 数据库连接时 发生错误&#xff1a; 解决方式&#xff1a; SqlConnection conn new SqlConnection("serverlocalhost;databaseMyBBSDb;uidsa;pwd123456;Encryptfalse;") ;conn.Open();SqlCommand cmd new SqlCommand("SELECT * FROM…

Debug-017-elementUI-el-cascader组件首次选择选项不触发表单的自定义校验

前情提要&#xff1a; 今天维护一个表单校验的时候发现一件事情&#xff0c;就是在表单中使用了 el-cascader组件&#xff0c;希望根据接口返回数据去动态校验一下这里面的选项&#xff0c;符合逻辑就通过自定义的表单校验&#xff0c;不符合就在这一项的下面标红提示。做的时候…

OpenHarmony 入门——单元测试UnitTest快速入门

引言 OpenHarmony 的单元测试&#xff08;UnitTest&#xff09;是一个关键的软件开发过程&#xff0c;它确保代码的各个部分能够按预期工作&#xff0c;OpenHarmony的测试框架中提供了很多种的单元测试&#xff0c;今天简单介绍下UnitTest 类型的TDD测试。 OpenHarmony 的TDD …

群体优化算法---文化算法介绍,求解背包问题

介绍 文化算法&#xff08;Cultural Algorithm, CA&#xff09;是一种基于文化进化理论的优化算法&#xff0c;首次由Robert G. Reynolds在20世纪90年代提出。文化算法通过模拟人类社会中的文化进化过程&#xff0c;利用个体与群体的双重进化机制来解决优化问题。其基本思想是…

MGRE复习综合实验

R1与R5之间使用ppp的pap认证&#xff0c;R5为主认证方&#xff1a; R1 interface Serial4/0/0ip address 15.0.0.1 8link-protocol pppppp pap local-user huawei password cipher 123456 R5 aaalocal-user huawei password cipher 123456local-user huawei service-type…

海外媒体发稿-全媒体百科

全球知名媒体机构 在全球范围内&#xff0c;有许多知名的新闻机构负责报道世界各地的新闻事件。以下是一些国外常见的媒体机构&#xff1a; AP&#xff08;美联社&#xff09;合众国际社&#xff08;UPI&#xff09;AFP(法新社)EFE&#xff08;埃菲通讯社&#xff09;Europa …

JavaSE学习笔记第二弹——对象和多态(上)

目录 面向对象基础 面向对象程序设计的定义 类的基本结构 成员变量 成员方法 方法定义与使用 设计练习 方法重载 构造方法 静态变量和静态方法 String和StringBuilder 基本含义 区别 总结 今天我们继续来学习JavaSE&#xff0c;扩展和Java相关的知识&#xff0c;…

【软件分享】气象绘图软件Panoply

气象是大气中的物理现象&#xff0c;气象要素则是表明大气物理状况的要素&#xff0c;主要的气象要素有降水、风、气压、湿度等。为了研究气象要素在空间上的分布和运动状况&#xff0c;我们需要对气象要素进行空间上进行可视化&#xff0c;这个时候就需要气象领域的一些的绘图…