Add PolylineCustomEndpoint, PolylineDirection, PolylineDashArrow, PolylineFence, and PolylineMultiArrow material properties with corresponding examples. Also add bezier curve option to plot tool.pull/220/head
| name: '发光轨迹线', | name: '发光轨迹线', | ||||
| page: 'polyline_lighting_trail.html', | page: 'polyline_lighting_trail.html', | ||||
| }, | }, | ||||
| { | |||||
| name: '围栏线', | |||||
| page: 'polyline_fence.html', | |||||
| }, | |||||
| { | |||||
| name: '多箭头线', | |||||
| page: 'polyline_multi_arrow.html', | |||||
| }, | |||||
| { | |||||
| name: '虚线箭头线', | |||||
| page: 'polyline_dash_arrow.html', | |||||
| }, | |||||
| { | |||||
| name: '方向线', | |||||
| page: 'polyline_direction.html', | |||||
| }, | |||||
| { | |||||
| name: '自定义端点线', | |||||
| page: 'polyline_custom_endpoint.html', | |||||
| }, | |||||
| { | { | ||||
| name: '面', | name: '面', | ||||
| page: 'polygon_base.html', | page: 'polygon_base.html', | 
| <li><button onclick="draw('fine_arrow')">直箭头</button></li> | <li><button onclick="draw('fine_arrow')">直箭头</button></li> | ||||
| <li><button onclick="draw('tailed_attack_arrow')">燕尾箭头</button></li> | <li><button onclick="draw('tailed_attack_arrow')">燕尾箭头</button></li> | ||||
| <li><button onclick="draw('gathering_place')">聚集地</button></li> | <li><button onclick="draw('gathering_place')">聚集地</button></li> | ||||
| <li><button onclick="draw('bezier_curve')">曲线</button></li> | |||||
| <li><button onclick="removeAll()">清除</button></li> | <li><button onclick="removeAll()">清除</button></li> | ||||
| </ul> | </ul> | ||||
| </div> | </div> | 
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="utf-8" /> | |||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | |||||
| <title>dc-example</title> | |||||
| <script src="/libs/dc-sdk/dc.min.js"></script> | |||||
| <link href="/libs/dc-sdk/dc.min.css" type="text/css" rel="stylesheet" /> | |||||
| <link href="../index.css" type="text/css" rel="stylesheet" /> | |||||
| </head> | |||||
| <body> | |||||
| <div id="viewer-container" class="viewer-container"></div> | |||||
| <script> | |||||
| DC.config.baseUrl = '../libs/dc-sdk/resources/' | |||||
| let viewer = new DC.Viewer('viewer-container') | |||||
| let baseLayer = DC.ImageryLayerFactory.createImageryLayer( | |||||
| DC.ImageryType.AMAP, | |||||
| { | |||||
| style: 'img', | |||||
| crs: 'WGS84', | |||||
| } | |||||
| ) | |||||
| viewer.addBaseLayer(baseLayer, { | |||||
| brightness: 0.1, | |||||
| }) | |||||
| let layer = new DC.VectorLayer('layer') | |||||
| viewer.addLayer(layer) | |||||
| let polyline = new DC.Polyline('-75, 35; -125, 35; -125, 10') | |||||
| polyline.setStyle({ | |||||
| width: 20, | |||||
| material: new DC.PolylineCustomEndpointMaterialProperty({ | |||||
| color: DC.Color.BLUE, | |||||
| // outlineColor: DC.Color.GREEN, | |||||
| startType: 2, | |||||
| endType: 1, | |||||
| outlineShow: true, | |||||
| lineWidth: 50, | |||||
| }), | |||||
| clampToGround: true, | |||||
| }) | |||||
| layer.addOverlay(polyline) | |||||
| viewer.flyTo(layer) | |||||
| </script> | |||||
| </body> | |||||
| </html> | 
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="utf-8" /> | |||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | |||||
| <title>dc-example</title> | |||||
| <script src="/libs/dc-sdk/dc.min.js"></script> | |||||
| <link href="/libs/dc-sdk/dc.min.css" type="text/css" rel="stylesheet" /> | |||||
| <link href="../index.css" type="text/css" rel="stylesheet" /> | |||||
| </head> | |||||
| <body> | |||||
| <div id="viewer-container" class="viewer-container"></div> | |||||
| <script> | |||||
| DC.config.baseUrl = '../libs/dc-sdk/resources/' | |||||
| let viewer = new DC.Viewer('viewer-container') | |||||
| let baseLayer = DC.ImageryLayerFactory.createImageryLayer( | |||||
| DC.ImageryType.AMAP, | |||||
| { | |||||
| style: 'img', | |||||
| crs: 'WGS84', | |||||
| } | |||||
| ) | |||||
| viewer.addBaseLayer(baseLayer, { | |||||
| brightness: 0.1, | |||||
| }) | |||||
| let layer = new DC.VectorLayer('layer') | |||||
| viewer.addLayer(layer) | |||||
| let polyline = new DC.Polyline('-75, 35; -125, 35; -125, 10') | |||||
| polyline.setStyle({ | |||||
| width: 20, | |||||
| material: new DC.PolylineDashArrowMaterialProperty({ | |||||
| color: DC.Color.BLUE, | |||||
| }), | |||||
| clampToGround: true, | |||||
| }) | |||||
| layer.addOverlay(polyline) | |||||
| let polyline2 = new DC.Polyline('-60, 20; -110, 20; -110, -80') | |||||
| polyline2.setStyle({ | |||||
| width: 20, | |||||
| material: new DC.PolylineEmissionMaterialProperty({ | |||||
| color: DC.Color.BLUE, | |||||
| }), | |||||
| clampToGround: true, | |||||
| }) | |||||
| layer.addOverlay(polyline2) | |||||
| viewer.flyTo(layer) | |||||
| </script> | |||||
| </body> | |||||
| </html> | 
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="utf-8" /> | |||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | |||||
| <title>dc-example</title> | |||||
| <script src="/libs/dc-sdk/dc.min.js"></script> | |||||
| <link href="/libs/dc-sdk/dc.min.css" type="text/css" rel="stylesheet" /> | |||||
| <link href="../index.css" type="text/css" rel="stylesheet" /> | |||||
| </head> | |||||
| <body> | |||||
| <div id="viewer-container" class="viewer-container"></div> | |||||
| <script> | |||||
| DC.config.baseUrl = '../libs/dc-sdk/resources/' | |||||
| let viewer = new DC.Viewer('viewer-container') | |||||
| let baseLayer = DC.ImageryLayerFactory.createImageryLayer( | |||||
| DC.ImageryType.AMAP, | |||||
| { | |||||
| style: 'img', | |||||
| crs: 'WGS84', | |||||
| } | |||||
| ) | |||||
| viewer.addBaseLayer(baseLayer, { | |||||
| brightness: 0.1, | |||||
| }) | |||||
| let layer = new DC.VectorLayer('layer') | |||||
| viewer.addLayer(layer) | |||||
| let polyline = new DC.Polyline('-75, 35; -125, 35; -125, 10') | |||||
| polyline.setStyle({ | |||||
| width: 20, | |||||
| material: new DC.PolylineDirectionMaterialProperty({ | |||||
| color: DC.Color.BLUE, | |||||
| outlineColor: DC.Color.GREEN, | |||||
| outlineWidth: 5, | |||||
| }), | |||||
| clampToGround: true, | |||||
| }) | |||||
| layer.addOverlay(polyline) | |||||
| viewer.flyTo(layer) | |||||
| </script> | |||||
| </body> | |||||
| </html> | 
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="utf-8" /> | |||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | |||||
| <title>dc-example</title> | |||||
| <script src="/libs/dc-sdk/dc.min.js"></script> | |||||
| <link href="/libs/dc-sdk/dc.min.css" type="text/css" rel="stylesheet" /> | |||||
| <link href="../index.css" type="text/css" rel="stylesheet" /> | |||||
| </head> | |||||
| <body> | |||||
| <div id="viewer-container" class="viewer-container"></div> | |||||
| <script> | |||||
| DC.config.baseUrl = '../libs/dc-sdk/resources/' | |||||
| let viewer = new DC.Viewer('viewer-container') | |||||
| let baseLayer = DC.ImageryLayerFactory.createImageryLayer( | |||||
| DC.ImageryType.AMAP, | |||||
| { | |||||
| style: 'img', | |||||
| crs: 'WGS84', | |||||
| } | |||||
| ) | |||||
| viewer.addBaseLayer(baseLayer, { | |||||
| brightness: 0.1, | |||||
| }) | |||||
| let layer = new DC.VectorLayer('layer') | |||||
| viewer.addLayer(layer) | |||||
| let polyline = new DC.Polyline('-75, 35; -125, 35; -125, 10') | |||||
| polyline.setStyle({ | |||||
| width: 20, | |||||
| material: new DC.PolylineFenceMaterialProperty({ | |||||
| color: DC.Color.WHITE, | |||||
| outlineColor: new Cesium.Color(1, 1, 1, 0), | |||||
| outlineWidth: new Cesium.CallbackProperty((time) => { | |||||
| const seconds = Cesium.JulianDate.toDate(time).getSeconds() | |||||
| return 5 + Math.abs(Math.sin(seconds)) * 15 | |||||
| }, false), | |||||
| maskLength: 20, | |||||
| }), | |||||
| clampToGround: true, | |||||
| }) | |||||
| layer.addOverlay(polyline) | |||||
| viewer.flyTo(layer) | |||||
| </script> | |||||
| </body> | |||||
| </html> | 
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="utf-8" /> | |||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | |||||
| <title>dc-example</title> | |||||
| <script src="/libs/dc-sdk/dc.min.js"></script> | |||||
| <link href="/libs/dc-sdk/dc.min.css" type="text/css" rel="stylesheet" /> | |||||
| <link href="../index.css" type="text/css" rel="stylesheet" /> | |||||
| </head> | |||||
| <body> | |||||
| <div id="viewer-container" class="viewer-container"></div> | |||||
| <script> | |||||
| DC.config.baseUrl = '../libs/dc-sdk/resources/' | |||||
| let viewer = new DC.Viewer('viewer-container') | |||||
| let baseLayer = DC.ImageryLayerFactory.createImageryLayer( | |||||
| DC.ImageryType.AMAP, | |||||
| { | |||||
| style: 'img', | |||||
| crs: 'WGS84', | |||||
| } | |||||
| ) | |||||
| viewer.addBaseLayer(baseLayer, { | |||||
| brightness: 0.1, | |||||
| }) | |||||
| let layer = new DC.VectorLayer('layer') | |||||
| viewer.addLayer(layer) | |||||
| let polyline = new DC.Polyline('-75, 35; -125, 35; -125, 10') | |||||
| polyline.setStyle({ | |||||
| width: 20, | |||||
| material: new DC.PolylineMultiArrowMaterialProperty({ | |||||
| color: DC.Color.WHITE, | |||||
| repeatFactor: 100.0, | |||||
| antiClockWise: true, | |||||
| }), | |||||
| clampToGround: true, | |||||
| }) | |||||
| layer.addOverlay(polyline) | |||||
| viewer.flyTo(layer) | |||||
| </script> | |||||
| </body> | |||||
| </html> | 
| /** | /** | ||||
| * polyline material property | * polyline material property | ||||
| */ | */ | ||||
| export { default as PolylineCustomEndpointMaterialProperty } from './property/polyline/PolylineCustomEndpointMaterialProperty' | |||||
| export { default as PolylineDirectionMaterialProperty } from './property/polyline/PolylineDirectionMaterialProperty' | |||||
| export { default as PolylineDashArrowMaterialProperty } from './property/polyline/PolylineDashArrowMaterialProperty' | |||||
| export { default as PolylineEmissionMaterialProperty } from './property/polyline/PolylineEmissionMaterialProperty' | |||||
| export { default as PolylineFenceMaterialProperty } from './property/polyline/PolylineFenceMaterialProperty' | |||||
| export { default as PolylineFlickerMaterialProperty } from './property/polyline/PolylineFlickerMaterialProperty' | export { default as PolylineFlickerMaterialProperty } from './property/polyline/PolylineFlickerMaterialProperty' | ||||
| export { default as PolylineFlowMaterialProperty } from './property/polyline/PolylineFlowMaterialProperty' | export { default as PolylineFlowMaterialProperty } from './property/polyline/PolylineFlowMaterialProperty' | ||||
| export { default as PolylineImageTrailMaterialProperty } from './property/polyline/PolylineImageTrailMaterialProperty' | export { default as PolylineImageTrailMaterialProperty } from './property/polyline/PolylineImageTrailMaterialProperty' | ||||
| export { default as PolylineLightingMaterialProperty } from './property/polyline/PolylineLightingMaterialProperty' | export { default as PolylineLightingMaterialProperty } from './property/polyline/PolylineLightingMaterialProperty' | ||||
| export { default as PolylineLightingTrailMaterialProperty } from './property/polyline/PolylineLightingTrailMaterialProperty' | export { default as PolylineLightingTrailMaterialProperty } from './property/polyline/PolylineLightingTrailMaterialProperty' | ||||
| export { default as PolylineMultiArrowMaterialProperty } from './property/polyline/PolylineMultiArrowMaterialProperty' | |||||
| export { default as PolylineTrailMaterialProperty } from './property/polyline/PolylineTrailMaterialProperty' | export { default as PolylineTrailMaterialProperty } from './property/polyline/PolylineTrailMaterialProperty' | ||||
| /** | /** | 
| /** | |||||
| * PolylineCustomEndpoint Material Property | |||||
| * @Author : Converted from fh2 | |||||
| */ | |||||
| import { Cesium } from '../../../../libs' | |||||
| import MaterialProperty from '../../MaterialProperty' | |||||
| /** | |||||
| * PolylineCustomEndpointMaterialProperty | |||||
| */ | |||||
| class PolylineCustomEndpointMaterialProperty extends MaterialProperty { | |||||
| constructor(options = {}) { | |||||
| super(options) | |||||
| this.color = options.color || Cesium.Color.WHITE | |||||
| this._startType = undefined | |||||
| this._startTypeSubscription = undefined | |||||
| this.startType = options.startType | |||||
| this._endType = undefined | |||||
| this._endTypeSubscription = undefined | |||||
| this.endType = options.endType | |||||
| this._outlineShow = undefined | |||||
| this._outlineShowSubscription = undefined | |||||
| this.outlineShow = options.outlineShow || false | |||||
| this._lineWidth = undefined | |||||
| this._lineWidthSubscription = undefined | |||||
| this.lineWidth = options.lineWidth | |||||
| this._outlineColor = undefined | |||||
| this._outlineColorSubscription = undefined | |||||
| this.outlineColor = | |||||
| options.outlineColor || | |||||
| (this.outlineShow ? Cesium.Color.WHITE : this.color) | |||||
| } | |||||
| getType(time) { | |||||
| return Cesium.Material.PolylineCustomEndpointType | |||||
| } | |||||
| getValue(time, result) { | |||||
| if (!result) { | |||||
| result = {} | |||||
| } | |||||
| result.color = Cesium.Property.getValueOrUndefined(this._color, time) | |||||
| result.startType = Cesium.Property.getValueOrUndefined(this._startType, time) | |||||
| result.endType = Cesium.Property.getValueOrUndefined(this._endType, time) | |||||
| result.outlineShow = Cesium.Property.getValueOrUndefined(this._outlineShow, time) | |||||
| result.lineWidth = Cesium.Property.getValueOrUndefined(this._lineWidth, time) | |||||
| result.outlineColor = Cesium.Property.getValueOrUndefined(this._outlineColor, time) | |||||
| return result | |||||
| } | |||||
| equals(other) { | |||||
| return ( | |||||
| this === other || | |||||
| (other instanceof PolylineCustomEndpointMaterialProperty && | |||||
| Cesium.Property.equals(this._color, other._color) && | |||||
| Cesium.Property.equals(this._startType, other._startType) && | |||||
| Cesium.Property.equals(this._endType, other._endType) && | |||||
| Cesium.Property.equals(this._outlineShow, other._outlineShow) && | |||||
| Cesium.Property.equals(this._lineWidth, other._lineWidth) && | |||||
| Cesium.Property.equals(this._outlineColor, other._outlineColor)) | |||||
| ) | |||||
| } | |||||
| } | |||||
| Object.defineProperties(PolylineCustomEndpointMaterialProperty.prototype, { | |||||
| color: Cesium.createPropertyDescriptor('color'), | |||||
| startType: Cesium.createPropertyDescriptor('startType'), | |||||
| endType: Cesium.createPropertyDescriptor('endType'), | |||||
| outlineShow: Cesium.createPropertyDescriptor('outlineShow'), | |||||
| lineWidth: Cesium.createPropertyDescriptor('lineWidth'), | |||||
| outlineColor: Cesium.createPropertyDescriptor('outlineColor'), | |||||
| }) | |||||
| export default PolylineCustomEndpointMaterialProperty | 
| /** | |||||
| * PolylineDashArrow Material Property | |||||
| * @Author : Converted from fh2 | |||||
| */ | |||||
| import { Cesium } from '../../../../libs' | |||||
| import MaterialProperty from '../../MaterialProperty' | |||||
| /** | |||||
| * PolylineDashArrowMaterialProperty | |||||
| */ | |||||
| class PolylineDashArrowMaterialProperty extends MaterialProperty { | |||||
| constructor(options = {}) { | |||||
| super(options) | |||||
| } | |||||
| getType(time) { | |||||
| return Cesium.Material.PolylineDashArrowType | |||||
| } | |||||
| getValue(time, result) { | |||||
| if (!result) { | |||||
| result = {} | |||||
| } | |||||
| result.color = Cesium.Property.getValueOrUndefined(this._color, time) | |||||
| return result | |||||
| } | |||||
| equals(other) { | |||||
| return ( | |||||
| this === other || | |||||
| (other instanceof PolylineDashArrowMaterialProperty && | |||||
| Cesium.Property.equals(this._color, other._color)) | |||||
| ) | |||||
| } | |||||
| } | |||||
| Object.defineProperties(PolylineDashArrowMaterialProperty.prototype, { | |||||
| color: Cesium.createPropertyDescriptor('color'), | |||||
| }) | |||||
| export default PolylineDashArrowMaterialProperty | 
| /** | |||||
| * PolylineDirection Material Property | |||||
| * @Author : Converted from fh2 | |||||
| */ | |||||
| import { Cesium } from '../../../../libs' | |||||
| import MaterialProperty from '../../MaterialProperty' | |||||
| /** | |||||
| * PolylineDirectionMaterialProperty | |||||
| */ | |||||
| class PolylineDirectionMaterialProperty extends MaterialProperty { | |||||
| constructor(options = {}) { | |||||
| super(options) | |||||
| this._outlineWidth = undefined | |||||
| this._outlineWidthSubscription = undefined | |||||
| this.outlineWidth = options.outlineWidth | |||||
| this._outlineColor = undefined | |||||
| this._outlineColorSubscription = undefined | |||||
| this.outlineColor = options.outlineColor | |||||
| } | |||||
| getType(time) { | |||||
| return Cesium.Material.PolylineDirectionType | |||||
| } | |||||
| getValue(time, result) { | |||||
| if (!result) { | |||||
| result = {} | |||||
| } | |||||
| result.color = Cesium.Property.getValueOrUndefined(this._color, time) | |||||
| result.outlineWidth = Cesium.Property.getValueOrUndefined( | |||||
| this._outlineWidth, | |||||
| time | |||||
| ) | |||||
| result.outlineColor = Cesium.Property.getValueOrUndefined( | |||||
| this._outlineColor, | |||||
| time | |||||
| ) | |||||
| return result | |||||
| } | |||||
| equals(other) { | |||||
| return ( | |||||
| this === other || | |||||
| (other instanceof PolylineDirectionMaterialProperty && | |||||
| Cesium.Property.equals(this._color, other._color) && | |||||
| Cesium.Property.equals(this._outlineWidth, other._outlineWidth) && | |||||
| Cesium.Property.equals(this._outlineColor, other._outlineColor)) | |||||
| ) | |||||
| } | |||||
| } | |||||
| Object.defineProperties(PolylineDirectionMaterialProperty.prototype, { | |||||
| color: Cesium.createPropertyDescriptor('color'), | |||||
| outlineWidth: Cesium.createPropertyDescriptor('outlineWidth'), | |||||
| outlineColor: Cesium.createPropertyDescriptor('outlineColor'), | |||||
| }) | |||||
| export default PolylineDirectionMaterialProperty | 
| /** | |||||
| * PolylineFence Material Property | |||||
| * @Author : Converted from fh2 | |||||
| */ | |||||
| import { Cesium } from '../../../../libs' | |||||
| import MaterialProperty from '../../MaterialProperty' | |||||
| class PolylineFenceMaterialProperty extends MaterialProperty { | |||||
| constructor(options = {}) { | |||||
| super(options) | |||||
| this.color = options.color || Cesium.Color.WHITE | |||||
| this._outlineColor = undefined | |||||
| this._outlineColorSubscription = undefined | |||||
| this.outlineColor = options.outlineColor || new Cesium.Color(1, 1, 1, 0) | |||||
| this._outlineWidth = undefined | |||||
| this._outlineWidthSubscription = undefined | |||||
| this.outlineWidth = options.outlineWidth ?? 10 | |||||
| this._maskLength = undefined | |||||
| this._maskLengthSubscription = undefined | |||||
| this.maskLength = options.maskLength ?? 20 | |||||
| } | |||||
| getType(time) { | |||||
| return Cesium.Material.PolylineFenceType | |||||
| } | |||||
| getValue(time, result) { | |||||
| if (!result) { | |||||
| result = {} | |||||
| } | |||||
| result.color = Cesium.Property.getValueOrUndefined(this._color, time) | |||||
| result.outlineColor = Cesium.Property.getValueOrUndefined(this._outlineColor, time) | |||||
| result.outlineWidth = Cesium.Property.getValueOrUndefined(this._outlineWidth, time) | |||||
| result.maskLength = Cesium.Property.getValueOrUndefined(this._maskLength, time) | |||||
| return result | |||||
| } | |||||
| equals(other) { | |||||
| return ( | |||||
| this === other || | |||||
| (other instanceof PolylineFenceMaterialProperty && | |||||
| Cesium.Property.equals(this._color, other._color) && | |||||
| Cesium.Property.equals(this._outlineColor, other._outlineColor) && | |||||
| Cesium.Property.equals(this._outlineWidth, other._outlineWidth) && | |||||
| Cesium.Property.equals(this._maskLength, other._maskLength)) | |||||
| ) | |||||
| } | |||||
| } | |||||
| Object.defineProperties(PolylineFenceMaterialProperty.prototype, { | |||||
| color: Cesium.createPropertyDescriptor('color'), | |||||
| outlineColor: Cesium.createPropertyDescriptor('outlineColor'), | |||||
| outlineWidth: Cesium.createPropertyDescriptor('outlineWidth'), | |||||
| maskLength: Cesium.createPropertyDescriptor('maskLength'), | |||||
| }) | |||||
| export default PolylineFenceMaterialProperty | 
| /** | |||||
| * PolylineMultiArrow Material Property | |||||
| * @Author : Converted from fh2 | |||||
| */ | |||||
| import { Cesium } from '../../../../libs' | |||||
| import MaterialProperty from '../../MaterialProperty' | |||||
| /** | |||||
| * PolylineMultiArrowMaterialProperty | |||||
| */ | |||||
| class PolylineMultiArrowMaterialProperty extends MaterialProperty { | |||||
| constructor(options = {}) { | |||||
| super(options) | |||||
| this._repeatFactor = undefined | |||||
| this._repeatFactorSubscription = undefined | |||||
| this.repeatFactor = options.repeatFactor | |||||
| this._antiClockWise = undefined | |||||
| this._antiClockWiseSubscription = undefined | |||||
| this.antiClockWise = options.antiClockWise | |||||
| } | |||||
| getType(time) { | |||||
| return Cesium.Material.PolylineMultiArrowType | |||||
| } | |||||
| getValue(time, result) { | |||||
| if (!result) { | |||||
| result = {} | |||||
| } | |||||
| result.color = Cesium.Property.getValueOrUndefined(this._color, time) | |||||
| result.repeatFactor = Cesium.Property.getValueOrUndefined( | |||||
| this._repeatFactor, | |||||
| time | |||||
| ) | |||||
| result.antiClockWise = Cesium.Property.getValueOrUndefined( | |||||
| this._antiClockWise, | |||||
| time | |||||
| ) | |||||
| return result | |||||
| } | |||||
| equals(other) { | |||||
| return ( | |||||
| this === other || | |||||
| (other instanceof PolylineMultiArrowMaterialProperty && | |||||
| Cesium.Property.equals(this._color, other._color) && | |||||
| Cesium.Property.equals(this._repeatFactor, other._repeatFactor) && | |||||
| Cesium.Property.equals(this._antiClockWise, other._antiClockWise)) | |||||
| ) | |||||
| } | |||||
| } | |||||
| Object.defineProperties(PolylineMultiArrowMaterialProperty.prototype, { | |||||
| color: Cesium.createPropertyDescriptor('color'), | |||||
| repeatFactor: Cesium.createPropertyDescriptor('repeatFactor'), | |||||
| antiClockWise: Cesium.createPropertyDescriptor('antiClockWise'), | |||||
| }) | |||||
| export default PolylineMultiArrowMaterialProperty | 
| uniform vec4 color; // 线主体颜色 | |||||
| uniform float startType; // 起始点的类型 | |||||
| uniform float endType; // 终点的类型 | |||||
| uniform vec4 outlineColor; // 边界颜色 | |||||
| uniform bool outlineShow; | |||||
| uniform float lineWidth; | |||||
| const float SHAPE_TYPE_NORMAL = 0.0; // 普通 | |||||
| const float SHAPE_TYPE_ARROW= 1.0; // 箭头 | |||||
| const float SHAPE_TYPE_CIRCLE = 2.0; // 圆 | |||||
| const float SHAPE_TYPE_END = 3.0; // 终止竖线 | |||||
| const float ratio = 2.5; // 线宽和base的比例,测试经验值 | |||||
| float outlineWidth = 0.005; // 效果比较好的经验值,后面有需要再传入 | |||||
| float getArrowPointOnLine(vec2 p0, vec2 p1, float x){ | |||||
| float slope = (p0.y - p1.y) / (p0.x - p1.x); | |||||
| return slope * (x - p0.x) + p0.y; | |||||
| } | |||||
| float getCirclePointOnLine(vec2 center, float radius, float x, float upper) { | |||||
| // 计算 x 到圆心的水平距离的平方 | |||||
| float dx = x - center.x; | |||||
| // 在圆方程中求解出 y 变化部 | |||||
| float dy = sqrt(radius * radius - dx * dx); | |||||
| dy = dy * 0.5 / radius; | |||||
| // 根据 upper 的值决定上边还是下边 | |||||
| if (upper == 1.0) { | |||||
| return center.y + dy; // 上半边 | |||||
| } else { | |||||
| return center.y - dy; // 下半边 | |||||
| } | |||||
| } | |||||
| czm_material czm_getMaterial(czm_materialInput materialInput) | |||||
| { | |||||
| czm_material material = czm_getDefaultMaterial(materialInput); | |||||
| vec2 st = materialInput.st; | |||||
| #if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives)) | |||||
| float base = 1.0 - abs(fwidth(st.s)) * lineWidth * ratio * czm_pixelRatio; | |||||
| #else | |||||
| // If no derivatives available (IE 10?), 2.5% of the line will be the arrow head | |||||
| float base = 0.975; | |||||
| #endif | |||||
| float reverseBase = 1.0 - base; | |||||
| float halfB = reverseBase / 2.0; | |||||
| float baseLeft = reverseBase; | |||||
| if(startType == SHAPE_TYPE_END) { | |||||
| baseLeft = halfB; | |||||
| } | |||||
| if(endType == SHAPE_TYPE_END) { | |||||
| base += halfB; | |||||
| } | |||||
| // 这里用来解决圆形端点的裂缝问题 | |||||
| float circleOffset = 0.01 * baseLeft; | |||||
| float halfWidth = 0.08; | |||||
| // 左侧 | |||||
| if(st.s < baseLeft) { | |||||
| if(outlineShow) { | |||||
| halfWidth += outlineWidth; | |||||
| } | |||||
| float ptOnUpperLineLeft = 0.5 + halfWidth; | |||||
| float ptOnLowerLineLeft = 0.5 - halfWidth; | |||||
| if(startType == SHAPE_TYPE_CIRCLE && st.s < baseLeft - circleOffset) { | |||||
| float r = baseLeft / 2.0; | |||||
| vec2 leftCenter = vec2(r, 0.5); | |||||
| ptOnUpperLineLeft = getCirclePointOnLine(leftCenter, r, st.s, 1.0); | |||||
| ptOnLowerLineLeft = getCirclePointOnLine(leftCenter, r, st.s, 0.0); | |||||
| } else if(startType == SHAPE_TYPE_END) { | |||||
| ptOnUpperLineLeft = 1.0; | |||||
| ptOnLowerLineLeft = 0.0; | |||||
| } else if(startType == SHAPE_TYPE_ARROW) { | |||||
| vec2 leftCenter = vec2(0.0, 0.5); | |||||
| ptOnUpperLineLeft = getArrowPointOnLine(vec2(baseLeft, 1.0), leftCenter, st.s); | |||||
| ptOnLowerLineLeft = getArrowPointOnLine(vec2(baseLeft, 0.0), leftCenter, st.s); | |||||
| } | |||||
| float t = 1.0 - step(ptOnUpperLineLeft, st.t); | |||||
| t *= step(ptOnLowerLineLeft, st.t); | |||||
| float d1 = czm_infinity; | |||||
| if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth) | |||||
| { | |||||
| d1 = abs(st.s - baseLeft); | |||||
| } | |||||
| float d2 = abs(st.t - ptOnUpperLineLeft); | |||||
| float d3 = abs(st.t - ptOnLowerLineLeft); | |||||
| float dist = min(min(d1, d2), d3); | |||||
| float dtUpper = abs(st.t - ptOnUpperLineLeft); | |||||
| dtUpper = step(dtUpper, outlineWidth); | |||||
| float dtLower = abs(st.t - ptOnLowerLineLeft); | |||||
| dtLower = step(dtLower, outlineWidth); | |||||
| vec4 contentColor; | |||||
| if(outlineShow) { | |||||
| contentColor = mix(color, outlineColor, clamp(dtUpper + dtLower, 0.0, 1.0)); | |||||
| } else { | |||||
| contentColor = color; | |||||
| } | |||||
| vec4 outsideColor = vec4(0.0); | |||||
| vec4 currentColor = mix(outsideColor, contentColor, clamp(t, 0.0, 1.0)); | |||||
| vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist, 0.05); | |||||
| outColor = czm_gammaCorrect(outColor); | |||||
| material.diffuse = outColor.rgb; | |||||
| material.alpha = outColor.a; | |||||
| return material; | |||||
| } else if(st.s <= base) { | |||||
| float fuzzFactor = 0.1; // 效果比较好的经验值 | |||||
| if(lineWidth > 10.0) { | |||||
| fuzzFactor = 0.05; // 效果比较好的经验值 | |||||
| } | |||||
| if(outlineShow) { | |||||
| halfWidth += outlineWidth; | |||||
| } | |||||
| float ptOnUpperLineRight = 0.5 + halfWidth; | |||||
| float ptOnLowerLineRight = 0.5 - halfWidth; | |||||
| float s = step(0.5 - halfWidth, st.t); | |||||
| s *= 1.0 - step(0.5 + halfWidth, st.t); | |||||
| s *= 1.0 - step(base, st.s); | |||||
| float t = step(base, materialInput.st.s); | |||||
| t *= 1.0 - step(ptOnUpperLineRight, st.t); | |||||
| t *= step(ptOnLowerLineRight, st.t); | |||||
| // Find the distance from the closest separator (region between two colors) | |||||
| float d1 = abs(st.t - (0.5 - halfWidth)); | |||||
| float d2 = abs(st.t - (0.5 + halfWidth)); | |||||
| float dist = min(d1, d2); | |||||
| float dtUpper = abs(st.t - (0.5 + halfWidth)); | |||||
| dtUpper = step(dtUpper, outlineWidth); | |||||
| float dtLower = abs(st.t - (0.5 - halfWidth)); | |||||
| dtLower = step(dtLower, outlineWidth); | |||||
| vec4 contentColor; | |||||
| if(outlineShow) { | |||||
| contentColor = mix(color, outlineColor, clamp(dtUpper + dtLower, 0.0, 1.0)); | |||||
| } else { | |||||
| contentColor = color; | |||||
| } | |||||
| vec4 outsideColor = vec4(contentColor.r, contentColor.g, contentColor.b, 0.0); | |||||
| vec4 currentColor = mix(outsideColor, contentColor, clamp(s + t, 0.0, 1.0)); | |||||
| vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist, fuzzFactor); | |||||
| float delta = outlineWidth * 10.0; | |||||
| outColor = czm_gammaCorrect(outColor); | |||||
| material.diffuse = outColor.rgb; | |||||
| material.alpha = outColor.a; | |||||
| return material; | |||||
| } else { | |||||
| if(outlineShow) { | |||||
| halfWidth += outlineWidth; | |||||
| } | |||||
| float ptOnUpperLineRight = 0.5 + halfWidth; | |||||
| float ptOnLowerLineRight = 0.5 - halfWidth; | |||||
| if(endType == SHAPE_TYPE_CIRCLE && st.s > base + circleOffset) { | |||||
| float r = reverseBase / 2.0; | |||||
| vec2 rightCenter = vec2(1.0 - r, 0.5); | |||||
| ptOnUpperLineRight = getCirclePointOnLine(rightCenter, r, st.s, 1.0); | |||||
| ptOnLowerLineRight = getCirclePointOnLine(rightCenter, r, st.s, 0.0); | |||||
| } else if(endType == SHAPE_TYPE_END) { | |||||
| ptOnUpperLineRight = 1.0; | |||||
| ptOnLowerLineRight = 0.0; | |||||
| } else if(endType == SHAPE_TYPE_ARROW) { | |||||
| vec2 rightCenter = vec2(1.0, 0.5); | |||||
| ptOnUpperLineRight = getArrowPointOnLine(vec2(base, 1.0), rightCenter, st.s); | |||||
| ptOnLowerLineRight = getArrowPointOnLine(vec2(base, 0.0), rightCenter, st.s); | |||||
| } | |||||
| float s = step(0.5 - halfWidth, st.t); | |||||
| s *= 1.0 - step(0.5 + halfWidth, st.t); | |||||
| s *= 1.0 - step(base, st.s); | |||||
| float t = step(base, materialInput.st.s); | |||||
| t *= 1.0 - step(ptOnUpperLineRight, st.t); | |||||
| t *= step(ptOnLowerLineRight, st.t); | |||||
| // Find the distance from the closest separator (region between two colors) | |||||
| float d1 = czm_infinity; | |||||
| if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth) | |||||
| { | |||||
| d1 = abs(st.s - base); | |||||
| } | |||||
| float d2 = abs(st.t - ptOnUpperLineRight); | |||||
| float d3 = abs(st.t - ptOnLowerLineRight); | |||||
| float dist = min(min(d1, d2), d3); | |||||
| float dtUpper = abs(st.t - ptOnUpperLineRight); | |||||
| dtUpper = step(dtUpper, outlineWidth); | |||||
| float dtLower = abs(st.t - ptOnLowerLineRight); | |||||
| dtLower = step(dtLower, outlineWidth); | |||||
| vec4 contentColor; | |||||
| if(outlineShow) { | |||||
| contentColor = mix(color, outlineColor, clamp(dtUpper + dtLower, 0.0, 1.0)); | |||||
| } else { | |||||
| contentColor = color; | |||||
| } | |||||
| vec4 outsideColor = vec4(contentColor.r, contentColor.g, contentColor.b, 0.0); | |||||
| vec4 currentColor = mix(outsideColor, contentColor, clamp(s + t, 0.0, 1.0)); | |||||
| vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist, 0.05); | |||||
| outColor = czm_gammaCorrect(outColor); | |||||
| material.diffuse = outColor.rgb; | |||||
| material.alpha = outColor.a; | |||||
| return material; | |||||
| } | |||||
| } | 
| #ifdef GL_OES_standard_derivatives | |||||
| #extension GL_OES_standard_derivatives : enable | |||||
| #endif | |||||
| uniform vec4 color; | |||||
| uniform vec4 gapColor; | |||||
| uniform float dashLength; | |||||
| uniform float dashPattern; | |||||
| in float v_polylineAngle; | |||||
| in float v_width; | |||||
| const float maskLength = 16.0; | |||||
| mat2 rotate(float rad) { | |||||
| float c = cos(rad); | |||||
| float s = sin(rad); | |||||
| return mat2( | |||||
| c, s, | |||||
| -s, c | |||||
| ); | |||||
| } | |||||
| float getPointOnLine(vec2 p0, vec2 p1, float x) | |||||
| { | |||||
| float slope = (p0.y - p1.y) / (p0.x - p1.x); | |||||
| return slope * (x - p0.x) + p0.y; | |||||
| } | |||||
| czm_material czm_getMaterial(czm_materialInput materialInput) | |||||
| { | |||||
| czm_material material = czm_getDefaultMaterial(materialInput); | |||||
| vec2 pos = rotate(v_polylineAngle) * gl_FragCoord.xy; | |||||
| // Get the relative position within the dash from 0 to 1 | |||||
| float dashPosition = fract(pos.x / (dashLength * czm_pixelRatio)); | |||||
| // Figure out the mask index. | |||||
| float maskIndex = floor(dashPosition * maskLength); | |||||
| // Test the bit mask. | |||||
| float maskTest = floor(dashPattern / pow(2.0, maskIndex)); | |||||
| vec4 fragColor = (mod(maskTest, 2.0) < 1.0) ? gapColor : color; | |||||
| vec2 st = materialInput.st; | |||||
| #ifdef GL_OES_standard_derivatives | |||||
| float base = 1.0 - abs(fwidth(st.s)) * 10.0 * czm_pixelRatio; | |||||
| #else | |||||
| float base = 0.975; // 2.5% of the line will be the arrow head | |||||
| #endif | |||||
| vec2 center = vec2(1.0, 0.5); | |||||
| float ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s); | |||||
| float ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s); | |||||
| float halfWidth = 0.15; | |||||
| float s = step(0.5 - halfWidth, st.t); | |||||
| s *= 1.0 - step(0.5 + halfWidth, st.t); | |||||
| s *= 1.0 - step(base, st.s); | |||||
| float t = step(base, materialInput.st.s); | |||||
| t *= 1.0 - step(ptOnUpperLine, st.t); | |||||
| t *= step(ptOnLowerLine, st.t); | |||||
| // Find the distance from the closest separator (region between two colors) | |||||
| float dist; | |||||
| if (st.s < base) | |||||
| { | |||||
| if (fragColor.a < 0.005) { // matches 0/255 and 1/255 | |||||
| discard; | |||||
| } | |||||
| float d1 = abs(st.t - (0.5 - halfWidth)); | |||||
| float d2 = abs(st.t - (0.5 + halfWidth)); | |||||
| dist = min(d1, d2); | |||||
| } | |||||
| else | |||||
| { | |||||
| fragColor = color; | |||||
| float d1 = czm_infinity; | |||||
| if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth) | |||||
| { | |||||
| d1 = abs(st.s - base); | |||||
| } | |||||
| float d2 = abs(st.t - ptOnUpperLine); | |||||
| float d3 = abs(st.t - ptOnLowerLine); | |||||
| dist = min(min(d1, d2), d3); | |||||
| } | |||||
| vec4 outsideColor = vec4(0.0); | |||||
| vec4 currentColor = mix(outsideColor, fragColor, clamp(s + t, 0.0, 1.0)); | |||||
| vec4 outColor = czm_antialias(outsideColor, fragColor, currentColor, dist); | |||||
| outColor = czm_gammaCorrect(outColor); | |||||
| material.diffuse = outColor.rgb; | |||||
| material.alpha = outColor.a; | |||||
| return material; | |||||
| } | 
| #ifdef GL_OES_standard_derivatives | |||||
| #extension GL_OES_standard_derivatives : enable | |||||
| #endif | |||||
| uniform vec4 color; | |||||
| uniform vec4 directionColor; // 箭头颜色 | |||||
| uniform vec4 outlineColor; // 边界颜色 | |||||
| uniform float outlineWidth; // 边界宽度 | |||||
| in float v_width; // 线段宽度 | |||||
| in float v_polylineAngle; // 线段角度 | |||||
| const float fragLength = 100.0; // 每个箭头线段有多长 | |||||
| const float startPosition = 0.45; // 开始的位置,从 0 ~ 1 | |||||
| const float endPosition = 0.55; // 结束的位置,从 0 ~ 1 | |||||
| mat2 rotate(float rad) { | |||||
| float c = cos(rad); | |||||
| float s = sin(rad); | |||||
| return mat2( | |||||
| c, s, | |||||
| -s, c | |||||
| ); | |||||
| } | |||||
| float getPointOnLine(vec2 p0, vec2 p1, float x) | |||||
| { | |||||
| float slope = (p0.y - p1.y) / (p0.x - p1.x); // 根据两个点获取斜率 | |||||
| return slope * (x - p0.x) + p0.y; // 根据斜率和 x 值获取 y 值 | |||||
| } | |||||
| czm_material czm_getMaterial(czm_materialInput materialInput) | |||||
| { | |||||
| // 用 Dash 的方式渲染正常的线 | |||||
| czm_material material = czm_getDefaultMaterial(materialInput); | |||||
| vec2 st = materialInput.st; | |||||
| // copy from polyline outline | |||||
| float halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width; | |||||
| float b = step(0.5 - halfInteriorWidth, st.t); | |||||
| b *= 1.0 - step(0.5 + halfInteriorWidth, st.t); | |||||
| // Find the distance from the closest separator (region between two colors) | |||||
| float d1 = abs(st.t - (0.5 - halfInteriorWidth)); | |||||
| float d2 = abs(st.t - (0.5 + halfInteriorWidth)); | |||||
| float dist = min(d1, d2); | |||||
| vec4 currentColor = mix(outlineColor, color, b); | |||||
| vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist); | |||||
| outColor = czm_gammaCorrect(outColor); | |||||
| // 获取当前位置处于窗口的相对位置(像素值) | |||||
| vec2 pos = rotate(v_polylineAngle) * gl_FragCoord.xy; | |||||
| // 获取当前位置处于箭头线段的哪部分, 0 ~ 1 | |||||
| float maskS = fract(pos.x / (fragLength * czm_pixelRatio)); | |||||
| // float maskS = fract(st.s / (abs(fwidth(st.s)) * fragLength * czm_pixelRatio)); | |||||
| float maskT = st.t; | |||||
| // 判断是正常的线还是箭头 | |||||
| bool isDirection = (maskS > startPosition) && (maskS <= endPosition); | |||||
| vec4 fragColor; | |||||
| if (isDirection) { | |||||
| // 渲染箭头 | |||||
| float arrowWidth = (endPosition - startPosition) / 2.0; | |||||
| float midS = startPosition + arrowWidth; | |||||
| float t = 1.0; | |||||
| if (maskS < midS) { | |||||
| // 左边的三角形 | |||||
| vec2 center = vec2(midS, 0.5); | |||||
| float ptOnUpperLine = getPointOnLine(vec2(startPosition, 1.0), center, maskS); // 三角形上边的线 | |||||
| float ptOnLowerLine = getPointOnLine(vec2(startPosition, 0.0), center, maskS); // 三角形下边的线 | |||||
| t *= 1.0 - step(ptOnUpperLine, maskT); // 低于上面的线 | |||||
| t *= step(ptOnLowerLine, maskT); // 而且高于下面的线 | |||||
| t = 1.0 - t; // 取反 | |||||
| } else { | |||||
| // 右边的三角形 | |||||
| vec2 center = vec2(endPosition, 0.5); | |||||
| float ptOnUpperLine = getPointOnLine(vec2(midS, 1.0), center, maskS); // 三角形上边的线 | |||||
| float ptOnLowerLine = getPointOnLine(vec2(midS, 0.0), center, maskS); // 三角形下边的线 | |||||
| t *= 1.0 - step(ptOnUpperLine, maskT); // 低于上面的线 | |||||
| t *= step(ptOnLowerLine, maskT); // 而且高于下面的线 | |||||
| } | |||||
| vec4 outsideColor = outColor; | |||||
| vec4 currentColor = mix(outsideColor, directionColor, clamp(t, 0.0, 1.0)); | |||||
| fragColor = currentColor; | |||||
| } else { | |||||
| fragColor = outColor; | |||||
| } | |||||
| fragColor = czm_gammaCorrect(fragColor); | |||||
| material.diffuse = fragColor.rgb; | |||||
| material.alpha = fragColor.a; | |||||
| return material; | |||||
| } | 
| #ifdef GL_OES_standard_derivatives | |||||
| #extension GL_OES_standard_derivatives : enable | |||||
| #endif | |||||
| uniform vec4 color; | |||||
| uniform float dashLength; | |||||
| uniform float dashPattern; | |||||
| uniform float maskLength; | |||||
| uniform float outlineWidth; | |||||
| uniform vec4 outlineColor; | |||||
| in float v_polylineAngle; | |||||
| in float v_width; // 线段宽度 | |||||
| mat2 rotate(float rad) { | |||||
| float c = cos(rad); | |||||
| float s = sin(rad); | |||||
| return mat2( | |||||
| c, s, | |||||
| -s, c | |||||
| ); | |||||
| } | |||||
| // 计算给定输入的材质 | |||||
| // 栅栏形状的polyline是以虚线材质未基础,往虚线空隙里面填充外轮廓是透明的外轮廓线所绘制的 | |||||
| czm_material czm_getMaterial(czm_materialInput materialInput) | |||||
| { | |||||
| // 获取默认的材质 | |||||
| czm_material material = czm_getDefaultMaterial(materialInput); | |||||
| // 外轮廓纹理部分 | |||||
| // 获取标准化的纹理坐标 | |||||
| vec2 st = materialInput.st; | |||||
| //v_width是整个线宽,outlineWidth是轮廓线宽,两者差值的一半就是外轮廓线内部线条的宽度 | |||||
| float halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width; | |||||
| // 判断当前的纹理坐标是否在内部线条范围内,如果在范围内,b值将为1,否则为0。step(edge, x)函数会返回一个值,如果x < edge,返回0.0,否则返回1.0 | |||||
| float b = step(0.5 - halfInteriorWidth, st.t); | |||||
| b *= 1.0 - step(0.5 + halfInteriorWidth, st.t); | |||||
| //计算当前片元距离最近的颜色分隔线的距离,这个距离将被用于后面的抗锯齿处理。 | |||||
| float d1 = abs(st.t - (0.5 - halfInteriorWidth)); | |||||
| float d2 = abs(st.t - (0.5 + halfInteriorWidth)); | |||||
| float dist = min(d1, d2); | |||||
| // 根据b的值选择颜色,如果b是1,则选择color,否则选择outlineColor。这就确定了当前片元的基础颜色 | |||||
| vec4 currentColor = mix(outlineColor, color, b); | |||||
| // 使用czm_antialias()函数进行抗锯齿处理,输入参数包括轮廓色,内部色,当前色和距离 | |||||
| vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist); | |||||
| // 对经过抗锯齿处理后的颜色进行伽马校正 | |||||
| vec4 gapColor = czm_gammaCorrect(outColor); | |||||
| // 虚线纹理部分 | |||||
| // 计算旋转后的片元位置。 | |||||
| vec2 pos = rotate(v_polylineAngle) * gl_FragCoord.xy; | |||||
| // 计算当前片元在虚线模式中的位置。 | |||||
| float dashPosition = fract(pos.x / (dashLength * czm_pixelRatio)); | |||||
| // 计算对应虚线模式的索引位置。 | |||||
| float maskIndex = floor(dashPosition * maskLength); | |||||
| // 通过使用虚线模式和索引位置,计算当前位置是否应有线条。 | |||||
| float maskTest = floor(dashPattern / pow(2.0, maskIndex)); | |||||
| // 如果当前位置应为虚线的间隔部分,则颜色设为gapColor,否则设为color。 | |||||
| vec4 fragColor = (mod(maskTest, 2.0) < 1.0) ? gapColor : color; | |||||
| if (fragColor.a < 0.005) { | |||||
| discard; | |||||
| } | |||||
| // 设置材质的颜色和透明度,后返回处理过后的材质 | |||||
| fragColor = czm_gammaCorrect(fragColor); | |||||
| material.emission = fragColor.rgb; | |||||
| material.alpha = fragColor.a; | |||||
| return material; | |||||
| } | 
| #ifdef GL_OES_standard_derivatives | |||||
| #extension GL_OES_standard_derivatives : enable | |||||
| #endif | |||||
| uniform vec4 color; | |||||
| uniform float repeatFactor;// 重复箭头的次数 | |||||
| uniform bool antiClockWise; // 确定箭头的方向 | |||||
| // 一个辅助函数,给定两点(p0, p1)和一个x坐标,返回直线上对应的y坐标 | |||||
| float getPointOnLine(vec2 p0, vec2 p1, float x) | |||||
| { | |||||
| float slope = (p0.y - p1.y) / (p0.x - p1.x);// 计算斜率 | |||||
| return slope * (x - p0.x) + p0.y;// 使用斜率公式返回y坐标 | |||||
| } | |||||
| // 主材质函数,将被Cesium调用以获得每个片元的材质属性 | |||||
| czm_material czm_getMaterial(czm_materialInput materialInput) | |||||
| { | |||||
| czm_material material = czm_getDefaultMaterial(materialInput);// 获取默认材质 | |||||
| vec2 st = materialInput.st;// 获取当前片元的纹理坐标 | |||||
| if (antiClockWise) { // 根据antiClockWise的值选择性地翻转s坐标 | |||||
| st.s = 1.0 - st.s; | |||||
| } | |||||
| float arrowWidth = 1.0 / repeatFactor;// 每个箭头的宽度 | |||||
| // 使用mod函数将片元的s坐标映射到[0, arrowWidth]的范围内,从而实现箭头的重复 | |||||
| st.s = mod(st.s, arrowWidth) / arrowWidth; | |||||
| // 如果可用,使用fwidth函数来获得箭头的宽度,否则使用固定值 | |||||
| #if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives)) | |||||
| float base = 1.0 - abs(fwidth(st.s)) * 10.0 * czm_pixelRatio; | |||||
| #else | |||||
| float base = 0.995; | |||||
| #endif | |||||
| vec2 center = vec2(1.0, 0.5);// 箭头的顶点坐标 | |||||
| // 增大箭头的尺寸来覆盖空隙 | |||||
| center.s += 0.01; | |||||
| // 计算箭头上部和下部直线上的点 | |||||
| float ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s); | |||||
| float ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s); | |||||
| float halfWidth = 0.15;// 箭头的半宽 | |||||
| // 计算箭头主体部分的纹理坐标 | |||||
| float s = step(0.5 - halfWidth, st.t); | |||||
| s *= 1.0 - step(0.5 + halfWidth, st.t); | |||||
| s *= 1.0 - step(base, st.s); | |||||
| // 计算箭头顶部部分的纹理坐标 | |||||
| float t = step(base, st.s); | |||||
| t *= 1.0 - step(ptOnUpperLine, st.t); | |||||
| t *= step(ptOnLowerLine, st.t); | |||||
| // 计算片元与箭头边界的距离,以便进行抗锯齿处理 | |||||
| float dist; | |||||
| if (st.s < base) | |||||
| { | |||||
| float d1 = abs(st.t - (0.5 - halfWidth)); | |||||
| float d2 = abs(st.t - (0.5 + halfWidth)); | |||||
| dist = min(d1, d2); | |||||
| } | |||||
| else | |||||
| { | |||||
| float d1 = czm_infinity; | |||||
| if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth) | |||||
| { | |||||
| d1 = abs(st.s - base); | |||||
| } | |||||
| float d2 = abs(st.t - ptOnUpperLine); | |||||
| float d3 = abs(st.t - ptOnLowerLine); | |||||
| dist = min(min(d1, d2), d3); | |||||
| } | |||||
| vec4 outsideColor = vec4(0.0);// 外部颜色(非箭头部分) | |||||
| // 根据s和t的值混合颜色,如果片元位于箭头上,则使用箭头颜色,否则使用外部颜色 | |||||
| vec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0)); | |||||
| // 使用czm_antialias函数进行抗锯齿处理 | |||||
| vec4 outColor = czm_antialias(outsideColor, color, currentColor, dist); | |||||
| outColor = czm_gammaCorrect(outColor); | |||||
| material.diffuse = outColor.rgb;// 设置材质的漫反射颜色 | |||||
| material.alpha = outColor.a;// 设置材质的透明度 | |||||
| return material;// 返回材质 | |||||
| } | |||||
| import LineLightingMaterial from '../shader/polyline/PolylineLightingMaterial.glsl' | import LineLightingMaterial from '../shader/polyline/PolylineLightingMaterial.glsl' | ||||
| import LineLightingTrailMaterial from '../shader/polyline/PolylineLightingTrailMaterial.glsl' | import LineLightingTrailMaterial from '../shader/polyline/PolylineLightingTrailMaterial.glsl' | ||||
| import LineTrailMaterial from '../shader/polyline/PolylineTrailMaterial.glsl' | import LineTrailMaterial from '../shader/polyline/PolylineTrailMaterial.glsl' | ||||
| import LineFenceMaterial from '../shader/polyline/PolylineFenceMaterial.glsl' | |||||
| import LineMultiArrowMaterial from '../shader/polyline/PolylineMultiArrowMaterial.glsl' | |||||
| import LineDashArrowMaterial from '../shader/polyline/PolylineDashArrowMaterial.glsl' | |||||
| import LineDirectionMaterial from '../shader/polyline/PolylineDirectionMaterial.glsl' | |||||
| import LineCustomEndpointMaterial from '../shader/polyline/PolylineCustomEndpointMaterial.glsl' | |||||
| /** | /** | ||||
| * PolylineFlicker | * PolylineFlicker | ||||
| return true | return true | ||||
| }, | }, | ||||
| }) | }) | ||||
| /** | |||||
| * PolylineFence | |||||
| * @type {string} | |||||
| */ | |||||
| Cesium.Material.PolylineFenceType = 'PolylineFence' | |||||
| Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineFenceType, { | |||||
| fabric: { | |||||
| type: Cesium.Material.PolylineFenceType, | |||||
| uniforms: { | |||||
| color: new Cesium.Color(1.0, 1.0, 1.0, 1.0), | |||||
| outlineColor: new Cesium.Color(1.0, 1.0, 1.0, 1.0), | |||||
| dashLength: 10, | |||||
| dashPattern: 15, | |||||
| outlineWidth: 16, | |||||
| maskLength: 20, | |||||
| }, | |||||
| source: LineFenceMaterial, | |||||
| }, | |||||
| translucent: function (material) { | |||||
| return true | |||||
| }, | |||||
| }) | |||||
| /** | |||||
| * PolylineMultiArrow | |||||
| * @type {string} | |||||
| */ | |||||
| Cesium.Material.PolylineMultiArrowType = 'PolylineMultiArrow' | |||||
| Cesium.Material._materialCache.addMaterial( | |||||
| Cesium.Material.PolylineMultiArrowType, | |||||
| { | |||||
| strict: true, | |||||
| fabric: { | |||||
| type: Cesium.Material.PolylineMultiArrowType, | |||||
| uniforms: { | |||||
| color: Cesium.Color.WHITE, | |||||
| repeatFactor: 1, | |||||
| antiClockWise: true, | |||||
| }, | |||||
| source: LineMultiArrowMaterial, | |||||
| }, | |||||
| translucent: function (material) { | |||||
| return true | |||||
| }, | |||||
| } | |||||
| ) | |||||
| /** | |||||
| * PolylineDashArrow | |||||
| * @type {string} | |||||
| */ | |||||
| Cesium.Material.PolylineDashArrowType = 'PolylineDashArrow' | |||||
| Cesium.Material._materialCache.addMaterial( | |||||
| Cesium.Material.PolylineDashArrowType, | |||||
| { | |||||
| strict: true, | |||||
| fabric: { | |||||
| type: Cesium.Material.PolylineDashArrowType, | |||||
| uniforms: { | |||||
| color: Cesium.Color.WHITE, | |||||
| gapColor: Cesium.Color.TRANSPARENT, | |||||
| dashLength: 16, | |||||
| dashPattern: 255, | |||||
| }, | |||||
| source: LineDashArrowMaterial, | |||||
| }, | |||||
| translucent: function (material) { | |||||
| return true | |||||
| }, | |||||
| } | |||||
| ) | |||||
| /** | |||||
| * PolylineDirection | |||||
| * @type {string} | |||||
| */ | |||||
| Cesium.Material.PolylineDirectionType = 'PolylineDirection' | |||||
| Cesium.Material._materialCache.addMaterial( | |||||
| Cesium.Material.PolylineDirectionType, | |||||
| { | |||||
| fabric: { | |||||
| type: Cesium.Material.PolylineDirectionType, | |||||
| uniforms: { | |||||
| color: new Cesium.Color(0, 1, 1, 1), | |||||
| directionColor: new Cesium.Color(1, 1, 1, 1), | |||||
| outlineColor: new Cesium.Color(1, 1, 1, 1), | |||||
| outlineWidth: 0, | |||||
| }, | |||||
| source: LineDirectionMaterial, | |||||
| }, | |||||
| translucent: function (material) { | |||||
| return true | |||||
| }, | |||||
| } | |||||
| ) | |||||
| /** | |||||
| * PolylineCustomEndpoint | |||||
| * @type {string} | |||||
| */ | |||||
| Cesium.Material.PolylineCustomEndpointType = 'PolylineCustomEndpoint' | |||||
| Cesium.Material._materialCache.addMaterial( | |||||
| Cesium.Material.PolylineCustomEndpointType, | |||||
| { | |||||
| strict: true, | |||||
| fabric: { | |||||
| type: Cesium.Material.PolylineCustomEndpointType, | |||||
| uniforms: { | |||||
| color: Cesium.Color.WHITE, | |||||
| startType: 0.0, // 普通 0.0; 箭头 1.0; 圆 2.0; 终止竖线 3.0 | |||||
| endType: 0.0, // 普通 0.0; 箭头 1.0; 圆 2.0; 终止竖线 3.0 | |||||
| outlineColor: Cesium.Color.WHITE, | |||||
| outlineShow: !1, | |||||
| lineWidth: 3, | |||||
| }, | |||||
| source: LineCustomEndpointMaterial, | |||||
| }, | |||||
| translucent: function (material) { | |||||
| return true | |||||
| }, | |||||
| } | |||||
| ) | 
| export { default as PolylineVolume } from './vector/PolylineVolume' | export { default as PolylineVolume } from './vector/PolylineVolume' | ||||
| export { default as Rect } from './vector/Rect' | export { default as Rect } from './vector/Rect' | ||||
| export { default as Wall } from './vector/Wall' | export { default as Wall } from './vector/Wall' | ||||
| export { default as BezierCurve } from './vector/BezierCurve' | 
| /** | |||||
| * BezierCurve - 贝塞尔曲线覆盖物 | |||||
| * @Author : zishang520 | |||||
| */ | |||||
| import { Cesium } from '../../../libs' | |||||
| import Overlay from '../Overlay' | |||||
| import Parse from '../../parse/Parse' | |||||
| import State from '../../state/State' | |||||
| import { Transform } from '../../transform' | |||||
| import { Util } from '../../utils' | |||||
| class BezierCurve extends Overlay { | |||||
| constructor(positions, options = {}) { | |||||
| super() | |||||
| this._positions = Parse.parsePositions(positions) | |||||
| this._delegate = new Cesium.Entity({ polyline: {} }) | |||||
| // 贝塞尔曲线配置参数 | |||||
| this.resolution = options.resolution || 100 // 曲线分段数 | |||||
| this.curveType = options.curveType || 'spline' // 'quadratic' | 'cubic' | 'auto' | |||||
| this.showControlPoints = options.showControlPoints || false | |||||
| this.controlPointStyle = options.controlPointStyle || { | |||||
| pixelSize: 8, | |||||
| color: Cesium.Color.YELLOW, | |||||
| outlineColor: Cesium.Color.BLACK, | |||||
| outlineWidth: 2, | |||||
| } | |||||
| this._controlPointEntities = [] | |||||
| this._state = State.INITIALIZED | |||||
| } | |||||
| get type() { | |||||
| return Overlay.getOverlayType('bezier_curve') | |||||
| } | |||||
| set positions(positions) { | |||||
| this._positions = Parse.parsePositions(positions) | |||||
| this._updateCurve() | |||||
| } | |||||
| get positions() { | |||||
| return this._positions | |||||
| } | |||||
| /** | |||||
| * 计算贝塞尔曲线点 | |||||
| * @private | |||||
| */ | |||||
| _calculateBezierPoints() { | |||||
| if (this._positions.length < 2) { | |||||
| return [] | |||||
| } | |||||
| const cartesianPositions = Transform.transformWGS84ArrayToCartesianArray( | |||||
| this._positions | |||||
| ) | |||||
| // 根据控制点数量决定曲线类型 | |||||
| let curvePoints = [] | |||||
| const pointCount = cartesianPositions.length | |||||
| if (this.curveType === 'auto') { | |||||
| if (pointCount === 2) { | |||||
| curvePoints = this._calculateLinear(cartesianPositions) | |||||
| } else if (pointCount === 3) { | |||||
| curvePoints = this._calculateQuadraticBezier(cartesianPositions) | |||||
| } else if (pointCount === 4) { | |||||
| curvePoints = this._calculateCubicBezier(cartesianPositions) | |||||
| } else { | |||||
| // 使用Cardinal样条处理多个点 | |||||
| curvePoints = this._calculateCardinalSpline(cartesianPositions) | |||||
| } | |||||
| } else if (this.curveType === 'quadratic' && pointCount >= 3) { | |||||
| curvePoints = this._calculateQuadraticBezier( | |||||
| cartesianPositions.slice(0, 3) | |||||
| ) | |||||
| } else if (this.curveType === 'cubic' && pointCount >= 4) { | |||||
| curvePoints = this._calculateCubicBezier(cartesianPositions.slice(0, 4)) | |||||
| } else if (this.curveType === 'spline') { | |||||
| // 新增样条类型 | |||||
| curvePoints = this._calculateCardinalSpline(cartesianPositions) | |||||
| } else { | |||||
| curvePoints = this._calculateLinear(cartesianPositions) | |||||
| } | |||||
| return curvePoints | |||||
| } | |||||
| /** | |||||
| * 计算线性插值 | |||||
| * @param {Array} points | |||||
| * @private | |||||
| */ | |||||
| _calculateLinear(points) { | |||||
| if (points.length < 2) return points | |||||
| const result = [] | |||||
| const p0 = points[0] | |||||
| const p1 = points[1] | |||||
| for (let i = 0; i <= this.resolution; i++) { | |||||
| const t = i / this.resolution | |||||
| const point = new Cesium.Cartesian3( | |||||
| p0.x + t * (p1.x - p0.x), | |||||
| p0.y + t * (p1.y - p0.y), | |||||
| p0.z + t * (p1.z - p0.z) | |||||
| ) | |||||
| result.push(point) | |||||
| } | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * 计算二次贝塞尔曲线 | |||||
| * @param {Array} points [P0, P1, P2] | |||||
| * @private | |||||
| */ | |||||
| _calculateQuadraticBezier(points) { | |||||
| if (points.length < 3) return points | |||||
| const result = [] | |||||
| const [p0, p1, p2] = points | |||||
| for (let i = 0; i <= this.resolution; i++) { | |||||
| const t = i / this.resolution | |||||
| const u = 1 - t | |||||
| // B(t) = (1-t)²P0 + 2(1-t)tP1 + t²P2 | |||||
| const point = new Cesium.Cartesian3( | |||||
| u * u * p0.x + 2 * u * t * p1.x + t * t * p2.x, | |||||
| u * u * p0.y + 2 * u * t * p1.y + t * t * p2.y, | |||||
| u * u * p0.z + 2 * u * t * p1.z + t * t * p2.z | |||||
| ) | |||||
| result.push(point) | |||||
| } | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * 计算三次贝塞尔曲线 | |||||
| * @param {Array} points [P0, P1, P2, P3] | |||||
| * @private | |||||
| */ | |||||
| _calculateCubicBezier(points) { | |||||
| if (points.length < 4) return points | |||||
| const result = [] | |||||
| const [p0, p1, p2, p3] = points | |||||
| for (let i = 0; i <= this.resolution; i++) { | |||||
| const t = i / this.resolution | |||||
| const u = 1 - t | |||||
| // B(t) = (1-t)³P0 + 3(1-t)²tP1 + 3(1-t)t²P2 + t³P3 | |||||
| const point = new Cesium.Cartesian3( | |||||
| u * u * u * p0.x + | |||||
| 3 * u * u * t * p1.x + | |||||
| 3 * u * t * t * p2.x + | |||||
| t * t * t * p3.x, | |||||
| u * u * u * p0.y + | |||||
| 3 * u * u * t * p1.y + | |||||
| 3 * u * t * t * p2.y + | |||||
| t * t * t * p3.y, | |||||
| u * u * u * p0.z + | |||||
| 3 * u * u * t * p1.z + | |||||
| 3 * u * t * t * p2.z + | |||||
| t * t * t * p3.z | |||||
| ) | |||||
| result.push(point) | |||||
| } | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * 计算多段贝塞尔曲线(使用Catmull-Rom样条或连续三次贝塞尔) | |||||
| * @param {Array} points | |||||
| * @private | |||||
| */ | |||||
| _calculateMultiSegmentBezier(points) { | |||||
| if (points.length < 4) { | |||||
| return points.length === 3 | |||||
| ? this._calculateQuadraticBezier(points) | |||||
| : this._calculateLinear(points) | |||||
| } | |||||
| // 使用连续的三次贝塞尔曲线方法 | |||||
| return this._calculateContinuousCubicBezier(points) | |||||
| } | |||||
| /** | |||||
| * 计算连续三次贝塞尔曲线 | |||||
| * 使用控制点生成平滑的连续曲线 | |||||
| * @param {Array} points | |||||
| * @private | |||||
| */ | |||||
| _calculateContinuousCubicBezier(points) { | |||||
| if (points.length < 4) { | |||||
| return this._calculateQuadraticBezier(points.slice(0, 3)) | |||||
| } | |||||
| const result = [] | |||||
| // 方法1: 使用原始控制点序列作为贝塞尔控制点 | |||||
| if (points.length === 4) { | |||||
| return this._calculateCubicBezier(points) | |||||
| } | |||||
| // 方法2: 对于超过4个点,使用分段插值 | |||||
| // 将控制点作为关键点,生成中间的控制点 | |||||
| const keyPoints = points | |||||
| const segments = keyPoints.length - 1 | |||||
| for (let i = 0; i < segments; i++) { | |||||
| const p0 = keyPoints[Math.max(0, i - 1)] | |||||
| const p1 = keyPoints[i] | |||||
| const p2 = keyPoints[i + 1] | |||||
| const p3 = keyPoints[Math.min(keyPoints.length - 1, i + 2)] | |||||
| // 使用Catmull-Rom样条的控制点计算方法 | |||||
| const segmentPoints = this._generateBezierControlPoints(p0, p1, p2, p3) | |||||
| const segmentCurve = this._calculateCubicBezier(segmentPoints) | |||||
| // 避免重复点 | |||||
| const startFrom = i === 0 ? 0 : 1 | |||||
| result.push(...segmentCurve.slice(startFrom)) | |||||
| } | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * 根据四个关键点生成三次贝塞尔控制点 | |||||
| * 使用Catmull-Rom样条的切线方法 | |||||
| * @param {Cesium.Cartesian3} p0 | |||||
| * @param {Cesium.Cartesian3} p1 | |||||
| * @param {Cesium.Cartesian3} p2 | |||||
| * @param {Cesium.Cartesian3} p3 | |||||
| * @private | |||||
| */ | |||||
| _generateBezierControlPoints(p0, p1, p2, p3) { | |||||
| // Catmull-Rom to Bezier conversion | |||||
| const tension = 0.5 // 可调节张力参数 | |||||
| // 计算切线 | |||||
| const t1 = new Cesium.Cartesian3( | |||||
| tension * (p2.x - p0.x), | |||||
| tension * (p2.y - p0.y), | |||||
| tension * (p2.z - p0.z) | |||||
| ) | |||||
| const t2 = new Cesium.Cartesian3( | |||||
| tension * (p3.x - p1.x), | |||||
| tension * (p3.y - p1.y), | |||||
| tension * (p3.z - p1.z) | |||||
| ) | |||||
| // 生成贝塞尔控制点 | |||||
| const cp1 = new Cesium.Cartesian3( | |||||
| p1.x + t1.x / 3, | |||||
| p1.y + t1.y / 3, | |||||
| p1.z + t1.z / 3 | |||||
| ) | |||||
| const cp2 = new Cesium.Cartesian3( | |||||
| p2.x - t2.x / 3, | |||||
| p2.y - t2.y / 3, | |||||
| p2.z - t2.z / 3 | |||||
| ) | |||||
| return [p1, cp1, cp2, p2] | |||||
| } | |||||
| /** | |||||
| * 使用Cardinal样条方法(备选实现) | |||||
| * @param {Array} points | |||||
| * @private | |||||
| */ | |||||
| _calculateCardinalSpline(points) { | |||||
| if (points.length < 3) { | |||||
| return this._calculateLinear(points) | |||||
| } | |||||
| const result = [] | |||||
| const tension = 0.5 | |||||
| // 添加虚拟端点以确保曲线通过第一个和最后一个点 | |||||
| const extendedPoints = [ | |||||
| points[0], // 重复第一个点 | |||||
| ...points, | |||||
| points[points.length - 1], // 重复最后一个点 | |||||
| ] | |||||
| for (let i = 1; i < extendedPoints.length - 2; i++) { | |||||
| const p0 = extendedPoints[i - 1] | |||||
| const p1 = extendedPoints[i] | |||||
| const p2 = extendedPoints[i + 1] | |||||
| const p3 = extendedPoints[i + 2] | |||||
| // Cardinal spline interpolation | |||||
| for (let t = 0; t <= 1; t += 1 / this.resolution) { | |||||
| if (i === 1 && t === 0) { | |||||
| // 添加起始点 | |||||
| result.push(p1) | |||||
| continue | |||||
| } | |||||
| const t2 = t * t | |||||
| const t3 = t2 * t | |||||
| // Cardinal spline基函数 | |||||
| const h1 = 2 * t3 - 3 * t2 + 1 | |||||
| const h2 = -2 * t3 + 3 * t2 | |||||
| const h3 = t3 - 2 * t2 + t | |||||
| const h4 = t3 - t2 | |||||
| // 切线向量 | |||||
| const tan1 = new Cesium.Cartesian3( | |||||
| tension * (p2.x - p0.x), | |||||
| tension * (p2.y - p0.y), | |||||
| tension * (p2.z - p0.z) | |||||
| ) | |||||
| const tan2 = new Cesium.Cartesian3( | |||||
| tension * (p3.x - p1.x), | |||||
| tension * (p3.y - p1.y), | |||||
| tension * (p3.z - p1.z) | |||||
| ) | |||||
| const point = new Cesium.Cartesian3( | |||||
| h1 * p1.x + h2 * p2.x + h3 * tan1.x + h4 * tan2.x, | |||||
| h1 * p1.y + h2 * p2.y + h3 * tan1.y + h4 * tan2.y, | |||||
| h1 * p1.z + h2 * p2.z + h3 * tan1.z + h4 * tan2.z | |||||
| ) | |||||
| result.push(point) | |||||
| } | |||||
| } | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * 更新曲线 | |||||
| * @private | |||||
| */ | |||||
| _updateCurve() { | |||||
| const curvePoints = this._calculateBezierPoints() | |||||
| this._delegate.polyline.positions = curvePoints | |||||
| if (this.showControlPoints) { | |||||
| this._updateControlPoints() | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 更新控制点显示 | |||||
| * @private | |||||
| */ | |||||
| _updateControlPoints() { | |||||
| // 清除现有控制点 | |||||
| this._clearControlPoints() | |||||
| if (!this.showControlPoints) return | |||||
| const cartesianPositions = Transform.transformWGS84ArrayToCartesianArray( | |||||
| this._positions | |||||
| ) | |||||
| cartesianPositions.forEach((position, index) => { | |||||
| const controlPoint = new Cesium.Entity({ | |||||
| position: position, | |||||
| point: { | |||||
| ...this.controlPointStyle, | |||||
| disableDepthTestDistance: Number.POSITIVE_INFINITY, | |||||
| }, | |||||
| label: { | |||||
| text: `C${index}`, | |||||
| font: '12pt sans-serif', | |||||
| pixelOffset: new Cesium.Cartesian2(0, -25), | |||||
| fillColor: Cesium.Color.WHITE, | |||||
| outlineColor: Cesium.Color.BLACK, | |||||
| outlineWidth: 1, | |||||
| style: Cesium.LabelStyle.FILL_AND_OUTLINE, | |||||
| disableDepthTestDistance: Number.POSITIVE_INFINITY, | |||||
| }, | |||||
| }) | |||||
| this._controlPointEntities.push(controlPoint) | |||||
| }) | |||||
| } | |||||
| /** | |||||
| * 清除控制点 | |||||
| * @private | |||||
| */ | |||||
| _clearControlPoints() { | |||||
| this._controlPointEntities.forEach((entity) => { | |||||
| if (entity && entity.parent) { | |||||
| entity.parent.entities.remove(entity) | |||||
| } | |||||
| }) | |||||
| this._controlPointEntities = [] | |||||
| } | |||||
| /** | |||||
| * 挂载钩子 | |||||
| * @private | |||||
| */ | |||||
| _mountedHook() { | |||||
| this.positions = this._positions | |||||
| } | |||||
| /** | |||||
| * 设置曲线类型 | |||||
| * @param {string} type 'linear' | 'quadratic' | 'cubic' | 'auto' | 'spline' | |||||
| * @returns {BezierCurve} | |||||
| */ | |||||
| setCurveType(type) { | |||||
| this.curveType = type | |||||
| this._updateCurve() | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * 设置分辨率 | |||||
| * @param {number} resolution | |||||
| * @returns {BezierCurve} | |||||
| */ | |||||
| setResolution(resolution) { | |||||
| this.resolution = Math.max(10, Math.min(1000, resolution)) | |||||
| this._updateCurve() | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * 显示/隐藏控制点 | |||||
| * @param {boolean} show | |||||
| * @returns {BezierCurve} | |||||
| */ | |||||
| setShowControlPoints(show) { | |||||
| this.showControlPoints = show | |||||
| if (show) { | |||||
| this._updateControlPoints() | |||||
| } else { | |||||
| this._clearControlPoints() | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * 设置标签(贝塞尔曲线通常不需要标签,但保持接口一致性) | |||||
| * @param {string} text | |||||
| * @param {Object} textStyle | |||||
| * @returns {BezierCurve} | |||||
| */ | |||||
| setLabel(text, textStyle) { | |||||
| // 可以在曲线中点添加标签 | |||||
| if (text) { | |||||
| const curvePoints = this._calculateBezierPoints() | |||||
| if (curvePoints.length > 0) { | |||||
| const midIndex = Math.floor(curvePoints.length / 2) | |||||
| this._delegate.label = { | |||||
| text: text, | |||||
| position: curvePoints[midIndex], | |||||
| ...textStyle, | |||||
| } | |||||
| } | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * 设置样式 | |||||
| * @param {Object} style | |||||
| * @returns {BezierCurve} | |||||
| */ | |||||
| setStyle(style) { | |||||
| if (Object.keys(style).length === 0) { | |||||
| return this | |||||
| } | |||||
| delete style['positions'] | |||||
| Util.merge(this._style, style) | |||||
| Util.merge(this._delegate.polyline, style) | |||||
| // 更新控制点样式 | |||||
| if (style.controlPointStyle) { | |||||
| this.controlPointStyle = { | |||||
| ...this.controlPointStyle, | |||||
| ...style.controlPointStyle, | |||||
| } | |||||
| if (this.showControlPoints) { | |||||
| this._updateControlPoints() | |||||
| } | |||||
| } | |||||
| return this | |||||
| } | |||||
| /** | |||||
| * 获取曲线长度(近似) | |||||
| * @returns {number} | |||||
| */ | |||||
| getCurveLength() { | |||||
| const curvePoints = this._calculateBezierPoints() | |||||
| let length = 0 | |||||
| for (let i = 1; i < curvePoints.length; i++) { | |||||
| length += Cesium.Cartesian3.distance(curvePoints[i - 1], curvePoints[i]) | |||||
| } | |||||
| return length | |||||
| } | |||||
| /** | |||||
| * 在曲线上获取指定参数t处的点 | |||||
| * @param {number} t 参数值 (0-1) | |||||
| * @returns {Cesium.Cartesian3} | |||||
| */ | |||||
| getPointAtParameter(t) { | |||||
| t = Math.max(0, Math.min(1, t)) | |||||
| const curvePoints = this._calculateBezierPoints() | |||||
| const index = Math.floor(t * (curvePoints.length - 1)) | |||||
| return curvePoints[index] || curvePoints[curvePoints.length - 1] | |||||
| } | |||||
| /** | |||||
| * 销毁 | |||||
| */ | |||||
| destroy() { | |||||
| this._clearControlPoints() | |||||
| super.destroy?.() | |||||
| } | |||||
| } | |||||
| // 注册覆盖物类型 | |||||
| Overlay.registerType('bezier_curve') | |||||
| export default BezierCurve | 
| import DrawFineArrow from './draw/DrawFineArrow' | import DrawFineArrow from './draw/DrawFineArrow' | ||||
| import DrawGatheringPlace from './draw/DrawGatheringPlace' | import DrawGatheringPlace from './draw/DrawGatheringPlace' | ||||
| import DrawTailedAttackArrow from './draw/DrawTailedAttackArrow' | import DrawTailedAttackArrow from './draw/DrawTailedAttackArrow' | ||||
| import DrawBezierCurve from './draw/DrawBezierCurve' | |||||
| import EditPoint from './edit/EditPoint' | import EditPoint from './edit/EditPoint' | ||||
| import EditPolyline from './edit/EditPolyline' | import EditPolyline from './edit/EditPolyline' | ||||
| import EditFineArrow from './edit/EditFineArrow' | import EditFineArrow from './edit/EditFineArrow' | ||||
| import EditGatheringPlace from './edit/EditGatheringPlace' | import EditGatheringPlace from './edit/EditGatheringPlace' | ||||
| import EditTailedAttackArrow from './edit/EditTailedAttackArrow' | import EditTailedAttackArrow from './edit/EditTailedAttackArrow' | ||||
| import EditBezierCurve from './edit/EditBezierCurve' | |||||
| class Plot { | class Plot { | ||||
| constructor(viewer, options = {}) { | constructor(viewer, options = {}) { | ||||
| case OverlayType.GATHERING_PLACE: | case OverlayType.GATHERING_PLACE: | ||||
| drawWorker = new DrawGatheringPlace(style) | drawWorker = new DrawGatheringPlace(style) | ||||
| break | break | ||||
| case OverlayType.BEZIER_CURVE: | |||||
| drawWorker = new DrawBezierCurve(style) | |||||
| break | |||||
| default: | default: | ||||
| break | break | ||||
| } | } | ||||
| case OverlayType.GATHERING_PLACE: | case OverlayType.GATHERING_PLACE: | ||||
| editWorker = new EditGatheringPlace(overlay) | editWorker = new EditGatheringPlace(overlay) | ||||
| break | break | ||||
| case OverlayType.BEZIER_CURVE: | |||||
| editWorker = new EditBezierCurve(overlay) | |||||
| break | |||||
| default: | default: | ||||
| break | break | ||||
| } | } | 
| /** | |||||
| * DrawBezierCurve - 绘制贝塞尔曲线工具 | |||||
| * @Author : zisahng520 | |||||
| */ | |||||
| import { Cesium } from '../../../libs' | |||||
| import Draw from './Draw' | |||||
| import { PlotEventType } from '../../event' | |||||
| import { Transform } from '../../transform' | |||||
| import { BezierCurve } from '../../overlay' | |||||
| const DEF_STYLE = { | |||||
| width: 3, | |||||
| material: Cesium.Color.CYAN, | |||||
| clampToGround: true, | |||||
| } | |||||
| class DrawBezierCurve extends Draw { | |||||
| constructor(style, options = {}) { | |||||
| super() | |||||
| this._minAnchorSize = options.minPoints || 2 | |||||
| this._curveType = options.curveType || 'spline' | |||||
| this._resolution = options.resolution || 100 | |||||
| this._showControlPoints = (options.showControlPoints || false) !== false | |||||
| this._style = { | |||||
| ...DEF_STYLE, | |||||
| ...style, | |||||
| } | |||||
| this._previewCurve = new BezierCurve([], { | |||||
| curveType: this._curveType, | |||||
| resolution: this._resolution, | |||||
| showControlPoints: this._showControlPoints, | |||||
| }) | |||||
| } | |||||
| /** | |||||
| * 挂载钩子 | |||||
| * @private | |||||
| */ | |||||
| _mountedHook() { | |||||
| this.drawTool.tooltipMess = '单击添加控制点,右击完成绘制' | |||||
| this._delegate = new Cesium.Entity({ | |||||
| polyline: { | |||||
| ...this._style, | |||||
| positions: new Cesium.CallbackProperty(() => { | |||||
| if (this._positions.length >= this._minAnchorSize) { | |||||
| const wgs84Positions = | |||||
| Transform.transformCartesianArrayToWGS84Array(this._positions) | |||||
| this._previewCurve.positions = wgs84Positions | |||||
| return this._previewCurve._calculateBezierPoints() | |||||
| } | |||||
| return this._positions | |||||
| }, false), | |||||
| }, | |||||
| }) | |||||
| this._layer.entities.add(this._delegate) | |||||
| this._createControlPointsPreview() | |||||
| } | |||||
| /** | |||||
| * 创建控制点预览 | |||||
| * @private | |||||
| */ | |||||
| _createControlPointsPreview() { | |||||
| if (!this._showControlPoints) return | |||||
| this._controlPointsEntity = new Cesium.Entity({ | |||||
| point: { | |||||
| pixelSize: 0, // 隐藏主点 | |||||
| }, | |||||
| }) | |||||
| // 使用 CallbackProperty 动态显示控制点 | |||||
| this._controlPointsEntity.position = new Cesium.CallbackProperty(() => { | |||||
| return ( | |||||
| this._positions[this._positions.length - 1] || new Cesium.Cartesian3() | |||||
| ) | |||||
| }, false) | |||||
| this._layer.entities.add(this._controlPointsEntity) | |||||
| } | |||||
| /** | |||||
| * 停止钩子 | |||||
| * @private | |||||
| */ | |||||
| _stoppedHook() { | |||||
| let bezierCurve = null | |||||
| if (this._positions.length >= this._minAnchorSize) { | |||||
| const wgs84Positions = Transform.transformCartesianArrayToWGS84Array( | |||||
| this._positions | |||||
| ) | |||||
| bezierCurve = new BezierCurve(wgs84Positions, { | |||||
| curveType: this._curveType, | |||||
| resolution: this._resolution, | |||||
| showControlPoints: this._showControlPoints, | |||||
| }).setStyle(this._style) | |||||
| } | |||||
| this._options.onDrawStop && this._options.onDrawStop(bezierCurve) | |||||
| } | |||||
| /** | |||||
| * 锚点绘制处理 | |||||
| * @param {Cesium.Cartesian3} position | |||||
| * @private | |||||
| */ | |||||
| _onDrawAnchor(position) { | |||||
| this._positions.push(position) | |||||
| this.drawTool.fire(PlotEventType.CREATE_ANCHOR, { position }) | |||||
| // 创建控制点可视化 | |||||
| if (this._showControlPoints) { | |||||
| const controlPoint = this._layer.entities.add({ | |||||
| position: position, | |||||
| point: { | |||||
| pixelSize: 8, | |||||
| color: Cesium.Color.YELLOW, | |||||
| outlineColor: Cesium.Color.BLACK, | |||||
| outlineWidth: 2, | |||||
| disableDepthTestDistance: Number.POSITIVE_INFINITY, | |||||
| }, | |||||
| label: { | |||||
| text: `C${this._positions.length - 1}`, | |||||
| font: '12pt sans-serif', | |||||
| pixelOffset: new Cesium.Cartesian2(0, -25), | |||||
| fillColor: Cesium.Color.WHITE, | |||||
| outlineColor: Cesium.Color.BLACK, | |||||
| outlineWidth: 1, | |||||
| style: Cesium.LabelStyle.FILL_AND_OUTLINE, | |||||
| }, | |||||
| }) | |||||
| if (!this._tempControlPoints) { | |||||
| this._tempControlPoints = [] | |||||
| } | |||||
| this._tempControlPoints.push(controlPoint) | |||||
| } | |||||
| // 更新提示信息 | |||||
| if (this._positions.length < this._minAnchorSize) { | |||||
| this.drawTool.tooltipMess = `还需要 ${ | |||||
| this._minAnchorSize - this._positions.length | |||||
| } 个控制点` | |||||
| } else { | |||||
| this.drawTool.tooltipMess = '继续添加控制点或右击完成' | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 右键完成绘制 | |||||
| * @param {Cesium.Cartesian3} position | |||||
| * @private | |||||
| */ | |||||
| _onDrawRight(position) { | |||||
| if (this._positions.length >= this._minAnchorSize) { | |||||
| this.drawTool.fire(PlotEventType.DRAW_STOP) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 设置曲线类型 | |||||
| * @param {string} type | |||||
| */ | |||||
| setCurveType(type) { | |||||
| this._curveType = type | |||||
| if (this._previewCurve) { | |||||
| this._previewCurve.setCurveType(type) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 设置分辨率 | |||||
| * @param {number} resolution | |||||
| */ | |||||
| setResolution(resolution) { | |||||
| this._resolution = resolution | |||||
| if (this._previewCurve) { | |||||
| this._previewCurve.setResolution(resolution) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 清理临时控制点 | |||||
| * @private | |||||
| */ | |||||
| _cleanup() { | |||||
| if (this._tempControlPoints) { | |||||
| this._tempControlPoints.forEach((point) => { | |||||
| this._layer.entities.remove(point) | |||||
| }) | |||||
| this._tempControlPoints = [] | |||||
| } | |||||
| super._cleanup?.() | |||||
| } | |||||
| } | |||||
| export default DrawBezierCurve | 
| /** | |||||
| * EditBezierCurve - 编辑贝塞尔曲线工具 | |||||
| * @Author : zishang520 | |||||
| */ | |||||
| import { Cesium } from '../../../libs' | |||||
| import Edit from './Edit' | |||||
| import { PlotEventType } from '../../event' | |||||
| import { Transform } from '../../transform' | |||||
| class EditBezierCurve extends Edit { | |||||
| constructor(overlay, options = {}) { | |||||
| super(overlay) | |||||
| this._options = { | |||||
| showAnchors: true, | |||||
| allowAddPoints: true, | |||||
| allowRemovePoints: true, | |||||
| minPoints: 2, | |||||
| maxPoints: 20, | |||||
| ...options, | |||||
| } | |||||
| this._previewCurve = overlay | |||||
| this._anchors = [] | |||||
| this._isEditing = false | |||||
| } | |||||
| /** | |||||
| * 挂载钩子 | |||||
| * @private | |||||
| */ | |||||
| _mountedHook() { | |||||
| try { | |||||
| // 设置动态更新 | |||||
| this._delegate.polyline.positions = new Cesium.CallbackProperty(() => { | |||||
| if (this._positions.length >= 2) { | |||||
| const wgs84Positions = Transform.transformCartesianArrayToWGS84Array( | |||||
| this._positions | |||||
| ) | |||||
| this._previewCurve.positions = wgs84Positions | |||||
| return this._previewCurve._calculateBezierPoints() | |||||
| } | |||||
| return this._positions | |||||
| }, false) | |||||
| // 添加编辑模式样式 | |||||
| this._delegate.polyline.width = (this._delegate.polyline.width || 3) + 1 | |||||
| this._delegate.polyline.material = Cesium.Color.ORANGE.withAlpha(0.8) | |||||
| this._layer.entities.add(this._delegate) | |||||
| this._createAnchors() | |||||
| this._setupDragHandlers() | |||||
| this._isEditing = true | |||||
| this.editTool?.fire(PlotEventType.EDIT_START, { | |||||
| overlay: this._overlay, | |||||
| positions: this._positions, | |||||
| }) | |||||
| } catch (error) { | |||||
| console.error('Failed to mount EditBezierCurve:', error) | |||||
| this._cleanup() | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 创建锚点 | |||||
| * @private | |||||
| */ | |||||
| _createAnchors() { | |||||
| if (!this._options.showAnchors) return | |||||
| this._cleanupAnchors() | |||||
| this._anchors = [] | |||||
| this._positions.forEach((position, index) => { | |||||
| const anchor = this._layer.entities.add({ | |||||
| position: position, | |||||
| point: { | |||||
| pixelSize: 10, | |||||
| color: Cesium.Color.LIME, | |||||
| outlineColor: Cesium.Color.BLACK, | |||||
| outlineWidth: 2, | |||||
| heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, | |||||
| disableDepthTestDistance: Number.POSITIVE_INFINITY, | |||||
| }, | |||||
| label: { | |||||
| text: `C${index}`, | |||||
| font: '12pt sans-serif', | |||||
| pixelOffset: new Cesium.Cartesian2(0, -30), | |||||
| fillColor: Cesium.Color.WHITE, | |||||
| outlineColor: Cesium.Color.BLACK, | |||||
| outlineWidth: 2, | |||||
| style: Cesium.LabelStyle.FILL_AND_OUTLINE, | |||||
| }, | |||||
| }) | |||||
| anchor._editIndex = index | |||||
| this._anchors.push(anchor) | |||||
| }) | |||||
| } | |||||
| /** | |||||
| * 设置拖拽处理器 | |||||
| * @private | |||||
| */ | |||||
| _setupDragHandlers() { | |||||
| if (!this.editTool || !this.editTool.viewer) return | |||||
| const viewer = this.editTool.viewer | |||||
| const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas) | |||||
| let isDragging = false | |||||
| let draggedAnchor = null | |||||
| let draggedIndex = -1 | |||||
| // 左键按下事件 | |||||
| handler.setInputAction((click) => { | |||||
| const pickedObject = viewer.scene.pick(click.position) | |||||
| if ( | |||||
| pickedObject && | |||||
| pickedObject.id && | |||||
| this._anchors.includes(pickedObject.id) | |||||
| ) { | |||||
| isDragging = true | |||||
| draggedAnchor = pickedObject.id | |||||
| draggedIndex = draggedAnchor._editIndex | |||||
| viewer.scene.screenSpaceCameraController.enableRotate = false | |||||
| viewer.scene.screenSpaceCameraController.enableTranslate = false | |||||
| viewer.scene.screenSpaceCameraController.enableZoom = false | |||||
| } | |||||
| }, Cesium.ScreenSpaceEventType.LEFT_DOWN) | |||||
| // 鼠标移动事件 | |||||
| handler.setInputAction((movement) => { | |||||
| if (isDragging && draggedAnchor) { | |||||
| const ray = viewer.camera.getPickRay(movement.endPosition) | |||||
| const newPosition = viewer.scene.globe.pick(ray, viewer.scene) | |||||
| if (newPosition) { | |||||
| this.updateAnchorPosition(draggedIndex, newPosition) | |||||
| } | |||||
| } | |||||
| }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) | |||||
| // 左键释放事件 | |||||
| handler.setInputAction(() => { | |||||
| if (isDragging) { | |||||
| isDragging = false | |||||
| draggedAnchor = null | |||||
| draggedIndex = -1 | |||||
| viewer.scene.screenSpaceCameraController.enableRotate = true | |||||
| viewer.scene.screenSpaceCameraController.enableTranslate = true | |||||
| viewer.scene.screenSpaceCameraController.enableZoom = true | |||||
| } | |||||
| }, Cesium.ScreenSpaceEventType.LEFT_UP) | |||||
| // 右键菜单事件(可选功能:添加/删除控制点) | |||||
| handler.setInputAction((click) => { | |||||
| const pickedObject = viewer.scene.pick(click.position) | |||||
| if ( | |||||
| pickedObject && | |||||
| pickedObject.id && | |||||
| this._anchors.includes(pickedObject.id) | |||||
| ) { | |||||
| const anchorIndex = pickedObject.id._editIndex | |||||
| this._showContextMenu(click.position, anchorIndex) | |||||
| } | |||||
| }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) | |||||
| // 存储handler以便清理 | |||||
| this._dragHandler = handler | |||||
| } | |||||
| /** | |||||
| * 显示右键菜单 | |||||
| * @param {Cesium.Cartesian2} position | |||||
| * @param {number} anchorIndex | |||||
| * @private | |||||
| */ | |||||
| _showContextMenu(position, anchorIndex) { | |||||
| // 这里可以集成一个简单的上下文菜单 | |||||
| const actions = [] | |||||
| if ( | |||||
| this._options.allowAddPoints && | |||||
| this._positions.length < this._options.maxPoints | |||||
| ) { | |||||
| actions.push({ | |||||
| text: '在此处插入点', | |||||
| action: () => { | |||||
| const ray = this.editTool.viewer.camera.getPickRay(position) | |||||
| const newPosition = this.editTool.viewer.scene.globe.pick( | |||||
| ray, | |||||
| this.editTool.viewer.scene | |||||
| ) | |||||
| if (newPosition) { | |||||
| this.addControlPoint(newPosition, anchorIndex + 1) | |||||
| } | |||||
| }, | |||||
| }) | |||||
| } | |||||
| if ( | |||||
| this._options.allowRemovePoints && | |||||
| this._positions.length > this._options.minPoints | |||||
| ) { | |||||
| actions.push({ | |||||
| text: '删除此点', | |||||
| action: () => { | |||||
| this.removeControlPoint(anchorIndex) | |||||
| }, | |||||
| }) | |||||
| } | |||||
| // 触发菜单事件,让外部处理菜单显示 | |||||
| this.editTool?.fire(PlotEventType.SHOW_CONTEXT_MENU, { | |||||
| position, | |||||
| anchorIndex, | |||||
| actions, | |||||
| overlay: this._overlay, | |||||
| }) | |||||
| } | |||||
| /** | |||||
| * @param {number} anchorIndex | |||||
| * @param {Cesium.Cartesian3} newPosition | |||||
| */ | |||||
| updateAnchorPosition(anchorIndex, newPosition) { | |||||
| if (anchorIndex >= 0 && anchorIndex < this._positions.length) { | |||||
| this._positions[anchorIndex] = newPosition | |||||
| // 更新锚点显示 | |||||
| if (this._anchors[anchorIndex]) { | |||||
| this._anchors[anchorIndex].position = newPosition | |||||
| } | |||||
| // 更新原始覆盖物 | |||||
| const wgs84Positions = Transform.transformCartesianArrayToWGS84Array( | |||||
| this._positions | |||||
| ) | |||||
| this._overlay.positions = wgs84Positions | |||||
| this.editTool?.fire(PlotEventType.EDIT_ANCHOR_UPDATE, { | |||||
| overlay: this._overlay, | |||||
| anchorIndex, | |||||
| position: newPosition, | |||||
| positions: this._positions, | |||||
| }) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 添加控制点 | |||||
| * @param {Cesium.Cartesian3} position | |||||
| * @param {number} insertIndex | |||||
| */ | |||||
| addControlPoint(position, insertIndex = -1) { | |||||
| if (this._positions.length >= this._options.maxPoints) { | |||||
| console.warn(`已达到最大控制点数量 (${this._options.maxPoints})`) | |||||
| return false | |||||
| } | |||||
| if (insertIndex === -1) { | |||||
| this._positions.push(position) | |||||
| } else { | |||||
| this._positions.splice(insertIndex, 0, position) | |||||
| } | |||||
| this._createAnchors() | |||||
| const wgs84Positions = Transform.transformCartesianArrayToWGS84Array( | |||||
| this._positions | |||||
| ) | |||||
| this._overlay.positions = wgs84Positions | |||||
| this.editTool?.fire(PlotEventType.EDIT_ANCHOR_ADD, { | |||||
| overlay: this._overlay, | |||||
| position, | |||||
| insertIndex, | |||||
| positions: this._positions, | |||||
| }) | |||||
| return true | |||||
| } | |||||
| /** | |||||
| * 删除控制点 | |||||
| * @param {number} anchorIndex | |||||
| */ | |||||
| removeControlPoint(anchorIndex) { | |||||
| if (this._positions.length <= this._options.minPoints) { | |||||
| console.warn(`至少需要 ${this._options.minPoints} 个控制点`) | |||||
| return false | |||||
| } | |||||
| if (anchorIndex >= 0 && anchorIndex < this._positions.length) { | |||||
| const removedPosition = this._positions.splice(anchorIndex, 1)[0] | |||||
| this._createAnchors() | |||||
| const wgs84Positions = Transform.transformCartesianArrayToWGS84Array( | |||||
| this._positions | |||||
| ) | |||||
| this._overlay.positions = wgs84Positions | |||||
| this.editTool?.fire(PlotEventType.EDIT_ANCHOR_REMOVE, { | |||||
| overlay: this._overlay, | |||||
| anchorIndex, | |||||
| removedPosition, | |||||
| positions: this._positions, | |||||
| }) | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| /** | |||||
| * 清理锚点 | |||||
| * @private | |||||
| */ | |||||
| _cleanupAnchors() { | |||||
| if (this._anchors) { | |||||
| this._anchors.forEach((anchor) => { | |||||
| this._layer.entities.remove(anchor) | |||||
| }) | |||||
| this._anchors = [] | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 完成编辑 | |||||
| */ | |||||
| finishEdit() { | |||||
| if (this._isEditing) { | |||||
| this._cleanup() | |||||
| this._cleanupAnchors() | |||||
| if (this._dragHandler) { | |||||
| this._dragHandler.destroy() | |||||
| this._dragHandler = null | |||||
| } | |||||
| this._isEditing = false | |||||
| this.editTool?.fire(PlotEventType.EDIT_STOP, { | |||||
| overlay: this._overlay, | |||||
| positions: this._positions | |||||
| }) | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 取消编辑 | |||||
| */ | |||||
| cancelEdit() { | |||||
| if (this._isEditing) { | |||||
| // 恢复原始位置 | |||||
| this._overlay.positions = this._originalPositions | |||||
| this._cleanup() | |||||
| this.editTool?.fire(PlotEventType.EDIT_CANCEL, { | |||||
| overlay: this._overlay, | |||||
| }) | |||||
| this._isEditing = false | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 获取编辑状态 | |||||
| */ | |||||
| getEditState() { | |||||
| return { | |||||
| isEditing: this._isEditing, | |||||
| positions: this._positions, | |||||
| controlPointCount: this._positions.length, | |||||
| canAddPoints: this._positions.length < this._options.maxPoints, | |||||
| canRemovePoints: this._positions.length > this._options.minPoints, | |||||
| curveType: this._overlay.curveType, | |||||
| curveLength: this._overlay.getCurveLength(), | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 清理资源 | |||||
| * @private | |||||
| */ | |||||
| _cleanup() { | |||||
| this._cleanupAnchors() | |||||
| // 清理拖拽处理器 | |||||
| if (this._dragHandler) { | |||||
| this._dragHandler.destroy() | |||||
| this._dragHandler = null | |||||
| } | |||||
| // 恢复相机控制 | |||||
| if (this.editTool && this.editTool.viewer) { | |||||
| const viewer = this.editTool.viewer | |||||
| viewer.scene.screenSpaceCameraController.enableRotate = true | |||||
| viewer.scene.screenSpaceCameraController.enableTranslate = true | |||||
| viewer.scene.screenSpaceCameraController.enableZoom = true | |||||
| } | |||||
| super._cleanup?.() | |||||
| } | |||||
| /** | |||||
| * 销毁 | |||||
| */ | |||||
| destroy() { | |||||
| this.cancelEdit() | |||||
| this._previewCurve = null | |||||
| super.destroy?.() | |||||
| } | |||||
| } | |||||
| export default EditBezierCurve |