diff --git a/src/Global/efflect/Sunshine/eventBinding.js b/src/Global/efflect/Sunshine/eventBinding.js index 6e1b840..321dbdb 100644 --- a/src/Global/efflect/Sunshine/eventBinding.js +++ b/src/Global/efflect/Sunshine/eventBinding.js @@ -1,45 +1,89 @@ -class eventBinding { +class EventBinding { constructor() { this.element = {} } static event = {} getEvent(name) { - return eventBinding.event[name] + return EventBinding.event[name] } getEventAll() { - return eventBinding.event + return EventBinding.event } setEvent(name, event) { - eventBinding.event[name] = event + EventBinding.event[name] = event } on(that, elements) { + this.element = {} for (let i = 0; i < elements.length; i++) { - let Event = [] - let isEvent = false - let removeName = [] if (!elements[i] || !elements[i].attributes) { continue; } + let Event = { + 'input': [], + 'change': [], + 'blur': [], + 'click': [] + } + let isEvent = false + let removeName = [] for (let m of elements[i].attributes) { switch (m.name) { case '@model': { isEvent = true if (elements[i].type == 'checkbox') { - Event.push((e) => { that[m.value] = e.target.checked }) + Event.change.push((e) => { that[m.value] = e.target.checked }) elements[i].checked = that[m.value] } else { - Event.push((e) => { - let value = e.target.value - if (e.target.type == 'number') { - value = Number(value) - } - that[m.value] = value - }) + if (elements[i].type == 'number') { + Event.input.push((e) => { + if (e.target.value || e.target.value === 0) { + let value = e.target.value + value = Number(value) + if (e.data != '.' && (e.data != '-' || e.target.value)) { + if (((!e.target.max) && (!e.target.min)) || ((value <= Number(e.target.max)) && value >= Number(e.target.min))) { + // that[m.value] = value + value = value + } + if ((e.target.max) && value > Number(e.target.max)) { + value = Number(e.target.max) + } + if ((e.target.min) && value < Number(e.target.min)) { + value = Number(e.target.min) + } + // if ((e.target.dataset.min) && value < Number(e.target.dataset.min)) { + // value = Number(e.target.dataset.min) + // } + that[m.value] = value + } + } + }) + Event.blur.push((e) => { + let value = e.target.value + if (e.target.value || (e.target.dataset.null !== 'undefined' && e.target.dataset.null !== '' && !Boolean(e.target.dataset.null))) { + value = Number(value) + if ((e.target.max) && value > Number(e.target.max)) { + value = Number(e.target.max) + } + if ((e.target.min) && value < Number(e.target.min)) { + value = Number(e.target.min) + } + if ((e.target.dataset.min) && value < Number(e.target.dataset.min)) { + value = Number(e.target.dataset.min) + } + } + that[m.value] = value + }) + } + else { + Event.input.push((e) => { + that[m.value] = e.target.value + }) + } if (elements[i].nodeName == 'IMG') { elements[i].src = that[m.value] } @@ -57,13 +101,13 @@ class eventBinding { break; } case '@click': { - elements[i].addEventListener('click', (e) => { - if (typeof (that.Dialog[m.value]) === 'function') { - that.Dialog[m.value](e) + isEvent = true + Event.click.push((e) => { + if (typeof (that[m.value]) === 'function') { + that[m.value](e) } - }); + }) removeName.push(m.name) - // elements[i].attributes.removeNamedItem(m.name) break; } } @@ -74,19 +118,18 @@ class eventBinding { } if (isEvent) { - let ventType = 'input' - if (elements[i].tagName != 'INPUT' || elements[i].type == 'checkbox') { - ventType = 'change' - } - elements[i].addEventListener(ventType, (e) => { - for (let t = 0; t < Event.length; t++) { - Event[t](e) + for (let key in Event) { + if (Event[key].length > 0) { + elements[i].addEventListener(key, (e) => { + for (let t = 0; t < Event[key].length; t++) { + Event[key][t](e) + } + }); } - }); + } } } } } -const EventBinding = new eventBinding(); export default EventBinding; diff --git a/src/Global/efflect/Sunshine/index.js b/src/Global/efflect/Sunshine/index.js index 12119d5..4a921a1 100644 --- a/src/Global/efflect/Sunshine/index.js +++ b/src/Global/efflect/Sunshine/index.js @@ -3,7 +3,7 @@ */ import Dialog from '../../../Obj/Element/Dialog'; import { html } from "./_element"; -import EventBinding from '../../../Obj/Element/Dialog/eventBinding'; +import EventBinding from './eventBinding'; import { syncData } from '../../MultiViewportMode' import Tools from '../../../Tools' import TimeLine from './TimeLine' diff --git a/src/In/index.js b/src/In/index.js index ac158cb..ebfff60 100644 --- a/src/In/index.js +++ b/src/In/index.js @@ -187,7 +187,7 @@ import DrawTakeOff from '../Obj/AirLine/DrawTakeOff' import FlowLine from '../Obj/Base/FlowLine' import Sunshine from '../Global/efflect/Sunshine' // import Road2 from '../Obj/Base/RoadObject' -// import TextBox from '../Obj/Base/TextBox' +import TextBox from '../Obj/Base/TextBox' import BatchModel from '../Obj/Base/BatchModel' const YJEarthismeasuring = Symbol('测量状态') @@ -262,7 +262,7 @@ if (!window.YJ) { Dialog, FlowLine, // Road2, - // TextBox, + TextBox, BatchModel }, YJEarth, diff --git a/src/Obj/Analysis/test2/index.js b/src/Obj/Analysis/test2/index.js index 1cb3415..61fdea9 100644 --- a/src/Obj/Analysis/test2/index.js +++ b/src/Obj/Analysis/test2/index.js @@ -292,7 +292,7 @@ class PolygonObject extends Base { } set labelShow(v) { this.options.label.show = v - if (this.show) { + if (this.show && !this.showView || this.showView == 3) { this.label.show = v } else { diff --git a/src/Obj/Base/AttackArrowObject/index.js b/src/Obj/Base/AttackArrowObject/index.js index f1ca715..278e654 100644 --- a/src/Obj/Base/AttackArrowObject/index.js +++ b/src/Obj/Base/AttackArrowObject/index.js @@ -324,7 +324,7 @@ class AttackArrowObject extends Base { } set labelShow(v) { this.options.label.show = v - if (this.show &&!this.showView || this.showView == 3) { + if (this.show && !this.showView || this.showView == 3) { this.label.show = v } else { diff --git a/src/Obj/Base/BatchModel/_element_拓展.js b/src/Obj/Base/BatchModel/_element_拓展.js new file mode 100644 index 0000000..e64eaa5 --- /dev/null +++ b/src/Obj/Base/BatchModel/_element_拓展.js @@ -0,0 +1,229 @@ +import { attributeElm } from '../../Element/elm_html' + +function html(that) { + return ` + +
+
+
+ 颜色 +
+
+
+
+
+
+ +
+
+
+
+
添加方式 +
+
+
+
+
+
+
+ 朝向偏移 +
+ + ° + +
+
+
+
+
+

模型间隔

+
+
+
+ + 自定义距离 +
+
+
+
+ + 固定距离 +
+
+
+ 模型间隔 +
+ + + +
+
+
+

线型选择

+
+
+
+ + 折线 +
+
+
+
+ + 曲线 +
+
+
+ 线条数量 +
+ + + +
+
+
+ 线条间隔 +
+ + + +
+
+
+
+
+
+ + 随机采样 +
+
+
+ 随机数量 +
+ + + +
+
+
+
+
+
+
+ + 网格采样 +
+
+
+ 首边间隔 +
+ + + +
+
+
+ 次边间隔 +
+ + + +
+
+
+
+ +
+ + +
+
+ 高度模式 +
+
+
+
+
+
+
缩放 +
+ + 是否等比例缩放 +
+
+
+
+
+
+ +
+
+
+ 新增模型风格设置 + +
+
+ +
+
+ +
+
+ 显隐 + +
+
+ 图标 +
+ +
+
+
+ 默认图标 +
+ +
+
+
+ 图标倍数 +
+ + + +
+
+
+
+
+

文字设置

+
+
+ 显隐 + +
+
+ 字体选择 +
+
+
+ 文字大小 +
+ + px + +
+
+
+ 文字颜色 +
+
+
+
+
+
+
+ + ` +} + +export { html } diff --git a/src/Obj/Base/BatchModel/index.js b/src/Obj/Base/BatchModel/index.js index d61e6cd..a42c94e 100644 --- a/src/Obj/Base/BatchModel/index.js +++ b/src/Obj/Base/BatchModel/index.js @@ -48,7 +48,7 @@ class BatchModel extends Base { this.sdk.addIncetance(this.options.id, this) // BatchModel.computeDis(this) // if (this.options.positions.length > 0 || this.options.positions.lng) { - if (options.type && options.spacing != undefined) { + if ((options.type && options.spacing != undefined) || options.type == '点') { // BatchModel.computeDis(this) let Draw diff --git a/src/Obj/Base/BillboardObject/index.js b/src/Obj/Base/BillboardObject/index.js index c6275ee..8a222b8 100644 --- a/src/Obj/Base/BillboardObject/index.js +++ b/src/Obj/Base/BillboardObject/index.js @@ -40,6 +40,11 @@ import { import { getGoodsList } from '../../../Tools/getGoodsList' class BillboardObject extends Base { + #_postRenderEvent = null + #_destroyMouseEvent = null + #_billboardHeight = 0 + + /** * @constructor * @description 创建点标注 @@ -118,6 +123,7 @@ class BillboardObject extends Base { this.options.positions.alt = Number( Number(options.positions.alt || 0).toFixed(2) ) + this.#_billboardHeight = this.options.positions.alt // this.options.diffuseShow = options.diffuseShow || false // this.options.diffuseRadius = (options.diffuseRadius || options.diffuseRadius === 0) ? options.diffuseRadius : 10 // this.options.diffuseDuration = (options.diffuseDuration || options.diffuseDuration === 0) ? options.diffuseDuration : 2000 @@ -145,11 +151,18 @@ class BillboardObject extends Base { this.options.attribute.goods.content || [] this.options.attributeType = options.attributeType || 'richText' this.options.coordinate = options.coordinate || '' + this.options.attributeBoxState = options.attributeBoxState || false this.operate = {} this._elms = {} this.previous = { positions: { ...this.options.positions } } + this.options.attributePos = options.attributePos || { + x: 60, + y: 60, + width: 200, + height: 120 + } this.entity this._proj = this.sdk.proj @@ -182,7 +195,109 @@ class BillboardObject extends Base { + this.#_destroyMouseEvent = () => { + this.attributeElm && (this.attributeElm.style.pointerEvents = 'unset') + this.sdk.viewer._element.onmousemove = null + document.removeEventListener('mouseup', this.#_destroyMouseEvent) + document.removeEventListener('mouseleave', this.#_destroyMouseEvent) + } + this.#_postRenderEvent = () => { + let siteInfoPosition = Cesium.Cartesian3.fromDegrees( + this.options.positions.lng, + this.options.positions.lat, + this.#_billboardHeight + ) + if (this.attributeElm && this.entity) { + let winpos = this.sdk.viewer.scene.cartesianToCanvasCoordinates( + siteInfoPosition + ) + let pixelOffset = this.entity.label.pixelOffset.getValue() + if (winpos) { + let scale = getCurrentBillboardScale(this.entity, this.sdk.viewer.scene) + let height = ((this.entity.billboard.height.getValue() * (this.options.billboard.scale || 0)) + this.options.label.fontSize) * (1 - (scale * scale)) + let flag = false + let lineElm = this.attributeElm.getElementsByClassName('billboard-attribute-box-line')[0] + let leftTopElm = this.attributeElm.getElementsByClassName('left-top')[0] + let rightTopElm = this.attributeElm.getElementsByClassName('right-top')[0] + this.attributeElm.style.left = (winpos.x + this.options.attributePos.x).toFixed(0) + 'px' + this.attributeElm.style.top = (winpos.y + pixelOffset.y - (this.options.label.show ? (this.options.label.fontSize / 2) : -(this.options.label.fontSize / 2)) - this.attributeElm.offsetHeight - this.options.attributePos.y + height).toFixed(0) + 'px' + this.attributeElm.style.width = this.options.attributePos.width + 'px' + this.attributeElm.style.height = this.options.attributePos.height + 'px' + lineElm.style.zIndex = '-1' + if (this.options.attributePos.x < -this.options.attributePos.width / 2) { + flag = true + lineElm.style.left = 'unset' + lineElm.style.right = '0' + leftTopElm.style.display = 'block' + rightTopElm.style.display = 'none' + } + else { + lineElm.style.left = '0' + lineElm.style.right = 'unset' + leftTopElm.style.display = 'none' + rightTopElm.style.display = 'block' + } + + let lineLength + let lineAngleRad + let lineAngle + let x + let y + if (flag) { + x = this.attributeElm.offsetWidth + this.options.attributePos.x + y = this.options.attributePos.y ? this.options.attributePos.y : 0 + } + else { + x = this.options.attributePos.x + y = this.options.attributePos.y ? this.options.attributePos.y : 0 + } + lineLength = Math.sqrt((x * x) + (y * y)).toFixed(2); + lineAngleRad = Math.atan(x / y); + lineAngle = parseFloat((lineAngleRad * 180 / Math.PI).toFixed(2)); + if (this.options.attributePos.y < 0) { + lineAngle = lineAngle + 180 + } + // if(this.options.attributePos.y<-this.options.attributePos.height/2) { + // lineElm.style.bottom = 'unset' + // lineElm.style.top = '0' + // } + // else { + // lineElm.style.bottom = -lineLength + 'px' + // lineElm.style.top = 'unset' + // } + lineElm.style.height = lineLength + 'px' + lineElm.style.transform = 'rotate(' + lineAngle + 'deg)' + } + } + } + + function getCurrentBillboardScale(entity, scene) { + // 获取相机到Billboard的距离 + const distance = Cesium.Cartesian3.distance( + scene.camera.positionWC, + entity.position.getValue() + ); + // 获取缩放距离配置 + const scaleByDistance = entity.billboard.scaleByDistance ? entity.billboard.scaleByDistance.getValue() : undefined; + + if (!scaleByDistance) { + // 如果没有设置距离缩放,则使用基础缩放值 + return 1.0; + } + + // 解析缩放距离参数 [near, nearScale, far, farScale] + const { near, nearValue, far, farValue } = scaleByDistance; + if (distance <= near) { + return nearValue; + } else if (distance >= far) { + return farValue; + } else { + // 计算中间距离的缩放值(线性插值) + const t = (distance - near) / (far - near); + return Cesium.Math.lerp(nearValue, farValue, t); + } + } this.sdk.addIncetance(this.options.id, this) @@ -243,6 +358,7 @@ class BillboardObject extends Base { that.entity.billboard.imgHeight = 0 that.entity.billboard.image = canvas addCluster(that.sdk, that.entity) + that.attributeBoxState && (that.attributeBoxState = true) } return } @@ -267,6 +383,7 @@ class BillboardObject extends Base { return img }, false) addCluster(that.sdk, that.entity) + that.attributeBoxState && (that.attributeBoxState = true) } }) } @@ -298,6 +415,7 @@ class BillboardObject extends Base { that.entity.billboard.imgHeight = height that.entity.billboard.image = canvas addCluster(that.sdk, that.entity) + that.attributeBoxState && (that.attributeBoxState = true) } } image.onerror = function (err) { @@ -309,6 +427,7 @@ class BillboardObject extends Base { that.entity.billboard.imgHeight = 0 that.entity.billboard.image = canvas addCluster(that.sdk, that.entity) + that.attributeBoxState && (that.attributeBoxState = true) } }; } @@ -465,15 +584,36 @@ class BillboardObject extends Base { return this.options.show } set show(v) { - if(!this.isShowView) { + if (!this.isShowView) { this.options.show = v this.originalOptions.show = v } - if(!this.showView || this.showView == 3) { + if (!this.showView || this.showView == 3) { this.entity && (this.entity.show = this.options.show) + if (this.attributeBoxState && this.options.show) { + this.attributeBoxState = this.options.show + } + else { + // 关闭属性框 + document.addEventListener('mouseup', this.#_destroyMouseEvent); + document.addEventListener('mouseleave', this.#_destroyMouseEvent); + if (this.attributeElm) { + this.sdk.viewer._element.removeChild(this.attributeElm) + this.attributeElm = null + } + this.sdk.viewer.scene.postRender.removeEventListener(this.#_postRenderEvent) + } } else { this.entity && (this.entity.show = false) + // 关闭属性框 + document.addEventListener('mouseup', this.#_destroyMouseEvent); + document.addEventListener('mouseleave', this.#_destroyMouseEvent); + if (this.attributeElm) { + this.sdk.viewer._element.removeChild(this.attributeElm) + this.attributeElm = null + } + this.sdk.viewer.scene.postRender.removeEventListener(this.#_postRenderEvent) } syncData(this.sdk, this.options.id) syncSplitData(this.sdk, this.options.id) @@ -562,6 +702,26 @@ class BillboardObject extends Base { if (this.entity) { this.entity.billboard.heightReference = heightMode this.entity.label.heightReference = heightMode + if(heightMode == Cesium.HeightReference.CLAMP_TO_GROUND) { + if (this.sdk.viewer.scene.terrainProvider.availability) { + Cesium.sampleTerrainMostDetailed( + this.sdk.viewer.scene.terrainProvider, + [ + Cesium.Cartographic.fromDegrees( + this.options.positions.lng, + this.options.positions.lat + ) + ] + ).then(position => { + this.#_billboardHeight = position[0].height + }) + } else { + this.#_billboardHeight = 0 + } + } + else { + this.#_billboardHeight = this.options.positions.alt + } } this._elms.heightMode && (this._elms.heightMode.value = heightModeName) } @@ -616,6 +776,7 @@ class BillboardObject extends Base { } set alt(v) { this.options.positions.alt = Number(Number(v).toFixed(2)) + this.#_billboardHeight = this.options.positions.alt // this.scan && (this.scan.alt = v) // this.diffuse && (this.diffuse.alt = v) this.renewPoint() @@ -1716,6 +1877,22 @@ class BillboardObject extends Base { this.cameraSelect && this.cameraSelect() this.ISCSelect && this.ISCSelect() this.goodsSelect && this.goodsSelect() + + let col = document.createElement('div') + col.className = 'col' + col.style.flex = '0 0 110px' + col.innerHTML = ` + 属性框 + + ` + + let row = this._DialogObject._element.content.getElementsByClassName('attribute')[0].getElementsByClassName('row')[0] + row.appendChild(col) + let boxSwitch = col.getElementsByClassName('btn-switch')[0] + boxSwitch.checked = this.attributeBoxState + boxSwitch.addEventListener('change', (e) => { + this.attributeBoxState = boxSwitch.checked + }) let tagData = this.attributeSelect let attributeElm = this._DialogObject._element.content.getElementsByClassName( 'attribute-select-box' @@ -2227,6 +2404,7 @@ class BillboardObject extends Base { this.attributeCamera = this.options.attribute.camera.content this.attributeGoods = this.options.attribute.goods.content this.attributeISC = this.options.attribute.ISC.content + this.attributeBoxState = this.options.attributeBoxState this.cameraSelect && this.cameraSelect() this.goodsSelect && this.goodsSelect() } @@ -2234,6 +2412,7 @@ class BillboardObject extends Base { async remove() { await remove_entity_from_cluster(this.sdk.viewer, this.entity) this.entity = null + this.attributeBoxState = false if (!this.sdk.viewer || !this.sdk.viewer.entities) { return } @@ -2424,6 +2603,7 @@ class BillboardObject extends Base { } if (height !== undefined) { this.options.positions.alt = Number(Number(height).toFixed(2)) + this.#_billboardHeight = this.options.positions.alt this._elms.alt && this._elms.alt.forEach(item => { item.value = this.options.positions.alt @@ -2439,6 +2619,7 @@ class BillboardObject extends Base { switch (this._elms.heightMode.value) { case '海拔高度': heightElm.value = this.options.positions.alt + this.#_billboardHeight = this.options.positions.alt break case '相对地表': if (this.sdk.viewer.scene.terrainProvider.availability) { @@ -2454,15 +2635,18 @@ class BillboardObject extends Base { heightElm.value = Number( (this.options.positions.alt - position[0].height).toFixed(2) ) + this.#_billboardHeight = this.options.positions.alt }) } else { heightElm.value = this.options.positions.alt + this.#_billboardHeight = this.options.positions.alt } break case '依附地表': break case '依附模型': heightElm.value = this.options.positions.alt + this.#_billboardHeight = this.options.positions.alt break } } @@ -2736,6 +2920,216 @@ class BillboardObject extends Base { (this.originalOptions.customView = this.options.customView) } } + + get attributeBoxState() { + return this.options.attributeBoxState + } + + set attributeBoxState(state) { + state = state ? true : false + this.options.attributeBoxState = state + document.addEventListener('mouseup', this.#_destroyMouseEvent); + document.addEventListener('mouseleave', this.#_destroyMouseEvent); + if (this.attributeElm) { + this.sdk.viewer._element.removeChild(this.attributeElm) + this.attributeElm = null + } + this.sdk.viewer.scene.postRender.removeEventListener(this.#_postRenderEvent) + if (state && this.sdk && this.sdk.viewer && this.sdk.viewer._element && this.show) { + let attributeElm = document.createElement('div') + this.attributeElm = attributeElm + attributeElm.className = 'billboard-attribute-box' + attributeElm.style.top = '0px' + attributeElm.style.left = '0px' + attributeElm.style.width = 0 + attributeElm.style.height = 0 + // attributeElm.innerHTML = this.options.richTextContent + this.sdk.viewer._element.appendChild(attributeElm) + let linkHtml = '' + let goodsHtml = '' + let richTextHtml = '' + for (let i = 0; i < this.options.attribute.link.content.length; i++) { + linkHtml += `` + } + if (this.options.attribute.goods && this.options.attribute.goods.content && this.options.attribute.goods.content.length > 0) { + goodsHtml += ` +
+
+
+
序号
+
名称
+
数量
+
+
+
+ ` + for (let i = 0; i < this.options.attribute.goods.content.length; i++) { + goodsHtml += `
+
${i + 1}
+
${this.options.attribute.goods.content[i].name}
+
${this.options.attribute.goods.content[i].cnt}
+
` + } + goodsHtml += `
` + } + if (this.options.richTextContent) { + richTextHtml = ` + ${this.options.richTextContent} + ` + } + + let boxHtml = ` + + + ` + + if (!linkHtml && !goodsHtml && !richTextHtml) { + boxHtml = boxHtml + '

暂无属性信息

' + } + else { + boxHtml = boxHtml + ` + + ${richTextHtml} + ${goodsHtml} + ${linkHtml} + +
` + } + + attributeElm.innerHTML = boxHtml + + if (attributeElm.getElementsByClassName('tabs')[0]) { + let tabsElm = new cy_tabs(attributeElm.getElementsByClassName('tabs')[0], undefined, this.sdk) + } + + let imgElm = attributeElm.getElementsByTagName('img') + for (let i = 0; i < imgElm.length; i++) { + if (!imgElm[i].style.width) { + imgElm[i].style.width = '100%' + } + } + + this.sdk.viewer.scene.postRender.addEventListener(this.#_postRenderEvent) + let leftOnmousedown = (e) => { + if (this.options.attributePos.width < 200) { + this.options.attributePos.width = 200 + } + if (this.options.attributePos.height < 120) { + this.options.attributePos.height = 120 + } + let x = e.x + let y = e.y + let width = this.options.attributePos.width + let height = this.options.attributePos.height + let positionx = this.options.attributePos.x + this.sdk.viewer._element.onmousemove = (e2) => { + this.options.attributePos.width = width + (x - e2.x) + this.options.attributePos.height = height + (y - e2.y) + if (this.options.attributePos.width < 200) { + this.options.attributePos.width = 200 + } + else { + this.options.attributePos.x = positionx - (x - e2.x) + } + if (this.options.attributePos.height < 120) { + this.options.attributePos.height = 120 + } + // this.options.attributePos.y = positiony + (y - e2.y) + } + document.addEventListener('mouseup', this.#_destroyMouseEvent); + document.addEventListener('mouseleave', this.#_destroyMouseEvent); + } + let rightOnmousedown = (e) => { + let x = e.x + let y = e.y + if (this.options.attributePos.width < 200) { + this.options.attributePos.width = 200 + } + if (this.options.attributePos.height < 120) { + this.options.attributePos.height = 120 + } + let width = this.options.attributePos.width + let height = this.options.attributePos.height + this.sdk.viewer._element.onmousemove = (e2) => { + this.options.attributePos.width = width + (e2.x - x) + this.options.attributePos.height = height + (y - e2.y) + } + document.addEventListener('mouseup', this.#_destroyMouseEvent); + document.addEventListener('mouseleave', this.#_destroyMouseEvent); + } + // leftTopElm.onmousedown = (e) => { + // console.log(1111111111) + // if (this.options.attributePos.width < 200) { + // this.options.attributePos.width = 200 + // } + // if (this.options.attributePos.height < 120) { + // this.options.attributePos.height = 120 + // } + // let x = e.x + // let y = e.y + // let width = this.options.attributePos.width + // let height = this.options.attributePos.height + // let positionx = this.options.attributePos.x + // this.sdk.viewer._element.onmousemove = (e2) => { + // this.options.attributePos.width = width + (x - e2.x) + // this.options.attributePos.height = height + (y - e2.y) + // if (this.options.attributePos.width < 200) { + // this.options.attributePos.width = 200 + // } + // else { + // this.options.attributePos.x = positionx - (x - e2.x) + // } + // if (this.options.attributePos.height < 120) { + // this.options.attributePos.height = 120 + // } + // // this.options.attributePos.y = positiony + (y - e2.y) + // } + // document.addEventListener('mouseup', this.#_destroyMouseEvent); + // document.addEventListener('mouseleave', this.#_destroyMouseEvent); + // } + // rightTopElm.onmousedown = (e) => { + // let x = e.x + // let y = e.y + // if (this.options.attributePos.width < 200) { + // this.options.attributePos.width = 200 + // } + // if (this.options.attributePos.height < 120) { + // this.options.attributePos.height = 120 + // } + // let width = this.options.attributePos.width + // let height = this.options.attributePos.height + // this.sdk.viewer._element.onmousemove = (e2) => { + // this.options.attributePos.width = width + (e2.x - x) + // this.options.attributePos.height = height + (y - e2.y) + // } + // document.addEventListener('mouseup', this.#_destroyMouseEvent); + // document.addEventListener('mouseleave', this.#_destroyMouseEvent); + // } + + attributeElm.onmousedown = (e) => { + attributeElm.style.pointerEvents = 'none' + if (e.target.className.indexOf('left-top') != -1) { + leftOnmousedown(e) + } + else if (e.target.className.indexOf('right-top') != -1) { + rightOnmousedown(e) + } + else { + let x = e.x + let y = e.y + let oldX = this.options.attributePos.x + let oldXY = this.options.attributePos.y + let height = this.options.attributePos.height + this.sdk.viewer._element.onmousemove = (e2) => { + this.options.attributePos.x = oldX + (e2.x - x) + this.options.attributePos.y = oldXY - (e2.y - y) + } + document.addEventListener('mouseup', this.#_destroyMouseEvent); + document.addEventListener('mouseleave', this.#_destroyMouseEvent); + } + } + } + } } export default BillboardObject diff --git a/src/Obj/Base/LabelObject/index.js b/src/Obj/Base/LabelObject/index.js index 5b127cd..322dd8a 100644 --- a/src/Obj/Base/LabelObject/index.js +++ b/src/Obj/Base/LabelObject/index.js @@ -14,6 +14,8 @@ import { class LabelObject extends Base { #updateBillboardImageTimeout + #canvas = document.createElement('canvas') + #canvas2 = document.createElement('canvas') constructor(sdk, options = {}, model) { super(sdk, options) this.model = model @@ -438,11 +440,12 @@ class LabelObject extends Base { this.updateBillboardImage() } updateBillboardImage() { - clearTimeout(this.#updateBillboardImageTimeout) - this.#updateBillboardImageTimeout = setTimeout(() => { - clearTimeout(this.#updateBillboardImageTimeout) - this.entity && (this.entity.billboard.image = this.getcanvas()) - }, 500) + this.entity.billboard.image = this.getcanvas() + // clearTimeout(this.#updateBillboardImageTimeout) + // this.#updateBillboardImageTimeout = setTimeout(() => { + // clearTimeout(this.#updateBillboardImageTimeout) + // this.entity.billboard.image = this.getcanvas() + // }, 500) } get lineColor() { return this.options.pixelOffset @@ -489,9 +492,8 @@ class LabelObject extends Base { // } getcanvas() { - const canvas = document.createElement('canvas') - const ctx = canvas.getContext('2d') - + const ctx = this.#canvas.getContext('2d') + ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height); ctx.font = this.options.fontSize + 'px ' + this.font let texts = this.options.text.split('\n') let canvasWidth = 0 @@ -509,9 +511,8 @@ class LabelObject extends Base { if (canvasWidth < this.options.lineWidth) { canvasWidth = this.options.lineWidth } - canvas.width = canvasWidth - - canvas.height = this.options.pixelOffset + canvasHeight + this.#canvas.width = canvasWidth + this.#canvas.height = this.options.pixelOffset + canvasHeight const linearGradient = ctx.createLinearGradient( 0, 0, @@ -558,15 +559,14 @@ class LabelObject extends Base { ctx.stroke() ctx.closePath() - const canvas2 = document.createElement('canvas') - const ctx2 = canvas2.getContext('2d') - canvas2.width = canvas.width + 10 - canvas2.height = canvas.height + 10 - ctx2.drawImage(canvas, 5, 5); + const ctx2 = this.#canvas2.getContext('2d') + this.#canvas2.width = this.#canvas.width + 10 + this.#canvas2.height = this.#canvas.height + 10 + ctx2.drawImage(this.#canvas, 5, 5); // const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); // ctx.putImageData(imageData, 40, 40); - return canvas2 + return this.#canvas2.toDataURL("image/png") } remove() { diff --git a/src/Obj/Base/Road/index.js b/src/Obj/Base/Road/index.js index bb43225..2e946f1 100644 --- a/src/Obj/Base/Road/index.js +++ b/src/Obj/Base/Road/index.js @@ -5,7 +5,7 @@ class Corridor extends Base { // /** // * @constructor // * @description 道路 - // * @param sdk + // * @param sdk // * @param options {object} 属性 // * @param options.name{string} 名称 // * @param options.image{string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} 指定 Image、URL、Canvas 或 Video 的属性 @@ -67,7 +67,7 @@ class Corridor extends Base { // material: new Cesium.ImageMaterialProperty({ // image: this.options.image, // repeat: new Cesium.Cartesian2(100, 1.0), - // color: Cesium.Color.TOMATO + // color: Cesium.Color.TOMATO // }) // } // }); @@ -217,10 +217,10 @@ class Corridor extends Base { let aa = 0 const shader = ` - uniform sampler2D image; + uniform sampler2D image; uniform vec4 color; uniform vec2 repeat; - + czm_material czm_getMaterial(czm_materialInput materialInput){ czm_material material=czm_getDefaultMaterial(materialInput); mat2 rotationMatrix = mat2(cos(radians(-rotate)), sin(radians(-rotate)), -sin(radians(-rotate)), cos(radians(-rotate))); diff --git a/src/Obj/Base/RoadObject/_element.js b/src/Obj/Base/RoadObject/_element.js new file mode 100644 index 0000000..49b49dc --- /dev/null +++ b/src/Obj/Base/RoadObject/_element.js @@ -0,0 +1,39 @@ +function html() { + return ` + +
+
+
+ 名称 + +
+
+ 道路类型 +
+
+
+
+ +
+
+
+ 车道宽度 +
+ + +
+
+
+ 人行道宽度 +
+ + +
+
+
+
+ + ` +} + +export { html } diff --git a/src/Obj/Base/RoadObject/eventBinding.js b/src/Obj/Base/RoadObject/eventBinding.js new file mode 100644 index 0000000..ccbf026 --- /dev/null +++ b/src/Obj/Base/RoadObject/eventBinding.js @@ -0,0 +1,92 @@ +class eventBinding { + constructor() { + this.element = {} + } + static event = {} + + getEvent(name) { + return eventBinding.event[name] + } + + getEventAll() { + return eventBinding.event + } + + setEvent(name, event) { + eventBinding.event[name] = event + } + + on(that, elements) { + for (let i = 0; i < elements.length; i++) { + let Event = [] + let isEvent = false + let removeName = [] + if (!elements[i] || !elements[i].attributes) { + continue; + } + for (let m of elements[i].attributes) { + switch (m.name) { + case '@model': { + isEvent = true + if (elements[i].type == 'checkbox') { + Event.push((e) => { that[m.value] = e.target.checked }) + elements[i].checked = that[m.value] + } + else { + Event.push((e) => { + let value = e.target.value + if (e.target.type == 'number') { + value = Number(value) + } + that[m.value] = value + }) + if (elements[i].nodeName == 'IMG') { + elements[i].src = that[m.value] + } + else { + elements[i].value = that[m.value] + } + } + if (this.element[m.value]) { + this.element[m.value].push(elements[i]) + } + else { + this.element[m.value] = [elements[i]] + } + removeName.push(m.name) + break; + } + case '@click': { + elements[i].addEventListener('click', (e) => { + if (typeof (that.Dialog[m.value]) === 'function') { + that.Dialog[m.value](e) + } + }); + removeName.push(m.name) + // elements[i].attributes.removeNamedItem(m.name) + break; + } + } + // elements[i].attributes[m] = undefined + } + for (let n = 0; n < removeName.length; n++) { + elements[i].attributes.removeNamedItem(removeName[n]) + } + + if (isEvent) { + let ventType = 'input' + if (elements[i].tagName != 'INPUT' || elements[i].type == 'checkbox') { + ventType = 'change' + } + elements[i].addEventListener(ventType, (e) => { + for (let t = 0; t < Event.length; t++) { + Event[t](e) + } + }); + } + } + } +} + +const EventBinding = new eventBinding(); +export default EventBinding; \ No newline at end of file diff --git a/src/Obj/Base/RoadObject/index-8.4.js b/src/Obj/Base/RoadObject/index-8.4.js new file mode 100644 index 0000000..48f1d50 --- /dev/null +++ b/src/Obj/Base/RoadObject/index-8.4.js @@ -0,0 +1,1549 @@ +/** + * @description 道路 + */ +import Dialog from '../../Element/Dialog'; +import { html } from "./_element"; +import EventBinding from '../../Element/Dialog/eventBinding'; +import Base from "../index"; +import { syncData } from '../../../Global/MultiViewportMode' +import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen' +import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' + +class Road extends Base { + /** + * @constructor + * @param sdk + * @description 道路 + * @param options {object} 道路属性 + * @param options.name=未命名对象 {string} 名称 + * @param options.carRoadWidth=2 {number} 车道宽度 + * @param options.sideWidth=2 {number} 人行道宽度 + * @param options.positions=[] {array} 道路positions + * @param options.roadImage='' {string} 车道贴图 + * @param options.sideImage='' {string} 人行道贴图 + * @param Dialog {object} 弹框对象 + * @param Dialog.confirmCallBack {function} 弹框确认时的回调 + * */ + constructor(sdk, options = {}, _Dialog = {}) { + super(sdk, options); + this.viewer = this.sdk.viewer + this.options.name = options.name || '道路' + this.options.carRoadWidth = options.carRoadWidth || 10 + this.options.sideWidth = options.sideWidth || 5 + this.options.positions = options.positions || [] + this.options.roadImage = options.roadImage || (this.getSourceRootPath() + '/img/roadPhoto.png') + this.options.sideImage = options.sideImage || (this.getSourceRootPath() + '/img/sidePhoto.png') + this.options.show = (options.show || options.show === false) ? options.show : true + this.Dialog = _Dialog + this._EventBinding = new EventBinding() + this._elms = {}; + this.positionArea = [] + this.positions = [] + this.lineEntity = '' + this.crossArr = [] + this.pointArr = [] + this.positionChangeIndex = [] + + this.sdk.addIncetance(this.options.id, this) + Road.create(this) + } + // 创建道路 + static create(that) { + let positions = [] + that.options.positions.forEach(v => { + positions.push(new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) + }) + let newPosi = [] + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + const end = positions[i + 1]; + newPosi.push([start, end]) + that.pointArr = newPosi + } + + let area = [[], [], []] + + // area[1] = that.getRectangle(positions, that.options.carRoadWidth) + area[1][0] = that.getRectangle(newPosi, that.options.carRoadWidth) + let sideArr = that.getSideRectangle(area[1][0], that.options.sideWidth) + area[0] = sideArr.left + area[2] = sideArr.right + + // area[1] = that.createLineBufferPolygon2(positions, that.options.carRoadWidth / 2) + // area[1] = newPositions + // area[0] = that.createLineBufferPolygonSide(area[1][2], -that.options.sideWidth) + // area[2] = that.createLineBufferPolygonSide(area[1][1], that.options.sideWidth) + + //判断道路边是否相交 + for (let i = 0; i < area[0].length - 1; i++) { + + let leftItem = area[0][i] + let leftItem2 = area[0][i + 1] + let rightItem = area[2][i] + let rightItem2 = area[2][i + 1] + let carItem = area[1][0][i] + let carItem2 = area[1][0][i + 1] + let leftLine = that.getIntersects(leftItem[2], leftItem[3], leftItem2[2], leftItem2[3]) + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: [leftItem[2], leftItem[3]], + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: Cesium.Color.YELLOW, + // }), + // }, + // }); + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: [leftItem2[2], leftItem2[3]], + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: Cesium.Color.YELLOW, + // }), + // }, + // }); + + let rightLine = that.getIntersects(rightItem[0], rightItem[1], rightItem2[0], rightItem2[1]) + // if (!leftLine && !rightLine) { + // for (let index = 0; index < 4; index++) { + // let positions = [] + // index === 0 ? positions.push(leftItem[2], leftItem[3]) : index === 1 ? positions.push(leftItem2[2], leftItem2[3]) : index === 2 ? positions.push(rightItem[0], rightItem[1]) : positions.push(rightItem2[0], rightItem2[1]) + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: positions, + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: index === 0 ? Cesium.Color.RED : index === 1 ? Cesium.Color.BLUE : index === 2 ? Cesium.Color.YELLOW : Cesium.Color.GREEN, + // }), + // }, + // }); + + // } + // } + + + + for (let index = 0; index < 4; index++) { + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: index, + // position: area[0][i][index], + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + index + ':', + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: index, + // position: area[2][i][index], + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + index + '/', + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + } + + + if (leftLine) {//左侧相交 + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: 1, + // position: leftLine, + // billboard: { + // image: that.getSourceRootPath() + '/img/locate2.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '', + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + + //获取右侧延长交点 + let point1 = that.getExtendPoint(rightItem[0], rightItem[1], 1000) + let point2 = that.getExtendPoint(rightItem2[1], rightItem2[0], 1000) + + that.sdk.viewer.entities.add({ + polyline: { + positions: [rightItem[0], point1], + width: 2.0, + clampToGround: true, + material: new Cesium.PolylineGlowMaterialProperty({ + color: Cesium.Color.AQUA, + }), + }, + }); + that.sdk.viewer.entities.add({ + polyline: { + positions: [rightItem2[1], point2], + width: 2.0, + clampToGround: true, + material: new Cesium.PolylineGlowMaterialProperty({ + color: Cesium.Color.AQUA, + }), + }, + }); + + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: i, + position: point1, + billboard: { + image: that.getSourceRootPath() + '/img/point.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '' + 7 + "", + pixelOffset: { x: 0, y: -20 }, + }, + }) + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: i, + position: point2, + billboard: { + image: that.getSourceRootPath() + '/img/end.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '' + 7 + "", + pixelOffset: { x: 0, y: -20 }, + }, + }) + + + let rightIntersection = that.getIntersects(rightItem[0], point1, rightItem2[1], point2) + if (!rightIntersection) { + return + } + + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + + let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + + + //跟左侧里相交点 + let leftLineNei = that.getIntersects(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint) + //跟车道左侧相交点 + let carLeft = that.getIntersects(leftLine, rightIntersection, carItem[3], carLeftPoint) + + //跟车道右侧相交点 + let carRight = that.getIntersects(leftLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(leftLine, rightIntersection, rightItem[3], rightLineNeiPoint) + // let leftLineNei = that.getIntersects(leftLine, rightItem[2], leftItem[0], leftItem[3]) + // let carLeft = that.getIntersects(leftLine, rightItem[2], carItem[3], carItem[2]) + // let carRight = that.getIntersects(leftLine, rightItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, rightItem[2], rightItem[0], rightItem[3]) + + // let leftLineNei = that.getIntersects(leftLine, intersection, leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(leftLine, intersection, carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(leftLine, intersection, carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, intersection, rightItem[0], rightItem[3]) + + leftItem[2] = leftLine + leftItem[1] = leftLineNei + // carItem[2] = carLeft + carItem[2] = leftLineNei + // carItem[1] = carRight + carItem[1] = rightLineNei + rightItem[2] = rightLineNei + rightItem[1] = rightIntersection + + + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: 1, + // position: leftLineNei, + // billboard: { + // image: that.getSourceRootPath() + '/img/locate2.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '', + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: 1, + position: rightIntersection, + billboard: { + image: that.getSourceRootPath() + '/img/locate2.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '', + pixelOffset: { x: 0, y: -20 }, + }, + }) + + + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[1], leftItem2[0], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + // let leftLineNei2 = that.getIntersects(leftLine, rightItem2[1], leftItem2[0], leftItem2[3]) + // let carLeft2 = that.getIntersects(leftLine, rightItem2[1], carItem2[3], carItem2[2]) + // let carRight2 = that.getIntersects(leftLine, rightItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, rightItem2[1], rightItem2[0], rightItem2[3]) + + + + let leftLineNei2 = that.getIntersects(leftLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + let carLeft2 = that.getIntersects(leftLine, rightIntersection, carItem2[2], carLeftPoint2) + let carRight2 = that.getIntersects(leftLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(leftLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + + // let arr = [leftLine, rightIntersection, leftItem2[3], leftLineNeiPoint2] + // arr.forEach((item, index) => { + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: i, + // position: item, + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + index, + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + // }) + + // let leftLineNei2 = that.getIntersects(leftLine, intersection, leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(leftLine, intersection, carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(leftLine, intersection, carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, intersection, rightItem2[0], rightItem2[3]) + + leftItem2[3] = leftLine + leftItem2[0] = leftLineNei + // carItem2[3] = carLeft + carItem2[3] = leftLineNei + // carItem2[0] = carRight + carItem2[0] = rightLineNei + rightItem2[3] = rightLineNei + rightItem2[0] = rightIntersection + + + } else if (rightLine) {//右侧相交 + + //获取左侧延长交点 + let point1 = that.getExtendPoint(leftItem[3], leftItem[2], 1000) + let point2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + + that.sdk.viewer.entities.add({ + polyline: { + positions: [leftItem[3], point1], + width: 2.0, + clampToGround: true, + material: new Cesium.PolylineGlowMaterialProperty({ + color: Cesium.Color.AQUA, + }), + }, + }); + that.sdk.viewer.entities.add({ + polyline: { + positions: [leftItem2[2], point2], + width: 2.0, + clampToGround: true, + material: new Cesium.PolylineGlowMaterialProperty({ + color: Cesium.Color.AQUA, + }), + }, + }); + + let rightIntersection = that.getIntersects(leftItem[3], point1, leftItem2[2], point2) + if (!rightIntersection) { + return + } + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + // //跟左侧里相交点 + let leftLineNei = that.getIntersects(rightLine, rightIntersection, leftItem[0], leftLineNeiPoint) + //跟车道左侧相交点 + let carLeft = that.getIntersects(rightLine, rightIntersection, carItem[3], carLeftPoint) + //跟车道右侧相交点 + let carRight = that.getIntersects(rightLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(rightLine, rightIntersection, rightItem[3], rightLineNeiPoint) + // //跟左侧里相交点 + // let leftLineNei = that.getIntersects(rightLine, leftItem[2], leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(rightLine, leftItem[2], carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(rightLine, leftItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(rightLine, leftItem[2], rightItem[0], rightItem[3]) + + + leftItem[2] = rightIntersection + leftItem[1] = leftLineNei + // carItem[2] = carLeft + carItem[2] = leftLineNei + // carItem[1] = carRight + carItem[1] = rightLineNei + rightItem[2] = rightLineNei + rightItem[1] = rightLine + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + let leftLineNei2 = that.getIntersects(rightLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + //跟车道左侧相交点 + let carLeft2 = that.getIntersects(rightLine, rightIntersection, carItem2[2], carLeftPoint2) + //跟车道右侧相交点 + let carRight2 = that.getIntersects(rightLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(rightLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + // let leftLineNei2 = that.getIntersects(rightLine, leftItem2[1], leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(rightLine, leftItem2[1], carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(rightLine, leftItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(rightLine, leftItem2[1], rightItem2[0], rightItem2[3]) + + leftItem2[3] = rightIntersection + leftItem2[0] = leftLineNei + // carItem2[3] = carLeft + carItem2[3] = leftLineNei + // carItem2[0] = carRight + carItem2[0] = rightLineNei + rightItem2[3] = rightLineNei + rightItem2[0] = rightLine + + // leftItem[2] = rightIntersection + // leftItem[1] = leftLineNei + // // carItem[2] = carLeft + // carItem[2] = leftLineNei + // // carItem[1] = carRight + // carItem[1] = rightLineNei + // rightItem[2] = rightLineNei + // rightItem[1] = rightLine + } + + // area[0][i] = leftItem + // area[0][i + 1] = leftItem2 + // area[2][i] = rightItem + // area[2][i + 1] = rightItem2 + // area[1][0][i] = carItem + // area[1][0][i + 1] = carItem2 + } + if (that.viewer.entities.getById(that.options.id)) { + that.viewer.entities.getById(that.options.id)._children.forEach((item) => { + that.viewer.entities.remove(item); + }); + that.viewer.entities.remove(that.viewer.entities.getById(that.options.id)) + } + that.lineEntity = that.viewer.entities.add(new Cesium.Entity({ id: that.options.id, show: that.options.show })) + + const myImg = new Image() + myImg.src = that.options.roadImage + myImg.onload = function () { + area[1][0].forEach((item, index) => { + that.viewer.entities.add({ + // id: that.options.id, + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, + classificationType: Cesium.ClassificationType.BOTH, + distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), + material: new Cesium.ImageMaterialProperty({ + image: that.options.roadImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg) + }), + // stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + stRotation: that.calculateRoadAngle(item[0], item[1]) + // material: Cesium.Color.fromRandom({ alpha: 0.5 }), + } + }); + }) + } + + const myImg2 = new Image() + myImg2.src = that.options.sideImage + myImg2.onload = function () { + area[0].forEach((item, index) => { + that.viewer.entities.add({ + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + // material: Cesium.Color.fromRandom({ alpha: 0.5 }), + } + }); + }) + + area[2].forEach((item, index) => { + that.viewer.entities.add({ + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + // material: Cesium.Color.fromRandom({ alpha: 0.5 }), + } + }); + }) + } + + } + getSideRectangle(positions, width) { + let right = [] + let left = [] + let that = this + positions.forEach((item, i) => { + // console.log(that.positionChangeIndex, 'positionChangeIndex') + // if (that.positionChangeIndex[i + '']) { + // console.log('1111') + // right.push([item[2], item[3]]) + // left.push([item[0], item[1]]) + // } else { + right.push([item[0], item[1]]) + // left.push([item[2], item[3]]) + left.push([item[3], item[2]]) + // } + + + for (let index = 0; index < 2; index++) { + let ArrArr = [] + index === 0 ? ArrArr.push(item[0], item[1]) : ArrArr.push(item[2], item[3]); + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: ArrArr, + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: index === 0 ? Cesium.Color.RED : Cesium.Color.BLUE, + // }), + // }, + // }); + } + }) + let rightPosi = that.getRectangle(right, width, 'side') + let newRightPosi = [] + right.forEach((item, index) => { + newRightPosi.push([rightPosi[index][0], rightPosi[index][1], item[1], item[0]]) + }) + + + let leftPosi = this.getRectangle(left, width, 'side') + let newLeftPosi = [] + left.forEach((item, index) => { + // newLeftPosi.push([item[0], item[1], leftPosi[index][2]], leftPosi[index][3]) + newLeftPosi.push([item[0], item[1], leftPosi[index][2], leftPosi[index][3]]) + }) + return { left: newLeftPosi, right: newRightPosi } + } + getRectangle(positions, width, type) { + let areaArr = [] + let newPositions = [] + let that = this + // for (let i = 0; i < positions.length - 1; i++) { + for (let i = 0; i < positions.length; i++) { + const start = positions[i][0]; + const end = positions[i][1]; + + + areaArr[i] = [] + let posi = [] + let Outlinegeometry = new Cesium.CorridorGeometry({ + positions: [start, end], + width: width, + cornerType: Cesium.CornerType.MITERED, + vertexFormat: Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat + }) + let geometry = Cesium.CorridorGeometry.createGeometry(Outlinegeometry) + for (let j = 0; j < geometry.attributes.position.values.length; j += 3) { + let val = that.cartesian3Towgs84(new Cesium.Cartesian3(geometry.attributes.position.values[j], geometry.attributes.position.values[j + 1], geometry.attributes.position.values[j + 2]), that.sdk.viewer) + posi.push([val.lng, val.lat]) + } + + for (let x = 0; x < geometry.indices.length; x += 3) { + areaArr[i].push(turf.polygon([[posi[geometry.indices[x]], posi[geometry.indices[x + 1]], posi[geometry.indices[x + 2]], posi[geometry.indices[x]]]])) + } + + let geojson = turf.union(areaArr[i][0], areaArr[i][1]); + let arr = [] + geojson.geometry.coordinates[0].pop() + geojson.geometry.coordinates[0].forEach(item => { + arr.push(new Cesium.Cartesian3.fromDegrees(item[0], item[1])) + }) + let dotResult, angle + const tempVec = new Cesium.Cartesian3(); + + // 计算并归一化第一个向量 + const vector1 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(that.pointArr[i][1], that.pointArr[i][0], tempVec), + tempVec + ); + + // 计算并归一化第二个向量 + const vector2 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(arr[1], arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + dotResult = Cesium.Cartesian3.dot(vector1, vector2); + if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + // let newArr = [] + // newArr[0] = arr[2] + // newArr[1] = arr[3] + // newArr[2] = arr[0] + // newArr[3] = arr[1] + // newPositions.push(newArr) + //判断方向是否正确 + const vec1 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(start, arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + // 计算并归一化第二个向量 + const vec2 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(arr[1], arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + let dRst = Cesium.Cartesian3.dot(vec1, vec2); + + + if (0 < dRst && dRst < 0.0001) { + newPositions.push(arr) + } else { + + let dis1 = that.distancePointToLine(start, arr[0], arr[1]) + let dis2 = that.distancePointToLine(start, arr[2], arr[3]) + let newArr = [] + if (dis1 > dis2) {// + newArr[0] = arr[3] + newArr[1] = arr[0] + newArr[2] = arr[1] + newArr[3] = arr[2] + } else { + newArr[0] = arr[2] + newArr[1] = arr[3] + newArr[2] = arr[0] + newArr[3] = arr[1] + } + newPositions.push(newArr) + + + // let newArr = [] + // newArr[0] = arr[2] + // newArr[1] = arr[3] + // newArr[2] = arr[0] + // newArr[3] = arr[1] + // newPositions.push(newArr) + } + + // newPositions.push(arr) + + if (!type) { + for (let index = 0; index < 4; index++) { + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: index, + position: arr[index], + billboard: { + image: this.getSourceRootPath() + '/img/point.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '' + index + '’', + pixelOffset: { x: 0, y: -20 }, + }, + }) + + } + + } + } else { + let dis1 = that.distancePointToLine(that.pointArr[i][0], arr[0], arr[1]) + let dis2 = that.distancePointToLine(that.pointArr[i][0], arr[2], arr[3]) + let newArr = [] + if (dis1 > dis2) { + newArr[0] = arr[3] + newArr[1] = arr[0] + newArr[2] = arr[1] + newArr[3] = arr[2] + } else { + newArr[0] = arr[1] + newArr[1] = arr[2] + newArr[2] = arr[3] + newArr[3] = arr[0] + } + newPositions.push(newArr) + + if (!type) { + for (let index = 0; index < 4; index++) { + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: index, + // position: newArr[index], + position: newArr[index], + billboard: { + image: this.getSourceRootPath() + '/img/point.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '' + index, + pixelOffset: { x: 0, y: -20 }, + }, + }) + } + } + // !type && that.positionChangeIndex.push(i + "") + } + // } + + // if (!type) { + // // if (cross > 0 && !type) {//调整方向 + // if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + // newPositions.push(arr) + // } else { + // let newArr = [] + // newArr[0] = arr[1] + // newArr[1] = arr[2] + // newArr[2] = arr[3] + // newArr[3] = arr[0] + // newPositions.push(newArr) + // } + // } else { + // newPositions.push(arr) + // } + } + return newPositions + } + distancePointToLine(p, a, b) { + let ab = new Cesium.Cartesian3(); + Cesium.Cartesian3.subtract(b, a, ab); + + let ap = new Cesium.Cartesian3(); + Cesium.Cartesian3.subtract(p, a, ap); + + let abNormalized = new Cesium.Cartesian3(); + Cesium.Cartesian3.normalize(ab, abNormalized); + + let apProjectionMagnitude = Cesium.Cartesian3.dot(ap, abNormalized); + let apProjection = Cesium.Cartesian3.multiplyByScalar(abNormalized, apProjectionMagnitude, new Cesium.Cartesian3()); + + let footPoint = new Cesium.Cartesian3(); + Cesium.Cartesian3.add(a, apProjection, footPoint); + + return Cesium.Cartesian3.distance(p, footPoint); + } + getExtendPoint2(position1, position2, distance) { + // let position1 = Cesium.Cartesian3.fromDegrees(p1[0], p1[1], 0); + // let position2 = Cesium.Cartesian3.fromDegrees(p2[0], p2[1], 0); + let pot = Cesium.Cartesian3.subtract(position2, position1, new Cesium.Cartesian3());//方向 + var dir = Cesium.Cartesian3.normalize(pot, new Cesium.Cartesian3());//向量归一化 + + var ray = new Cesium.Ray(position1, dir); + let np = Cesium.Ray.getPoint(ray, distance * 10);//计算延长点 + return np + } + getExtendPoint3(pos1, pos2, distance) { + const geodesic = new Cesium.EllipsoidGeodesic(); + geodesic.setEndPoints(pos1, pos2); + + // 关键步骤:获取实际测地距离 + const actualDist = geodesic.surfaceDistance; + const ratio = Math.max(1.1, distance / actualDist); // 强制外延比例 + + // 基于地理坐标的弧度插值 + const carto1 = Cesium.Cartographic.fromCartesian(pos1); + const carto2 = Cesium.Cartographic.fromCartesian(pos2); + + const resultCarto = new Cesium.Cartographic( + carto1.longitude + (carto2.longitude - carto1.longitude) * ratio, + carto1.latitude + (carto2.latitude - carto1.latitude) * ratio, + 0 + ); + + return Cesium.Cartesian3.fromRadians( + resultCarto.longitude, + resultCarto.latitude + ); + } + getExtendPoint(position1, position2, distance) { + // 1. 向量计算与归一化 + const direction = Cesium.Cartesian3.subtract( + position2, + position1, + new Cesium.Cartesian3() + ); + Cesium.Cartesian3.normalize(direction, direction); + + // 2. 使用Ellipsoid修正地球曲率影响 + const ellipsoid = Cesium.Ellipsoid.WGS84; + const geodesic = new Cesium.EllipsoidGeodesic(); + geodesic.setEndPoints(position1, position2); + const actualDistance = geodesic.surfaceDistance; // 获取实际测地距离 + if (distance <= actualDistance) distance = actualDistance * 100; // 强制向外延伸 + + // 3. 考虑椭球面曲率的精确延长 + const surfaceNormal = ellipsoid.geodeticSurfaceNormal(position1); + const projection = Cesium.Cartesian3.multiplyByScalar( + surfaceNormal, + Cesium.Cartesian3.dot(direction, surfaceNormal), + new Cesium.Cartesian3() + ); + Cesium.Cartesian3.subtract(direction, projection, direction); + Cesium.Cartesian3.normalize(direction, direction); + + // 4. 最终坐标计算 + return Cesium.Cartesian3.add( + position2, + Cesium.Cartesian3.multiplyByScalar(direction, distance, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + } + getArr(arr1, arr2) { + arr2 = arr2.reverse() + let polygon = [] + for (let index = 0; index < arr1.length - 1; index++) { + polygon.push([arr1[index], arr1[index + 1], arr2[index + 1], arr2[index]]) + } + return polygon + } + calculateRoadAngle2(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = this.sdk.viewer.scene.globe.ellipsoid.geodeticSurfaceNormal( + startPoint, new Cesium.Cartesian3()); + + // 2. 构建带椭球参数的ENU矩阵 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( + startPoint, this.sdk.viewer.scene.globe.ellipsoid, normal); + const inverseMatrix = Cesium.Matrix4.inverse( + enuMatrix, new Cesium.Matrix4()); + + // 3. 转换坐标并计算相对向量 + const localEnd = Cesium.Matrix4.multiplyByPoint( + inverseMatrix, endPoint, new Cesium.Cartesian3()); + const heightFactor = Math.abs(localEnd.z) / 1000; // 高度差补偿 + + // 4. 使用四象限反正切计算角度 + const angle = Math.atan2(localEnd.y, localEnd.x); + const adjustedAngle = angle - (heightFactor * 0.01); // 高度补偿 + let result = Cesium.Math.toDegrees(adjustedAngle) + return result; + } + calculateRoadAngle3(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建精确ENU坐标系 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse(enuMatrix, new Cesium.Matrix4()); + + // 3. 转换终点并计算水平向量 + const localEnd = Cesium.Matrix4.multiplyByPoint(inverseMatrix, endPoint, new Cesium.Cartesian3()); + const horizontalVec = new Cesium.Cartesian2(localEnd.x, localEnd.y); + Cesium.Cartesian2.normalize(horizontalVec, horizontalVec); + + const north = new Cesium.Cartesian2(1, 0); + + const angle = Cesium.Cartesian2.angleBetween(north, horizontalVec); + const cross = Cesium.Cartesian2.cross(north, horizontalVec, new Cesium.Cartesian2()); + return cross < 0 ? angle : -angle; + } + calculateRoadAngle(startPoint, endPoint) { + // 1. 获取精确地形法向量(需配合地形服务使用) + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建ENU坐标系(增加异常处理) + if (!Cesium.defined(startPoint) || !Cesium.defined(endPoint)) { + return 0; + } + + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( + startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse( + enuMatrix, new Cesium.Matrix4()); + + // 3. 三维向量转换计算 + const localEnd = Cesium.Matrix4.multiplyByPoint( + inverseMatrix, endPoint, new Cesium.Cartesian3()); + + // 4. 使用三维向量计算角度(保留高程信息) + const north3D = new Cesium.Cartesian3(1, 0, 0); + const direction3D = new Cesium.Cartesian3( + localEnd.x, localEnd.y, localEnd.z); + Cesium.Cartesian3.normalize(direction3D, direction3D); + + // 5. 计算带符号角度(考虑三维空间关系) + const angle = Cesium.Cartesian3.angleBetween( + north3D, direction3D); + const cross = Cesium.Cartesian3.cross( + north3D, direction3D, new Cesium.Cartesian3()); + + // 6. 返回带符号角度(Z轴分量为负则取反) + return cross.z < 0 ? angle : -angle; + } + calculatePolygonOrientation(positions) { + + // 假设 position 是 Cesium.Cartesian3 对象,表示地球上的某个点 + var position = positions[0] + // 获取东、北、上坐标系 + var eastNorthUp = Cesium.Transforms.eastNorthUpToFixedFrame(position); + // northAxis 是北方向向量 + var northAxis = eastNorthUp.getColumn(1, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(northAxis, northAxis); + + const direction = Cesium.Cartesian3.subtract(positions[0], positions[1], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + + const dot = Cesium.Cartesian3.dot(northAxis, direction); + const magA = Cesium.Cartesian3.magnitude(northAxis); + const magB = Cesium.Cartesian3.magnitude(direction); + return Math.acos(dot / (magA * magB)); + } + calculateTextureRepeat(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + let widthDis = Cesium.Cartesian3.distance(polygonPositions[0], polygonPositions[1]) + let heightDis = Cesium.Cartesian3.distance(polygonPositions[0], polygonPositions[3]) + + // 计算纹理实际尺寸(米) + // const textureWidthMeters = textureSize.width * meterPerPixel; + // const textureHeightMeters = textureSize.height * meterPerPixel; + const textureWidthMeters = textureSize.width; + const textureHeightMeters = textureSize.height; + console.log(textureWidthMeters, textureHeightMeters, widthDis, heightDis, '宽度') + + // 保持宽高比计算重复次数 + const repeatX = widthDis / textureWidthMeters; + const repeatY = heightDis / textureHeightMeters; + const aspectRatio = textureWidthMeters / textureHeightMeters; + console.log(aspectRatio, 'aspectRatio') + + // 选择主导轴并保持比例 + const dominantRepeat = Math.max(repeatX, repeatY); + let x = Math.max(1, Math.ceil(widthDis / (aspectRatio * heightDis))) + console.log(x, '10') + return new Cesium.Cartesian2( + x, + 1 + ); + } + calculateTextureRepeat2(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + // 创建多边形几何体 + const geometry = Cesium.PolygonGeometry.createGeometry( + new Cesium.PolygonGeometry({ + polygonHierarchy: new Cesium.PolygonHierarchy(polygonPositions), + vertexFormat: Cesium.VertexFormat.POSITION_ONLY + }) + ); + + // 计算多边形面积(平方米) + let area = 0; + const indices = geometry.indices; + const positions = geometry.attributes.position.values; + for (let i = 0; i < indices.length; i += 3) { + const i0 = indices[i] * 3; + const i1 = indices[i + 1] * 3; + const i2 = indices[i + 2] * 3; + + const p0 = new Cesium.Cartesian3(positions[i0], positions[i0 + 1], positions[i0 + 2]); + const p1 = new Cesium.Cartesian3(positions[i1], positions[i1 + 1], positions[i1 + 2]); + const p2 = new Cesium.Cartesian3(positions[i2], positions[i2 + 1], positions[i2 + 2]); + + const cross = Cesium.Cartesian3.cross( + Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()), + Cesium.Cartesian3.subtract(p2, p0, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + area += Cesium.Cartesian3.magnitude(cross) * 0.5; + } + + // 将像素尺寸转换为实际尺寸(平方米) + const textureWidthMeters = textureSize.width * meterPerPixel; + const textureHeightMeters = textureSize.height * meterPerPixel; + const textureArea = textureWidthMeters * textureHeightMeters; + + // 计算各轴向重复次数 + const repeatX = Math.sqrt(area) / textureWidthMeters; + const repeatY = Math.sqrt(area) / textureHeightMeters; + + return new Cesium.Cartesian2(Math.max(1, Math.ceil(repeatX)), 1.0); + } + swapLastElements(arr1, arr2) { + const last = arr1[arr1.length - 1] + const first = arr2[0] + arr1[arr1.length - 1] = first + arr2[0] = last + + return [arr1, arr2]; + } + createLineBufferPolygonSide(positions, width) { + let area = [] + for (let i = 0; i < positions.length; i++) { + const posi = positions[i]; + + const dir = Cesium.Cartesian3.subtract(posi[1], posi[0], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(posi[0], offset, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(posi[1], offset, new Cesium.Cartesian3()) + + // i == positions.length - 2 ? area.push(start, point1, end, point3) : area.push(start, point1) + area.push([posi[0], point1, point3, posi[1]]) + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + return area + } + createLineBufferPolygon2(positions, width) { + let area = [] + let leftPositions = []; + let rightPositions = []; + + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + // const end = positions[i + 1] || positions[i - 1]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + const dir2 = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir2, dir2); + + // 获取垂直向量(基于Z轴) + const perp2 = Cesium.Cartesian3.cross(dir2, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp2, perp2); + + + + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + const offset2 = Cesium.Cartesian3.multiplyByScalar(perp, -width, new Cesium.Cartesian3()); + + const offsetEnd = Cesium.Cartesian3.multiplyByScalar(perp2, -width, new Cesium.Cartesian3()); + const offsetEnd2 = Cesium.Cartesian3.multiplyByScalar(perp2, width, new Cesium.Cartesian3()); + + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point2 = Cesium.Cartesian3.add(start, offset2, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offsetEnd, new Cesium.Cartesian3()) + let point4 = Cesium.Cartesian3.add(end, offsetEnd2, new Cesium.Cartesian3()) + + area.push([point1, point3, point4, point2]) + + rightPositions.push([point1, point3]) + leftPositions.push([point2, point4]) + + // if (i == positions.length - 2) { + // area.push(point1, point2, point3, point4) + // rightPositions.push(point1) + // leftPositions.push(point2) + // leftPositions.push(point4) + // rightPositions.push(point3) + // } else { + // area.push(point1, point2) + // rightPositions.push(point1) + // leftPositions.push(point2) + // } + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + let that = this + // return [arr, rightPositions, leftPositions] + return [area, rightPositions, leftPositions] + } + getIntersects2(segment1Start, segment1End, segment2Start, segment2End) { + // 构造平面(使用线段2的起点和方向向量) + let direction = Cesium.Cartesian3.subtract(segment2End, segment2Start, new Cesium.Cartesian3()); + let plane = Cesium.Plane.fromPointNormal(segment2Start, direction); + + // 计算线段1与平面的交点(增加容差参数) + let intersection = Cesium.IntersectionTests.lineSegmentPlane( + segment1Start, segment1End, plane, 1e-10 + ); + if (!intersection) return null; + + // 使用参数方程验证交点有效性 + let vecToIntersect = Cesium.Cartesian3.subtract(intersection, segment2Start, new Cesium.Cartesian3()); + let t = Cesium.Cartesian3.dot(vecToIntersect, direction) / + Cesium.Cartesian3.magnitudeSquared(direction); + + let result = (t >= -1e-10 && t <= 1.0 + 1e-10) ? intersection : null; + return result; + } + getIntersects(point1, point2, point3, point4) { + let carPoint1 = this.getLonLat(point1) + let carPoint2 = this.getLonLat(point2) + let carPoint3 = this.getLonLat(point3) + let carPoint4 = this.getLonLat(point4) + var line1 = turf.lineString([ + [carPoint1.lon, carPoint1.lat], + [carPoint2.lon, carPoint2.lat] + ]); + var line2 = turf.lineString([ + [carPoint3.lon, carPoint3.lat], + [carPoint4.lon, carPoint4.lat] + ]); + var intersects = turf.lineIntersect(line1, line2); + if (intersects.features.length > 0) { + return Cesium.Cartesian3.fromDegrees(intersects.features[0].geometry.coordinates[0], intersects.features[0].geometry.coordinates[1]) + } + } + getLonLat(point) { + let pointDe = Cesium.Cartographic.fromCartesian(point) + const longitude = Cesium.Math.toDegrees(pointDe.longitude); + const latitude = Cesium.Math.toDegrees(pointDe.latitude); + return { lon: longitude, lat: latitude } + + } + createLineBufferPolygon(viewer, positions, width) { + // 计算每个线段的左右偏移点 + const leftPositions = []; + const rightPositions = []; + + for (let i = 0; i < positions.length; i++) { + const start = positions[i]; + const end = positions[i + 1] || positions[i - 1]; + + // 计算线段方向向量 + const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + // const direction = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量(使用上向量叉积) + const up = Cesium.Cartesian3.UNIT_Z; + const perpendicular = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perpendicular, perpendicular); + + // 计算左右偏移点 + const leftOffset = Cesium.Cartesian3.multiplyByScalar( + perpendicular, + width, + new Cesium.Cartesian3() + ); + + if (width > 0) { + rightPositions.unshift(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } else if (width < 0) { + rightPositions.push(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } + + } + return rightPositions + } + //计算角度 + calculateAangle(arr) { + // let fromDegreesArray = that.calSector(that.options.center, that.options.radius, that.options.startAngle, that.options.endAngle, 360, true) + + function getAangle(start, end) { + let rad = Math.PI / 180, + lat1 = start.y * rad, + lat2 = end.y * rad, + lon1 = start.x * rad, + lon2 = end.x * rad; + const a = Math.sin(lon2 - lon1) * Math.cos(lat2); + const b = + Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); + const radians = Math.atan2(a, b) + const degrees = radians % (2 * Math.PI); + let bearing = 450 - ((degrees * 180) / Math.PI < 0 + ? 360 + (degrees * 180) / Math.PI + : (degrees * 180) / Math.PI) - 90; + return 360 - (bearing % 360) + } + + let center = arr[0] + let pos84_1 = arr[1] + let pos84_2 = arr[2] + + let start = { x: center.lng, y: center.lat } + let end1 = { x: pos84_1.lng, y: pos84_1.lat } + let end2 = { x: pos84_2.lng, y: pos84_2.lat } + + let angle1 = getAangle(start, end1) + let angle2 = getAangle(start, end2) + + return { + angle1, + angle2 + } + } + + get carRoadWidth() { + return this.options.carRoadWidth + } + + set carRoadWidth(v) { + this.options.carRoadWidth = v + Road.create(this) + + } + get sideWidth() { + return this.options.sideWidth + } + set sideWidth(v) { + this.options.sideWidth = v + Road.create(this) + } + /** + * @description 编辑框 + * @param state=false {boolean} 状态: true打开, false关闭 + */ + async edit(state = false) { + let _this = this + this.originalOptions = this.deepCopyObj(this.options) + + if (this._DialogObject && this._DialogObject.close) { + this._DialogObject.close() + this._DialogObject = null + } + + if (state) { + this._DialogObject = await new Dialog(this.sdk, this.originalOptions, { + title: '道路属性', left: '180px', top: '100px', + confirmCallBack: (options) => { + this.name = this.name.trim() + if (!this.name) { + this.name = '道路' + } + this.originalOptions = this.deepCopyObj(this.options) + this._DialogObject.close() + this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions) + syncData(this.sdk, this.options.id) + syncSplitData(this.sdk, this.options.id) + }, + resetCallBack: () => { + this.reset() + this.Dialog.resetCallBack && this.Dialog.resetCallBack() + }, + closeCallBack: () => { + this.reset() + this.Dialog.closeCallBack && this.Dialog.closeCallBack() + }, + showCallBack: (show) => { + this.show = show + this.Dialog.showCallBack && this.Dialog.showCallBack() + } + }, true) + this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' road-surface' + let contentElm = document.createElement('div'); + contentElm.innerHTML = html() + this._DialogObject.contentAppChild(contentElm) + + + // 下拉选项 + // let heightModeData = [ + // { + // name: '海拔高度', + // value: '海拔高度', + // key: '0', + // }, + // { + // name: '相对地表', + // value: '相对地表', + // key: '1', + // }, + // { + // name: '依附模型', + // value: '依附模型', + // key: '2', + // } + // ] + // let heightModeObject = legp( + // this._DialogObject._element.content.getElementsByClassName( + // 'road-box' + // )[0], + // '.road-type' + // ) + // if (heightModeObject) { + // heightModeObject.legp_search(heightModeData) + // let heightModeDataLegpElm = this._DialogObject._element.content + // .getElementsByClassName('road-type')[0] + // .getElementsByTagName('input')[0] + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].key == this.heightMode) { + // heightModeDataLegpElm.value = heightModeData[i].value + // heightModeObject.legp_searchActive( + // heightModeData[i].value + // ) + // break + // } + // } + // heightModeDataLegpElm.addEventListener('input', () => { + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].value === heightModeDataLegpElm.value) { + // this.heightMode = heightModeData[i].key + // break + // } + // } + // }) + + + // this._elms.height = heightElm + // this._elms.heightBox = heightBoxElm + // this._elms.heightMode = heightModeDataLegpElm + // this._elms.heightConfirm = heightConfirmElm + // this._elms.heightModeObject = heightModeObject + + // heightConfirmElm.addEventListener('click', () => { + // this.positionEditing = false + // for (let i = 0; i < this.options.positions.length; i++) { + // this.options.positions[i].alt = Number((this.options.positions[i].alt + Number(heightElm.value)).toFixed(2)) + // this._elms.alt[i].innerHTML = this.options.positions[i].alt + // } + // let fromDegreesArray = this.renewPositions(this.options.positions) + // this.entity.polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights( + // fromDegreesArray + // ) + + // this.positionEditing = false + // PolylineObject.closeNodeEdit(this) + // }) + // } + + + + + + let all_elm = contentElm.getElementsByTagName("*") + this._EventBinding.on(this, all_elm) + this._elms = this._EventBinding.element + } else { + // if (this._element_style) { + // document.getElementsByTagName('head')[0].removeChild(this._element_style) + // this._element_style = null + // } + // if (this._DialogObject && this._DialogObject.remove) { + // this._DialogObject.remove() + // this._DialogObject = null + // } + } + } + + reset() { + if (!this.viewer.entities.getById(this.options.id)) { + return + } + this.name = this.originalOptions.name + this.carRoadWidth = this.originalOptions.carRoadWidth + this.sideWidth = this.originalOptions.sideWidth + this.positions = this.originalOptions.positions + this.roadImage = this.originalOptions.roadImage + this.sideImage = this.originalOptions.sideImage + } + + /** + * 飞到对应实体 + */ + async flyTo(options = {}) { + setActiveViewer(0) + closeRotateAround(this.sdk) + closeViewFollow(this.sdk) + + if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { + let orientation = { + heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), + pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), + roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) + } + + let lng = this.options.customView.relativePosition.lng + let lat = this.options.customView.relativePosition.lat + let alt = this.options.customView.relativePosition.alt + let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + + let position = { lng: 0, lat: 0 } + if (this.options.position) { + position = { ...this.options.position } + } + else if (this.options.positions) { + position = { ...this.options.positions[0] } + } + else if (this.options.center) { + position = { ...this.options.center } + } + else if (this.options.start) { + position = { ...this.options.start } + } + else { + if (this.options.hasOwnProperty('lng')) { + position.lng = this.options.lng + } + if (this.options.hasOwnProperty('lat')) { + position.lat = this.options.lat + } + if (this.options.hasOwnProperty('alt')) { + position.alt = this.options.alt + } + } + // 如果没有高度值,则获取紧贴高度计算 + // if (!position.hasOwnProperty('alt')) { + // position.alt = await this.getClampToHeight(position) + // } + lng = this.options.customView.relativePosition.lng + position.lng + lat = this.options.customView.relativePosition.lat + position.lat + alt = this.options.customView.relativePosition.alt + position.alt + destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + this.sdk.viewer.camera.flyTo({ + destination: destination, + orientation: orientation + }) + } + else { + let positionArray = [] + for (let i = 0; i < this.positions.length; i++) { + let a = Cesium.Cartesian3.fromDegrees( + this.positions[i][0], + this.positions[i][1], + this.options.height + this.options.heightDifference / 2 + ) + positionArray.push(a.x, a.y, a.z) + } + let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) + this.viewer.camera.flyToBoundingSphere(BoundingSphere, { + offset: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-20.0), + roll: Cesium.Math.toRadians(0.0) + } + }) + + } + } + + getSphere() { + return new Promise((resolve) => { + // entity没有加载完成时 state 不会等于0 所以设置定时器直到获取到为止 + const interval = setInterval(() => { + const sphere = new Cesium.BoundingSphere() + const state = this.sdk.viewer._dataSourceDisplay.getBoundingSphere( + this.viewer.entities.getById(this.options.id), + false, + sphere + ) + if (state === Cesium.BoundingSphereState.DONE) { + clearInterval(interval) + } + }, 1000) + }) + } + + /** + * 删除 + */ + async remove() { + this.positions = [] + this.lineEntity = null + + if (this.viewer.entities.getById(this.options.id)) { + this.viewer.entities.getById(this.options.id)._children.forEach((item) => { + this.viewer.entities.remove(item); + }); + this.viewer.entities.remove(this.viewer.entities.getById(this.options.id)) + } + + if (this._DialogObject && !this._DialogObject.isDestroy) { + this._DialogObject.close() + this._DialogObject = null + } + await this.sdk.removeIncetance(this.options.id) + await syncData(this.sdk, this.options.id) + } + + flicker() { } +} + +export default Road diff --git a/src/Obj/Base/RoadObject/index-last.js b/src/Obj/Base/RoadObject/index-last.js new file mode 100644 index 0000000..e6a958e --- /dev/null +++ b/src/Obj/Base/RoadObject/index-last.js @@ -0,0 +1,1704 @@ +/** + * @description 道路 + */ +import Dialog from '../../Element/Dialog'; +import { html } from "./_element"; +import EventBinding from '../../Element/Dialog/eventBinding'; +import Base from "../index"; +import { syncData } from '../../../Global/MultiViewportMode' +import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen' +import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' + +class Road extends Base { + /** + * @constructor + * @param sdk + * @description 道路 + * @param options {object} 道路属性 + * @param options.name=未命名对象 {string} 名称 + * @param options.carRoadWidth=2 {number} 车道宽度 + * @param options.sideWidth=2 {number} 人行道宽度 + * @param options.positions=[] {array} 道路positions + * @param options.roadImage='' {string} 车道贴图 + * @param options.sideImage='' {string} 人行道贴图 + * @param Dialog {object} 弹框对象 + * @param Dialog.confirmCallBack {function} 弹框确认时的回调 + * */ + constructor(sdk, options = {}, _Dialog = {}) { + super(sdk, options); + this.viewer = this.sdk.viewer + this.options.name = options.name || '道路' + this.options.carRoadWidth = options.carRoadWidth || 10 + this.options.sideWidth = options.sideWidth || 5 + this.options.positions = options.positions || [] + this.options.roadImage = options.roadImage || (this.getSourceRootPath() + '/img/roadPhoto.png') + this.options.sideImage = options.sideImage || (this.getSourceRootPath() + '/img/sidePhoto.png') + this.options.show = (options.show || options.show === false) ? options.show : true + this.Dialog = _Dialog + this._EventBinding = new EventBinding() + this._elms = {}; + this.positionArea = [] + this.positions = [] + this.lineEntity = '' + this.crossArr = [] + this.pointArr = [] + this.positionChangeIndex = [] + + this.sdk.addIncetance(this.options.id, this) + // Road.create(this) + const myImg = new Image() + myImg.src = this.options.roadImage + myImg.onload = () => { + console.log('加载完成') + this.createCorridor(myImg, this.options.positions) + } + } + + // 创建走廊几何体 + createCorridor(myImg, posis) { + let posiArr = [] + posis.forEach(item => { + posiArr.push(item.lng, item.lat) + }) + console.log(posiArr, 'posiArr') + + const positions = Cesium.Cartesian3.fromDegreesArray(posiArr); + + const corridorInstance = new Cesium.GeometryInstance({ + geometry: new Cesium.CorridorGeometry({ + positions: positions, + width: this.options.carRoadWidth, + vertexFormat: Cesium.VertexFormat.POSITION_AND_ST, + cornerType: Cesium.CornerType.MITERED, + extrudedHeight: 10.0 + }), + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE) + } + }); + + const primitive = new Cesium.Primitive({ + geometryInstances: corridorInstance, + appearance: new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + type: 'Image', + uniforms: { + image: myImg + } + } + }), + translucent: false + }), + asynchronous: false + }); + + this.sdk.viewer.scene.primitives.add(primitive); + + // 定位到走廊 + // this.sdk.viewer.camera.flyTo({ + // destination: Cesium.Cartesian3.fromDegrees(103.70271877620554, 41.95279346036913, 100), + // // orientation: { + // // heading: Cesium.Math.toRadians(0), + // // pitch: Cesium.Math.toRadians(-30), + // // roll: 0.0 + // // } + // }); + + return primitive; + } + // 横断面计算函数 + computeCrossSection(width, slope) { + const halfWidth = width / 2; + return [ + new Cesium.Cartesian2(-halfWidth, 0), + new Cesium.Cartesian2(-halfWidth, -slope * 10), + new Cesium.Cartesian2(halfWidth, -slope * 10), + new Cesium.Cartesian2(halfWidth, 0) + ]; + } + computeST(geometry) { + // 安全校验:确保几何体包含位置属性 + if (!geometry.attributes.position) { + throw new Error('Geometry must contain position attribute'); + } + + const positions = geometry.attributes.position.values; + const vertexCount = positions.length / 3; + const st = new Float32Array(vertexCount * 2); + + // 计算UV坐标(改进版) + for (let i = 0; i < vertexCount; i++) { + const vertexIndex = i * 3; + const uvIndex = i * 2; + + // 根据顶点在横截面中的位置计算V坐标 + const isTopVertex = positions[vertexIndex + 2] > 0; // Z坐标判断顶面/底面 + st[uvIndex + 1] = isTopVertex ? 1 : 0; + + // 根据路径比例计算U坐标(自动适应不同路段长度) + const pathProgress = i % 4; // 每4个顶点为一个横截面 + st[uvIndex] = (Math.floor(i / 4) + pathProgress / 4) / (vertexCount / 4) * 10; + } + return st; + } + // 创建道路 + static create(that) { + let positions = [] + that.options.positions.forEach(v => { + positions.push(new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) + }) + let newPosi = [] + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + const end = positions[i + 1]; + newPosi.push([start, end]) + that.pointArr = newPosi + // 1. 定义道路中心线路径(WGS84坐标) + const roadPath = [start, end]; + // 3. 计算纹理坐标(确保贴图沿道路方向连续) + console.log(roadPath, 'roadPath') + // 4. 创建道路几何体 + const roadGeometry = new Cesium.PolylineVolumeGeometry({ + polylinePositions: roadPath, + shapePositions: that.computeCrossSection(20, 0.5), + vertexFormat: Cesium.VertexFormat.POSITION_AND_ST, + cornerType: Cesium.CornerType.ROUNDED + }); + console.log('kkkkk') + + // 5. 使用Primitive渲染带贴图的道路 + const roadPrimitive = that.viewer.scene.primitives.add( + new Cesium.Primitive({ + geometryInstances: new Cesium.GeometryInstance({ + geometry: roadGeometry, + attributes: { + st: new Cesium.GeometryAttribute({ + componentDatatype: Cesium.ComponentDatatype.FLOAT, + componentsPerAttribute: 2, + values: (function () { + if (!roadGeometry.attributes.position) { + console.error('Road geometry lacks position data'); + return new Float32Array(0); + } + return that.computeST(roadGeometry); + })() + }) + } + }), + appearance: new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + type: 'Image', + uniforms: { + image: that.options.roadImage, // 沥青纹理示例 + repeat: new Cesium.Cartesian2(1, 1) + } + }, + translucent: false + }), + faceForward: false // 确保双面渲染 + }) + }) + ); + + } + + let area = [[], [], []] + + // area[1] = that.getRectangle(positions, that.options.carRoadWidth) + area[1][0] = that.getRectangle(newPosi, that.options.carRoadWidth) + let sideArr = that.getSideRectangle(area[1][0], that.options.sideWidth) + area[0] = sideArr.left + area[2] = sideArr.right + + // 参数化生成路基模型 + + + + + + + + // area[1] = that.createLineBufferPolygon2(positions, that.options.carRoadWidth / 2) + // area[1] = newPositions + // area[0] = that.createLineBufferPolygonSide(area[1][2], -that.options.sideWidth) + // area[2] = that.createLineBufferPolygonSide(area[1][1], that.options.sideWidth) + + //判断道路边是否相交 + // for (let i = 0; i < area[0].length - 1; i++) { + + // let leftItem = area[0][i] + // let leftItem2 = area[0][i + 1] + // let rightItem = area[2][i] + // let rightItem2 = area[2][i + 1] + // let carItem = area[1][0][i] + // let carItem2 = area[1][0][i + 1] + // let leftLine = that.getIntersects(leftItem[2], leftItem[3], leftItem2[2], leftItem2[3]) + // // that.sdk.viewer.entities.add({ + // // polyline: { + // // positions: [leftItem[2], leftItem[3]], + // // width: 2.0, + // // clampToGround: true, + // // material: new Cesium.PolylineGlowMaterialProperty({ + // // color: Cesium.Color.YELLOW, + // // }), + // // }, + // // }); + // // that.sdk.viewer.entities.add({ + // // polyline: { + // // positions: [leftItem2[2], leftItem2[3]], + // // width: 2.0, + // // clampToGround: true, + // // material: new Cesium.PolylineGlowMaterialProperty({ + // // color: Cesium.Color.YELLOW, + // // }), + // // }, + // // }); + + // let rightLine = that.getIntersects(rightItem[0], rightItem[1], rightItem2[0], rightItem2[1]) + // // if (!leftLine && !rightLine) { + // // for (let index = 0; index < 4; index++) { + // // let positions = [] + // // index === 0 ? positions.push(leftItem[2], leftItem[3]) : index === 1 ? positions.push(leftItem2[2], leftItem2[3]) : index === 2 ? positions.push(rightItem[0], rightItem[1]) : positions.push(rightItem2[0], rightItem2[1]) + // // that.sdk.viewer.entities.add({ + // // polyline: { + // // positions: positions, + // // width: 2.0, + // // clampToGround: true, + // // material: new Cesium.PolylineGlowMaterialProperty({ + // // color: index === 0 ? Cesium.Color.RED : index === 1 ? Cesium.Color.BLUE : index === 2 ? Cesium.Color.YELLOW : Cesium.Color.GREEN, + // // }), + // // }, + // // }); + + // // } + // // } + + + + // for (let index = 0; index < 4; index++) { + // // that.sdk.viewer.entities.add({ + // // name: 'node-secondary-edit-point', + // // index: index, + // // position: area[0][i][index], + // // billboard: { + // // image: that.getSourceRootPath() + '/img/point.png', + // // width: 15, + // // height: 15, + // // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // // color: Cesium.Color.WHITE.withAlpha(0.99) + // // }, + // // label: { + // // text: '' + index + ':', + // // pixelOffset: { x: 0, y: -20 }, + // // }, + // // }) + + // // that.sdk.viewer.entities.add({ + // // name: 'node-secondary-edit-point', + // // index: index, + // // position: area[2][i][index], + // // billboard: { + // // image: that.getSourceRootPath() + '/img/point.png', + // // width: 15, + // // height: 15, + // // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // // color: Cesium.Color.WHITE.withAlpha(0.99) + // // }, + // // label: { + // // text: '' + index + '/', + // // pixelOffset: { x: 0, y: -20 }, + // // }, + // // }) + // } + + + // if (leftLine) {//左侧相交 + // // that.sdk.viewer.entities.add({ + // // name: 'node-secondary-edit-point', + // // index: 1, + // // position: leftLine, + // // billboard: { + // // image: that.getSourceRootPath() + '/img/locate2.png', + // // width: 15, + // // height: 15, + // // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // // color: Cesium.Color.WHITE.withAlpha(0.99) + // // }, + // // label: { + // // text: '', + // // pixelOffset: { x: 0, y: -20 }, + // // }, + // // }) + + // //获取右侧延长交点 + // let point1 = that.getExtendPoint(rightItem[0], rightItem[1], 1000) + // let point2 = that.getExtendPoint(rightItem2[1], rightItem2[0], 1000) + + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: [rightItem[0], point1], + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: Cesium.Color.AQUA, + // }), + // }, + // }); + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: [rightItem2[1], point2], + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: Cesium.Color.AQUA, + // }), + // }, + // }); + + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: i, + // position: point1, + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + 7 + "", + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: i, + // position: point2, + // billboard: { + // image: that.getSourceRootPath() + '/img/end.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + 7 + "", + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + + + // let rightIntersection = that.getIntersects(rightItem[0], point1, rightItem2[1], point2) + // if (!rightIntersection) { + // return + // } + + // //将其他几条边都延长 + // let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + // let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + // let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + + // let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + + + // //跟左侧里相交点 + // let leftLineNei = that.getIntersects(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(leftLine, rightIntersection, carItem[3], carLeftPoint) + + // //跟车道右侧相交点 + // let carRight = that.getIntersects(leftLine, rightIntersection, carItem[0], carRightPoint) + // let rightLineNei = that.getIntersects(leftLine, rightIntersection, rightItem[3], rightLineNeiPoint) + // // let leftLineNei = that.getIntersects(leftLine, rightItem[2], leftItem[0], leftItem[3]) + // // let carLeft = that.getIntersects(leftLine, rightItem[2], carItem[3], carItem[2]) + // // let carRight = that.getIntersects(leftLine, rightItem[2], carItem[0], carItem[1]) + // // let rightLineNei = that.getIntersects(leftLine, rightItem[2], rightItem[0], rightItem[3]) + + // // let leftLineNei = that.getIntersects(leftLine, intersection, leftItem[0], leftItem[3]) + // // //跟车道左侧相交点 + // // let carLeft = that.getIntersects(leftLine, intersection, carItem[3], carItem[2]) + // // //跟车道右侧相交点 + // // let carRight = that.getIntersects(leftLine, intersection, carItem[0], carItem[1]) + // // let rightLineNei = that.getIntersects(leftLine, intersection, rightItem[0], rightItem[3]) + + // leftItem[2] = leftLine + // leftItem[1] = leftLineNei + // // carItem[2] = carLeft + // carItem[2] = leftLineNei + // // carItem[1] = carRight + // carItem[1] = rightLineNei + // rightItem[2] = rightLineNei + // rightItem[1] = rightIntersection + + + // // that.sdk.viewer.entities.add({ + // // name: 'node-secondary-edit-point', + // // index: 1, + // // position: leftLineNei, + // // billboard: { + // // image: that.getSourceRootPath() + '/img/locate2.png', + // // width: 15, + // // height: 15, + // // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // // color: Cesium.Color.WHITE.withAlpha(0.99) + // // }, + // // label: { + // // text: '', + // // pixelOffset: { x: 0, y: -20 }, + // // }, + // // }) + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: 1, + // position: rightIntersection, + // billboard: { + // image: that.getSourceRootPath() + '/img/locate2.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '', + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + + + + // //将其他几条边都延长 + // let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[1], leftItem2[0], 1000) + // let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + // let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + // let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + // // let leftLineNei2 = that.getIntersects(leftLine, rightItem2[1], leftItem2[0], leftItem2[3]) + // // let carLeft2 = that.getIntersects(leftLine, rightItem2[1], carItem2[3], carItem2[2]) + // // let carRight2 = that.getIntersects(leftLine, rightItem2[1], carItem2[0], carItem2[1]) + // // let rightLineNei2 = that.getIntersects(leftLine, rightItem2[1], rightItem2[0], rightItem2[3]) + + + + // let leftLineNei2 = that.getIntersects(leftLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + // let carLeft2 = that.getIntersects(leftLine, rightIntersection, carItem2[2], carLeftPoint2) + // let carRight2 = that.getIntersects(leftLine, rightIntersection, carItem2[1], carRightPoint2) + // let rightLineNei2 = that.getIntersects(leftLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + + // // let arr = [leftLine, rightIntersection, leftItem2[3], leftLineNeiPoint2] + // // arr.forEach((item, index) => { + // // that.sdk.viewer.entities.add({ + // // name: 'node-secondary-edit-point', + // // index: i, + // // position: item, + // // billboard: { + // // image: that.getSourceRootPath() + '/img/point.png', + // // width: 15, + // // height: 15, + // // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // // color: Cesium.Color.WHITE.withAlpha(0.99) + // // }, + // // label: { + // // text: '' + index, + // // pixelOffset: { x: 0, y: -20 }, + // // }, + // // }) + // // }) + + // // let leftLineNei2 = that.getIntersects(leftLine, intersection, leftItem2[0], leftItem2[3]) + // // //跟车道左侧相交点 + // // let carLeft2 = that.getIntersects(leftLine, intersection, carItem2[3], carItem2[2]) + // // //跟车道右侧相交点 + // // let carRight2 = that.getIntersects(leftLine, intersection, carItem2[0], carItem2[1]) + // // let rightLineNei2 = that.getIntersects(leftLine, intersection, rightItem2[0], rightItem2[3]) + + // leftItem2[3] = leftLine + // leftItem2[0] = leftLineNei + // // carItem2[3] = carLeft + // carItem2[3] = leftLineNei + // // carItem2[0] = carRight + // carItem2[0] = rightLineNei + // rightItem2[3] = rightLineNei + // rightItem2[0] = rightIntersection + + + // } else if (rightLine) {//右侧相交 + + // //获取左侧延长交点 + // let point1 = that.getExtendPoint(leftItem[3], leftItem[2], 1000) + // let point2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: [leftItem[3], point1], + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: Cesium.Color.AQUA, + // }), + // }, + // }); + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: [leftItem2[2], point2], + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: Cesium.Color.AQUA, + // }), + // }, + // }); + + // let rightIntersection = that.getIntersects(leftItem[3], point1, leftItem2[2], point2) + // if (!rightIntersection) { + // return + // } + // //将其他几条边都延长 + // let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + + // let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + // let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + // let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + // // //跟左侧里相交点 + // let leftLineNei = that.getIntersects(rightLine, rightIntersection, leftItem[0], leftLineNeiPoint) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(rightLine, rightIntersection, carItem[3], carLeftPoint) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(rightLine, rightIntersection, carItem[0], carRightPoint) + // let rightLineNei = that.getIntersects(rightLine, rightIntersection, rightItem[3], rightLineNeiPoint) + // // //跟左侧里相交点 + // // let leftLineNei = that.getIntersects(rightLine, leftItem[2], leftItem[0], leftItem[3]) + // // //跟车道左侧相交点 + // // let carLeft = that.getIntersects(rightLine, leftItem[2], carItem[3], carItem[2]) + // // //跟车道右侧相交点 + // // let carRight = that.getIntersects(rightLine, leftItem[2], carItem[0], carItem[1]) + // // let rightLineNei = that.getIntersects(rightLine, leftItem[2], rightItem[0], rightItem[3]) + + + // leftItem[2] = rightIntersection + // leftItem[1] = leftLineNei + // // carItem[2] = carLeft + // carItem[2] = leftLineNei + // // carItem[1] = carRight + // carItem[1] = rightLineNei + // rightItem[2] = rightLineNei + // rightItem[1] = rightLine + + // //将其他几条边都延长 + // let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + // let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + // let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + // let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + // let leftLineNei2 = that.getIntersects(rightLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(rightLine, rightIntersection, carItem2[2], carLeftPoint2) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(rightLine, rightIntersection, carItem2[1], carRightPoint2) + // let rightLineNei2 = that.getIntersects(rightLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + // // let leftLineNei2 = that.getIntersects(rightLine, leftItem2[1], leftItem2[0], leftItem2[3]) + // // //跟车道左侧相交点 + // // let carLeft2 = that.getIntersects(rightLine, leftItem2[1], carItem2[3], carItem2[2]) + // // //跟车道右侧相交点 + // // let carRight2 = that.getIntersects(rightLine, leftItem2[1], carItem2[0], carItem2[1]) + // // let rightLineNei2 = that.getIntersects(rightLine, leftItem2[1], rightItem2[0], rightItem2[3]) + + // leftItem2[3] = rightIntersection + // leftItem2[0] = leftLineNei + // // carItem2[3] = carLeft + // carItem2[3] = leftLineNei + // // carItem2[0] = carRight + // carItem2[0] = rightLineNei + // rightItem2[3] = rightLineNei + // rightItem2[0] = rightLine + + // // leftItem[2] = rightIntersection + // // leftItem[1] = leftLineNei + // // // carItem[2] = carLeft + // // carItem[2] = leftLineNei + // // // carItem[1] = carRight + // // carItem[1] = rightLineNei + // // rightItem[2] = rightLineNei + // // rightItem[1] = rightLine + // } + + // // area[0][i] = leftItem + // // area[0][i + 1] = leftItem2 + // // area[2][i] = rightItem + // // area[2][i + 1] = rightItem2 + // // area[1][0][i] = carItem + // // area[1][0][i + 1] = carItem2 + // } + // if (that.viewer.entities.getById(that.options.id)) { + // that.viewer.entities.getById(that.options.id)._children.forEach((item) => { + // that.viewer.entities.remove(item); + // }); + // that.viewer.entities.remove(that.viewer.entities.getById(that.options.id)) + // } + // that.lineEntity = that.viewer.entities.add(new Cesium.Entity({ id: that.options.id, show: that.options.show })) + + // const myImg = new Image() + // myImg.src = that.options.roadImage + // myImg.onload = function () { + // area[1][0].forEach((item, index) => { + + + + + // // that.viewer.entities.add({ + // // // id: that.options.id, + // // parent: that.lineEntity, + // // polygon: { + // // hierarchy: new Cesium.PolygonHierarchy(item), + // // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, + // // classificationType: Cesium.ClassificationType.BOTH, + // // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), + // // material: new Cesium.ImageMaterialProperty({ + // // image: that.options.roadImage, + // // transparent: true,// 如果图片有透明部分,需要设置为 true + // // repeat: that.calculateTextureRepeat(item, myImg) + // // }), + // // // stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + // // stRotation: that.calculateRoadAngle(item[0], item[1]) + // // // material: Cesium.Color.fromRandom({ alpha: 0.5 }), + // // } + // // }); + // }) + // } + + // const myImg2 = new Image() + // myImg2.src = that.options.sideImage + // myImg2.onload = function () { + // area[0].forEach((item, index) => { + // that.viewer.entities.add({ + // parent: that.lineEntity, + // polygon: { + // hierarchy: new Cesium.PolygonHierarchy(item), + // material: new Cesium.ImageMaterialProperty({ + // image: that.options.sideImage, + // transparent: true,// 如果图片有透明部分,需要设置为 true + // repeat: that.calculateTextureRepeat(item, myImg2) + // }), + // stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + // // material: Cesium.Color.fromRandom({ alpha: 0.5 }), + // } + // }); + // }) + + // area[2].forEach((item, index) => { + // that.viewer.entities.add({ + // parent: that.lineEntity, + // polygon: { + // hierarchy: new Cesium.PolygonHierarchy(item), + // material: new Cesium.ImageMaterialProperty({ + // image: that.options.sideImage, + // transparent: true,// 如果图片有透明部分,需要设置为 true + // repeat: that.calculateTextureRepeat(item, myImg2) + // }), + // stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + // // material: Cesium.Color.fromRandom({ alpha: 0.5 }), + // } + // }); + // }) + // } + + } + getSideRectangle(positions, width) { + let right = [] + let left = [] + let that = this + positions.forEach((item, i) => { + // console.log(that.positionChangeIndex, 'positionChangeIndex') + // if (that.positionChangeIndex[i + '']) { + // console.log('1111') + // right.push([item[2], item[3]]) + // left.push([item[0], item[1]]) + // } else { + right.push([item[0], item[1]]) + // left.push([item[2], item[3]]) + left.push([item[3], item[2]]) + // } + + + for (let index = 0; index < 2; index++) { + let ArrArr = [] + index === 0 ? ArrArr.push(item[0], item[1]) : ArrArr.push(item[2], item[3]); + // that.sdk.viewer.entities.add({ + // polyline: { + // positions: ArrArr, + // width: 2.0, + // clampToGround: true, + // material: new Cesium.PolylineGlowMaterialProperty({ + // color: index === 0 ? Cesium.Color.RED : Cesium.Color.BLUE, + // }), + // }, + // }); + } + }) + let rightPosi = that.getRectangle(right, width, 'side') + let newRightPosi = [] + right.forEach((item, index) => { + newRightPosi.push([rightPosi[index][0], rightPosi[index][1], item[1], item[0]]) + }) + + + let leftPosi = this.getRectangle(left, width, 'side') + let newLeftPosi = [] + left.forEach((item, index) => { + // newLeftPosi.push([item[0], item[1], leftPosi[index][2]], leftPosi[index][3]) + newLeftPosi.push([item[0], item[1], leftPosi[index][2], leftPosi[index][3]]) + }) + return { left: newLeftPosi, right: newRightPosi } + } + getRectangle(positions, width, type) { + let areaArr = [] + let newPositions = [] + let that = this + // for (let i = 0; i < positions.length - 1; i++) { + for (let i = 0; i < positions.length; i++) { + const start = positions[i][0]; + const end = positions[i][1]; + + + areaArr[i] = [] + let posi = [] + let Outlinegeometry = new Cesium.CorridorGeometry({ + positions: [start, end], + width: width, + cornerType: Cesium.CornerType.MITERED, + vertexFormat: Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat + }) + let geometry = Cesium.CorridorGeometry.createGeometry(Outlinegeometry) + for (let j = 0; j < geometry.attributes.position.values.length; j += 3) { + let val = that.cartesian3Towgs84(new Cesium.Cartesian3(geometry.attributes.position.values[j], geometry.attributes.position.values[j + 1], geometry.attributes.position.values[j + 2]), that.sdk.viewer) + posi.push([val.lng, val.lat]) + } + + for (let x = 0; x < geometry.indices.length; x += 3) { + areaArr[i].push(turf.polygon([[posi[geometry.indices[x]], posi[geometry.indices[x + 1]], posi[geometry.indices[x + 2]], posi[geometry.indices[x]]]])) + } + + let geojson = turf.union(areaArr[i][0], areaArr[i][1]); + let arr = [] + geojson.geometry.coordinates[0].pop() + geojson.geometry.coordinates[0].forEach(item => { + arr.push(new Cesium.Cartesian3.fromDegrees(item[0], item[1])) + }) + let dotResult, angle + const tempVec = new Cesium.Cartesian3(); + + // 计算并归一化第一个向量 + const vector1 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(that.pointArr[i][1], that.pointArr[i][0], tempVec), + tempVec + ); + + // 计算并归一化第二个向量 + const vector2 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(arr[1], arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + dotResult = Cesium.Cartesian3.dot(vector1, vector2); + if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + // let newArr = [] + // newArr[0] = arr[2] + // newArr[1] = arr[3] + // newArr[2] = arr[0] + // newArr[3] = arr[1] + // newPositions.push(newArr) + //判断方向是否正确 + const vec1 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(start, arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + // 计算并归一化第二个向量 + const vec2 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(arr[1], arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + let dRst = Cesium.Cartesian3.dot(vec1, vec2); + + + if (0 < dRst && dRst < 0.0001) { + newPositions.push(arr) + } else { + + let dis1 = that.distancePointToLine(start, arr[0], arr[1]) + let dis2 = that.distancePointToLine(start, arr[2], arr[3]) + let newArr = [] + if (dis1 > dis2) {// + newArr[0] = arr[3] + newArr[1] = arr[0] + newArr[2] = arr[1] + newArr[3] = arr[2] + } else { + newArr[0] = arr[2] + newArr[1] = arr[3] + newArr[2] = arr[0] + newArr[3] = arr[1] + } + newPositions.push(newArr) + + + // let newArr = [] + // newArr[0] = arr[2] + // newArr[1] = arr[3] + // newArr[2] = arr[0] + // newArr[3] = arr[1] + // newPositions.push(newArr) + } + + // newPositions.push(arr) + + if (!type) { + for (let index = 0; index < 4; index++) { + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: index, + position: arr[index], + billboard: { + image: this.getSourceRootPath() + '/img/point.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '' + index + '’', + pixelOffset: { x: 0, y: -20 }, + }, + }) + + } + + } + } else { + let dis1 = that.distancePointToLine(that.pointArr[i][0], arr[0], arr[1]) + let dis2 = that.distancePointToLine(that.pointArr[i][0], arr[2], arr[3]) + let newArr = [] + if (dis1 > dis2) { + newArr[0] = arr[3] + newArr[1] = arr[0] + newArr[2] = arr[1] + newArr[3] = arr[2] + } else { + newArr[0] = arr[1] + newArr[1] = arr[2] + newArr[2] = arr[3] + newArr[3] = arr[0] + } + newPositions.push(newArr) + + if (!type) { + for (let index = 0; index < 4; index++) { + that.sdk.viewer.entities.add({ + name: 'node-secondary-edit-point', + index: index, + // position: newArr[index], + position: newArr[index], + billboard: { + image: this.getSourceRootPath() + '/img/point.png', + width: 15, + height: 15, + disableDepthTestDistance: Number.POSITIVE_INFINITY, + color: Cesium.Color.WHITE.withAlpha(0.99) + }, + label: { + text: '' + index, + pixelOffset: { x: 0, y: -20 }, + }, + }) + } + } + // !type && that.positionChangeIndex.push(i + "") + } + // } + + // if (!type) { + // // if (cross > 0 && !type) {//调整方向 + // if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + // newPositions.push(arr) + // } else { + // let newArr = [] + // newArr[0] = arr[1] + // newArr[1] = arr[2] + // newArr[2] = arr[3] + // newArr[3] = arr[0] + // newPositions.push(newArr) + // } + // } else { + // newPositions.push(arr) + // } + } + return newPositions + } + distancePointToLine(p, a, b) { + let ab = new Cesium.Cartesian3(); + Cesium.Cartesian3.subtract(b, a, ab); + + let ap = new Cesium.Cartesian3(); + Cesium.Cartesian3.subtract(p, a, ap); + + let abNormalized = new Cesium.Cartesian3(); + Cesium.Cartesian3.normalize(ab, abNormalized); + + let apProjectionMagnitude = Cesium.Cartesian3.dot(ap, abNormalized); + let apProjection = Cesium.Cartesian3.multiplyByScalar(abNormalized, apProjectionMagnitude, new Cesium.Cartesian3()); + + let footPoint = new Cesium.Cartesian3(); + Cesium.Cartesian3.add(a, apProjection, footPoint); + + return Cesium.Cartesian3.distance(p, footPoint); + } + getExtendPoint2(position1, position2, distance) { + // let position1 = Cesium.Cartesian3.fromDegrees(p1[0], p1[1], 0); + // let position2 = Cesium.Cartesian3.fromDegrees(p2[0], p2[1], 0); + let pot = Cesium.Cartesian3.subtract(position2, position1, new Cesium.Cartesian3());//方向 + var dir = Cesium.Cartesian3.normalize(pot, new Cesium.Cartesian3());//向量归一化 + + var ray = new Cesium.Ray(position1, dir); + let np = Cesium.Ray.getPoint(ray, distance * 10);//计算延长点 + return np + } + getExtendPoint3(pos1, pos2, distance) { + const geodesic = new Cesium.EllipsoidGeodesic(); + geodesic.setEndPoints(pos1, pos2); + + // 关键步骤:获取实际测地距离 + const actualDist = geodesic.surfaceDistance; + const ratio = Math.max(1.1, distance / actualDist); // 强制外延比例 + + // 基于地理坐标的弧度插值 + const carto1 = Cesium.Cartographic.fromCartesian(pos1); + const carto2 = Cesium.Cartographic.fromCartesian(pos2); + + const resultCarto = new Cesium.Cartographic( + carto1.longitude + (carto2.longitude - carto1.longitude) * ratio, + carto1.latitude + (carto2.latitude - carto1.latitude) * ratio, + 0 + ); + + return Cesium.Cartesian3.fromRadians( + resultCarto.longitude, + resultCarto.latitude + ); + } + getExtendPoint(position1, position2, distance) { + // 1. 向量计算与归一化 + const direction = Cesium.Cartesian3.subtract( + position2, + position1, + new Cesium.Cartesian3() + ); + Cesium.Cartesian3.normalize(direction, direction); + + // 2. 使用Ellipsoid修正地球曲率影响 + const ellipsoid = Cesium.Ellipsoid.WGS84; + const geodesic = new Cesium.EllipsoidGeodesic(); + geodesic.setEndPoints(position1, position2); + const actualDistance = geodesic.surfaceDistance; // 获取实际测地距离 + if (distance <= actualDistance) distance = actualDistance * 100; // 强制向外延伸 + + // 3. 考虑椭球面曲率的精确延长 + const surfaceNormal = ellipsoid.geodeticSurfaceNormal(position1); + const projection = Cesium.Cartesian3.multiplyByScalar( + surfaceNormal, + Cesium.Cartesian3.dot(direction, surfaceNormal), + new Cesium.Cartesian3() + ); + Cesium.Cartesian3.subtract(direction, projection, direction); + Cesium.Cartesian3.normalize(direction, direction); + + // 4. 最终坐标计算 + return Cesium.Cartesian3.add( + position2, + Cesium.Cartesian3.multiplyByScalar(direction, distance, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + } + getArr(arr1, arr2) { + arr2 = arr2.reverse() + let polygon = [] + for (let index = 0; index < arr1.length - 1; index++) { + polygon.push([arr1[index], arr1[index + 1], arr2[index + 1], arr2[index]]) + } + return polygon + } + calculateRoadAngle2(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = this.sdk.viewer.scene.globe.ellipsoid.geodeticSurfaceNormal( + startPoint, new Cesium.Cartesian3()); + + // 2. 构建带椭球参数的ENU矩阵 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( + startPoint, this.sdk.viewer.scene.globe.ellipsoid, normal); + const inverseMatrix = Cesium.Matrix4.inverse( + enuMatrix, new Cesium.Matrix4()); + + // 3. 转换坐标并计算相对向量 + const localEnd = Cesium.Matrix4.multiplyByPoint( + inverseMatrix, endPoint, new Cesium.Cartesian3()); + const heightFactor = Math.abs(localEnd.z) / 1000; // 高度差补偿 + + // 4. 使用四象限反正切计算角度 + const angle = Math.atan2(localEnd.y, localEnd.x); + const adjustedAngle = angle - (heightFactor * 0.01); // 高度补偿 + let result = Cesium.Math.toDegrees(adjustedAngle) + return result; + } + calculateRoadAngle3(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建精确ENU坐标系 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse(enuMatrix, new Cesium.Matrix4()); + + // 3. 转换终点并计算水平向量 + const localEnd = Cesium.Matrix4.multiplyByPoint(inverseMatrix, endPoint, new Cesium.Cartesian3()); + const horizontalVec = new Cesium.Cartesian2(localEnd.x, localEnd.y); + Cesium.Cartesian2.normalize(horizontalVec, horizontalVec); + + const north = new Cesium.Cartesian2(1, 0); + + const angle = Cesium.Cartesian2.angleBetween(north, horizontalVec); + const cross = Cesium.Cartesian2.cross(north, horizontalVec, new Cesium.Cartesian2()); + return cross < 0 ? angle : -angle; + } + calculateRoadAngle(startPoint, endPoint) { + // 1. 获取精确地形法向量(需配合地形服务使用) + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建ENU坐标系(增加异常处理) + if (!Cesium.defined(startPoint) || !Cesium.defined(endPoint)) { + return 0; + } + + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( + startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse( + enuMatrix, new Cesium.Matrix4()); + + // 3. 三维向量转换计算 + const localEnd = Cesium.Matrix4.multiplyByPoint( + inverseMatrix, endPoint, new Cesium.Cartesian3()); + + // 4. 使用三维向量计算角度(保留高程信息) + const north3D = new Cesium.Cartesian3(1, 0, 0); + const direction3D = new Cesium.Cartesian3( + localEnd.x, localEnd.y, localEnd.z); + Cesium.Cartesian3.normalize(direction3D, direction3D); + + // 5. 计算带符号角度(考虑三维空间关系) + const angle = Cesium.Cartesian3.angleBetween( + north3D, direction3D); + const cross = Cesium.Cartesian3.cross( + north3D, direction3D, new Cesium.Cartesian3()); + + // 6. 返回带符号角度(Z轴分量为负则取反) + return cross.z < 0 ? angle : -angle; + } + calculatePolygonOrientation(positions) { + + // 假设 position 是 Cesium.Cartesian3 对象,表示地球上的某个点 + var position = positions[0] + // 获取东、北、上坐标系 + var eastNorthUp = Cesium.Transforms.eastNorthUpToFixedFrame(position); + // northAxis 是北方向向量 + var northAxis = eastNorthUp.getColumn(1, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(northAxis, northAxis); + + const direction = Cesium.Cartesian3.subtract(positions[0], positions[1], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + + const dot = Cesium.Cartesian3.dot(northAxis, direction); + const magA = Cesium.Cartesian3.magnitude(northAxis); + const magB = Cesium.Cartesian3.magnitude(direction); + return Math.acos(dot / (magA * magB)); + } + calculateTextureRepeat(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + let widthDis = Cesium.Cartesian3.distance(polygonPositions[0], polygonPositions[1]) + let heightDis = Cesium.Cartesian3.distance(polygonPositions[0], polygonPositions[3]) + + // 计算纹理实际尺寸(米) + // const textureWidthMeters = textureSize.width * meterPerPixel; + // const textureHeightMeters = textureSize.height * meterPerPixel; + const textureWidthMeters = textureSize.width; + const textureHeightMeters = textureSize.height; + console.log(textureWidthMeters, textureHeightMeters, widthDis, heightDis, '宽度') + + // 保持宽高比计算重复次数 + const repeatX = widthDis / textureWidthMeters; + const repeatY = heightDis / textureHeightMeters; + const aspectRatio = textureWidthMeters / textureHeightMeters; + console.log(aspectRatio, 'aspectRatio') + + // 选择主导轴并保持比例 + const dominantRepeat = Math.max(repeatX, repeatY); + let x = Math.max(1, Math.ceil(widthDis / (aspectRatio * heightDis))) + console.log(x, '10') + return new Cesium.Cartesian2( + x, + 1 + ); + } + calculateTextureRepeat2(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + // 创建多边形几何体 + const geometry = Cesium.PolygonGeometry.createGeometry( + new Cesium.PolygonGeometry({ + polygonHierarchy: new Cesium.PolygonHierarchy(polygonPositions), + vertexFormat: Cesium.VertexFormat.POSITION_ONLY + }) + ); + + // 计算多边形面积(平方米) + let area = 0; + const indices = geometry.indices; + const positions = geometry.attributes.position.values; + for (let i = 0; i < indices.length; i += 3) { + const i0 = indices[i] * 3; + const i1 = indices[i + 1] * 3; + const i2 = indices[i + 2] * 3; + + const p0 = new Cesium.Cartesian3(positions[i0], positions[i0 + 1], positions[i0 + 2]); + const p1 = new Cesium.Cartesian3(positions[i1], positions[i1 + 1], positions[i1 + 2]); + const p2 = new Cesium.Cartesian3(positions[i2], positions[i2 + 1], positions[i2 + 2]); + + const cross = Cesium.Cartesian3.cross( + Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()), + Cesium.Cartesian3.subtract(p2, p0, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + area += Cesium.Cartesian3.magnitude(cross) * 0.5; + } + + // 将像素尺寸转换为实际尺寸(平方米) + const textureWidthMeters = textureSize.width * meterPerPixel; + const textureHeightMeters = textureSize.height * meterPerPixel; + const textureArea = textureWidthMeters * textureHeightMeters; + + // 计算各轴向重复次数 + const repeatX = Math.sqrt(area) / textureWidthMeters; + const repeatY = Math.sqrt(area) / textureHeightMeters; + + return new Cesium.Cartesian2(Math.max(1, Math.ceil(repeatX)), 1.0); + } + swapLastElements(arr1, arr2) { + const last = arr1[arr1.length - 1] + const first = arr2[0] + arr1[arr1.length - 1] = first + arr2[0] = last + + return [arr1, arr2]; + } + createLineBufferPolygonSide(positions, width) { + let area = [] + for (let i = 0; i < positions.length; i++) { + const posi = positions[i]; + + const dir = Cesium.Cartesian3.subtract(posi[1], posi[0], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(posi[0], offset, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(posi[1], offset, new Cesium.Cartesian3()) + + // i == positions.length - 2 ? area.push(start, point1, end, point3) : area.push(start, point1) + area.push([posi[0], point1, point3, posi[1]]) + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + return area + } + createLineBufferPolygon2(positions, width) { + let area = [] + let leftPositions = []; + let rightPositions = []; + + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + // const end = positions[i + 1] || positions[i - 1]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + const dir2 = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir2, dir2); + + // 获取垂直向量(基于Z轴) + const perp2 = Cesium.Cartesian3.cross(dir2, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp2, perp2); + + + + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + const offset2 = Cesium.Cartesian3.multiplyByScalar(perp, -width, new Cesium.Cartesian3()); + + const offsetEnd = Cesium.Cartesian3.multiplyByScalar(perp2, -width, new Cesium.Cartesian3()); + const offsetEnd2 = Cesium.Cartesian3.multiplyByScalar(perp2, width, new Cesium.Cartesian3()); + + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point2 = Cesium.Cartesian3.add(start, offset2, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offsetEnd, new Cesium.Cartesian3()) + let point4 = Cesium.Cartesian3.add(end, offsetEnd2, new Cesium.Cartesian3()) + + area.push([point1, point3, point4, point2]) + + rightPositions.push([point1, point3]) + leftPositions.push([point2, point4]) + + // if (i == positions.length - 2) { + // area.push(point1, point2, point3, point4) + // rightPositions.push(point1) + // leftPositions.push(point2) + // leftPositions.push(point4) + // rightPositions.push(point3) + // } else { + // area.push(point1, point2) + // rightPositions.push(point1) + // leftPositions.push(point2) + // } + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + let that = this + // return [arr, rightPositions, leftPositions] + return [area, rightPositions, leftPositions] + } + getIntersects2(segment1Start, segment1End, segment2Start, segment2End) { + // 构造平面(使用线段2的起点和方向向量) + let direction = Cesium.Cartesian3.subtract(segment2End, segment2Start, new Cesium.Cartesian3()); + let plane = Cesium.Plane.fromPointNormal(segment2Start, direction); + + // 计算线段1与平面的交点(增加容差参数) + let intersection = Cesium.IntersectionTests.lineSegmentPlane( + segment1Start, segment1End, plane, 1e-10 + ); + if (!intersection) return null; + + // 使用参数方程验证交点有效性 + let vecToIntersect = Cesium.Cartesian3.subtract(intersection, segment2Start, new Cesium.Cartesian3()); + let t = Cesium.Cartesian3.dot(vecToIntersect, direction) / + Cesium.Cartesian3.magnitudeSquared(direction); + + let result = (t >= -1e-10 && t <= 1.0 + 1e-10) ? intersection : null; + return result; + } + getIntersects(point1, point2, point3, point4) { + let carPoint1 = this.getLonLat(point1) + let carPoint2 = this.getLonLat(point2) + let carPoint3 = this.getLonLat(point3) + let carPoint4 = this.getLonLat(point4) + var line1 = turf.lineString([ + [carPoint1.lon, carPoint1.lat], + [carPoint2.lon, carPoint2.lat] + ]); + var line2 = turf.lineString([ + [carPoint3.lon, carPoint3.lat], + [carPoint4.lon, carPoint4.lat] + ]); + var intersects = turf.lineIntersect(line1, line2); + if (intersects.features.length > 0) { + return Cesium.Cartesian3.fromDegrees(intersects.features[0].geometry.coordinates[0], intersects.features[0].geometry.coordinates[1]) + } + } + getLonLat(point) { + let pointDe = Cesium.Cartographic.fromCartesian(point) + const longitude = Cesium.Math.toDegrees(pointDe.longitude); + const latitude = Cesium.Math.toDegrees(pointDe.latitude); + return { lon: longitude, lat: latitude } + + } + createLineBufferPolygon(viewer, positions, width) { + // 计算每个线段的左右偏移点 + const leftPositions = []; + const rightPositions = []; + + for (let i = 0; i < positions.length; i++) { + const start = positions[i]; + const end = positions[i + 1] || positions[i - 1]; + + // 计算线段方向向量 + const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + // const direction = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量(使用上向量叉积) + const up = Cesium.Cartesian3.UNIT_Z; + const perpendicular = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perpendicular, perpendicular); + + // 计算左右偏移点 + const leftOffset = Cesium.Cartesian3.multiplyByScalar( + perpendicular, + width, + new Cesium.Cartesian3() + ); + + if (width > 0) { + rightPositions.unshift(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } else if (width < 0) { + rightPositions.push(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } + + } + return rightPositions + } + //计算角度 + calculateAangle(arr) { + // let fromDegreesArray = that.calSector(that.options.center, that.options.radius, that.options.startAngle, that.options.endAngle, 360, true) + + function getAangle(start, end) { + let rad = Math.PI / 180, + lat1 = start.y * rad, + lat2 = end.y * rad, + lon1 = start.x * rad, + lon2 = end.x * rad; + const a = Math.sin(lon2 - lon1) * Math.cos(lat2); + const b = + Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); + const radians = Math.atan2(a, b) + const degrees = radians % (2 * Math.PI); + let bearing = 450 - ((degrees * 180) / Math.PI < 0 + ? 360 + (degrees * 180) / Math.PI + : (degrees * 180) / Math.PI) - 90; + return 360 - (bearing % 360) + } + + let center = arr[0] + let pos84_1 = arr[1] + let pos84_2 = arr[2] + + let start = { x: center.lng, y: center.lat } + let end1 = { x: pos84_1.lng, y: pos84_1.lat } + let end2 = { x: pos84_2.lng, y: pos84_2.lat } + + let angle1 = getAangle(start, end1) + let angle2 = getAangle(start, end2) + + return { + angle1, + angle2 + } + } + + get carRoadWidth() { + return this.options.carRoadWidth + } + + set carRoadWidth(v) { + this.options.carRoadWidth = v + Road.create(this) + + } + get sideWidth() { + return this.options.sideWidth + } + set sideWidth(v) { + this.options.sideWidth = v + Road.create(this) + } + /** + * @description 编辑框 + * @param state=false {boolean} 状态: true打开, false关闭 + */ + async edit(state = false) { + let _this = this + this.originalOptions = this.deepCopyObj(this.options) + + if (this._DialogObject && this._DialogObject.close) { + this._DialogObject.close() + this._DialogObject = null + } + + if (state) { + this._DialogObject = await new Dialog(this.sdk, this.originalOptions, { + title: '道路属性', left: '180px', top: '100px', + confirmCallBack: (options) => { + this.name = this.name.trim() + if (!this.name) { + this.name = '道路' + } + this.originalOptions = this.deepCopyObj(this.options) + this._DialogObject.close() + this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions) + syncData(this.sdk, this.options.id) + syncSplitData(this.sdk, this.options.id) + }, + resetCallBack: () => { + this.reset() + this.Dialog.resetCallBack && this.Dialog.resetCallBack() + }, + closeCallBack: () => { + this.reset() + this.Dialog.closeCallBack && this.Dialog.closeCallBack() + }, + showCallBack: (show) => { + this.show = show + this.Dialog.showCallBack && this.Dialog.showCallBack() + } + }, true) + this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' road-surface' + let contentElm = document.createElement('div'); + contentElm.innerHTML = html() + this._DialogObject.contentAppChild(contentElm) + + + // 下拉选项 + // let heightModeData = [ + // { + // name: '海拔高度', + // value: '海拔高度', + // key: '0', + // }, + // { + // name: '相对地表', + // value: '相对地表', + // key: '1', + // }, + // { + // name: '依附模型', + // value: '依附模型', + // key: '2', + // } + // ] + // let heightModeObject = legp( + // this._DialogObject._element.content.getElementsByClassName( + // 'road-box' + // )[0], + // '.road-type' + // ) + // if (heightModeObject) { + // heightModeObject.legp_search(heightModeData) + // let heightModeDataLegpElm = this._DialogObject._element.content + // .getElementsByClassName('road-type')[0] + // .getElementsByTagName('input')[0] + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].key == this.heightMode) { + // heightModeDataLegpElm.value = heightModeData[i].value + // heightModeObject.legp_searchActive( + // heightModeData[i].value + // ) + // break + // } + // } + // heightModeDataLegpElm.addEventListener('input', () => { + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].value === heightModeDataLegpElm.value) { + // this.heightMode = heightModeData[i].key + // break + // } + // } + // }) + + + // this._elms.height = heightElm + // this._elms.heightBox = heightBoxElm + // this._elms.heightMode = heightModeDataLegpElm + // this._elms.heightConfirm = heightConfirmElm + // this._elms.heightModeObject = heightModeObject + + // heightConfirmElm.addEventListener('click', () => { + // this.positionEditing = false + // for (let i = 0; i < this.options.positions.length; i++) { + // this.options.positions[i].alt = Number((this.options.positions[i].alt + Number(heightElm.value)).toFixed(2)) + // this._elms.alt[i].innerHTML = this.options.positions[i].alt + // } + // let fromDegreesArray = this.renewPositions(this.options.positions) + // this.entity.polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights( + // fromDegreesArray + // ) + + // this.positionEditing = false + // PolylineObject.closeNodeEdit(this) + // }) + // } + + + + + + let all_elm = contentElm.getElementsByTagName("*") + this._EventBinding.on(this, all_elm) + this._elms = this._EventBinding.element + } else { + // if (this._element_style) { + // document.getElementsByTagName('head')[0].removeChild(this._element_style) + // this._element_style = null + // } + // if (this._DialogObject && this._DialogObject.remove) { + // this._DialogObject.remove() + // this._DialogObject = null + // } + } + } + + reset() { + if (!this.viewer.entities.getById(this.options.id)) { + return + } + this.name = this.originalOptions.name + this.carRoadWidth = this.originalOptions.carRoadWidth + this.sideWidth = this.originalOptions.sideWidth + this.positions = this.originalOptions.positions + this.roadImage = this.originalOptions.roadImage + this.sideImage = this.originalOptions.sideImage + } + + /** + * 飞到对应实体 + */ + async flyTo(options = {}) { + setActiveViewer(0) + closeRotateAround(this.sdk) + closeViewFollow(this.sdk) + + if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { + let orientation = { + heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), + pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), + roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) + } + + let lng = this.options.customView.relativePosition.lng + let lat = this.options.customView.relativePosition.lat + let alt = this.options.customView.relativePosition.alt + let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + + let position = { lng: 0, lat: 0 } + if (this.options.position) { + position = { ...this.options.position } + } + else if (this.options.positions) { + position = { ...this.options.positions[0] } + } + else if (this.options.center) { + position = { ...this.options.center } + } + else if (this.options.start) { + position = { ...this.options.start } + } + else { + if (this.options.hasOwnProperty('lng')) { + position.lng = this.options.lng + } + if (this.options.hasOwnProperty('lat')) { + position.lat = this.options.lat + } + if (this.options.hasOwnProperty('alt')) { + position.alt = this.options.alt + } + } + // 如果没有高度值,则获取紧贴高度计算 + // if (!position.hasOwnProperty('alt')) { + // position.alt = await this.getClampToHeight(position) + // } + lng = this.options.customView.relativePosition.lng + position.lng + lat = this.options.customView.relativePosition.lat + position.lat + alt = this.options.customView.relativePosition.alt + position.alt + destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + this.sdk.viewer.camera.flyTo({ + destination: destination, + orientation: orientation + }) + } + else { + let positionArray = [] + for (let i = 0; i < this.positions.length; i++) { + let a = Cesium.Cartesian3.fromDegrees( + this.positions[i][0], + this.positions[i][1], + this.options.height + this.options.heightDifference / 2 + ) + positionArray.push(a.x, a.y, a.z) + } + let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) + this.viewer.camera.flyToBoundingSphere(BoundingSphere, { + offset: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-20.0), + roll: Cesium.Math.toRadians(0.0) + } + }) + + } + } + + getSphere() { + return new Promise((resolve) => { + // entity没有加载完成时 state 不会等于0 所以设置定时器直到获取到为止 + const interval = setInterval(() => { + const sphere = new Cesium.BoundingSphere() + const state = this.sdk.viewer._dataSourceDisplay.getBoundingSphere( + this.viewer.entities.getById(this.options.id), + false, + sphere + ) + if (state === Cesium.BoundingSphereState.DONE) { + clearInterval(interval) + } + }, 1000) + }) + } + + /** + * 删除 + */ + async remove() { + this.positions = [] + this.lineEntity = null + + if (this.viewer.entities.getById(this.options.id)) { + this.viewer.entities.getById(this.options.id)._children.forEach((item) => { + this.viewer.entities.remove(item); + }); + this.viewer.entities.remove(this.viewer.entities.getById(this.options.id)) + } + + if (this._DialogObject && !this._DialogObject.isDestroy) { + this._DialogObject.close() + this._DialogObject = null + } + await this.sdk.removeIncetance(this.options.id) + await syncData(this.sdk, this.options.id) + } + + flicker() { } +} + +export default Road diff --git a/src/Obj/Base/RoadObject/index-拐角连接.js b/src/Obj/Base/RoadObject/index-拐角连接.js new file mode 100644 index 0000000..9fb0c6c --- /dev/null +++ b/src/Obj/Base/RoadObject/index-拐角连接.js @@ -0,0 +1,889 @@ +/** + * @description 道路 + */ +import Dialog from '../../Element/Dialog'; +import { html } from "./_element"; +import EventBinding from '../../Element/Dialog/eventBinding'; +import Base from "../index"; +import { syncData } from '../../../Global/MultiViewportMode' +import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen' +import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' + +class Road extends Base { + /** + * @constructor + * @param sdk + * @description 道路 + * @param options {object} 道路属性 + * @param options.name=未命名对象 {string} 名称 + * @param options.carRoadWidth=2 {number} 车道宽度 + * @param options.sideWidth=2 {number} 人行道宽度 + * @param options.positions=[] {array} 道路positions + * @param options.roadImage='' {string} 车道贴图 + * @param options.sideImage='' {string} 人行道贴图 + * @param Dialog {object} 弹框对象 + * @param Dialog.confirmCallBack {function} 弹框确认时的回调 + * */ + constructor(sdk, options = {}, _Dialog = {}) { + super(sdk, options); + this.viewer = this.sdk.viewer + this.options.name = options.name || '道路' + this.options.carRoadWidth = options.carRoadWidth || 10 + this.options.sideWidth = options.sideWidth || 5 + this.options.positions = options.positions || [] + this.options.roadImage = options.roadImage || (this.getSourceRootPath() + '/img/roadPhoto.png') + this.options.sideImage = options.sideImage || (this.getSourceRootPath() + '/img/sidePhoto.png') + this.options.show = (options.show || options.show === false) ? options.show : true + this.Dialog = _Dialog + this._EventBinding = new EventBinding() + this._elms = {}; + this.positionArea = [] + this.positions = [] + this.lineEntity = '' + + this.sdk.addIncetance(this.options.id, this) + Road.create(this) + } + + // 创建道路 + static create(that) { + let positions = [] + that.options.positions.forEach(v => { + positions.push(new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) + }) + + let area = [[], [], []] + area[1] = that.createLineBufferPolygon2(positions, that.options.carRoadWidth / 2) + area[0] = that.createLineBufferPolygonSide(area[1][2], -that.options.sideWidth) + area[2] = that.createLineBufferPolygonSide(area[1][1], that.options.sideWidth) + + //判断道路边是否相交 + for (let i = 0; i < area[0].length - 1; i++) { + + let leftItem = area[0][i] + let leftItem2 = area[0][i + 1] + let rightItem = area[2][i] + let rightItem2 = area[2][i + 1] + let carItem = area[1][0][i] + let carItem2 = area[1][0][i + 1] + let leftLine = that.getIntersects(leftItem[1], leftItem[2], leftItem2[1], leftItem2[2]) + let rightLine = that.getIntersects(rightItem[1], rightItem[2], rightItem2[1], rightItem2[2]) + + console.log(leftLine, 'leftLine') + if (leftLine) {//左侧相交 + //获取右侧延长交点 + let point1 = that.getExtendPoint(rightItem[1], rightItem[2], 1000) + let point2 = that.getExtendPoint(rightItem2[2], rightItem2[1], 1000) + let rightIntersection = that.getIntersects(rightItem[2], point1, rightItem2[1], point2) + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[3], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + let rightLineNeiPoint = that.getExtendPoint(rightItem[0], rightItem[3], 1000) + + + + + //跟左侧里相交点 + let leftLineNei = that.getIntersects(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint) + //跟车道左侧相交点 + let carLeft = that.getIntersects(leftLine, rightIntersection, carItem[3], carLeftPoint) + //跟车道右侧相交点 + let carRight = that.getIntersects(leftLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(leftLine, rightIntersection, rightItem[0], rightLineNeiPoint) + + // let leftLineNei = that.getIntersects(leftLine, rightItem[2], leftItem[0], leftItem[3]) + // let carLeft = that.getIntersects(leftLine, rightItem[2], carItem[3], carItem[2]) + // let carRight = that.getIntersects(leftLine, rightItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, rightItem[2], rightItem[0], rightItem[3]) + + // let leftLineNei = that.getIntersects(leftLine, intersection, leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(leftLine, intersection, carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(leftLine, intersection, carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, intersection, rightItem[0], rightItem[3]) + + leftItem[2] = leftLine + leftItem[3] = leftLineNei + carItem[2] = carLeft + carItem[1] = carRight + rightItem[3] = rightLineNei + rightItem[2] = rightIntersection + console.log(leftItem, carItem, rightItem, 'leftItemleft') + + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[3], leftItem2[0], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[3], rightItem2[0], 1000) + + // let leftLineNei2 = that.getIntersects(leftLine, rightItem2[1], leftItem2[0], leftItem2[3]) + // let carLeft2 = that.getIntersects(leftLine, rightItem2[1], carItem2[3], carItem2[2]) + // let carRight2 = that.getIntersects(leftLine, rightItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, rightItem2[1], rightItem2[0], rightItem2[3]) + + + + let leftLineNei2 = that.getIntersects(leftLine, rightIntersection, leftItem2[3], leftLineNeiPoint2) + let carLeft2 = that.getIntersects(leftLine, rightIntersection, carItem2[2], carLeftPoint2) + let carRight2 = that.getIntersects(leftLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(leftLine, rightIntersection, rightItem2[3], rightLineNeiPoint2) + + // let arr = [leftLine, rightIntersection, leftItem2[3], leftLineNeiPoint2] + // arr.forEach((item, index) => { + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: i, + // position: item, + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + index, + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + // }) + + // let leftLineNei2 = that.getIntersects(leftLine, intersection, leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(leftLine, intersection, carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(leftLine, intersection, carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, intersection, rightItem2[0], rightItem2[3]) + + leftItem2[1] = leftLine + leftItem2[0] = leftLineNei2 + carItem2[3] = carLeft2 + carItem2[0] = carRight2 + rightItem2[0] = rightLineNei2 + rightItem2[1] = rightIntersection + console.log(leftItem2, carItem2, rightItem2, 'leftItem2left') + + } else if (rightLine) {//右侧相交 + + //获取左侧延长交点 + let point1 = that.getExtendPoint(leftItem[1], leftItem[2], 1000) + let point2 = that.getExtendPoint(leftItem2[2], leftItem2[1], 1000) + let rightIntersection = that.getIntersects(leftItem[2], point1, leftItem2[1], point2) + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[3], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + let rightLineNeiPoint = that.getExtendPoint(rightItem[0], rightItem[3], 1000) + + // //跟左侧里相交点 + let leftLineNei = that.getIntersects(rightLine, rightIntersection, leftItem[0], leftLineNeiPoint) + //跟车道左侧相交点 + let carLeft = that.getIntersects(rightLine, rightIntersection, carItem[3], carLeftPoint) + //跟车道右侧相交点 + let carRight = that.getIntersects(rightLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(rightLine, rightIntersection, rightItem[0], rightLineNeiPoint) + // //跟左侧里相交点 + // let leftLineNei = that.getIntersects(rightLine, leftItem[2], leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(rightLine, leftItem[2], carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(rightLine, leftItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(rightLine, leftItem[2], rightItem[0], rightItem[3]) + + + leftItem[2] = rightIntersection + leftItem[3] = leftLineNei + carItem[2] = carLeft + carItem[1] = carRight + rightItem[3] = rightLineNei + rightItem[2] = rightLine + console.log(leftItem, carItem, rightItem, 'leftItemright') + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[3], leftItem2[0], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[3], rightItem2[0], 1000) + + let leftLineNei2 = that.getIntersects(rightLine, rightIntersection, leftItem2[3], leftLineNeiPoint2) + //跟车道左侧相交点 + let carLeft2 = that.getIntersects(rightLine, rightIntersection, carItem2[2], carLeftPoint2) + //跟车道右侧相交点 + let carRight2 = that.getIntersects(rightLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(rightLine, rightIntersection, rightItem2[3], rightLineNeiPoint2) + // let leftLineNei2 = that.getIntersects(rightLine, leftItem2[1], leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(rightLine, leftItem2[1], carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(rightLine, leftItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(rightLine, leftItem2[1], rightItem2[0], rightItem2[3]) + + leftItem2[1] = rightIntersection + leftItem2[0] = leftLineNei2 + carItem2[3] = carLeft2 + carItem2[0] = carRight2 + rightItem2[0] = rightLineNei2 + rightItem2[1] = rightLine + console.log(leftItem2, carItem2, rightItem2, 'leftItem2right') + + } + } + + + console.log(area[0], 'area') + + if (that.viewer.entities.getById(that.options.id)) { + that.viewer.entities.getById(that.options.id)._children.forEach((item) => { + that.viewer.entities.remove(item); + }); + that.viewer.entities.remove(that.viewer.entities.getById(that.options.id)) + } + that.lineEntity = that.viewer.entities.add(new Cesium.Entity({ id: that.options.id, show: that.options.show })) + + const myImg = new Image() + myImg.src = that.options.roadImage + myImg.onload = function () { + console.log(area[1][0], 'arr') + area[1][0].forEach((item, index) => { + that.viewer.entities.add({ + // id: that.options.id, + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.roadImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + } + + const myImg2 = new Image() + myImg2.src = that.options.sideImage + myImg2.onload = function () { + area[0].forEach((item, index) => { + that.viewer.entities.add({ + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + area[2].forEach((item, index) => { + that.viewer.entities.add({ + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + } + + } + getExtendPoint(position1, position2, distance) { + // let position1 = Cesium.Cartesian3.fromDegrees(p1[0], p1[1], 0); + // let position2 = Cesium.Cartesian3.fromDegrees(p2[0], p2[1], 0); + let pot = Cesium.Cartesian3.subtract(position2, position1, new Cesium.Cartesian3());//方向 + var dir = Cesium.Cartesian3.normalize(pot, new Cesium.Cartesian3());//向量归一化 + + var ray = new Cesium.Ray(position1, dir); + let np = Cesium.Ray.getPoint(ray, distance * 10);//计算延长点 + return np + } + getArr(arr1, arr2) { + arr2 = arr2.reverse() + let polygon = [] + for (let index = 0; index < arr1.length - 1; index++) { + polygon.push([arr1[index], arr1[index + 1], arr2[index + 1], arr2[index]]) + } + return polygon + } + + calculateRoadAngle(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建精确ENU坐标系 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse(enuMatrix, new Cesium.Matrix4()); + + // 3. 转换终点并计算水平向量 + const localEnd = Cesium.Matrix4.multiplyByPoint(inverseMatrix, endPoint, new Cesium.Cartesian3()); + const horizontalVec = new Cesium.Cartesian2(localEnd.x, localEnd.y); + Cesium.Cartesian2.normalize(horizontalVec, horizontalVec); + + const north = new Cesium.Cartesian2(1, 0); + + const angle = Cesium.Cartesian2.angleBetween(north, horizontalVec); + const cross = Cesium.Cartesian2.cross(north, horizontalVec, new Cesium.Cartesian2()); + return cross < 0 ? angle : -angle; + } + + calculatePolygonOrientation(positions) { + + // 假设 position 是 Cesium.Cartesian3 对象,表示地球上的某个点 + var position = positions[0] + // 获取东、北、上坐标系 + var eastNorthUp = Cesium.Transforms.eastNorthUpToFixedFrame(position); + // northAxis 是北方向向量 + var northAxis = eastNorthUp.getColumn(1, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(northAxis, northAxis); + + const direction = Cesium.Cartesian3.subtract(positions[0], positions[1], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + + const dot = Cesium.Cartesian3.dot(northAxis, direction); + const magA = Cesium.Cartesian3.magnitude(northAxis); + const magB = Cesium.Cartesian3.magnitude(direction); + return Math.acos(dot / (magA * magB)); + } + calculateTextureRepeat(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + // 创建多边形几何体 + const geometry = Cesium.PolygonGeometry.createGeometry( + new Cesium.PolygonGeometry({ + polygonHierarchy: new Cesium.PolygonHierarchy(polygonPositions), + vertexFormat: Cesium.VertexFormat.POSITION_ONLY + }) + ); + + // 计算多边形面积(平方米) + let area = 0; + const indices = geometry.indices; + const positions = geometry.attributes.position.values; + for (let i = 0; i < indices.length; i += 3) { + const i0 = indices[i] * 3; + const i1 = indices[i + 1] * 3; + const i2 = indices[i + 2] * 3; + + const p0 = new Cesium.Cartesian3(positions[i0], positions[i0 + 1], positions[i0 + 2]); + const p1 = new Cesium.Cartesian3(positions[i1], positions[i1 + 1], positions[i1 + 2]); + const p2 = new Cesium.Cartesian3(positions[i2], positions[i2 + 1], positions[i2 + 2]); + + const cross = Cesium.Cartesian3.cross( + Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()), + Cesium.Cartesian3.subtract(p2, p0, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + area += Cesium.Cartesian3.magnitude(cross) * 0.5; + } + + // 将像素尺寸转换为实际尺寸(平方米) + const textureWidthMeters = textureSize.width * meterPerPixel; + const textureHeightMeters = textureSize.height * meterPerPixel; + const textureArea = textureWidthMeters * textureHeightMeters; + + // 计算各轴向重复次数 + const repeatX = Math.sqrt(area) / textureWidthMeters; + const repeatY = Math.sqrt(area) / textureHeightMeters; + + return new Cesium.Cartesian2(Math.max(1, Math.ceil(repeatX)), 1.0); + } + swapLastElements(arr1, arr2) { + const last = arr1[arr1.length - 1] + const first = arr2[0] + arr1[arr1.length - 1] = first + arr2[0] = last + + return [arr1, arr2]; + } + createLineBufferPolygonSide(positions, width) { + let area = [] + for (let i = 0; i < positions.length; i++) { + const posi = positions[i]; + + const dir = Cesium.Cartesian3.subtract(posi[1], posi[0], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(posi[0], offset, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(posi[1], offset, new Cesium.Cartesian3()) + + // i == positions.length - 2 ? area.push(start, point1, end, point3) : area.push(start, point1) + area.push([posi[0], point1, point3, posi[1]]) + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + return area + } + createLineBufferPolygon2(positions, width) { + let area = [] + let leftPositions = []; + let rightPositions = []; + + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + // const end = positions[i + 1] || positions[i - 1]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + const dir2 = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir2, dir2); + + // 获取垂直向量(基于Z轴) + const perp2 = Cesium.Cartesian3.cross(dir2, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp2, perp2); + + + + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + const offset2 = Cesium.Cartesian3.multiplyByScalar(perp, -width, new Cesium.Cartesian3()); + + const offsetEnd = Cesium.Cartesian3.multiplyByScalar(perp2, -width, new Cesium.Cartesian3()); + const offsetEnd2 = Cesium.Cartesian3.multiplyByScalar(perp2, width, new Cesium.Cartesian3()); + + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point2 = Cesium.Cartesian3.add(start, offset2, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offsetEnd, new Cesium.Cartesian3()) + let point4 = Cesium.Cartesian3.add(end, offsetEnd2, new Cesium.Cartesian3()) + + area.push([point1, point3, point4, point2]) + + rightPositions.push([point1, point3]) + leftPositions.push([point2, point4]) + + // if (i == positions.length - 2) { + // area.push(point1, point2, point3, point4) + // rightPositions.push(point1) + // leftPositions.push(point2) + // leftPositions.push(point4) + // rightPositions.push(point3) + // } else { + // area.push(point1, point2) + // rightPositions.push(point1) + // leftPositions.push(point2) + // } + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + console.log(area, rightPositions, 'rightPositions') + let that = this + // return [arr, rightPositions, leftPositions] + return [area, rightPositions, leftPositions] + } + getIntersects(point1, point2, point3, point4) { + let carPoint1 = this.getLonLat(point1) + let carPoint2 = this.getLonLat(point2) + let carPoint3 = this.getLonLat(point3) + let carPoint4 = this.getLonLat(point4) + var line1 = turf.lineString([ + [carPoint1.lon, carPoint1.lat], + [carPoint2.lon, carPoint2.lat] + ]); + var line2 = turf.lineString([ + [carPoint3.lon, carPoint3.lat], + [carPoint4.lon, carPoint4.lat] + ]); + var intersects = turf.lineIntersect(line1, line2); + if (intersects.features.length > 0) { + console.log(intersects.features, 'ooooo') + return Cesium.Cartesian3.fromDegrees(intersects.features[0].geometry.coordinates[0], intersects.features[0].geometry.coordinates[1]) + } + } + getLonLat(point) { + let pointDe = Cesium.Cartographic.fromCartesian(point) + const longitude = Cesium.Math.toDegrees(pointDe.longitude); + const latitude = Cesium.Math.toDegrees(pointDe.latitude); + return { lon: longitude, lat: latitude } + + } + createLineBufferPolygon(viewer, positions, width) { + // 计算每个线段的左右偏移点 + const leftPositions = []; + const rightPositions = []; + + for (let i = 0; i < positions.length; i++) { + const start = positions[i]; + const end = positions[i + 1] || positions[i - 1]; + + // 计算线段方向向量 + const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + // const direction = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量(使用上向量叉积) + const up = Cesium.Cartesian3.UNIT_Z; + const perpendicular = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perpendicular, perpendicular); + + // 计算左右偏移点 + const leftOffset = Cesium.Cartesian3.multiplyByScalar( + perpendicular, + width, + new Cesium.Cartesian3() + ); + + if (width > 0) { + rightPositions.unshift(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } else if (width < 0) { + rightPositions.push(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } + + } + return rightPositions + } + //计算角度 + calculateAangle(arr) { + // let fromDegreesArray = that.calSector(that.options.center, that.options.radius, that.options.startAngle, that.options.endAngle, 360, true) + + function getAangle(start, end) { + let rad = Math.PI / 180, + lat1 = start.y * rad, + lat2 = end.y * rad, + lon1 = start.x * rad, + lon2 = end.x * rad; + const a = Math.sin(lon2 - lon1) * Math.cos(lat2); + const b = + Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); + const radians = Math.atan2(a, b) + const degrees = radians % (2 * Math.PI); + let bearing = 450 - ((degrees * 180) / Math.PI < 0 + ? 360 + (degrees * 180) / Math.PI + : (degrees * 180) / Math.PI) - 90; + return 360 - (bearing % 360) + } + + let center = arr[0] + let pos84_1 = arr[1] + let pos84_2 = arr[2] + + let start = { x: center.lng, y: center.lat } + let end1 = { x: pos84_1.lng, y: pos84_1.lat } + let end2 = { x: pos84_2.lng, y: pos84_2.lat } + + let angle1 = getAangle(start, end1) + let angle2 = getAangle(start, end2) + + return { + angle1, + angle2 + } + } + + get carRoadWidth() { + return this.options.carRoadWidth + } + + set carRoadWidth(v) { + this.options.carRoadWidth = v + Road.create(this) + + } + get sideWidth() { + return this.options.sideWidth + } + set sideWidth(v) { + this.options.sideWidth = v + Road.create(this) + } + /** + * @description 编辑框 + * @param state=false {boolean} 状态: true打开, false关闭 + */ + async edit(state = false) { + let _this = this + this.originalOptions = this.deepCopyObj(this.options) + + if (this._DialogObject && this._DialogObject.close) { + this._DialogObject.close() + this._DialogObject = null + } + + if (state) { + this._DialogObject = await new Dialog(this.sdk, this.originalOptions, { + title: '道路属性', left: '180px', top: '100px', + confirmCallBack: (options) => { + this.name = this.name.trim() + if (!this.name) { + this.name = '道路' + } + this.originalOptions = this.deepCopyObj(this.options) + this._DialogObject.close() + this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions) + syncData(this.sdk, this.options.id) + syncSplitData(this.sdk, this.options.id) + }, + resetCallBack: () => { + this.reset() + this.Dialog.resetCallBack && this.Dialog.resetCallBack() + }, + closeCallBack: () => { + this.reset() + this.Dialog.closeCallBack && this.Dialog.closeCallBack() + }, + showCallBack: (show) => { + this.show = show + this.Dialog.showCallBack && this.Dialog.showCallBack() + } + }, true) + this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' road-surface' + let contentElm = document.createElement('div'); + contentElm.innerHTML = html() + this._DialogObject.contentAppChild(contentElm) + + + // 下拉选项 + // let heightModeData = [ + // { + // name: '海拔高度', + // value: '海拔高度', + // key: '0', + // }, + // { + // name: '相对地表', + // value: '相对地表', + // key: '1', + // }, + // { + // name: '依附模型', + // value: '依附模型', + // key: '2', + // } + // ] + // let heightModeObject = legp( + // this._DialogObject._element.content.getElementsByClassName( + // 'road-box' + // )[0], + // '.road-type' + // ) + // if (heightModeObject) { + // heightModeObject.legp_search(heightModeData) + // let heightModeDataLegpElm = this._DialogObject._element.content + // .getElementsByClassName('road-type')[0] + // .getElementsByTagName('input')[0] + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].key == this.heightMode) { + // heightModeDataLegpElm.value = heightModeData[i].value + // heightModeObject.legp_searchActive( + // heightModeData[i].value + // ) + // break + // } + // } + // heightModeDataLegpElm.addEventListener('input', () => { + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].value === heightModeDataLegpElm.value) { + // this.heightMode = heightModeData[i].key + // break + // } + // } + // }) + + + // this._elms.height = heightElm + // this._elms.heightBox = heightBoxElm + // this._elms.heightMode = heightModeDataLegpElm + // this._elms.heightConfirm = heightConfirmElm + // this._elms.heightModeObject = heightModeObject + + // heightConfirmElm.addEventListener('click', () => { + // this.positionEditing = false + // for (let i = 0; i < this.options.positions.length; i++) { + // this.options.positions[i].alt = Number((this.options.positions[i].alt + Number(heightElm.value)).toFixed(2)) + // this._elms.alt[i].innerHTML = this.options.positions[i].alt + // } + // let fromDegreesArray = this.renewPositions(this.options.positions) + // this.entity.polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights( + // fromDegreesArray + // ) + + // this.positionEditing = false + // PolylineObject.closeNodeEdit(this) + // }) + // } + + + + + + let all_elm = contentElm.getElementsByTagName("*") + this._EventBinding.on(this, all_elm) + this._elms = this._EventBinding.element + } else { + // if (this._element_style) { + // document.getElementsByTagName('head')[0].removeChild(this._element_style) + // this._element_style = null + // } + // if (this._DialogObject && this._DialogObject.remove) { + // this._DialogObject.remove() + // this._DialogObject = null + // } + } + } + + reset() { + if (!this.viewer.entities.getById(this.options.id)) { + return + } + this.name = this.originalOptions.name + this.carRoadWidth = this.originalOptions.carRoadWidth + this.sideWidth = this.originalOptions.sideWidth + this.positions = this.originalOptions.positions + this.roadImage = this.originalOptions.roadImage + this.sideImage = this.originalOptions.sideImage + } + + /** + * 飞到对应实体 + */ + async flyTo(options = {}) { + setActiveViewer(0) + closeRotateAround(this.sdk) + closeViewFollow(this.sdk) + + if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { + let orientation = { + heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), + pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), + roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) + } + + let lng = this.options.customView.relativePosition.lng + let lat = this.options.customView.relativePosition.lat + let alt = this.options.customView.relativePosition.alt + let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + + let position = { lng: 0, lat: 0 } + if (this.options.position) { + position = { ...this.options.position } + } + else if (this.options.positions) { + position = { ...this.options.positions[0] } + } + else if (this.options.center) { + position = { ...this.options.center } + } + else if (this.options.start) { + position = { ...this.options.start } + } + else { + if (this.options.hasOwnProperty('lng')) { + position.lng = this.options.lng + } + if (this.options.hasOwnProperty('lat')) { + position.lat = this.options.lat + } + if (this.options.hasOwnProperty('alt')) { + position.alt = this.options.alt + } + } + // 如果没有高度值,则获取紧贴高度计算 + // if (!position.hasOwnProperty('alt')) { + // position.alt = await this.getClampToHeight(position) + // } + lng = this.options.customView.relativePosition.lng + position.lng + lat = this.options.customView.relativePosition.lat + position.lat + alt = this.options.customView.relativePosition.alt + position.alt + destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + this.sdk.viewer.camera.flyTo({ + destination: destination, + orientation: orientation + }) + } + else { + let positionArray = [] + for (let i = 0; i < this.positions.length; i++) { + let a = Cesium.Cartesian3.fromDegrees( + this.positions[i][0], + this.positions[i][1], + this.options.height + this.options.heightDifference / 2 + ) + positionArray.push(a.x, a.y, a.z) + } + let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) + this.viewer.camera.flyToBoundingSphere(BoundingSphere, { + offset: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-20.0), + roll: Cesium.Math.toRadians(0.0) + } + }) + + } + } + + getSphere() { + return new Promise((resolve) => { + // entity没有加载完成时 state 不会等于0 所以设置定时器直到获取到为止 + const interval = setInterval(() => { + const sphere = new Cesium.BoundingSphere() + const state = this.sdk.viewer._dataSourceDisplay.getBoundingSphere( + this.viewer.entities.getById(this.options.id), + false, + sphere + ) + if (state === Cesium.BoundingSphereState.DONE) { + clearInterval(interval) + } + }, 1000) + }) + } + + /** + * 删除 + */ + async remove() { + this.positions = [] + this.lineEntity = null + + if (this.viewer.entities.getById(this.options.id)) { + this.viewer.entities.getById(this.options.id)._children.forEach((item) => { + this.viewer.entities.remove(item); + }); + this.viewer.entities.remove(this.viewer.entities.getById(this.options.id)) + } + + if (this._DialogObject && !this._DialogObject.isDestroy) { + this._DialogObject.close() + this._DialogObject = null + } + await this.sdk.removeIncetance(this.options.id) + await syncData(this.sdk, this.options.id) + } + + flicker() { } +} + +export default Road diff --git a/src/Obj/Base/RoadObject/index-直接连接.js b/src/Obj/Base/RoadObject/index-直接连接.js new file mode 100644 index 0000000..e31297a --- /dev/null +++ b/src/Obj/Base/RoadObject/index-直接连接.js @@ -0,0 +1,615 @@ +/** + * @description 道路 + */ +import Dialog from '../../Element/Dialog'; +import { html } from "./_element"; +import EventBinding from '../../Element/Dialog/eventBinding'; +import Base from "../index"; +import { syncData } from '../../../Global/MultiViewportMode' +import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen' +import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' + +class Road extends Base { + /** + * @constructor + * @param sdk + * @description 道路 + * @param options {object} 道路属性 + * @param options.name=未命名对象 {string} 名称 + * @param options.carRoadWidth=2 {number} 车道宽度 + * @param options.sideWidth=2 {number} 人行道宽度 + * @param options.positions=[] {array} 道路positions + * @param options.roadImage='' {string} 车道贴图 + * @param options.sideImage='' {string} 人行道贴图 + * @param Dialog {object} 弹框对象 + * @param Dialog.confirmCallBack {function} 弹框确认时的回调 + * */ + constructor(sdk, options = {}, _Dialog = {}) { + super(sdk, options); + this.viewer = this.sdk.viewer + this.options.name = options.name || '道路' + this.options.carRoadWidth = options.carRoadWidth || 10 + this.options.sideWidth = options.sideWidth || 5 + this.options.positions = options.positions || [] + this.options.roadImage = options.roadImage || (this.getSourceRootPath() + '/img/roadPhoto.png') + this.options.sideImage = options.sideImage || (this.getSourceRootPath() + '/img/sidePhoto.png') + this.options.show = (options.show || options.show === false) ? options.show : true + this.Dialog = _Dialog + this._EventBinding = new EventBinding() + this._elms = {}; + this.positionArea = [] + this.positions = [] + this.lineEntity = '' + + this.sdk.addIncetance(this.options.id, this) + Road.create(this) + } + + // 创建道路 + static create(that) { + let positions = [] + that.options.positions.forEach(v => { + positions.push(new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) + }) + + let area = [[], [], []] + area[1] = that.createLineBufferPolygon2(positions, that.options.carRoadWidth / 2) + area[0] = that.createLineBufferPolygonSide(area[1][2], -that.options.sideWidth) + area[2] = that.createLineBufferPolygonSide(area[1][1], that.options.sideWidth) + + if (that.viewer.entities.getById(that.options.id)) { + that.viewer.entities.getById(that.options.id)._children.forEach((item) => { + that.viewer.entities.remove(item); + }); + that.viewer.entities.remove(that.viewer.entities.getById(that.options.id)) + } + that.lineEntity = that.viewer.entities.add(new Cesium.Entity({ id: that.options.id, show: that.options.show })) + + const myImg = new Image() + myImg.src = that.options.roadImage + myImg.onload = function () { + area[1][0].forEach((item, index) => { + that.viewer.entities.add({ + // id: that.options.id, + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.roadImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + } + + const myImg2 = new Image() + myImg2.src = that.options.sideImage + myImg2.onload = function () { + area[0].forEach((item, index) => { + that.viewer.entities.add({ + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + area[2].forEach((item, index) => { + that.viewer.entities.add({ + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + } + + } + getArr(arr1, arr2) { + arr2 = arr2.reverse() + let polygon = [] + for (let index = 0; index < arr1.length - 1; index++) { + polygon.push([arr1[index], arr1[index + 1], arr2[index + 1], arr2[index]]) + } + return polygon + } + + calculateRoadAngle(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建精确ENU坐标系 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse(enuMatrix, new Cesium.Matrix4()); + + // 3. 转换终点并计算水平向量 + const localEnd = Cesium.Matrix4.multiplyByPoint(inverseMatrix, endPoint, new Cesium.Cartesian3()); + const horizontalVec = new Cesium.Cartesian2(localEnd.x, localEnd.y); + Cesium.Cartesian2.normalize(horizontalVec, horizontalVec); + + const north = new Cesium.Cartesian2(1, 0); + + const angle = Cesium.Cartesian2.angleBetween(north, horizontalVec); + const cross = Cesium.Cartesian2.cross(north, horizontalVec, new Cesium.Cartesian2()); + return cross < 0 ? angle : -angle; + } + + calculatePolygonOrientation(positions) { + + // 假设 position 是 Cesium.Cartesian3 对象,表示地球上的某个点 + var position = positions[0] + // 获取东、北、上坐标系 + var eastNorthUp = Cesium.Transforms.eastNorthUpToFixedFrame(position); + // northAxis 是北方向向量 + var northAxis = eastNorthUp.getColumn(1, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(northAxis, northAxis); + + const direction = Cesium.Cartesian3.subtract(positions[0], positions[1], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + + const dot = Cesium.Cartesian3.dot(northAxis, direction); + const magA = Cesium.Cartesian3.magnitude(northAxis); + const magB = Cesium.Cartesian3.magnitude(direction); + return Math.acos(dot / (magA * magB)); + } + calculateTextureRepeat(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + // 创建多边形几何体 + const geometry = Cesium.PolygonGeometry.createGeometry( + new Cesium.PolygonGeometry({ + polygonHierarchy: new Cesium.PolygonHierarchy(polygonPositions), + vertexFormat: Cesium.VertexFormat.POSITION_ONLY + }) + ); + + // 计算多边形面积(平方米) + let area = 0; + const indices = geometry.indices; + const positions = geometry.attributes.position.values; + for (let i = 0; i < indices.length; i += 3) { + const i0 = indices[i] * 3; + const i1 = indices[i + 1] * 3; + const i2 = indices[i + 2] * 3; + + const p0 = new Cesium.Cartesian3(positions[i0], positions[i0 + 1], positions[i0 + 2]); + const p1 = new Cesium.Cartesian3(positions[i1], positions[i1 + 1], positions[i1 + 2]); + const p2 = new Cesium.Cartesian3(positions[i2], positions[i2 + 1], positions[i2 + 2]); + + const cross = Cesium.Cartesian3.cross( + Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()), + Cesium.Cartesian3.subtract(p2, p0, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + area += Cesium.Cartesian3.magnitude(cross) * 0.5; + } + + // 将像素尺寸转换为实际尺寸(平方米) + const textureWidthMeters = textureSize.width * meterPerPixel; + const textureHeightMeters = textureSize.height * meterPerPixel; + const textureArea = textureWidthMeters * textureHeightMeters; + + // 计算各轴向重复次数 + const repeatX = Math.sqrt(area) / textureWidthMeters; + const repeatY = Math.sqrt(area) / textureHeightMeters; + + return new Cesium.Cartesian2(Math.max(1, Math.ceil(repeatX)), 1.0); + } + swapLastElements(arr1, arr2) { + const last = arr1[arr1.length - 1] + const first = arr2[0] + arr1[arr1.length - 1] = first + arr2[0] = last + + return [arr1, arr2]; + } + createLineBufferPolygonSide(positions, width) { + let area = [] + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offset, new Cesium.Cartesian3()) + + i == positions.length - 2 ? area.push(start, point1, end, point3) : area.push(start, point1) + } + let arr = [] + for (let i = 0; i < area.length - 2; i += 2) { + arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + } + return arr + } + createLineBufferPolygon2(positions, width) { + let area = [] + let leftPositions = []; + let rightPositions = []; + + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + // const end = positions[i + 1] || positions[i - 1]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + const offset2 = Cesium.Cartesian3.multiplyByScalar(perp, -width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point2 = Cesium.Cartesian3.add(start, offset2, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offset, new Cesium.Cartesian3()) + let point4 = Cesium.Cartesian3.add(end, offset2, new Cesium.Cartesian3()) + + if (i == positions.length - 2) { + area.push(point1, point2, point3, point4) + rightPositions.push(point1) + leftPositions.push(point2) + leftPositions.push(point4) + rightPositions.push(point3) + } else { + area.push(point1, point2) + rightPositions.push(point1) + leftPositions.push(point2) + } + } + let arr = [] + for (let i = 0; i < area.length - 2; i += 2) { + arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + } + return [arr, rightPositions, leftPositions] + } + createLineBufferPolygon(viewer, positions, width) { + // 计算每个线段的左右偏移点 + const leftPositions = []; + const rightPositions = []; + + for (let i = 0; i < positions.length; i++) { + const start = positions[i]; + const end = positions[i + 1] || positions[i - 1]; + + // 计算线段方向向量 + const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + // const direction = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量(使用上向量叉积) + const up = Cesium.Cartesian3.UNIT_Z; + const perpendicular = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perpendicular, perpendicular); + + // 计算左右偏移点 + const leftOffset = Cesium.Cartesian3.multiplyByScalar( + perpendicular, + width, + new Cesium.Cartesian3() + ); + + if (width > 0) { + rightPositions.unshift(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } else if (width < 0) { + rightPositions.push(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } + + } + return rightPositions + } + + get carRoadWidth() { + return this.options.carRoadWidth + } + + set carRoadWidth(v) { + this.options.carRoadWidth = v + Road.create(this) + + } + get sideWidth() { + return this.options.sideWidth + } + set sideWidth(v) { + this.options.sideWidth = v + Road.create(this) + } + /** + * @description 编辑框 + * @param state=false {boolean} 状态: true打开, false关闭 + */ + async edit(state = false) { + let _this = this + this.originalOptions = this.deepCopyObj(this.options) + + if (this._DialogObject && this._DialogObject.close) { + this._DialogObject.close() + this._DialogObject = null + } + + if (state) { + this._DialogObject = await new Dialog(this.sdk, this.originalOptions, { + title: '道路属性', left: '180px', top: '100px', + confirmCallBack: (options) => { + this.name = this.name.trim() + if (!this.name) { + this.name = '道路' + } + this.originalOptions = this.deepCopyObj(this.options) + this._DialogObject.close() + this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions) + syncData(this.sdk, this.options.id) + syncSplitData(this.sdk, this.options.id) + }, + resetCallBack: () => { + this.reset() + this.Dialog.resetCallBack && this.Dialog.resetCallBack() + }, + closeCallBack: () => { + this.reset() + this.Dialog.closeCallBack && this.Dialog.closeCallBack() + }, + showCallBack: (show) => { + this.show = show + this.Dialog.showCallBack && this.Dialog.showCallBack() + } + }, true) + this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' road-surface' + let contentElm = document.createElement('div'); + contentElm.innerHTML = html() + this._DialogObject.contentAppChild(contentElm) + + + // 下拉选项 + // let heightModeData = [ + // { + // name: '海拔高度', + // value: '海拔高度', + // key: '0', + // }, + // { + // name: '相对地表', + // value: '相对地表', + // key: '1', + // }, + // { + // name: '依附模型', + // value: '依附模型', + // key: '2', + // } + // ] + // let heightModeObject = legp( + // this._DialogObject._element.content.getElementsByClassName( + // 'road-box' + // )[0], + // '.road-type' + // ) + // if (heightModeObject) { + // heightModeObject.legp_search(heightModeData) + // let heightModeDataLegpElm = this._DialogObject._element.content + // .getElementsByClassName('road-type')[0] + // .getElementsByTagName('input')[0] + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].key == this.heightMode) { + // heightModeDataLegpElm.value = heightModeData[i].value + // heightModeObject.legp_searchActive( + // heightModeData[i].value + // ) + // break + // } + // } + // heightModeDataLegpElm.addEventListener('input', () => { + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].value === heightModeDataLegpElm.value) { + // this.heightMode = heightModeData[i].key + // break + // } + // } + // }) + + + // this._elms.height = heightElm + // this._elms.heightBox = heightBoxElm + // this._elms.heightMode = heightModeDataLegpElm + // this._elms.heightConfirm = heightConfirmElm + // this._elms.heightModeObject = heightModeObject + + // heightConfirmElm.addEventListener('click', () => { + // this.positionEditing = false + // for (let i = 0; i < this.options.positions.length; i++) { + // this.options.positions[i].alt = Number((this.options.positions[i].alt + Number(heightElm.value)).toFixed(2)) + // this._elms.alt[i].innerHTML = this.options.positions[i].alt + // } + // let fromDegreesArray = this.renewPositions(this.options.positions) + // this.entity.polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights( + // fromDegreesArray + // ) + + // this.positionEditing = false + // PolylineObject.closeNodeEdit(this) + // }) + // } + + + + + + let all_elm = contentElm.getElementsByTagName("*") + this._EventBinding.on(this, all_elm) + this._elms = this._EventBinding.element + } else { + // if (this._element_style) { + // document.getElementsByTagName('head')[0].removeChild(this._element_style) + // this._element_style = null + // } + // if (this._DialogObject && this._DialogObject.remove) { + // this._DialogObject.remove() + // this._DialogObject = null + // } + } + } + + reset() { + if (!this.viewer.entities.getById(this.options.id)) { + return + } + this.name = this.originalOptions.name + this.carRoadWidth = this.originalOptions.carRoadWidth + this.sideWidth = this.originalOptions.sideWidth + this.positions = this.originalOptions.positions + this.roadImage = this.originalOptions.roadImage + this.sideImage = this.originalOptions.sideImage + } + + /** + * 飞到对应实体 + */ + async flyTo(options = {}) { + setActiveViewer(0) + closeRotateAround(this.sdk) + closeViewFollow(this.sdk) + + if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { + let orientation = { + heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), + pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), + roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) + } + + let lng = this.options.customView.relativePosition.lng + let lat = this.options.customView.relativePosition.lat + let alt = this.options.customView.relativePosition.alt + let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + + let position = { lng: 0, lat: 0 } + if (this.options.position) { + position = { ...this.options.position } + } + else if (this.options.positions) { + position = { ...this.options.positions[0] } + } + else if (this.options.center) { + position = { ...this.options.center } + } + else if (this.options.start) { + position = { ...this.options.start } + } + else { + if (this.options.hasOwnProperty('lng')) { + position.lng = this.options.lng + } + if (this.options.hasOwnProperty('lat')) { + position.lat = this.options.lat + } + if (this.options.hasOwnProperty('alt')) { + position.alt = this.options.alt + } + } + // 如果没有高度值,则获取紧贴高度计算 + // if (!position.hasOwnProperty('alt')) { + // position.alt = await this.getClampToHeight(position) + // } + lng = this.options.customView.relativePosition.lng + position.lng + lat = this.options.customView.relativePosition.lat + position.lat + alt = this.options.customView.relativePosition.alt + position.alt + destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + this.sdk.viewer.camera.flyTo({ + destination: destination, + orientation: orientation + }) + } + else { + let positionArray = [] + for (let i = 0; i < this.positions.length; i++) { + let a = Cesium.Cartesian3.fromDegrees( + this.positions[i][0], + this.positions[i][1], + this.options.height + this.options.heightDifference / 2 + ) + positionArray.push(a.x, a.y, a.z) + } + let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) + this.viewer.camera.flyToBoundingSphere(BoundingSphere, { + offset: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-20.0), + roll: Cesium.Math.toRadians(0.0) + } + }) + + } + } + + getSphere() { + return new Promise((resolve) => { + // entity没有加载完成时 state 不会等于0 所以设置定时器直到获取到为止 + const interval = setInterval(() => { + const sphere = new Cesium.BoundingSphere() + const state = this.sdk.viewer._dataSourceDisplay.getBoundingSphere( + this.viewer.entities.getById(this.options.id), + false, + sphere + ) + if (state === Cesium.BoundingSphereState.DONE) { + clearInterval(interval) + } + }, 1000) + }) + } + + /** + * 删除 + */ + async remove() { + this.positions = [] + this.lineEntity = null + + if (this.viewer.entities.getById(this.options.id)) { + this.viewer.entities.getById(this.options.id)._children.forEach((item) => { + this.viewer.entities.remove(item); + }); + this.viewer.entities.remove(this.viewer.entities.getById(this.options.id)) + } + + if (this._DialogObject && !this._DialogObject.isDestroy) { + this._DialogObject.close() + this._DialogObject = null + } + await this.sdk.removeIncetance(this.options.id) + await syncData(this.sdk, this.options.id) + } + + flicker() { } +} + +export default Road diff --git a/src/Obj/Base/RoadObject/index-面大小一致.js b/src/Obj/Base/RoadObject/index-面大小一致.js new file mode 100644 index 0000000..620efa6 --- /dev/null +++ b/src/Obj/Base/RoadObject/index-面大小一致.js @@ -0,0 +1,1023 @@ +/** + * @description 道路 + */ +import Dialog from '../../Element/Dialog'; +import { html } from "./_element"; +import EventBinding from '../../Element/Dialog/eventBinding'; +import Base from "../index"; +import { syncData } from '../../../Global/MultiViewportMode' +import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen' +import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' + +class Road extends Base { + /** + * @constructor + * @param sdk + * @description 道路 + * @param options {object} 道路属性 + * @param options.name=未命名对象 {string} 名称 + * @param options.carRoadWidth=2 {number} 车道宽度 + * @param options.sideWidth=2 {number} 人行道宽度 + * @param options.positions=[] {array} 道路positions + * @param options.roadImage='' {string} 车道贴图 + * @param options.sideImage='' {string} 人行道贴图 + * @param Dialog {object} 弹框对象 + * @param Dialog.confirmCallBack {function} 弹框确认时的回调 + * */ + constructor(sdk, options = {}, _Dialog = {}) { + super(sdk, options); + this.viewer = this.sdk.viewer + this.options.name = options.name || '道路' + this.options.carRoadWidth = options.carRoadWidth || 10 + this.options.sideWidth = options.sideWidth || 5 + this.options.positions = options.positions || [] + this.options.roadImage = options.roadImage || (this.getSourceRootPath() + '/img/roadPhoto.png') + this.options.sideImage = options.sideImage || (this.getSourceRootPath() + '/img/sidePhoto.png') + this.options.show = (options.show || options.show === false) ? options.show : true + this.Dialog = _Dialog + this._EventBinding = new EventBinding() + this._elms = {}; + this.positionArea = [] + this.positions = [] + this.lineEntity = '' + this.crossArr = [] + this.pointArr = [] + + this.sdk.addIncetance(this.options.id, this) + Road.create(this) + } + // 创建道路 + static create(that) { + let positions = [] + that.options.positions.forEach(v => { + positions.push(new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) + }) + let newPosi = [] + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + const end = positions[i + 1]; + newPosi.push([start, end]) + that.pointArr = newPosi + } + + let area = [[], [], []] + + // area[1] = that.getRectangle(positions, that.options.carRoadWidth) + area[1][0] = that.getRectangle(newPosi, that.options.carRoadWidth) + let sideArr = that.getSideRectangle(area[1][0], that.options.sideWidth) + area[0] = sideArr.left + area[2] = sideArr.right + // area[1] = that.createLineBufferPolygon2(positions, that.options.carRoadWidth / 2) + // area[1] = newPositions + // area[0] = that.createLineBufferPolygonSide(area[1][2], -that.options.sideWidth) + // area[2] = that.createLineBufferPolygonSide(area[1][1], that.options.sideWidth) + + //判断道路边是否相交 + for (let i = 0; i < area[0].length - 1; i++) { + + let leftItem = area[0][i] + let leftItem2 = area[0][i + 1] + let rightItem = area[2][i] + let rightItem2 = area[2][i + 1] + let carItem = area[1][0][i] + let carItem2 = area[1][0][i + 1] + let leftLine = that.getIntersects(leftItem[2], leftItem[3], leftItem2[2], leftItem2[3]) + let rightLine = that.getIntersects(rightItem[0], rightItem[1], rightItem2[0], rightItem2[1]) + + console.log(leftLine, rightLine, 'leftLine') + if (leftLine) {//左侧相交 + //获取右侧延长交点 + let point1 = that.getExtendPoint(rightItem[0], rightItem[1], 1000) + let point2 = that.getExtendPoint(rightItem2[1], rightItem2[0], 1000) + console.log('aaaa') + let rightIntersection = that.getIntersects(rightItem[0], point1, rightItem2[1], point2) + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + + let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + + + console.log(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint, 'bbbb') + //跟左侧里相交点 + let leftLineNei = that.getIntersects(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint) + console.log(leftLineNei, 'leftLineNei') + //跟车道左侧相交点 + let carLeft = that.getIntersects(leftLine, rightIntersection, carItem[3], carLeftPoint) + + //跟车道右侧相交点 + let carRight = that.getIntersects(leftLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(leftLine, rightIntersection, rightItem[3], rightLineNeiPoint) + console.log('ccc') + // let leftLineNei = that.getIntersects(leftLine, rightItem[2], leftItem[0], leftItem[3]) + // let carLeft = that.getIntersects(leftLine, rightItem[2], carItem[3], carItem[2]) + // let carRight = that.getIntersects(leftLine, rightItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, rightItem[2], rightItem[0], rightItem[3]) + + // let leftLineNei = that.getIntersects(leftLine, intersection, leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(leftLine, intersection, carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(leftLine, intersection, carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, intersection, rightItem[0], rightItem[3]) + + leftItem[2] = leftLine + leftItem[1] = leftLineNei + carItem[2] = carLeft + carItem[1] = carRight + rightItem[2] = rightLineNei + rightItem[1] = rightIntersection + console.log(leftItem, carItem, rightItem, 'leftItemleft') + + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[1], leftItem2[0], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + // let leftLineNei2 = that.getIntersects(leftLine, rightItem2[1], leftItem2[0], leftItem2[3]) + // let carLeft2 = that.getIntersects(leftLine, rightItem2[1], carItem2[3], carItem2[2]) + // let carRight2 = that.getIntersects(leftLine, rightItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, rightItem2[1], rightItem2[0], rightItem2[3]) + + + + let leftLineNei2 = that.getIntersects(leftLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + let carLeft2 = that.getIntersects(leftLine, rightIntersection, carItem2[2], carLeftPoint2) + let carRight2 = that.getIntersects(leftLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(leftLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + + // let arr = [leftLine, rightIntersection, leftItem2[3], leftLineNeiPoint2] + // arr.forEach((item, index) => { + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: i, + // position: item, + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + index, + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + // }) + + // let leftLineNei2 = that.getIntersects(leftLine, intersection, leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(leftLine, intersection, carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(leftLine, intersection, carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, intersection, rightItem2[0], rightItem2[3]) + + leftItem2[3] = leftLine + leftItem2[0] = leftLineNei + carItem2[3] = carLeft + carItem2[0] = carRight + rightItem2[3] = rightLineNei + rightItem2[0] = rightIntersection + console.log(leftItem2, carItem2, rightItem2, 'leftItem2left') + + } else if (rightLine) {//右侧相交 + + //获取左侧延长交点 + let point1 = that.getExtendPoint(leftItem[3], leftItem[2], 1000) + let point2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + let rightIntersection = that.getIntersects(leftItem[3], point1, leftItem2[2], point2) + if (!rightIntersection) { + return + } + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + // //跟左侧里相交点 + let leftLineNei = that.getIntersects(rightLine, rightIntersection, leftItem[0], leftLineNeiPoint) + //跟车道左侧相交点 + let carLeft = that.getIntersects(rightLine, rightIntersection, carItem[3], carLeftPoint) + //跟车道右侧相交点 + let carRight = that.getIntersects(rightLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(rightLine, rightIntersection, rightItem[3], rightLineNeiPoint) + // //跟左侧里相交点 + // let leftLineNei = that.getIntersects(rightLine, leftItem[2], leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(rightLine, leftItem[2], carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(rightLine, leftItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(rightLine, leftItem[2], rightItem[0], rightItem[3]) + + + leftItem[2] = rightIntersection + leftItem[1] = leftLineNei + carItem[2] = carLeft + carItem[1] = carRight + rightItem[2] = rightLineNei + rightItem[1] = rightLine + console.log(leftItem, carItem, rightItem, 'leftItemright') + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + let leftLineNei2 = that.getIntersects(rightLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + //跟车道左侧相交点 + let carLeft2 = that.getIntersects(rightLine, rightIntersection, carItem2[2], carLeftPoint2) + //跟车道右侧相交点 + let carRight2 = that.getIntersects(rightLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(rightLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + // let leftLineNei2 = that.getIntersects(rightLine, leftItem2[1], leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(rightLine, leftItem2[1], carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(rightLine, leftItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(rightLine, leftItem2[1], rightItem2[0], rightItem2[3]) + + leftItem2[3] = rightIntersection + leftItem2[0] = leftLineNei + carItem2[3] = carLeft + carItem2[0] = carRight + rightItem2[3] = rightLineNei + rightItem2[0] = rightLine + console.log(leftItem2, carItem2, rightItem2, 'leftItem2right') + + } + } + + if (that.viewer.entities.getById(that.options.id)) { + that.viewer.entities.getById(that.options.id)._children.forEach((item) => { + that.viewer.entities.remove(item); + }); + that.viewer.entities.remove(that.viewer.entities.getById(that.options.id)) + } + that.lineEntity = that.viewer.entities.add(new Cesium.Entity({ id: that.options.id, show: that.options.show })) + + const myImg = new Image() + myImg.src = that.options.roadImage + myImg.onload = function () { + console.log(area[1][0], that.options.roadImage, 'llll') + area[1][0].forEach((item, index) => { + that.viewer.entities.add({ + // id: that.options.id, + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.roadImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + } + + const myImg2 = new Image() + myImg2.src = that.options.sideImage + myImg2.onload = function () { + // area[0].forEach((item, index) => { + area[0].forEach((item, index) => { + that.viewer.entities.add({ + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + // area[2].forEach((item, index) => { + area[2].forEach((item, index) => { + that.viewer.entities.add({ + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + } + + } + getSideRectangle(positions, width) { + let right = [] + let left = [] + let that = this + positions.forEach(item => { + right.push([item[0], item[1]]) + left.push([item[2], item[3]]) + }) + let rightPosi = that.getRectangle(right, width, 'side') + + let leftPosi = this.getRectangle(left, width, 'side') + return { left: leftPosi, right: rightPosi } + } + getRectangle(positions, width, type) { + let areaArr = [] + let newPositions = [] + let that = this + // for (let i = 0; i < positions.length - 1; i++) { + for (let i = 0; i < positions.length; i++) { + const start = positions[i][0]; + const end = positions[i][1]; + + areaArr[i] = [] + let posi = [] + let Outlinegeometry = new Cesium.CorridorGeometry({ + positions: [start, end], + width: width, + cornerType: Cesium.CornerType.MITERED, + vertexFormat: Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat + }) + let geometry = Cesium.CorridorGeometry.createGeometry(Outlinegeometry) + for (let j = 0; j < geometry.attributes.position.values.length; j += 3) { + let val = that.cartesian3Towgs84(new Cesium.Cartesian3(geometry.attributes.position.values[j], geometry.attributes.position.values[j + 1], geometry.attributes.position.values[j + 2]), that.sdk.viewer) + posi.push([val.lng, val.lat]) + } + + for (let x = 0; x < geometry.indices.length; x += 3) { + areaArr[i].push(turf.polygon([[posi[geometry.indices[x]], posi[geometry.indices[x + 1]], posi[geometry.indices[x + 2]], posi[geometry.indices[x]]]])) + } + + let geojson = turf.union(areaArr[i][0], areaArr[i][1]); + let arr = [] + geojson.geometry.coordinates[0].pop() + geojson.geometry.coordinates[0].forEach(item => { + arr.push(new Cesium.Cartesian3.fromDegrees(item[0], item[1])) + }) + let dotResult, angle + const tempVec = new Cesium.Cartesian3(); + + // 计算并归一化第一个向量 + const vector1 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(that.pointArr[i][1], that.pointArr[i][0], tempVec), + tempVec + ); + + // 计算并归一化第二个向量 + const vector2 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(arr[1], arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + dotResult = Cesium.Cartesian3.dot(vector1, vector2); + if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + newPositions.push(arr) + } else { + let newArr = [] + newArr[0] = arr[1] + newArr[1] = arr[2] + newArr[2] = arr[3] + newArr[3] = arr[0] + newPositions.push(newArr) + } + // } + + // if (!type) { + // // if (cross > 0 && !type) {//调整方向 + // if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + // newPositions.push(arr) + // } else { + // let newArr = [] + // newArr[0] = arr[1] + // newArr[1] = arr[2] + // newArr[2] = arr[3] + // newArr[3] = arr[0] + // newPositions.push(newArr) + // } + // } else { + // newPositions.push(arr) + // } + } + return newPositions + } + getExtendPoint(position1, position2, distance) { + // let position1 = Cesium.Cartesian3.fromDegrees(p1[0], p1[1], 0); + // let position2 = Cesium.Cartesian3.fromDegrees(p2[0], p2[1], 0); + let pot = Cesium.Cartesian3.subtract(position2, position1, new Cesium.Cartesian3());//方向 + var dir = Cesium.Cartesian3.normalize(pot, new Cesium.Cartesian3());//向量归一化 + + var ray = new Cesium.Ray(position1, dir); + let np = Cesium.Ray.getPoint(ray, distance * 10);//计算延长点 + return np + } + getArr(arr1, arr2) { + arr2 = arr2.reverse() + let polygon = [] + for (let index = 0; index < arr1.length - 1; index++) { + polygon.push([arr1[index], arr1[index + 1], arr2[index + 1], arr2[index]]) + } + return polygon + } + calculateRoadAngle2(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = this.sdk.viewer.scene.globe.ellipsoid.geodeticSurfaceNormal( + startPoint, new Cesium.Cartesian3()); + + // 2. 构建带椭球参数的ENU矩阵 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( + startPoint, this.sdk.viewer.scene.globe.ellipsoid, normal); + const inverseMatrix = Cesium.Matrix4.inverse( + enuMatrix, new Cesium.Matrix4()); + + // 3. 转换坐标并计算相对向量 + const localEnd = Cesium.Matrix4.multiplyByPoint( + inverseMatrix, endPoint, new Cesium.Cartesian3()); + const heightFactor = Math.abs(localEnd.z) / 1000; // 高度差补偿 + + // 4. 使用四象限反正切计算角度 + const angle = Math.atan2(localEnd.y, localEnd.x); + const adjustedAngle = angle - (heightFactor * 0.01); // 高度补偿 + let result = Cesium.Math.toDegrees(adjustedAngle) + console.log(result, 'result') + return result; + } + calculateRoadAngle(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建精确ENU坐标系 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse(enuMatrix, new Cesium.Matrix4()); + + // 3. 转换终点并计算水平向量 + const localEnd = Cesium.Matrix4.multiplyByPoint(inverseMatrix, endPoint, new Cesium.Cartesian3()); + const horizontalVec = new Cesium.Cartesian2(localEnd.x, localEnd.y); + Cesium.Cartesian2.normalize(horizontalVec, horizontalVec); + + const north = new Cesium.Cartesian2(1, 0); + + const angle = Cesium.Cartesian2.angleBetween(north, horizontalVec); + const cross = Cesium.Cartesian2.cross(north, horizontalVec, new Cesium.Cartesian2()); + return cross < 0 ? angle : -angle; + } + + calculatePolygonOrientation(positions) { + + // 假设 position 是 Cesium.Cartesian3 对象,表示地球上的某个点 + var position = positions[0] + // 获取东、北、上坐标系 + var eastNorthUp = Cesium.Transforms.eastNorthUpToFixedFrame(position); + // northAxis 是北方向向量 + var northAxis = eastNorthUp.getColumn(1, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(northAxis, northAxis); + + const direction = Cesium.Cartesian3.subtract(positions[0], positions[1], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + + const dot = Cesium.Cartesian3.dot(northAxis, direction); + const magA = Cesium.Cartesian3.magnitude(northAxis); + const magB = Cesium.Cartesian3.magnitude(direction); + return Math.acos(dot / (magA * magB)); + } + calculateTextureRepeat(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + // 创建多边形几何体 + const geometry = Cesium.PolygonGeometry.createGeometry( + new Cesium.PolygonGeometry({ + polygonHierarchy: new Cesium.PolygonHierarchy(polygonPositions), + vertexFormat: Cesium.VertexFormat.POSITION_ONLY + }) + ); + + // 计算多边形面积(平方米) + let area = 0; + const indices = geometry.indices; + const positions = geometry.attributes.position.values; + for (let i = 0; i < indices.length; i += 3) { + const i0 = indices[i] * 3; + const i1 = indices[i + 1] * 3; + const i2 = indices[i + 2] * 3; + + const p0 = new Cesium.Cartesian3(positions[i0], positions[i0 + 1], positions[i0 + 2]); + const p1 = new Cesium.Cartesian3(positions[i1], positions[i1 + 1], positions[i1 + 2]); + const p2 = new Cesium.Cartesian3(positions[i2], positions[i2 + 1], positions[i2 + 2]); + + const cross = Cesium.Cartesian3.cross( + Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()), + Cesium.Cartesian3.subtract(p2, p0, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + area += Cesium.Cartesian3.magnitude(cross) * 0.5; + } + + // 将像素尺寸转换为实际尺寸(平方米) + const textureWidthMeters = textureSize.width * meterPerPixel; + const textureHeightMeters = textureSize.height * meterPerPixel; + const textureArea = textureWidthMeters * textureHeightMeters; + + // 计算各轴向重复次数 + const repeatX = Math.sqrt(area) / textureWidthMeters; + const repeatY = Math.sqrt(area) / textureHeightMeters; + + return new Cesium.Cartesian2(Math.max(1, Math.ceil(repeatX)), 1.0); + } + swapLastElements(arr1, arr2) { + const last = arr1[arr1.length - 1] + const first = arr2[0] + arr1[arr1.length - 1] = first + arr2[0] = last + + return [arr1, arr2]; + } + createLineBufferPolygonSide(positions, width) { + let area = [] + for (let i = 0; i < positions.length; i++) { + const posi = positions[i]; + + const dir = Cesium.Cartesian3.subtract(posi[1], posi[0], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(posi[0], offset, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(posi[1], offset, new Cesium.Cartesian3()) + + // i == positions.length - 2 ? area.push(start, point1, end, point3) : area.push(start, point1) + area.push([posi[0], point1, point3, posi[1]]) + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + return area + } + createLineBufferPolygon2(positions, width) { + let area = [] + let leftPositions = []; + let rightPositions = []; + + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + // const end = positions[i + 1] || positions[i - 1]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + const dir2 = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir2, dir2); + + // 获取垂直向量(基于Z轴) + const perp2 = Cesium.Cartesian3.cross(dir2, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp2, perp2); + + + + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + const offset2 = Cesium.Cartesian3.multiplyByScalar(perp, -width, new Cesium.Cartesian3()); + + const offsetEnd = Cesium.Cartesian3.multiplyByScalar(perp2, -width, new Cesium.Cartesian3()); + const offsetEnd2 = Cesium.Cartesian3.multiplyByScalar(perp2, width, new Cesium.Cartesian3()); + + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point2 = Cesium.Cartesian3.add(start, offset2, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offsetEnd, new Cesium.Cartesian3()) + let point4 = Cesium.Cartesian3.add(end, offsetEnd2, new Cesium.Cartesian3()) + + area.push([point1, point3, point4, point2]) + + rightPositions.push([point1, point3]) + leftPositions.push([point2, point4]) + + // if (i == positions.length - 2) { + // area.push(point1, point2, point3, point4) + // rightPositions.push(point1) + // leftPositions.push(point2) + // leftPositions.push(point4) + // rightPositions.push(point3) + // } else { + // area.push(point1, point2) + // rightPositions.push(point1) + // leftPositions.push(point2) + // } + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + console.log(area, rightPositions, 'rightPositions') + let that = this + // return [arr, rightPositions, leftPositions] + return [area, rightPositions, leftPositions] + } + getIntersects(point1, point2, point3, point4) { + let carPoint1 = this.getLonLat(point1) + let carPoint2 = this.getLonLat(point2) + let carPoint3 = this.getLonLat(point3) + let carPoint4 = this.getLonLat(point4) + var line1 = turf.lineString([ + [carPoint1.lon, carPoint1.lat], + [carPoint2.lon, carPoint2.lat] + ]); + var line2 = turf.lineString([ + [carPoint3.lon, carPoint3.lat], + [carPoint4.lon, carPoint4.lat] + ]); + var intersects = turf.lineIntersect(line1, line2); + if (intersects.features.length > 0) { + return Cesium.Cartesian3.fromDegrees(intersects.features[0].geometry.coordinates[0], intersects.features[0].geometry.coordinates[1]) + } + } + getLonLat(point) { + let pointDe = Cesium.Cartographic.fromCartesian(point) + const longitude = Cesium.Math.toDegrees(pointDe.longitude); + const latitude = Cesium.Math.toDegrees(pointDe.latitude); + return { lon: longitude, lat: latitude } + + } + createLineBufferPolygon(viewer, positions, width) { + // 计算每个线段的左右偏移点 + const leftPositions = []; + const rightPositions = []; + + for (let i = 0; i < positions.length; i++) { + const start = positions[i]; + const end = positions[i + 1] || positions[i - 1]; + + // 计算线段方向向量 + const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + // const direction = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量(使用上向量叉积) + const up = Cesium.Cartesian3.UNIT_Z; + const perpendicular = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perpendicular, perpendicular); + + // 计算左右偏移点 + const leftOffset = Cesium.Cartesian3.multiplyByScalar( + perpendicular, + width, + new Cesium.Cartesian3() + ); + + if (width > 0) { + rightPositions.unshift(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } else if (width < 0) { + rightPositions.push(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } + + } + return rightPositions + } + //计算角度 + calculateAangle(arr) { + // let fromDegreesArray = that.calSector(that.options.center, that.options.radius, that.options.startAngle, that.options.endAngle, 360, true) + + function getAangle(start, end) { + let rad = Math.PI / 180, + lat1 = start.y * rad, + lat2 = end.y * rad, + lon1 = start.x * rad, + lon2 = end.x * rad; + const a = Math.sin(lon2 - lon1) * Math.cos(lat2); + const b = + Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); + const radians = Math.atan2(a, b) + const degrees = radians % (2 * Math.PI); + let bearing = 450 - ((degrees * 180) / Math.PI < 0 + ? 360 + (degrees * 180) / Math.PI + : (degrees * 180) / Math.PI) - 90; + return 360 - (bearing % 360) + } + + let center = arr[0] + let pos84_1 = arr[1] + let pos84_2 = arr[2] + + let start = { x: center.lng, y: center.lat } + let end1 = { x: pos84_1.lng, y: pos84_1.lat } + let end2 = { x: pos84_2.lng, y: pos84_2.lat } + + let angle1 = getAangle(start, end1) + let angle2 = getAangle(start, end2) + + return { + angle1, + angle2 + } + } + + get carRoadWidth() { + return this.options.carRoadWidth + } + + set carRoadWidth(v) { + this.options.carRoadWidth = v + Road.create(this) + + } + get sideWidth() { + return this.options.sideWidth + } + set sideWidth(v) { + this.options.sideWidth = v + Road.create(this) + } + /** + * @description 编辑框 + * @param state=false {boolean} 状态: true打开, false关闭 + */ + async edit(state = false) { + let _this = this + this.originalOptions = this.deepCopyObj(this.options) + + if (this._DialogObject && this._DialogObject.close) { + this._DialogObject.close() + this._DialogObject = null + } + + if (state) { + this._DialogObject = await new Dialog(this.sdk, this.originalOptions, { + title: '道路属性', left: '180px', top: '100px', + confirmCallBack: (options) => { + this.name = this.name.trim() + if (!this.name) { + this.name = '道路' + } + this.originalOptions = this.deepCopyObj(this.options) + this._DialogObject.close() + this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions) + syncData(this.sdk, this.options.id) + syncSplitData(this.sdk, this.options.id) + }, + resetCallBack: () => { + this.reset() + this.Dialog.resetCallBack && this.Dialog.resetCallBack() + }, + closeCallBack: () => { + this.reset() + this.Dialog.closeCallBack && this.Dialog.closeCallBack() + }, + showCallBack: (show) => { + this.show = show + this.Dialog.showCallBack && this.Dialog.showCallBack() + } + }, true) + this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' road-surface' + let contentElm = document.createElement('div'); + contentElm.innerHTML = html() + this._DialogObject.contentAppChild(contentElm) + + + // 下拉选项 + // let heightModeData = [ + // { + // name: '海拔高度', + // value: '海拔高度', + // key: '0', + // }, + // { + // name: '相对地表', + // value: '相对地表', + // key: '1', + // }, + // { + // name: '依附模型', + // value: '依附模型', + // key: '2', + // } + // ] + // let heightModeObject = legp( + // this._DialogObject._element.content.getElementsByClassName( + // 'road-box' + // )[0], + // '.road-type' + // ) + // if (heightModeObject) { + // heightModeObject.legp_search(heightModeData) + // let heightModeDataLegpElm = this._DialogObject._element.content + // .getElementsByClassName('road-type')[0] + // .getElementsByTagName('input')[0] + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].key == this.heightMode) { + // heightModeDataLegpElm.value = heightModeData[i].value + // heightModeObject.legp_searchActive( + // heightModeData[i].value + // ) + // break + // } + // } + // heightModeDataLegpElm.addEventListener('input', () => { + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].value === heightModeDataLegpElm.value) { + // this.heightMode = heightModeData[i].key + // break + // } + // } + // }) + + + // this._elms.height = heightElm + // this._elms.heightBox = heightBoxElm + // this._elms.heightMode = heightModeDataLegpElm + // this._elms.heightConfirm = heightConfirmElm + // this._elms.heightModeObject = heightModeObject + + // heightConfirmElm.addEventListener('click', () => { + // this.positionEditing = false + // for (let i = 0; i < this.options.positions.length; i++) { + // this.options.positions[i].alt = Number((this.options.positions[i].alt + Number(heightElm.value)).toFixed(2)) + // this._elms.alt[i].innerHTML = this.options.positions[i].alt + // } + // let fromDegreesArray = this.renewPositions(this.options.positions) + // this.entity.polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights( + // fromDegreesArray + // ) + + // this.positionEditing = false + // PolylineObject.closeNodeEdit(this) + // }) + // } + + + + + + let all_elm = contentElm.getElementsByTagName("*") + this._EventBinding.on(this, all_elm) + this._elms = this._EventBinding.element + } else { + // if (this._element_style) { + // document.getElementsByTagName('head')[0].removeChild(this._element_style) + // this._element_style = null + // } + // if (this._DialogObject && this._DialogObject.remove) { + // this._DialogObject.remove() + // this._DialogObject = null + // } + } + } + + reset() { + if (!this.viewer.entities.getById(this.options.id)) { + return + } + this.name = this.originalOptions.name + this.carRoadWidth = this.originalOptions.carRoadWidth + this.sideWidth = this.originalOptions.sideWidth + this.positions = this.originalOptions.positions + this.roadImage = this.originalOptions.roadImage + this.sideImage = this.originalOptions.sideImage + } + + /** + * 飞到对应实体 + */ + async flyTo(options = {}) { + setActiveViewer(0) + closeRotateAround(this.sdk) + closeViewFollow(this.sdk) + + if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { + let orientation = { + heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), + pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), + roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) + } + + let lng = this.options.customView.relativePosition.lng + let lat = this.options.customView.relativePosition.lat + let alt = this.options.customView.relativePosition.alt + let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + + let position = { lng: 0, lat: 0 } + if (this.options.position) { + position = { ...this.options.position } + } + else if (this.options.positions) { + position = { ...this.options.positions[0] } + } + else if (this.options.center) { + position = { ...this.options.center } + } + else if (this.options.start) { + position = { ...this.options.start } + } + else { + if (this.options.hasOwnProperty('lng')) { + position.lng = this.options.lng + } + if (this.options.hasOwnProperty('lat')) { + position.lat = this.options.lat + } + if (this.options.hasOwnProperty('alt')) { + position.alt = this.options.alt + } + } + // 如果没有高度值,则获取紧贴高度计算 + // if (!position.hasOwnProperty('alt')) { + // position.alt = await this.getClampToHeight(position) + // } + lng = this.options.customView.relativePosition.lng + position.lng + lat = this.options.customView.relativePosition.lat + position.lat + alt = this.options.customView.relativePosition.alt + position.alt + destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + this.sdk.viewer.camera.flyTo({ + destination: destination, + orientation: orientation + }) + } + else { + let positionArray = [] + for (let i = 0; i < this.positions.length; i++) { + let a = Cesium.Cartesian3.fromDegrees( + this.positions[i][0], + this.positions[i][1], + this.options.height + this.options.heightDifference / 2 + ) + positionArray.push(a.x, a.y, a.z) + } + let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) + this.viewer.camera.flyToBoundingSphere(BoundingSphere, { + offset: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-20.0), + roll: Cesium.Math.toRadians(0.0) + } + }) + + } + } + + getSphere() { + return new Promise((resolve) => { + // entity没有加载完成时 state 不会等于0 所以设置定时器直到获取到为止 + const interval = setInterval(() => { + const sphere = new Cesium.BoundingSphere() + const state = this.sdk.viewer._dataSourceDisplay.getBoundingSphere( + this.viewer.entities.getById(this.options.id), + false, + sphere + ) + if (state === Cesium.BoundingSphereState.DONE) { + clearInterval(interval) + } + }, 1000) + }) + } + + /** + * 删除 + */ + async remove() { + this.positions = [] + this.lineEntity = null + + if (this.viewer.entities.getById(this.options.id)) { + this.viewer.entities.getById(this.options.id)._children.forEach((item) => { + this.viewer.entities.remove(item); + }); + this.viewer.entities.remove(this.viewer.entities.getById(this.options.id)) + } + + if (this._DialogObject && !this._DialogObject.isDestroy) { + this._DialogObject.close() + this._DialogObject = null + } + await this.sdk.removeIncetance(this.options.id) + await syncData(this.sdk, this.options.id) + } + + flicker() { } +} + +export default Road diff --git a/src/Obj/Base/RoadObject/index.js b/src/Obj/Base/RoadObject/index.js new file mode 100644 index 0000000..8c58a0b --- /dev/null +++ b/src/Obj/Base/RoadObject/index.js @@ -0,0 +1,1207 @@ +/** + * @description 道路 + */ +import Dialog from '../../Element/Dialog'; +import { html } from "./_element"; +import EventBinding from '../../Element/Dialog/eventBinding'; +import Base from "../index"; +import { syncData } from '../../../Global/MultiViewportMode' +import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen' +import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' + +class Road extends Base { + /** + * @constructor + * @param sdk + * @description 道路 + * @param options {object} 道路属性 + * @param options.name=未命名对象 {string} 名称 + * @param options.carRoadWidth=2 {number} 车道宽度 + * @param options.sideWidth=2 {number} 人行道宽度 + * @param options.positions=[] {array} 道路positions + * @param options.roadImage='' {string} 车道贴图 + * @param options.sideImage='' {string} 人行道贴图 + * @param Dialog {object} 弹框对象 + * @param Dialog.confirmCallBack {function} 弹框确认时的回调 + * */ + constructor(sdk, options = {}, _Dialog = {}) { + super(sdk, options); + this.viewer = this.sdk.viewer + this.options.name = options.name || '道路' + this.options.carRoadWidth = options.carRoadWidth || 10 + this.options.sideWidth = options.sideWidth || 5 + this.options.positions = options.positions || [] + this.options.roadImage = options.roadImage || (this.getSourceRootPath() + '/img/roadPhoto.png') + this.options.sideImage = options.sideImage || (this.getSourceRootPath() + '/img/sidePhoto.png') + this.options.show = (options.show || options.show === false) ? options.show : true + this.Dialog = _Dialog + this._EventBinding = new EventBinding() + this._elms = {}; + this.positionArea = [] + this.positions = [] + this.lineEntity = '' + this.crossArr = [] + this.pointArr = [] + + this.sdk.addIncetance(this.options.id, this) + // Road.create(this) + // console.log('1212') + function createCustomCorridor(viewer, positions, width) { + // 计算两侧顶点位置 + const leftPositions = []; + const rightPositions = []; + const topPositions = []; + + // 生成两侧和顶部顶点 + for (let i = 0; i < positions.length; i++) { + const position = positions[i]; + const nextPosition = positions[i + 1]; + + if (!nextPosition) continue; + + // 计算方向向量 + const direction = Cesium.Cartesian3.subtract( + nextPosition, + position, + new Cesium.Cartesian3() + ); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量 + const normal = Cesium.Cartesian3.cross( + direction, + Cesium.Cartesian3.UNIT_Z, + new Cesium.Cartesian3() + ); + Cesium.Cartesian3.normalize(normal, normal); + + // 计算两侧偏移量 + const offset = Cesium.Cartesian3.multiplyByScalar( + normal, + width / 2, + new Cesium.Cartesian3() + ); + + // 左侧点 + const left = Cesium.Cartesian3.add(position, offset, new Cesium.Cartesian3()); + leftPositions.push(left.x, left.y, left.z); + + // 右侧点 + const right = Cesium.Cartesian3.subtract(position, offset, new Cesium.Cartesian3()); + rightPositions.push(right.x, right.y, right.z); + + // 顶部点(高度增加) + const top = Cesium.Cartesian3.clone(position); + top.z += 100; // 设置顶部高度 + topPositions.push(top.x, top.y, top.z); + } + + // 合并所有顶点 + const allPositions = new Float64Array([ + ...leftPositions, + ...rightPositions, + ...topPositions + ]); + + // 创建几何体 + const geometry = new Cesium.Geometry({ + attributes: { + position: new Cesium.GeometryAttribute({ + componentDatatype: Cesium.ComponentDatatype.DOUBLE, + componentsPerAttribute: 3, + values: allPositions + }) + }, + indices: new Uint16Array([ + // 左侧面索引 + 0, 1, 3, + 1, 4, 3, + // 右侧面索引 + 2, 5, 6, + 2, 6, 7, + // 顶面索引 + 8, 9, 10, + 8, 10, 11 + ]), + primitiveType: Cesium.PrimitiveType.TRIANGLES, + boundingSphere: Cesium.BoundingSphere.fromVertices(allPositions) + }); + + // 创建图元 + const primitive = new Cesium.Primitive({ + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry + }), + appearance: new Cesium.PerInstanceColorAppearance({ + flat: true, + translucent: false + }), + asynchronous: false + }); + + viewer.scene.primitives.add(primitive); + return primitive; + } + + // 使用示例 + const positions = Cesium.Cartesian3.fromDegreesArray([ + -75.0, 39.0, + -74.5, 39.5, + -74.0, 40.0 + ]); + createCustomCorridor(this.sdk.viewer, positions, 1000); + this.sdk.viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(-75.0, 39.0, 100), + // orientation: { + // heading: Cesium.Math.toRadians(0), + // pitch: Cesium.Math.toRadians(-30), + // roll: 0.0 + // } + }); + + + } + // 创建走廊几何体 + createCorridor(myImg) { + const positions = Cesium.Cartesian3.fromDegreesArray([ + 116.391, 39.907, // 北京 + 116.404, 39.914, + 116.417, 39.921, + 116.430, 39.928 + ]); + + const corridorInstance = new Cesium.GeometryInstance({ + geometry: new Cesium.CorridorGeometry({ + positions: positions, + width: 200.0, + vertexFormat: Cesium.VertexFormat.POSITION_AND_ST, + cornerType: Cesium.CornerType.ROUNDED + }), + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE) + } + }); + + const primitive = new Cesium.Primitive({ + geometryInstances: corridorInstance, + appearance: new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + type: 'Image', + uniforms: { + image: myImg + } + } + }), + translucent: false + }), + asynchronous: false + }); + + this.sdk.viewer.scene.primitives.add(primitive); + + // 定位到走廊 + this.sdk.viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(116.404, 39.914, 2000), + orientation: { + heading: Cesium.Math.toRadians(0), + pitch: Cesium.Math.toRadians(-30), + roll: 0.0 + } + }); + + return primitive; + } + // 创建道路 + static create(that) { + let positions = [] + that.options.positions.forEach(v => { + positions.push(new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) + }) + let newPosi = [] + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + const end = positions[i + 1]; + newPosi.push([start, end]) + that.pointArr = newPosi + } + + let area = [[], [], []] + + // area[1] = that.getRectangle(positions, that.options.carRoadWidth) + area[1][0] = that.getRectangle(newPosi, that.options.carRoadWidth) + let sideArr = that.getSideRectangle(area[1][0], that.options.sideWidth) + area[0] = sideArr.left + area[2] = sideArr.right + // area[1] = that.createLineBufferPolygon2(positions, that.options.carRoadWidth / 2) + // area[1] = newPositions + // area[0] = that.createLineBufferPolygonSide(area[1][2], -that.options.sideWidth) + // area[2] = that.createLineBufferPolygonSide(area[1][1], that.options.sideWidth) + + //判断道路边是否相交 + for (let i = 0; i < area[0].length - 1; i++) { + + let leftItem = area[0][i] + let leftItem2 = area[0][i + 1] + let rightItem = area[2][i] + let rightItem2 = area[2][i + 1] + let carItem = area[1][0][i] + let carItem2 = area[1][0][i + 1] + let leftLine = that.getIntersects(leftItem[2], leftItem[3], leftItem2[2], leftItem2[3]) + let rightLine = that.getIntersects(rightItem[0], rightItem[1], rightItem2[0], rightItem2[1]) + if (!leftLine && !rightLine) { + for (let index = 0; index < 4; index++) { + let positions = [] + index === 0 ? positions.push(leftItem[2], leftItem[3]) : index === 1 ? positions.push(leftItem2[2], leftItem2[3]) : index === 2 ? positions.push(rightItem[0], rightItem[1]) : positions.push(rightItem2[0], rightItem2[1]) + that.sdk.viewer.entities.add({ + polyline: { + positions: positions, + width: 10.0, + material: new Cesium.PolylineGlowMaterialProperty({ + color: index === 0 ? Cesium.Color.RED : index === 1 ? Cesium.Color.BLUE : index === 2 ? Cesium.Color.YELLOW : Cesium.Color.GREEN, + glowPower: 0.25, + }), + }, + }); + + } + + } + + console.log(leftLine, rightLine, 'leftLine') + if (leftLine) {//左侧相交 + //获取右侧延长交点 + let point1 = that.getExtendPoint(rightItem[0], rightItem[1], 1000) + let point2 = that.getExtendPoint(rightItem2[1], rightItem2[0], 1000) + console.log('aaaa') + let rightIntersection = that.getIntersects(rightItem[0], point1, rightItem2[1], point2) + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + + let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + + + console.log(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint, 'bbbb') + //跟左侧里相交点 + let leftLineNei = that.getIntersects(leftLine, rightIntersection, leftItem[0], leftLineNeiPoint) + console.log(leftLineNei, 'leftLineNei') + //跟车道左侧相交点 + let carLeft = that.getIntersects(leftLine, rightIntersection, carItem[3], carLeftPoint) + + //跟车道右侧相交点 + let carRight = that.getIntersects(leftLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(leftLine, rightIntersection, rightItem[3], rightLineNeiPoint) + console.log('ccc') + // let leftLineNei = that.getIntersects(leftLine, rightItem[2], leftItem[0], leftItem[3]) + // let carLeft = that.getIntersects(leftLine, rightItem[2], carItem[3], carItem[2]) + // let carRight = that.getIntersects(leftLine, rightItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, rightItem[2], rightItem[0], rightItem[3]) + + // let leftLineNei = that.getIntersects(leftLine, intersection, leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(leftLine, intersection, carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(leftLine, intersection, carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(leftLine, intersection, rightItem[0], rightItem[3]) + + leftItem[2] = leftLine + leftItem[1] = leftLineNei + carItem[2] = carLeft + carItem[1] = carRight + rightItem[2] = rightLineNei + rightItem[1] = rightIntersection + console.log(leftItem, carItem, rightItem, 'leftItemleft') + + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[1], leftItem2[0], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + // let leftLineNei2 = that.getIntersects(leftLine, rightItem2[1], leftItem2[0], leftItem2[3]) + // let carLeft2 = that.getIntersects(leftLine, rightItem2[1], carItem2[3], carItem2[2]) + // let carRight2 = that.getIntersects(leftLine, rightItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, rightItem2[1], rightItem2[0], rightItem2[3]) + + + + let leftLineNei2 = that.getIntersects(leftLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + let carLeft2 = that.getIntersects(leftLine, rightIntersection, carItem2[2], carLeftPoint2) + let carRight2 = that.getIntersects(leftLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(leftLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + + // let arr = [leftLine, rightIntersection, leftItem2[3], leftLineNeiPoint2] + // arr.forEach((item, index) => { + // that.sdk.viewer.entities.add({ + // name: 'node-secondary-edit-point', + // index: i, + // position: item, + // billboard: { + // image: that.getSourceRootPath() + '/img/point.png', + // width: 15, + // height: 15, + // disableDepthTestDistance: Number.POSITIVE_INFINITY, + // color: Cesium.Color.WHITE.withAlpha(0.99) + // }, + // label: { + // text: '' + index, + // pixelOffset: { x: 0, y: -20 }, + // }, + // }) + // }) + + // let leftLineNei2 = that.getIntersects(leftLine, intersection, leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(leftLine, intersection, carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(leftLine, intersection, carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(leftLine, intersection, rightItem2[0], rightItem2[3]) + + leftItem2[3] = leftLine + leftItem2[0] = leftLineNei + carItem2[3] = carLeft + carItem2[0] = carRight + rightItem2[3] = rightLineNei + rightItem2[0] = rightIntersection + console.log(leftItem2, carItem2, rightItem2, 'leftItem2left') + + } else if (rightLine) {//右侧相交 + + //获取左侧延长交点 + let point1 = that.getExtendPoint(leftItem[3], leftItem[2], 1000) + let point2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + let rightIntersection = that.getIntersects(leftItem[3], point1, leftItem2[2], point2) + if (!rightIntersection) { + return + } + //将其他几条边都延长 + let leftLineNeiPoint = that.getExtendPoint(leftItem[0], leftItem[1], 1000) + let carLeftPoint = that.getExtendPoint(carItem[3], carItem[2], 1000) + let carRightPoint = that.getExtendPoint(carItem[0], carItem[1], 1000) + let rightLineNeiPoint = that.getExtendPoint(rightItem[3], rightItem[2], 1000) + + // //跟左侧里相交点 + let leftLineNei = that.getIntersects(rightLine, rightIntersection, leftItem[0], leftLineNeiPoint) + //跟车道左侧相交点 + let carLeft = that.getIntersects(rightLine, rightIntersection, carItem[3], carLeftPoint) + //跟车道右侧相交点 + let carRight = that.getIntersects(rightLine, rightIntersection, carItem[0], carRightPoint) + let rightLineNei = that.getIntersects(rightLine, rightIntersection, rightItem[3], rightLineNeiPoint) + // //跟左侧里相交点 + // let leftLineNei = that.getIntersects(rightLine, leftItem[2], leftItem[0], leftItem[3]) + // //跟车道左侧相交点 + // let carLeft = that.getIntersects(rightLine, leftItem[2], carItem[3], carItem[2]) + // //跟车道右侧相交点 + // let carRight = that.getIntersects(rightLine, leftItem[2], carItem[0], carItem[1]) + // let rightLineNei = that.getIntersects(rightLine, leftItem[2], rightItem[0], rightItem[3]) + + + leftItem[2] = rightIntersection + leftItem[1] = leftLineNei + carItem[2] = carLeft + carItem[1] = carRight + rightItem[2] = rightLineNei + rightItem[1] = rightLine + console.log(leftItem, carItem, rightItem, 'leftItemright') + + //将其他几条边都延长 + let leftLineNeiPoint2 = that.getExtendPoint(leftItem2[2], leftItem2[3], 1000) + let carLeftPoint2 = that.getExtendPoint(carItem2[2], carItem2[3], 1000) + let carRightPoint2 = that.getExtendPoint(carItem2[1], carItem2[0], 1000) + let rightLineNeiPoint2 = that.getExtendPoint(rightItem2[2], rightItem2[3], 1000) + + let leftLineNei2 = that.getIntersects(rightLine, rightIntersection, leftItem2[1], leftLineNeiPoint2) + //跟车道左侧相交点 + let carLeft2 = that.getIntersects(rightLine, rightIntersection, carItem2[2], carLeftPoint2) + //跟车道右侧相交点 + let carRight2 = that.getIntersects(rightLine, rightIntersection, carItem2[1], carRightPoint2) + let rightLineNei2 = that.getIntersects(rightLine, rightIntersection, rightItem2[2], rightLineNeiPoint2) + // let leftLineNei2 = that.getIntersects(rightLine, leftItem2[1], leftItem2[0], leftItem2[3]) + // //跟车道左侧相交点 + // let carLeft2 = that.getIntersects(rightLine, leftItem2[1], carItem2[3], carItem2[2]) + // //跟车道右侧相交点 + // let carRight2 = that.getIntersects(rightLine, leftItem2[1], carItem2[0], carItem2[1]) + // let rightLineNei2 = that.getIntersects(rightLine, leftItem2[1], rightItem2[0], rightItem2[3]) + + leftItem2[3] = rightIntersection + leftItem2[0] = leftLineNei + carItem2[3] = carLeft + carItem2[0] = carRight + rightItem2[3] = rightLineNei + rightItem2[0] = rightLine + console.log(leftItem2, carItem2, rightItem2, 'leftItem2right') + + } + } + + if (that.viewer.entities.getById(that.options.id)) { + that.viewer.entities.getById(that.options.id)._children.forEach((item) => { + that.viewer.entities.remove(item); + }); + that.viewer.entities.remove(that.viewer.entities.getById(that.options.id)) + } + that.lineEntity = that.viewer.entities.add(new Cesium.Entity({ id: that.options.id, show: that.options.show })) + + const myImg = new Image() + myImg.src = that.options.roadImage + myImg.onload = function () { + console.log(area[1][0], that.options.roadImage, 'llll') + area[1][0].forEach((item, index) => { + that.viewer.entities.add({ + // id: that.options.id, + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.roadImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + } + + const myImg2 = new Image() + myImg2.src = that.options.sideImage + myImg2.onload = function () { + // area[0].forEach((item, index) => { + area[0].forEach((item, index) => { + that.viewer.entities.add({ + parent: that.lineEntity, + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + // area[2].forEach((item, index) => { + area[2].forEach((item, index) => { + that.viewer.entities.add({ + polygon: { + hierarchy: new Cesium.PolygonHierarchy(item), + material: new Cesium.ImageMaterialProperty({ + image: that.options.sideImage, + transparent: true,// 如果图片有透明部分,需要设置为 true + repeat: that.calculateTextureRepeat(item, myImg2) + }), + stRotation: that.calculateRoadAngle(positions[index], positions[index + 1]) + } + }); + }) + + } + + } + getSideRectangle(positions, width) { + let right = [] + let left = [] + let that = this + positions.forEach(item => { + right.push([item[0], item[1]]) + left.push([item[2], item[3]]) + }) + let rightPosi = that.getRectangle(right, width, 'side') + + let leftPosi = this.getRectangle(left, width, 'side') + return { left: leftPosi, right: rightPosi } + } + getRectangle(positions, width, type) { + let areaArr = [] + let newPositions = [] + let that = this + // for (let i = 0; i < positions.length - 1; i++) { + for (let i = 0; i < positions.length; i++) { + const start = positions[i][0]; + const end = positions[i][1]; + + areaArr[i] = [] + let posi = [] + let Outlinegeometry = new Cesium.CorridorGeometry({ + positions: [start, end], + width: width, + cornerType: Cesium.CornerType.MITERED, + vertexFormat: Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat + }) + let geometry = Cesium.CorridorGeometry.createGeometry(Outlinegeometry) + for (let j = 0; j < geometry.attributes.position.values.length; j += 3) { + let val = that.cartesian3Towgs84(new Cesium.Cartesian3(geometry.attributes.position.values[j], geometry.attributes.position.values[j + 1], geometry.attributes.position.values[j + 2]), that.sdk.viewer) + posi.push([val.lng, val.lat]) + } + + for (let x = 0; x < geometry.indices.length; x += 3) { + areaArr[i].push(turf.polygon([[posi[geometry.indices[x]], posi[geometry.indices[x + 1]], posi[geometry.indices[x + 2]], posi[geometry.indices[x]]]])) + } + + let geojson = turf.union(areaArr[i][0], areaArr[i][1]); + let arr = [] + geojson.geometry.coordinates[0].pop() + geojson.geometry.coordinates[0].forEach(item => { + arr.push(new Cesium.Cartesian3.fromDegrees(item[0], item[1])) + }) + let dotResult, angle + const tempVec = new Cesium.Cartesian3(); + + // 计算并归一化第一个向量 + const vector1 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(that.pointArr[i][1], that.pointArr[i][0], tempVec), + tempVec + ); + + // 计算并归一化第二个向量 + const vector2 = Cesium.Cartesian3.normalize( + Cesium.Cartesian3.subtract(arr[1], arr[0], new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + + dotResult = Cesium.Cartesian3.dot(vector1, vector2); + if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + newPositions.push(arr) + } else { + let newArr = [] + newArr[0] = arr[1] + newArr[1] = arr[2] + newArr[2] = arr[3] + newArr[3] = arr[0] + newPositions.push(newArr) + } + // } + + // if (!type) { + // // if (cross > 0 && !type) {//调整方向 + // if ((0.999 < dotResult && dotResult < 1.001) || (-0.999 > dotResult && dotResult > -1.001)) {//调整方向 + // newPositions.push(arr) + // } else { + // let newArr = [] + // newArr[0] = arr[1] + // newArr[1] = arr[2] + // newArr[2] = arr[3] + // newArr[3] = arr[0] + // newPositions.push(newArr) + // } + // } else { + // newPositions.push(arr) + // } + } + return newPositions + } + getExtendPoint(position1, position2, distance) { + // let position1 = Cesium.Cartesian3.fromDegrees(p1[0], p1[1], 0); + // let position2 = Cesium.Cartesian3.fromDegrees(p2[0], p2[1], 0); + let pot = Cesium.Cartesian3.subtract(position2, position1, new Cesium.Cartesian3());//方向 + var dir = Cesium.Cartesian3.normalize(pot, new Cesium.Cartesian3());//向量归一化 + + var ray = new Cesium.Ray(position1, dir); + let np = Cesium.Ray.getPoint(ray, distance * 10);//计算延长点 + return np + } + getArr(arr1, arr2) { + arr2 = arr2.reverse() + let polygon = [] + for (let index = 0; index < arr1.length - 1; index++) { + polygon.push([arr1[index], arr1[index + 1], arr2[index + 1], arr2[index]]) + } + return polygon + } + calculateRoadAngle2(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = this.sdk.viewer.scene.globe.ellipsoid.geodeticSurfaceNormal( + startPoint, new Cesium.Cartesian3()); + + // 2. 构建带椭球参数的ENU矩阵 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( + startPoint, this.sdk.viewer.scene.globe.ellipsoid, normal); + const inverseMatrix = Cesium.Matrix4.inverse( + enuMatrix, new Cesium.Matrix4()); + + // 3. 转换坐标并计算相对向量 + const localEnd = Cesium.Matrix4.multiplyByPoint( + inverseMatrix, endPoint, new Cesium.Cartesian3()); + const heightFactor = Math.abs(localEnd.z) / 1000; // 高度差补偿 + + // 4. 使用四象限反正切计算角度 + const angle = Math.atan2(localEnd.y, localEnd.x); + const adjustedAngle = angle - (heightFactor * 0.01); // 高度补偿 + let result = Cesium.Math.toDegrees(adjustedAngle) + console.log(result, 'result') + return result; + } + calculateRoadAngle(startPoint, endPoint) { + // 1. 获取地表法向量 + const normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(startPoint); + + // 2. 构建精确ENU坐标系 + const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(startPoint, undefined, normal); + const inverseMatrix = Cesium.Matrix4.inverse(enuMatrix, new Cesium.Matrix4()); + + // 3. 转换终点并计算水平向量 + const localEnd = Cesium.Matrix4.multiplyByPoint(inverseMatrix, endPoint, new Cesium.Cartesian3()); + const horizontalVec = new Cesium.Cartesian2(localEnd.x, localEnd.y); + Cesium.Cartesian2.normalize(horizontalVec, horizontalVec); + + const north = new Cesium.Cartesian2(1, 0); + + const angle = Cesium.Cartesian2.angleBetween(north, horizontalVec); + const cross = Cesium.Cartesian2.cross(north, horizontalVec, new Cesium.Cartesian2()); + return cross < 0 ? angle : -angle; + } + + calculatePolygonOrientation(positions) { + + // 假设 position 是 Cesium.Cartesian3 对象,表示地球上的某个点 + var position = positions[0] + // 获取东、北、上坐标系 + var eastNorthUp = Cesium.Transforms.eastNorthUpToFixedFrame(position); + // northAxis 是北方向向量 + var northAxis = eastNorthUp.getColumn(1, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(northAxis, northAxis); + + const direction = Cesium.Cartesian3.subtract(positions[0], positions[1], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + + const dot = Cesium.Cartesian3.dot(northAxis, direction); + const magA = Cesium.Cartesian3.magnitude(northAxis); + const magB = Cesium.Cartesian3.magnitude(direction); + return Math.acos(dot / (magA * magB)); + } + calculateTextureRepeat(polygonPositions, textureSize, meterPerPixel = 0.01) { + // 验证纹理尺寸 + if (!textureSize.width || !textureSize.height) { + throw new Error('Texture size must contain width and height in pixels'); + } + + // 创建多边形几何体 + const geometry = Cesium.PolygonGeometry.createGeometry( + new Cesium.PolygonGeometry({ + polygonHierarchy: new Cesium.PolygonHierarchy(polygonPositions), + vertexFormat: Cesium.VertexFormat.POSITION_ONLY + }) + ); + + // 计算多边形面积(平方米) + let area = 0; + const indices = geometry.indices; + const positions = geometry.attributes.position.values; + for (let i = 0; i < indices.length; i += 3) { + const i0 = indices[i] * 3; + const i1 = indices[i + 1] * 3; + const i2 = indices[i + 2] * 3; + + const p0 = new Cesium.Cartesian3(positions[i0], positions[i0 + 1], positions[i0 + 2]); + const p1 = new Cesium.Cartesian3(positions[i1], positions[i1 + 1], positions[i1 + 2]); + const p2 = new Cesium.Cartesian3(positions[i2], positions[i2 + 1], positions[i2 + 2]); + + const cross = Cesium.Cartesian3.cross( + Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()), + Cesium.Cartesian3.subtract(p2, p0, new Cesium.Cartesian3()), + new Cesium.Cartesian3() + ); + area += Cesium.Cartesian3.magnitude(cross) * 0.5; + } + + // 将像素尺寸转换为实际尺寸(平方米) + const textureWidthMeters = textureSize.width * meterPerPixel; + const textureHeightMeters = textureSize.height * meterPerPixel; + const textureArea = textureWidthMeters * textureHeightMeters; + + // 计算各轴向重复次数 + const repeatX = Math.sqrt(area) / textureWidthMeters; + const repeatY = Math.sqrt(area) / textureHeightMeters; + + return new Cesium.Cartesian2(Math.max(1, Math.ceil(repeatX)), 1.0); + } + swapLastElements(arr1, arr2) { + const last = arr1[arr1.length - 1] + const first = arr2[0] + arr1[arr1.length - 1] = first + arr2[0] = last + + return [arr1, arr2]; + } + createLineBufferPolygonSide(positions, width) { + let area = [] + for (let i = 0; i < positions.length; i++) { + const posi = positions[i]; + + const dir = Cesium.Cartesian3.subtract(posi[1], posi[0], new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + let point1 = Cesium.Cartesian3.add(posi[0], offset, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(posi[1], offset, new Cesium.Cartesian3()) + + // i == positions.length - 2 ? area.push(start, point1, end, point3) : area.push(start, point1) + area.push([posi[0], point1, point3, posi[1]]) + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + return area + } + createLineBufferPolygon2(positions, width) { + let area = [] + let leftPositions = []; + let rightPositions = []; + + for (let i = 0; i < positions.length - 1; i++) { + const start = positions[i]; + // const end = positions[i + 1] || positions[i - 1]; + const end = positions[i + 1]; + + const dir = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir, dir); + + // 获取垂直向量(基于Z轴) + const perp = Cesium.Cartesian3.cross(dir, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp, perp); + + const dir2 = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(dir2, dir2); + + // 获取垂直向量(基于Z轴) + const perp2 = Cesium.Cartesian3.cross(dir2, Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perp2, perp2); + + + + + // 生成偏移向量 + const offset = Cesium.Cartesian3.multiplyByScalar(perp, width, new Cesium.Cartesian3()); + const offset2 = Cesium.Cartesian3.multiplyByScalar(perp, -width, new Cesium.Cartesian3()); + + const offsetEnd = Cesium.Cartesian3.multiplyByScalar(perp2, -width, new Cesium.Cartesian3()); + const offsetEnd2 = Cesium.Cartesian3.multiplyByScalar(perp2, width, new Cesium.Cartesian3()); + + let point1 = Cesium.Cartesian3.add(start, offset, new Cesium.Cartesian3()) + let point2 = Cesium.Cartesian3.add(start, offset2, new Cesium.Cartesian3()) + let point3 = Cesium.Cartesian3.add(end, offsetEnd, new Cesium.Cartesian3()) + let point4 = Cesium.Cartesian3.add(end, offsetEnd2, new Cesium.Cartesian3()) + + area.push([point1, point3, point4, point2]) + + rightPositions.push([point1, point3]) + leftPositions.push([point2, point4]) + + // if (i == positions.length - 2) { + // area.push(point1, point2, point3, point4) + // rightPositions.push(point1) + // leftPositions.push(point2) + // leftPositions.push(point4) + // rightPositions.push(point3) + // } else { + // area.push(point1, point2) + // rightPositions.push(point1) + // leftPositions.push(point2) + // } + } + // let arr = [] + // for (let i = 0; i < area.length - 2; i += 2) { + // arr.push([area[i], area[i + 1], area[i + 3], area[i + 2]]) + // } + console.log(area, rightPositions, 'rightPositions') + let that = this + // return [arr, rightPositions, leftPositions] + return [area, rightPositions, leftPositions] + } + getIntersects(point1, point2, point3, point4) { + let carPoint1 = this.getLonLat(point1) + let carPoint2 = this.getLonLat(point2) + let carPoint3 = this.getLonLat(point3) + let carPoint4 = this.getLonLat(point4) + var line1 = turf.lineString([ + [carPoint1.lon, carPoint1.lat], + [carPoint2.lon, carPoint2.lat] + ]); + var line2 = turf.lineString([ + [carPoint3.lon, carPoint3.lat], + [carPoint4.lon, carPoint4.lat] + ]); + var intersects = turf.lineIntersect(line1, line2); + if (intersects.features.length > 0) { + return Cesium.Cartesian3.fromDegrees(intersects.features[0].geometry.coordinates[0], intersects.features[0].geometry.coordinates[1]) + } + } + getLonLat(point) { + let pointDe = Cesium.Cartographic.fromCartesian(point) + const longitude = Cesium.Math.toDegrees(pointDe.longitude); + const latitude = Cesium.Math.toDegrees(pointDe.latitude); + return { lon: longitude, lat: latitude } + + } + createLineBufferPolygon(viewer, positions, width) { + // 计算每个线段的左右偏移点 + const leftPositions = []; + const rightPositions = []; + + for (let i = 0; i < positions.length; i++) { + const start = positions[i]; + const end = positions[i + 1] || positions[i - 1]; + + // 计算线段方向向量 + const direction = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()); + // const direction = Cesium.Cartesian3.subtract(start, end, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(direction, direction); + + // 计算垂直向量(使用上向量叉积) + const up = Cesium.Cartesian3.UNIT_Z; + const perpendicular = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3()); + Cesium.Cartesian3.normalize(perpendicular, perpendicular); + + // 计算左右偏移点 + const leftOffset = Cesium.Cartesian3.multiplyByScalar( + perpendicular, + width, + new Cesium.Cartesian3() + ); + + if (width > 0) { + rightPositions.unshift(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } else if (width < 0) { + rightPositions.push(Cesium.Cartesian3.add(start, leftOffset, new Cesium.Cartesian3())); + } + + } + return rightPositions + } + //计算角度 + calculateAangle(arr) { + // let fromDegreesArray = that.calSector(that.options.center, that.options.radius, that.options.startAngle, that.options.endAngle, 360, true) + + function getAangle(start, end) { + let rad = Math.PI / 180, + lat1 = start.y * rad, + lat2 = end.y * rad, + lon1 = start.x * rad, + lon2 = end.x * rad; + const a = Math.sin(lon2 - lon1) * Math.cos(lat2); + const b = + Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); + const radians = Math.atan2(a, b) + const degrees = radians % (2 * Math.PI); + let bearing = 450 - ((degrees * 180) / Math.PI < 0 + ? 360 + (degrees * 180) / Math.PI + : (degrees * 180) / Math.PI) - 90; + return 360 - (bearing % 360) + } + + let center = arr[0] + let pos84_1 = arr[1] + let pos84_2 = arr[2] + + let start = { x: center.lng, y: center.lat } + let end1 = { x: pos84_1.lng, y: pos84_1.lat } + let end2 = { x: pos84_2.lng, y: pos84_2.lat } + + let angle1 = getAangle(start, end1) + let angle2 = getAangle(start, end2) + + return { + angle1, + angle2 + } + } + + get carRoadWidth() { + return this.options.carRoadWidth + } + + set carRoadWidth(v) { + this.options.carRoadWidth = v + Road.create(this) + + } + get sideWidth() { + return this.options.sideWidth + } + set sideWidth(v) { + this.options.sideWidth = v + Road.create(this) + } + /** + * @description 编辑框 + * @param state=false {boolean} 状态: true打开, false关闭 + */ + async edit(state = false) { + let _this = this + this.originalOptions = this.deepCopyObj(this.options) + + if (this._DialogObject && this._DialogObject.close) { + this._DialogObject.close() + this._DialogObject = null + } + + if (state) { + this._DialogObject = await new Dialog(this.sdk, this.originalOptions, { + title: '道路属性', left: '180px', top: '100px', + confirmCallBack: (options) => { + this.name = this.name.trim() + if (!this.name) { + this.name = '道路' + } + this.originalOptions = this.deepCopyObj(this.options) + this._DialogObject.close() + this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions) + syncData(this.sdk, this.options.id) + syncSplitData(this.sdk, this.options.id) + }, + resetCallBack: () => { + this.reset() + this.Dialog.resetCallBack && this.Dialog.resetCallBack() + }, + closeCallBack: () => { + this.reset() + this.Dialog.closeCallBack && this.Dialog.closeCallBack() + }, + showCallBack: (show) => { + this.show = show + this.Dialog.showCallBack && this.Dialog.showCallBack() + } + }, true) + this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' road-surface' + let contentElm = document.createElement('div'); + contentElm.innerHTML = html() + this._DialogObject.contentAppChild(contentElm) + + + // 下拉选项 + // let heightModeData = [ + // { + // name: '海拔高度', + // value: '海拔高度', + // key: '0', + // }, + // { + // name: '相对地表', + // value: '相对地表', + // key: '1', + // }, + // { + // name: '依附模型', + // value: '依附模型', + // key: '2', + // } + // ] + // let heightModeObject = legp( + // this._DialogObject._element.content.getElementsByClassName( + // 'road-box' + // )[0], + // '.road-type' + // ) + // if (heightModeObject) { + // heightModeObject.legp_search(heightModeData) + // let heightModeDataLegpElm = this._DialogObject._element.content + // .getElementsByClassName('road-type')[0] + // .getElementsByTagName('input')[0] + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].key == this.heightMode) { + // heightModeDataLegpElm.value = heightModeData[i].value + // heightModeObject.legp_searchActive( + // heightModeData[i].value + // ) + // break + // } + // } + // heightModeDataLegpElm.addEventListener('input', () => { + // for (let i = 0; i < heightModeData.length; i++) { + // if (heightModeData[i].value === heightModeDataLegpElm.value) { + // this.heightMode = heightModeData[i].key + // break + // } + // } + // }) + + + // this._elms.height = heightElm + // this._elms.heightBox = heightBoxElm + // this._elms.heightMode = heightModeDataLegpElm + // this._elms.heightConfirm = heightConfirmElm + // this._elms.heightModeObject = heightModeObject + + // heightConfirmElm.addEventListener('click', () => { + // this.positionEditing = false + // for (let i = 0; i < this.options.positions.length; i++) { + // this.options.positions[i].alt = Number((this.options.positions[i].alt + Number(heightElm.value)).toFixed(2)) + // this._elms.alt[i].innerHTML = this.options.positions[i].alt + // } + // let fromDegreesArray = this.renewPositions(this.options.positions) + // this.entity.polyline.positions = Cesium.Cartesian3.fromDegreesArrayHeights( + // fromDegreesArray + // ) + + // this.positionEditing = false + // PolylineObject.closeNodeEdit(this) + // }) + // } + + + + + + let all_elm = contentElm.getElementsByTagName("*") + this._EventBinding.on(this, all_elm) + this._elms = this._EventBinding.element + } else { + // if (this._element_style) { + // document.getElementsByTagName('head')[0].removeChild(this._element_style) + // this._element_style = null + // } + // if (this._DialogObject && this._DialogObject.remove) { + // this._DialogObject.remove() + // this._DialogObject = null + // } + } + } + + reset() { + if (!this.viewer.entities.getById(this.options.id)) { + return + } + this.name = this.originalOptions.name + this.carRoadWidth = this.originalOptions.carRoadWidth + this.sideWidth = this.originalOptions.sideWidth + this.positions = this.originalOptions.positions + this.roadImage = this.originalOptions.roadImage + this.sideImage = this.originalOptions.sideImage + } + + /** + * 飞到对应实体 + */ + async flyTo(options = {}) { + setActiveViewer(0) + closeRotateAround(this.sdk) + closeViewFollow(this.sdk) + + if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { + let orientation = { + heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), + pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), + roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) + } + + let lng = this.options.customView.relativePosition.lng + let lat = this.options.customView.relativePosition.lat + let alt = this.options.customView.relativePosition.alt + let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + + let position = { lng: 0, lat: 0 } + if (this.options.position) { + position = { ...this.options.position } + } + else if (this.options.positions) { + position = { ...this.options.positions[0] } + } + else if (this.options.center) { + position = { ...this.options.center } + } + else if (this.options.start) { + position = { ...this.options.start } + } + else { + if (this.options.hasOwnProperty('lng')) { + position.lng = this.options.lng + } + if (this.options.hasOwnProperty('lat')) { + position.lat = this.options.lat + } + if (this.options.hasOwnProperty('alt')) { + position.alt = this.options.alt + } + } + // 如果没有高度值,则获取紧贴高度计算 + // if (!position.hasOwnProperty('alt')) { + // position.alt = await this.getClampToHeight(position) + // } + lng = this.options.customView.relativePosition.lng + position.lng + lat = this.options.customView.relativePosition.lat + position.lat + alt = this.options.customView.relativePosition.alt + position.alt + destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) + this.sdk.viewer.camera.flyTo({ + destination: destination, + orientation: orientation + }) + } + else { + let positionArray = [] + for (let i = 0; i < this.positions.length; i++) { + let a = Cesium.Cartesian3.fromDegrees( + this.positions[i][0], + this.positions[i][1], + this.options.height + this.options.heightDifference / 2 + ) + positionArray.push(a.x, a.y, a.z) + } + let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) + this.viewer.camera.flyToBoundingSphere(BoundingSphere, { + offset: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-20.0), + roll: Cesium.Math.toRadians(0.0) + } + }) + + } + } + + getSphere() { + return new Promise((resolve) => { + // entity没有加载完成时 state 不会等于0 所以设置定时器直到获取到为止 + const interval = setInterval(() => { + const sphere = new Cesium.BoundingSphere() + const state = this.sdk.viewer._dataSourceDisplay.getBoundingSphere( + this.viewer.entities.getById(this.options.id), + false, + sphere + ) + if (state === Cesium.BoundingSphereState.DONE) { + clearInterval(interval) + } + }, 1000) + }) + } + + /** + * 删除 + */ + async remove() { + this.positions = [] + this.lineEntity = null + + if (this.viewer.entities.getById(this.options.id)) { + this.viewer.entities.getById(this.options.id)._children.forEach((item) => { + this.viewer.entities.remove(item); + }); + this.viewer.entities.remove(this.viewer.entities.getById(this.options.id)) + } + + if (this._DialogObject && !this._DialogObject.isDestroy) { + this._DialogObject.close() + this._DialogObject = null + } + await this.sdk.removeIncetance(this.options.id) + await syncData(this.sdk, this.options.id) + } + + flicker() { } +} + +export default Road diff --git a/src/Obj/Base/TextBox/index.js b/src/Obj/Base/TextBox/index.js index 0179243..bd8cfbc 100644 --- a/src/Obj/Base/TextBox/index.js +++ b/src/Obj/Base/TextBox/index.js @@ -53,8 +53,7 @@ class TextBox extends Base { // 配置CSS样式和内容结构 viewer.cesiumWidget.container.appendChild(dom); - let posi = Cesium.Cartesian3.fromDegrees(that.options.position.lng.toFixed(4), that.options.position.lat.toFixed(4), that.options.position.alt.toFixed(4)) - + let posi = Cesium.Cartesian3.fromDegrees(that.options.position.lng, that.options.position.lat, that.options.position.alt) that.handler = function () { const position = Cesium.SceneTransforms.wgs84ToWindowCoordinates( viewer.scene, posi @@ -70,22 +69,44 @@ class TextBox extends Base { that.textDom = dom; } + async isClick(posi, id) { + let params = [ + { + position: posi + }, + id, + null + ] + + this.clickCallBack({ position: posi }, id, null) + } async setHandeler(data) { let that = this - const ray = this.sdk.viewer.camera.getPickRay(new Cesium.Cartesian2(data.x, data.y)); - var cartesian = this.sdk.viewer.scene.globe.pick(ray, this.sdk.viewer.scene); + + let cartesian = this.sdk.viewer.scene.pickPosition(new Cesium.Cartesian2(data.x, data.y)); //屏幕坐标转为笛卡尔空间坐标 + // if (!cartesian) return; + + // let c = Cesium.Cartographic.fromCartesian(position); + if (!cartesian) { + const ray = this.sdk.viewer.camera.getPickRay(new Cesium.Cartesian2(data.x, data.y)); + cartesian = this.sdk.viewer.scene.globe.pick(ray, this.sdk.viewer.scene); + } + if (Cesium.defined(cartesian)) { that.sdk.viewer.scene.postRender.removeEventListener(that.handler); var cartographic = Cesium.Cartographic.fromCartesian(cartesian); var longitude = Cesium.Math.toDegrees(cartographic.longitude); var latitude = Cesium.Math.toDegrees(cartographic.latitude); + + let height = await that.getClampToHeight({ lng: longitude, lat: latitude }) that.position = { lng: longitude, lat: latitude, alt: cartographic.height + // alt: height } - let posi = Cesium.Cartesian3.fromDegrees(longitude.toFixed(4), latitude.toFixed(4), cartographic.height.toFixed(4)) + let posi = Cesium.Cartesian3.fromDegrees(longitude, latitude, cartographic.height) that.handler = function () { const position = Cesium.SceneTransforms.wgs84ToWindowCoordinates( @@ -108,6 +129,16 @@ class TextBox extends Base { async returnFun() { return this.handler } + get onClick() { + return this.clickCallBack + } + set onClick(val) { + if (val && typeof val !== 'function') { + console.error('val:', val, '不是一个function') + } else { + this.clickCallBack = val + } + } get show() { return this.options.show } diff --git a/src/Obj/Base/TrajectoryMotion/_element.js b/src/Obj/Base/TrajectoryMotion/_element.js index 3303918..81497e3 100644 --- a/src/Obj/Base/TrajectoryMotion/_element.js +++ b/src/Obj/Base/TrajectoryMotion/_element.js @@ -182,6 +182,23 @@ function html() { +
+
+
+ 油耗 +
+ + L/100km + +
+
+
+ 总油耗 + +
+
+
+ ` } diff --git a/src/Obj/Base/TrajectoryMotion/index.js b/src/Obj/Base/TrajectoryMotion/index.js index 167135a..aefb9dc 100644 --- a/src/Obj/Base/TrajectoryMotion/index.js +++ b/src/Obj/Base/TrajectoryMotion/index.js @@ -78,6 +78,7 @@ class TrajectoryMotion extends Base { this.options.line.smooth = options.line.smooth ? options.line.smooth : false this.options.line.noseToTail = options.line.noseToTail ? options.line.noseToTail : false this.positions_smooth = [] + this.options.unitFuelConsumption = options.unitFuelConsumption || 0 this.options.ground = options.ground || false this.options.state = (options.state || options.state === false) ? options.state : true this.options.routeDirection = (options.routeDirection || options.routeDirection === false) ? options.routeDirection : true @@ -180,7 +181,8 @@ class TrajectoryMotion extends Base { if (this.realTimeRoute) { this.realTimeLine && (this.realTimeLine.show = (!this.showView || this.showView == 3 || !sdkD) ? true : false) } - this.label && (this.label.show = (!this.showView || this.showView == 3 || !sdkD) ? this.options.label.show : false) + this.label && (this.label.show = (!this.showView || this.showView == 3) ? this.options.label.show : false) + this.fuelLabel && (this.fuelLabel.show = (!this.showView || this.showView == 3) ? this.options.fuelShow : false) } else { this.model.show = (!this.showView || this.showView == 3 || !sdkD) ? this.options.show : false @@ -203,6 +205,7 @@ class TrajectoryMotion extends Base { this.keyPoints[i].show = (!this.showView || this.showView == 3) ? show : false } this.label && (this.label.show = false) + this.fuelLabel && (this.fuelLabel.show = false) this.viewFollow = false } @@ -257,14 +260,17 @@ class TrajectoryMotion extends Base { // Cesium.Matrix4.multiplyByTranslation(this.model.modelMatrix, new Cesium.Cartesian3(0, 0, -difference), this.model.modelMatrix) // Cesium.Matrix4.getTranslation(this.model.modelMatrix, this.model.position) this.label && (this.label.show = this.label.show) + this.fuelLabel && (this.fuelLabel.show = this.fuelLabel.show) if (this.options.label.position) { setTimeout(() => { if (this.options.label.position.alt) { this.label && (this.label.position = [this.options.label.position.lng, this.options.label.position.lat, this.options.label.position.alt]) + this.fuelLabel && (this.fuelLabel.position = [this.options.label.position.lng, this.options.label.position.lat, this.options.label.position.alt]) } else { this.getClampToHeight({ lng: this.options.label.position.lng, lat: this.options.label.position.lat }).then((height) => { this.label && (this.label.position = [this.options.label.position.lng, this.options.label.position.lat, height]) + this.fuelLabel && (this.fuelLabel.position = [this.options.label.position.lng, this.options.label.position.lat, height]) }) } }, 0) @@ -1168,18 +1174,21 @@ class TrajectoryMotion extends Base { show = false } if (this.show) { - this.label && (this.label.show = show) - if (this.options.label.position) { - setTimeout(() => { - if (this.options.label.position.alt) { - this.label && (this.label.position = [this.options.label.position.lng, this.options.label.position.lat, this.options.label.position.alt]) - } - else { - this.getClampToHeight({ lng: this.options.label.position.lng, lat: this.options.label.position.lat }).then((height) => { - this.label && (this.label.position = [this.options.label.position.lng, this.options.label.position.lat, height]) - }) - } - }, 0); + if (this.label) { + this.label.show = show + this.label.pixelOffset = this.options.label.pixelOffset + (this.fuelShow ? this.labelFontSize + 20 : 0) + if (this.options.label.position) { + setTimeout(() => { + if (this.options.label.position.alt) { + this.label && (this.label.position = [this.options.label.position.lng, this.options.label.position.lat, this.options.label.position.alt]) + } + else { + this.getClampToHeight({ lng: this.options.label.position.lng, lat: this.options.label.position.lat }).then((height) => { + this.label && (this.label.position = [this.options.label.position.lng, this.options.label.position.lat, height]) + }) + } + }, 0); + } } } else { @@ -1197,6 +1206,7 @@ class TrajectoryMotion extends Base { set labelFontFamily(v) { this.options.label.fontFamily = v || 0 this.label && (this.label.fontFamily = this.options.label.fontFamily) + this.fuelLabel && (this.fuelLabel.fontFamily = this.options.label.fontFamily) let name = getFontFamilyName(this.labelFontFamily) || '' this._elms.labelFontFamily && @@ -1211,6 +1221,7 @@ class TrajectoryMotion extends Base { set labelColor(v) { this.options.label.color = v this.label && (this.label.color = v) + this.fuelLabel && (this.fuelLabel.color = v) if (this._elms.labelColor) { this._elms.labelColor.forEach((item, i) => { let labelColorPicker = new YJColorPicker({ @@ -1238,6 +1249,13 @@ class TrajectoryMotion extends Base { set labelFontSize(v) { this.options.label.fontSize = v this.label && (this.label.fontSize = v) + if (this.fuelLabel) { + this.fuelLabel.fontSize = v + this.label.pixelOffset = this.options.label.pixelOffset + v + 20 + } + else { + this.label.pixelOffset = this.options.label.pixelOffset + } this._elms.labelFontSize && this._elms.labelFontSize.forEach((item) => { item.value = v }) @@ -1249,6 +1267,7 @@ class TrajectoryMotion extends Base { set labelScaleByDistance(v) { this.options.label.scaleByDistance = v this.label && (this.label.scaleByDistance = v) + this.fuelLabel && (this.fuelLabel.scaleByDistance = v) this._elms.labelScaleByDistance && this._elms.labelScaleByDistance.forEach((item) => { item.checked = v }) @@ -1264,6 +1283,7 @@ class TrajectoryMotion extends Base { } this.options.label.near = near this.label && (this.label.near = near) + this.fuelLabel && (this.fuelLabel.near = near) this._elms.labelNear && this._elms.labelNear.forEach((item) => { item.value = near }) @@ -1279,11 +1299,66 @@ class TrajectoryMotion extends Base { } this.options.label.far = far this.label && (this.label.far = far) + this.fuelLabel && (this.fuelLabel.far = far) this._elms.labelFar && this._elms.labelFar.forEach((item) => { item.value = far }) } + get unitFuelConsumption() { + return this.options.unitFuelConsumption + } + + set unitFuelConsumption(v) { + this.options.unitFuelConsumption = v + this._elms.unitFuelConsumption && this._elms.unitFuelConsumption.forEach((item) => { + item.value = v + }) + } + + get fuelShow() { + return this.options.fuelShow + } + + set fuelShow(v) { + this.options.fuelShow = v + let show = v + if (this.show && (!this.showView || this.showView == 3)) { + show = v + } + else { + show = false + } + if (this.show) { + if (this.fuelLabel) { + this.fuelLabel.show = show + this.label.pixelOffset = this.options.label.pixelOffset + (show ? this.labelFontSize + 20 : 0) + } + else { + this.label.pixelOffset = this.options.label.pixelOffset + } + if (this.options.label.position) { + setTimeout(() => { + if (this.options.label.position.alt) { + this.fuelLabel && (this.fuelLabel.position = [this.options.label.position.lng, this.options.label.position.lat, this.options.label.position.alt]) + } + else { + this.getClampToHeight({ lng: this.options.label.position.lng, lat: this.options.label.position.lat }).then((height) => { + this.fuelLabel && (this.fuelLabel.position = [this.options.label.position.lng, this.options.label.position.lat, height]) + }) + } + }, 0); + } + } + else { + this.fuelLabel && (this.fuelLabel.show = false) + this.label.pixelOffset = this.options.label.pixelOffset + } + this._elms.fuelShow && this._elms.fuelShow.forEach((item) => { + item.checked = v + }) + } + // 创建路径 static addLine(that) { let positions_smooth = that.renewLinePositions(that.options.line.positions) @@ -1402,6 +1477,7 @@ class TrajectoryMotion extends Base { } let pos = that.smooth ? that.positions_smooth : Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArrayHeights) TrajectoryMotion.createLabel(that) + TrajectoryMotion.createFuelLabel(that) that.modelMove(pos) @@ -1411,13 +1487,13 @@ class TrajectoryMotion extends Base { static async createLabel(that) { let labelPosition = that.cartesian3Towgs84(that.model.position, that.sdk.viewer) that.label = new LabelObject(that.sdk, { - show: that.options.show ? (that.options.model.show ? that.options.label.show : false) : false, + show: that.options.show ? (that.options.label.show ? true : false) : false, position: [labelPosition.lng, labelPosition.lat, labelPosition.alt], text: that.options.name, fontSize: that.options.label.fontSize, fontFamily: that.options.label.fontFamily, color: that.options.label.color, - pixelOffset: that.options.label.pixelOffset, + pixelOffset: that.options.label.pixelOffset + (that.options.fuelShow ? that.options.label.fontSize + 20 : 0), backgroundColor: that.options.label.backgroundColor, lineColor: that.options.label.lineColor, lineWidth: that.options.label.lineWidth, @@ -1427,6 +1503,26 @@ class TrajectoryMotion extends Base { }, that.model) } + static async createFuelLabel(that) { + let labelPosition = that.cartesian3Towgs84(that.model.position, that.sdk.viewer) + that.fuelLabel = new LabelObject(that.sdk, { + show: that.options.show ? (that.options.fuelShow ? true : false) : false, + // show: true, + position: [labelPosition.lng, labelPosition.lat, labelPosition.alt], + text: '总油耗:', + fontSize: that.options.label.fontSize, + fontFamily: that.options.label.fontFamily, + color: that.options.label.color, + pixelOffset: 0, + backgroundColor: ['#6e6e6e', '#6e6e6e'], + lineColor: '#00ffff00', + lineWidth: 0, + scaleByDistance: that.options.label.scaleByDistance, + near: that.options.label.near, + far: that.options.label.far + }, that.model) + } + // 创建关键点 static async addKeyPoint(that) { for (let i = 0; i < that.options.line.positions.length; i++) { @@ -1531,8 +1627,8 @@ class TrajectoryMotion extends Base { else { setPosition(startDistance) setTimeout(() => { - _this.model && (_this.model.isMove = false) - }, 500); + _this.model.isMove = false + }, 1000); animateUpdate() @@ -1555,6 +1651,8 @@ class TrajectoryMotion extends Base { } async function setPosition(distance) { + _this.totalFuelConsumption = Number((distance / 100 * _this.unitFuelConsumption).toFixed(2)) + _this.fuelLabel.text = '总油耗:' + _this.totalFuelConsumption + ' L' _this.model.isMove = true let sdk2D = get2DView() let splitSdk = getSdk() @@ -1766,6 +1864,7 @@ class TrajectoryMotion extends Base { } let labelPosition = _this.cartesian3Towgs84(position, _this.sdk.viewer) _this.label.position = [labelPosition.lng, labelPosition.lat, labelPosition.alt] + _this.fuelLabel.position = [labelPosition.lng, labelPosition.lat, labelPosition.alt] lastDistance = distance // console.log(position) _this.realTimeRouteArray.push(position) @@ -2162,6 +2261,7 @@ class TrajectoryMotion extends Base { this.sdk.viewer.entities.remove(this.line) this.sdk.viewer.entities.remove(this.realTimeLine) this.label && this.label.remove() + this.fuelLabel && this.fuelLabel.remove() for (let i = 0; i < this.keyPointShow.length; i++) { this.sdk.viewer.entities.remove(this.keyPointShow[i]) } @@ -2169,6 +2269,7 @@ class TrajectoryMotion extends Base { this.realTimeLine = null this.model = null this.label = null + this.fuelLabel = null if (this._DialogObject && !this._DialogObject.isDestroy) { this._DialogObject.close() this._DialogObject = null @@ -2222,6 +2323,7 @@ class TrajectoryMotion extends Base { this.model && (this.model.show = false) } this.labelShow = this.originalOptions.label.show + this.fuelLabelShow = this.originalOptions.fuelShow this.labelColor = this.originalOptions.label.color this.labelFontSize = this.originalOptions.label.fontSize this.labelFontFamily = this.originalOptions.label.fontFamily diff --git a/src/Obj/Base/WallRealStereoscopic/index2.js b/src/Obj/Base/WallRealStereoscopic/index2.js index bb12e89..9583344 100644 --- a/src/Obj/Base/WallRealStereoscopic/index2.js +++ b/src/Obj/Base/WallRealStereoscopic/index2.js @@ -157,7 +157,7 @@ class WallStereoscopic extends Base { } set labelShow(v) { this.options.label.show = v - if (this.show) { + if (this.show && !this.showView || this.showView == 3) { this.label.show = v } else { diff --git a/src/Obj/Base/WallRealStereoscopic2/index.js b/src/Obj/Base/WallRealStereoscopic2/index.js index bd5ee5d..225c6d5 100644 --- a/src/Obj/Base/WallRealStereoscopic2/index.js +++ b/src/Obj/Base/WallRealStereoscopic2/index.js @@ -243,7 +243,7 @@ class WallRealStereoscopic extends Base { } set labelShow(v) { this.options.label.show = v - if (this.show) { + if (this.show && !this.showView || this.showView == 3) { this.label.show = v } else { diff --git a/src/Obj/Element/cy_html_tabs.js b/src/Obj/Element/cy_html_tabs.js index 1270e29..464c37b 100644 --- a/src/Obj/Element/cy_html_tabs.js +++ b/src/Obj/Element/cy_html_tabs.js @@ -1,6 +1,13 @@ class cy_tabs { - constructor(id, clickTabCallBack, sdk) { - let elm = document.getElementById(id); + constructor(boxElm, clickTabCallBack, sdk) { + let elm + if(typeof boxElm === 'string') { + elm = document.getElementById(boxElm); + } + else { + elm = boxElm + } + // let elm = document.getElementById(id); let pane = elm.getElementsByTagName('DIV-cy-tab-pane') let tabTop = `
` @@ -37,7 +44,9 @@ tabContent = tabContent + `
` let BoxElm = document.createElement('div'); - BoxElm.setAttribute('id', id) + if(typeof boxElm === 'string') { + BoxElm.setAttribute('id', boxElm) + } BoxElm.setAttribute('class', 'DIV-cy-tabs') BoxElm.innerHTML = tabTop + tabContent elm.parentNode.insertBefore(BoxElm, elm); diff --git a/src/Obj/Materail/RoadTextureMaterialProperty.js b/src/Obj/Materail/RoadTextureMaterialProperty.js new file mode 100644 index 0000000..8f759b2 --- /dev/null +++ b/src/Obj/Materail/RoadTextureMaterialProperty.js @@ -0,0 +1,113 @@ +/* + * @Description: 流动线 + */ +function RoadTexture() { + class RoadTextureMaterialProperty { + constructor(options) { + this._definitionChanged = new Cesium.Event(); + this._image = undefined; + this._repeat = undefined; + this._stRotation = undefined; + this._repeatLength = undefined; + this.image = options.image || ""; + this.repeat = options.repeat || 1.0; + this.stRotation = options.stRotation || 0.0; + // this.rotations = options.rotations || new Array(100).fill(0.0); + } + + get isConstant() { + return false; + } + + get definitionChanged() { + return this._definitionChanged; + } + + getType(time) { + return Cesium.Material.RoadTextureMaterialType; + } + + getValue(time, result) { + if (!Cesium.defined(result)) { + result = {}; + } + result.image = Cesium.Property.getValueOrDefault( + this._image, + time, + "", + result.image + ); + result.repeat = Cesium.Property.getValueOrDefault( + this._repeat, + time, + 1.0, + result.repeat + ); + result.stRotation = Cesium.Property.getValueOrDefault( + this._stRotation, + time, + 0.0, + result.stRotation + ); + console.log(result, 'result') + return result; + } + + equals(other) { + return ( + this === other || + (other instanceof RoadTextureMaterialProperty && + Cesium.Property.equals(this._image, other._image) && + Cesium.Property.equals(this._repeat, other._repeat) && + // Cesium.Property.equals(this._rotations, other._rotations) && + Cesium.Property.equals(this._stRotation, other._stRotation) + ) + ); + } + } + + Object.defineProperties(RoadTextureMaterialProperty.prototype, { + image: Cesium.createPropertyDescriptor("image"), + repeat: Cesium.createPropertyDescriptor("repeat"), + repeatLength: Cesium.createPropertyDescriptor("stRotation"), + }); + + Cesium.RoadTextureMaterialProperty = RoadTextureMaterialProperty; + Cesium.Material.RoadTextureMaterialProperty = "RoadTextureMaterialProperty"; + Cesium.Material.RoadTextureMaterialType = "RoadTextureMaterialType"; + Cesium.Material.RoadTextureMaterialSource = ` + uniform sampler2D image; + uniform float repeat; + czm_material czm_getMaterial(czm_materialInput materialInput) + { + czm_material material = czm_getDefaultMaterial(materialInput); + vec2 st = materialInput.st; + st.s *= repeat; + mat2 rot = mat2(cos(stRotation), -sin(stRotation), sin(stRotation), cos(stRotation)); + vec2 newSt = rot * (st - 0.5) + 0.5; + + vec4 colorImage = texture2D(image, newSt); + material.diffuse = colorImage.rgb; + return material; + } + `; + Cesium.Material._materialCache.addMaterial( + Cesium.Material.RoadTextureMaterialType, + { + fabric: { + type: Cesium.Material.RoadTextureMaterialType, + uniforms: { + image: '', + repeat: 1.0, + stRotation: 0.0, + }, + source: Cesium.Material.RoadTextureMaterialSource, + }, + translucent: function (material) { + return true; + }, + } + ); +} + +export { RoadTexture } diff --git a/src/Obj/Materail/index.js b/src/Obj/Materail/index.js index e7fff6b..324d41c 100644 --- a/src/Obj/Materail/index.js +++ b/src/Obj/Materail/index.js @@ -7,6 +7,7 @@ import { PolylineFlow } from './PolylineFlowMaterialProperty' import { PolylineFlowMult } from './PolylineFlowMultMaterialProperty' import { FlowDashedLine } from './FlowDashedLineFlowMaterialProperty' import { LineTexture } from './LineTextureMaterialProperty' +import { RoadTexture } from './RoadTextureMaterialProperty' function init_material() { StreamWall1() @@ -19,6 +20,7 @@ function init_material() { PolylineFlowMult() FlowDashedLine() LineTexture() + RoadTexture() } export { init_material } diff --git a/src/YJEarth/index.js b/src/YJEarth/index.js index 6fc9060..775f153 100644 --- a/src/YJEarth/index.js +++ b/src/YJEarth/index.js @@ -62,9 +62,9 @@ class YJEarth { removeIncetance(id) { this.entityMap.delete(id) - unRegLeftClickCallback(this,id) - unRegRightClickCallback(this,id) - unregMoveCallback(this,id) + unRegLeftClickCallback(this, id) + unRegRightClickCallback(this, id) + unregMoveCallback(this, id) syncSplitData(this, id) } @@ -436,6 +436,7 @@ class YJEarth { textList[i].style['pointer-events'] = 'all' textList[i].querySelector('textarea').focus() _this.isLeftClick = true + _this.entityMap.get(_this.clickTextDom.id).isClick(movement.position, _this.clickTextDom.id) break; } } diff --git a/static/custom/css/index.css b/static/custom/css/index.css index ed413e2..0ea4bcf 100644 --- a/static/custom/css/index.css +++ b/static/custom/css/index.css @@ -1429,6 +1429,24 @@ margin-bottom: 10px; display: flex; position: relative; + overflow-y: auto; +} + +.DIV-cy-tabs .DIV-cy-tab-top::-webkit-scrollbar { + width: 4px; + height: 4px; +} + +.DIV-cy-tabs .DIV-cy-tab-top::-webkit-scrollbar-thumb { + border-radius: 5px; + -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); + background-color: rgba(var(--color-sdk-base-rgb)); +} + +.DIV-cy-tabs .DIV-cy-tab-top::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); + border-radius: 5px; + background-color: rgba(var(--color-sdk-base-rgb), 0.1); } .DIV-cy-tabs .DIV-cy-tab-top::after { @@ -1473,7 +1491,14 @@ border-bottom: 2px solid #dddddd00; position: relative; z-index: 2; + white-space: nowrap; + user-select: none; cursor: pointer; + -webkit-pointer-events: auto; + -moz-pointer-events: auto; + -ms-pointer-events: auto; + -o-pointer-events: auto; + pointer-events: auto; } .DIV-cy-tabs .DIV-cy-tab-pane-title-p span { @@ -3097,9 +3122,9 @@ /* 文本框 */ .popup-textarea { /* width: 212px; */ - width: 161.6px; + width: 161px; /* height: 154px; */ - height: 119.2px; + height: 119px; display: block; pointer-events: none; position: absolute; @@ -3108,10 +3133,11 @@ background-size: 100% 100%; padding: 5px 5px 0px 5px; } - -.popup-textarea textarea { - background-color: unset !important; - border: unset !important; +.popup-textarea textarea{ + width: 158px; + height: 95px; + background-color: unset!important; + border: unset!important; color: #fff; } @@ -3588,12 +3614,21 @@ border: 1.5px solid; border-image: linear-gradient(to bottom, var(--color-sdk-gradual)) 1; color: #fff; + min-width: 200px; + min-height: 120px; + box-sizing: border-box; + /* -webkit-pointer-events: none; + -moz-pointer-events: none; + -ms-pointer-events: none; + -o-pointer-events: none; + pointer-events: none; */ } .billboard-attribute-box .DIV-cy-tabs { height: 100%; display: flex; flex-direction: column; + backdrop-filter: blur(2px); } .billboard-attribute-box .DIV-cy-tabs .DIV-cy-tab-top .DIV-cy-tab-pane-title { @@ -3616,9 +3651,120 @@ padding: 0 5px 5px 5px; box-sizing: border-box; flex: 1; + overflow: auto; +} + +.billboard-attribute-box .DIV-cy-tabs .DIV-cy-tab-content::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.billboard-attribute-box .DIV-cy-tabs .DIV-cy-tab-content::-webkit-scrollbar-thumb { + border-radius: 5px; + -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); + background-color: rgba(var(--color-sdk-base-rgb)); +} + +.billboard-attribute-box .DIV-cy-tabs .DIV-cy-tab-content::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); + border-radius: 5px; + background-color: rgba(var(--color-sdk-base-rgb), 0.1); +} + +.billboard-attribute-box .DIV-cy-tabs .DIV-cy-tab-content-pane { + width: 100%; + height: 100%; +} + +.billboard-attribute-box .DIV-cy-tabs .DIV-cy-tab-content-pane iframe { + border: none; +} + +.billboard-attribute-box .billboard-attribute-box-line { + position: absolute; + width: 0px; + /* border-left: 1px solid rgba(var(--color-sdk-base-rgb), 0.5); */ + border-left: 1px solid rgba(var(--color-sdk-base-rgb), 1); + /* transform: rotate(45deg); */ + transform-origin: 0px 0px; + -webkit-pointer-events: none; + -moz-pointer-events: none; + -ms-pointer-events: none; + -o-pointer-events: none; + pointer-events: none; +} + +.billboard-attribute-box .drag-nook { + position: absolute; + width: 12px; + height: 12px; + display: block; + user-select: none; + -webkit-pointer-events: auto; + -moz-pointer-events: auto; + -ms-pointer-events: auto; + -o-pointer-events: auto; + pointer-events: auto; + z-index: 3; + clip-path: polygon(0% 100%, 100% 100%, 50% 50%); + background-image: linear-gradient(to top, #ffffff 1px, #00000000 1px); + background-size: 100% 3px; + /* background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAJRJREFUWEftltsJgFAMQ5NNdBJ1Eh3NTdRJdJPIBQXF50/p/WgHSNNDCSGch877EQbyIyCpBtAa/cZEsj9qXwhImgEURgZA8rTzzkAiYGVgITm+ErC6/Ek3vycMAkHAnYCkAUDKAosZSTaeSZiCqIwgCgJBIG8CWyXzKySSZBGBu+afStYBqIxMfJdSo8WPslHJgsAKWjkmIRBy/c8AAAAASUVORK5CYII='); */ +} + +.billboard-attribute-box .drag-nook.left-top { + top: -6px; + left: -6px; + cursor: se-resize; + transform: rotate(-45deg); + display: none; +} + +.billboard-attribute-box .drag-nook.right-top { + top: -6px; + right: -6px; + cursor: ne-resize; + transform: rotate(45deg); + display: none; +} + +.billboard-attribute-box .table { + background-color: #ffffff00; + color: #ffffff; + overflow: hidden; + border: 1px solid rgba(var(--color-sdk-base-rgb), 0.5); +} + +.billboard-attribute-box .table .table-head .tr { + border-top: none; + border-left: none; + border-right: none; +} + +.billboard-attribute-box .table .tr { + display: flex; + border: 1px solid rgba(var(--color-sdk-base-rgb), 0.5); + border-right: none; +} +.billboard-attribute-box .table .tr .th, .billboard-attribute-box .table .tr .td { + border-right: 1px solid rgba(var(--color-sdk-base-rgb), 0.5); + display: flex; + justify-content: center; +} +.billboard-attribute-box .table .tr .th:last-child, .billboard-attribute-box .table .tr .td:last-child { + border-right: none; +} + + +.billboard-attribute-box .table .table-body .tr { + border-bottom: none; + border-left: none; +} + +.billboard-attribute-box .table .table-body .tr:first-child { + border-top: none; } -/* 自定义提示 */ #YJ-custom-message { /* 固定在顶部中央 */ position: fixed; @@ -3669,4 +3815,4 @@ top: -200px /* 移回顶部外 */ } -} \ No newline at end of file +} diff --git a/static/img/roadPhoto.png b/static/img/roadPhoto.png new file mode 100644 index 0000000..8000eb9 Binary files /dev/null and b/static/img/roadPhoto.png differ diff --git a/static/img/roadTexture.png b/static/img/roadTexture.png new file mode 100644 index 0000000..407266c Binary files /dev/null and b/static/img/roadTexture.png differ diff --git a/static/img/sidePhoto.png b/static/img/sidePhoto.png new file mode 100644 index 0000000..d6218a4 Binary files /dev/null and b/static/img/sidePhoto.png differ