Vue.js2+Cesium1.103.0 三、模型加载与切割

Vue.js2+Cesium1.103.0 三、模型加载与切割

Demo

模型加载

const tileset = new Cesium.Cesium3DTileset({
	url: 'https://lab.earthsdk.com/model/3610c2b0d08411eab7a4adf1d6568ff7/tileset.json',
	debugShowMemoryUsage: false,
})
viewer.scene.primitives.add(tileset)
viewer.zoomTo(tileset) // 视角切换到模型的位置

模型裁切

import { cutModelByPolygon } from '@/utils/ClippingPlane'

cutModelByPolygon(
	tileset,
	[
		[121.49260265519028, 31.242117807041236],
		[121.51355676668399, 31.245032122784824],
		[121.51871163020894, 31.232316199923016],
		[121.50450627122848, 31.227712061479057],
		[121.49406078139155, 31.238990131267578],
	],
	true // 外部裁切
)

模型切割实现对比效果

import { createClippingPlaneFun } from '@/utils/ClippingPlane'

// 模型一
const tileseta = createClippingPlaneFun(
	'https://lab.earthsdk.com/model/3610c2b0d08411eab7a4adf1d6568ff7/tileset.json',
	new Cesium.ClippingPlaneCollection({
		planes: [new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 0.0)],
		unionClippingRegions: true,
	})
)

// 模型二
const tilesetb = createClippingPlaneFun(
	'https://lab.earthsdk.com/model/908311a0ac2f11e99dbd8fd044883638/tileset.json',
	new Cesium.ClippingPlaneCollection({
		planes: [new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), 0.0)],
		// edgeColor: Cesium.Color.WHITE,
		// edgeWidth: 0.0,
		unionClippingRegions: true,
	})
)

viewer.zoomTo(tileseta)

// 交互
const leftBtn = document.getElementById('left')
leftBtn.onclick = function () {
	if (tileseta.clippingPlanes.get(0).distance > 3500) {
		return
	}
	tileseta.clippingPlanes.get(0).distance += 500
	tilesetb.clippingPlanes.get(0).distance -= 500
}

const rightBtn = document.getElementById('right')
rightBtn.onclick = function () {
	if (tilesetb.clippingPlanes.get(0).distance > 3500) {
		return
	}
	tilesetb.clippingPlanes.get(0).distance += 500
	tileseta.clippingPlanes.get(0).distance -= 500
}

切割方法

ClippingPlane.js

/* eslint-disable no-undef */
import * as turf from '@turf/turf'

/**
 * @description: 根据多边形裁切模型
 * @param {*} tileset 模型
 * @param {*} polygon 多边形
 * @param {*} model 裁切方式(正切/反切)
 * @return {*}
 */
export function cutModelByPolygon(tileset, polygon, model) {
	tileset.readyPromise.then(_tileset => {
		const inverseTransform = getInverseTransform(_tileset) // 转换矩阵
		// 切割的多边形
		const cutPolygon = polygon
		const cutList = isDirRes(cutPolygon, !model)

		const clippingPlanes1 = []
		for (let i = 0; i < cutList.length - 1; i++) {
			const plane = createPlane(cutList[i], cutList[i + 1], inverseTransform)
			clippingPlanes1.push(plane)
		}
		// 创建裁剪平面
		const clippingPlanes = new Cesium.ClippingPlaneCollection({
			// 一组 ClippingPlane 对象,用于选择性地禁用每个平面外部的渲染
			planes: clippingPlanes1,
			// 应用于裁剪对象的边缘的高光的宽度(以像素为单位)
			unionClippingRegions: model,
			edgeWidth: 1.0,
		})
		_tileset.clippingPlanes = clippingPlanes
	})
}

export function createPlaneUpdateFunction(plane) {
	return function () {
		return plane
	}
}

/**
 * @description: 给模型添加切割面
 * @param {*} url 模型地址
 * @param {*} clippingPlanes 切割面
 * @return {*}
 */
export function createClippingPlaneFun(url, clippingPlanes) {
	const planeEntities = []
	const option = {
		url: url,
		maximumScreenSpaceError: 8,
		clippingPlanes: clippingPlanes,
	}
	const tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset(option))

	tileset.readyPromise.then(function (tileset) {
		const boundingSphere = tileset.boundingSphere
		const radius = boundingSphere.radius
		if (!Cesium.Matrix4.equals(tileset.root.transform, Cesium.Matrix4.IDENTITY)) {
			// The clipping plane is initially positioned at the tileset's root transform.
			// Apply an additional matrix to center the clipping plane on the bounding sphere center.
			const transformCenter = Cesium.Matrix4.getTranslation(
				tileset.root.transform,
				new Cesium.Cartesian3()
			)
			const transformCartographic = Cesium.Cartographic.fromCartesian(transformCenter)
			const boundingSphereCartographic = Cesium.Cartographic.fromCartesian(
				tileset.boundingSphere.center
			)
			const height = boundingSphereCartographic.height - transformCartographic.height
			clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(
				new Cesium.Cartesian3(0.0, 0.0, height)
			)
			for (let i = 0; i < clippingPlanes.length; ++i) {
				const plane = clippingPlanes.get(i)
				const planeEntity = viewer.entities.add({
					position: boundingSphere.center,
					plane: {
						dimensions: new Cesium.Cartesian2(radius, radius),
						material: Cesium.Color.RED.withAlpha(0.0),
						plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane), false),
						outline: false,
						outlineColor: Cesium.Color.RED,
					},
				})
				planeEntities.push(planeEntity)
			}
			return tileset
		}
	})
	return tileset
}

export function isDirRes(polygon, isClockwise) {
	const lineStringList = []
	polygon.forEach(p => {
		lineStringList.push([p[0], p[1]])
	})

	const clockwiseRing = turf.lineString(lineStringList)
	const isR = turf.booleanClockwise(clockwiseRing)

	let points = []
	if (isClockwise) {
		if (!isR) {
			points = polygon
		} else {
			let count = 0
			for (let ii = polygon.length - 1; ii >= 0; ii--) {
				points[count] = polygon[ii]
				count++
			}
		}
	} else {
		if (isR) {
			points = polygon
		} else {
			let count = 0
			for (let ii = polygon.length - 1; ii >= 0; ii--) {
				points[count] = polygon[ii]
				count++
			}
		}
	}
	return points
}

export function getOriginCoordinateSystemPoint(point, inverseTransform) {
	const val = Cesium.Cartesian3.fromDegrees(point[0], point[1])
	return Cesium.Matrix4.multiplyByPoint(inverseTransform, val, new Cesium.Cartesian3(0, 0, 0))
}

/**
 * @description: 创建平面
 * @param {*} p1
 * @param {*} p2
 * @param {*} inverseTransform
 * @return {*}
 */
export function createPlane(p1, p2, inverseTransform) {
	const p1C3 = getOriginCoordinateSystemPoint(p1, inverseTransform)
	const p2C3 = getOriginCoordinateSystemPoint(p2, inverseTransform)
	const up = new Cesium.Cartesian3(0, 0, 10)
	const right = Cesium.Cartesian3.subtract(p2C3, p1C3, new Cesium.Cartesian3())
	let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3())
	normal = Cesium.Cartesian3.normalize(normal, normal)
	const planeTmp = Cesium.Plane.fromPointNormal(p1C3, normal)
	return Cesium.ClippingPlane.fromPlane(planeTmp)
}

/**
 * @description: 转换矩阵
 * @param {*} tileset
 * @return {*}
 */
export function getInverseTransform(tileset) {
	let transform
	const tmp = tileset.root.transform
	if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY))	 || !tmp) {
		transform = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center)
	} else {
		transform = Cesium.Matrix4.fromArray(tileset.root.transform)
	}
	return Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4())
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值