DESKTOP-CRQ4N2U\jintian 1 жил өмнө
parent
commit
8f5045a4ab
100 өөрчлөгдсөн 27377 нэмэгдсэн , 4 устгасан
  1. 1 0
      .gitignore
  2. 13 1
      package.json
  3. 39 0
      package.json编译SDK
  4. 41 0
      packages/Assets/styles/PopupWindow/HtmlWindow1.css
  5. 76 0
      packages/Assets/styles/PopupWindow/HtmlWindow2.css
  6. 66 0
      packages/Assets/styles/PopupWindow/HtmlWindow3.css
  7. 62 0
      packages/Assets/styles/PopupWindow/MultiFieldAdaptWindow.css
  8. 39 0
      packages/Assets/styles/PopupWindow/VideoWindow.css
  9. 74 0
      packages/Assets/styles/PopupWindow/VideoWindow2.css
  10. 66 0
      packages/Assets/styles/PopupWindow/VideoWindow3.css
  11. 41 0
      packages/Assets/styles/StatusBar.css
  12. 62 0
      packages/Assets/styles/base.css
  13. 99 0
      packages/Assets/styles/tooltip.css
  14. 230 0
      packages/Core/SkyBoxOnGround.js
  15. 67 0
      packages/Widgets/AroundPoint.js
  16. 70 0
      packages/Widgets/AroundView.js
  17. 160 0
      packages/Widgets/CircleObject.js
  18. 181 0
      packages/Widgets/CircleObject/CircleMaterialProperty.js
  19. 132 0
      packages/Widgets/CircleObject/CircleRippleMaterialProperty.js
  20. 627 0
      packages/Widgets/CrImageServerLayer.js
  21. 79 0
      packages/Widgets/DrawTools/CommonTools.js
  22. 684 0
      packages/Widgets/DrawTools/CrEditProperty.ce.vue
  23. 388 0
      packages/Widgets/DrawTools/CrEditProperty_MilitaryPlot.ce.vue
  24. 779 0
      packages/Widgets/DrawTools/CrEditProperty_Point.ce.vue
  25. 609 0
      packages/Widgets/DrawTools/DrawMilitaryPlot.js
  26. 1141 0
      packages/Widgets/DrawTools/DrawPoint.js
  27. 200 0
      packages/Widgets/DrawTools/DrawTools.js
  28. 672 0
      packages/Widgets/DrawTools/MilitaryPlot/EntityEdit.js
  29. 576 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawAttackArrow.js
  30. 534 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawBowLine.js
  31. 535 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawBowPlane.js
  32. 251 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawCircle.js
  33. 599 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawClosedCurve.js
  34. 510 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawCurve.js
  35. 463 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawCurveFlag.js
  36. 611 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawGatheringPlace.js
  37. 659 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPincerArrow.js
  38. 138 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPoint.js
  39. 229 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPolygon.js
  40. 223 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPolyline.js
  41. 289 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawRectFlag.js
  42. 228 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawRectangle.js
  43. 327 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawSector.js
  44. 424 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawStraightArrow.js
  45. 286 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawTriangleFlag.js
  46. 47 0
      packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/index.js
  47. 69 0
      packages/Widgets/DrawTools/SketchViewModel.js
  48. 1094 0
      packages/Widgets/PointObject.js
  49. 187 0
      packages/Widgets/PolygonObject.js
  50. 509 0
      packages/Widgets/PolylineObject.js
  51. 181 0
      packages/Widgets/PolylineObject/PolylineDirectionMaterialProperty.js
  52. 25 0
      packages/Widgets/PopupWindow.js
  53. 156 0
      packages/Widgets/PopupWindow/HtmlWindow.js
  54. 123 0
      packages/Widgets/PopupWindow/HtmlWindow2.js
  55. 124 0
      packages/Widgets/PopupWindow/HtmlWindow3.js
  56. 177 0
      packages/Widgets/PopupWindow/MultiFieldAdaptWindow.js
  57. 204 0
      packages/Widgets/PopupWindow/VideoWindow.js
  58. 170 0
      packages/Widgets/PopupWindow/VideoWindow2.js
  59. 170 0
      packages/Widgets/PopupWindow/VideoWindow3.js
  60. 546 0
      packages/Widgets/Roaming/Roaming.js
  61. 320 0
      packages/Widgets/Roaming/TrackRoam.js
  62. 14 0
      packages/Widgets/SceneControl.js
  63. 134 0
      packages/Widgets/SceneControl/ImageLayerSplit.js
  64. 106 0
      packages/Widgets/SceneControl/ViewerSplitScreen.js
  65. 19 0
      packages/Widgets/SceneEffects.js
  66. 203 0
      packages/Widgets/SceneEffects/ParticleSystem.js
  67. 148 0
      packages/Widgets/SceneEffects/SkyBox.js
  68. 278 0
      packages/Widgets/SceneEffects/Weather.js
  69. 31 0
      packages/Widgets/SpatialAnalysis.js
  70. 214 0
      packages/Widgets/SpatialAnalysis/CutFill.js
  71. 528 0
      packages/Widgets/SpatialAnalysis/Cutting.js
  72. 304 0
      packages/Widgets/SpatialAnalysis/GeologyClipPlan.js
  73. 167 0
      packages/Widgets/SpatialAnalysis/HeightLimit.js
  74. 142 0
      packages/Widgets/SpatialAnalysis/Profile.js
  75. 408 0
      packages/Widgets/SpatialAnalysis/SightLine.js
  76. 192 0
      packages/Widgets/SpatialAnalysis/SunshineShadow.js
  77. 582 0
      packages/Widgets/SpatialAnalysis/ViewShed.js
  78. 309 0
      packages/Widgets/StatusBar.js
  79. 414 0
      packages/Widgets/TerrainAnalysis/SlopeAspect.js
  80. 354 0
      packages/Widgets/TerrainAnalysis/TerrainExcavation.js
  81. 138 0
      packages/Widgets/WallObject.js
  82. 107 0
      packages/Widgets/WallObject/DynamicWallMaterialProperty.js
  83. 79 0
      packages/Widgets/WallObject/WallDiffuseMaterialProperty.js
  84. 186 0
      packages/Widgets/WallObject/WallMaterialProperty.js
  85. 513 0
      packages/Widgets/base.js
  86. 421 0
      packages/Widgets/common/CoordTransform.js
  87. 66 0
      packages/Widgets/common/ReminderTip.js
  88. 140 0
      packages/Widgets/common/RuntimeEnvironment.js
  89. 123 0
      packages/Widgets/common/Util.js
  90. 219 0
      packages/Widgets/common/common.js
  91. 183 0
      packages/Widgets/common/doms.js
  92. 1783 0
      packages/Widgets/layer.js
  93. 303 0
      packages/Widgets/locateUtil.js
  94. 15 0
      packages/Widgets/terrainAnalysis.js
  95. 159 0
      packages/index.js
  96. 39 0
      packages/package.json
  97. 2 1
      src/jtMap3d/Widgets/DrawTools/DrawMilitaryPlot.js
  98. 266 0
      src/jtMap3d/Widgets/DrawTools/components/MilitaryPlot.ce.vue
  99. 0 2
      src/jtMap3d/Widgets/SpatialAnalysis/HeightLimit.js
  100. 406 0
      src/jtMap3d/Widgets/SpatialAnalysis/ViewShedStage.js

+ 1 - 0
.gitignore

@@ -2,3 +2,4 @@ node_modules/
 dist/
 .idea/
 jsDoc/
+lib/

+ 13 - 1
package.json

@@ -1,6 +1,6 @@
 {
 	"name": "@jintian/jt-map3d-sdk",
-	"version": "0.0.1",
+	"version": "0.0.2",
 	"private": false,
 	"keywords": [
 	  "jt",
@@ -17,6 +17,18 @@
 		"jsDoc": "jsdoc -c jsdoc.json",
 		"doc": "jsdoc --configure Tools/jsdoc/conf.json"
 	},
+	"files": [
+	  "lib"
+	],
+	"main": "lib/jt-map3d-sdk.umd.js",
+	"module": "lib/jt-map3d-sdk.es.js",
+	"exports": {
+	  "./lib/style.css": "./lib/style.css",
+	  ".": {
+	    "import": "./lib/jt-map3d-sdk.es.js",
+	    "require": "./lib/jt-map3d-sdk.umd.js"
+	  }
+	},
 	"dependencies": {
 		"@jintian/jt-map3d-ui": "^0.0.3",
 		"@jintian/my-app": "^0.1.3",

+ 39 - 0
package.json编译SDK

@@ -0,0 +1,39 @@
+{
+	"name": "@jintian/jt-map3d-sdk",
+	"version": "0.0.2",
+	"private": false,
+	"keywords": [
+	  "jt",
+	  "map",
+	  "3d",
+	  "ui",
+	  "jt-map3d-sdk",
+	  "cesium"
+	],
+	"scripts": {
+		"dev": "vite",
+		"build": "vite build",
+		"serve": "vite preview",
+		"jsDoc": "jsdoc -c jsdoc.json",
+		"doc": "jsdoc --configure Tools/jsdoc/conf.json"
+	},
+	"files": [
+	  "lib"
+	],
+	"main": "lib/jt-map3d-sdk.umd.js",
+	"module": "lib/jt-map3d-sdk.es.js",
+	"exports": {
+	  "./lib/style.css": "./lib/style.css",
+	  ".": {
+	    "import": "./lib/jt-map3d-sdk.es.js",
+	    "require": "./lib/jt-map3d-sdk.umd.js"
+	  }
+	},
+	"dependencies": {
+		"vue": "^3.2.25"
+	},
+	"devDependencies": {
+		"@vitejs/plugin-vue": "^1.6.0",
+		"vite": "^2.5.2"
+	}
+}

+ 41 - 0
packages/Assets/styles/PopupWindow/HtmlWindow1.css

@@ -0,0 +1,41 @@
+.popup1{
+	position: absolute;
+	z-index: 999;
+}
+
+/*标题*/
+.popup1 .popup-header {
+	background: rgb(15, 85, 195);
+	color: rgb(255, 255, 255);
+	font-size: 15rem;
+	padding: 10rem;
+	text-align: left;
+}
+
+/*关闭按钮*/
+.popup1 .popup-header .popup1-close-button {
+	position: absolute;
+	right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.popup1 .popup-content {
+	padding: 5rem;
+	background: rgba(5, 45, 115, 0.7);
+	color: rgb(160, 255, 255);
+	text-align: left;
+}
+
+/*提示框-下三角*/
+.popup1 .popup-tip {
+	position: absolute;
+	bottom: -25rem;
+	left: 50%;
+	margin-left: -15rem;
+	width: 0;
+	height: 0;
+	border-left: 15rem solid transparent;
+	border-right: 15rem solid transparent;
+	border-top: 25rem solid rgba(5, 45, 115, 0.7);
+}

+ 76 - 0
packages/Assets/styles/PopupWindow/HtmlWindow2.css

@@ -0,0 +1,76 @@
+.popup2 {
+	position: absolute;
+	z-index: 999;
+	background: linear-gradient(180deg, rgba(5, 31, 72, 0.80) 0%, rgba(1, 12, 31, 0.80) 100%);
+	border: 1rem solid #2177f5;
+	color: #fff;
+}
+
+/* 横线 */
+.popup2 .rightLine-1 {
+	position: absolute;
+	top: 0;
+	background: #2177f5;
+	width: 4em;
+	right: -4em;
+	height: 0.2em;
+}
+
+/* 斜线 */
+.popup2 .rightLine-2 {
+	position: absolute;
+	top: 2.2em;
+	right: -9em;
+	background: #2177f5;
+	width: 6em;
+	height: 0.2em;
+	transform: rotate(47deg);
+	-ms-transform: rotate(47deg);
+	/* IE 9 */
+	-moz-transform: rotate(47deg);
+	/* Firefox */
+	-webkit-transform: rotate(47deg);
+	/* Safari 和 Chrome */
+	-o-transform: rotate(47deg);
+}
+
+/* 圆点 */
+.popup2 .rightLine-3 {
+	position: absolute;
+	top: 4em;
+	right: -8.6em;
+	width: 1em;
+	height: 1em;
+	background: #2177f5;
+	background-size: 100% 100%;
+	border: solid 4rem rgb(250, 172, 47);
+	border-radius: 100%;
+}
+
+/*标题*/
+.popup2 .popup-header {
+	width: 100%;
+	height: 30rem;
+	line-height: 30rem;
+	text-align: center;
+	background: linear-gradient(180deg, rgba(5, 31, 72, 0.80) 0%, rgba(1, 12, 31, 0.80) 100%);
+}
+
+.popup2 .popup-header .popup-title {
+	float: left;
+	padding-left: 10rem;
+}
+
+.popup2 .popup-header .popup2-close-button {
+	float: right;
+	padding-right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.popup2 .popup-content {
+	padding: 5rem;
+	width: 360rem;
+	height: 200rem;
+	overflow: auto;
+}

+ 66 - 0
packages/Assets/styles/PopupWindow/HtmlWindow3.css

@@ -0,0 +1,66 @@
+.popup3 {
+	position: absolute;
+	z-index: 999;
+	background: linear-gradient(180deg, rgba(5, 31, 72, 0.80) 0%, rgba(1, 12, 31, 0.80) 100%);
+	border-bottom: 3rem solid rgb(250, 172, 47);
+	color: #fff;
+}
+
+/* 斜线 */
+.popup3 .leftLine-1 {
+	position: absolute;
+	bottom: -2.55em;
+	left: -4.6em;
+	background: rgb(250, 172, 47);
+	width: 6em;
+	height: 0.2em;
+	transform: rotate(125deg);
+	-ms-transform: rotate(125deg);
+	/* IE 9 */
+	-moz-transform: rotate(125deg);
+	/* Firefox */
+	-webkit-transform: rotate(125deg);
+	/* Safari 和 Chrome */
+	-o-transform: rotate(125deg);
+}
+
+/* 圆点 */
+.popup3 .leftLine-2 {
+	position: absolute;
+	bottom: -5.6em;
+	left: -4em;
+	width: 1em;
+	height: 1em;
+	background: #fff;
+	background-size: 100% 100%;
+	border: 4rem solid rgb(250, 172, 47);
+	border-radius: 100%;
+}
+
+/*标题*/
+.popup3 .popup-header {
+	width: 100%;
+	height: 30rem;
+	line-height: 30rem;
+	text-align: center;
+	background: rgba(31, 63, 142, 1);
+}
+
+.popup3 .popup-header .popup-title {
+	float: left;
+	padding-left: 10rem;
+}
+
+.popup3 .popup-header .popup3-close-button {
+	float: right;
+	padding-right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.popup3 .popup-content {
+	padding: 5rem;
+	width: 360rem;
+	height: 200rem;
+	overflow: auto;
+}

+ 62 - 0
packages/Assets/styles/PopupWindow/MultiFieldAdaptWindow.css

@@ -0,0 +1,62 @@
+.MultiField-popup {
+	position: absolute;
+	z-index: 999;
+}
+
+/*标题*/
+.MultiField-popup .MultiField-popup-header {
+	background: rgb(15, 85, 195);
+	color: rgb(255, 255, 255);
+	font-size: 15rem;
+	padding: 10rem;
+	text-align: left;
+}
+
+/*关闭按钮*/
+.MultiField-popup .MultiField-popup-header .leaflet-popup-close-button {
+	position: absolute;
+	right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.MultiField-popup .MultiField-popup-content {
+	padding: 5rem;
+	background: rgba(5, 45, 115, 0.7);
+	color: rgb(160, 255, 255);
+}
+
+/*提示框-下三角*/
+.MultiField-popup .MultiField-popup-tip {
+	position: absolute;
+	bottom: -25rem;
+	left: 50%;
+	margin-left: -15rem;
+	width: 0;
+	height: 0;
+	border-left: 15rem solid transparent;
+	border-right: 15rem solid transparent;
+	border-top: 25rem solid rgba(5, 45, 115, 0.7);
+}
+
+/* 表格样式 */
+.MultiField-popup .MultiField-popup-content .table-popup {
+	border-collapse: collapse;
+	text-align: center;
+}
+
+.MultiField-popup .MultiField-popup-content .table-popup tr {
+	border: 1rem solid #cad9ea;
+	color: rgb(160, 255, 255);
+	height: 30rem;
+	padding: 5rem;
+}
+
+.MultiField-popup .MultiField-popup-content .table-popup .title-popup {
+	width: 100rem;
+	background-color: rgba(5, 45, 115, 0.7);
+}
+
+.MultiField-popup .MultiField-popup-content .table-popup .value-popup {
+	width: 120rem;
+}

+ 39 - 0
packages/Assets/styles/PopupWindow/VideoWindow.css

@@ -0,0 +1,39 @@
+.popup-video {
+	position: absolute;
+	z-index: 999;
+}
+
+/*标题*/
+.popup-video .popup-video-header {
+	background: rgb(15, 85, 195);
+	color: rgb(255, 255, 255);
+	font-size: 15rem;
+	padding: 10rem;
+	text-align: left;
+}
+
+/*关闭按钮*/
+.popup-video .popup-video-header .popup-video1-close-button {
+	position: absolute;
+	right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.popup-video .popup-video-content {
+	padding: 0rem;
+	width: 400rem;
+}
+
+/*提示框-下三角*/
+.popup-video .popup-video-tip {
+	position: absolute;
+	bottom: -25rem;
+	left: 50%;
+	margin-left: -15rem;
+	width: 0;
+	height: 0;
+	border-left: 15rem solid transparent;
+	border-right: 15rem solid transparent;
+	border-top: 25rem solid rgb(15, 85, 195);
+}

+ 74 - 0
packages/Assets/styles/PopupWindow/VideoWindow2.css

@@ -0,0 +1,74 @@
+.popup-video2 {
+	position: absolute;
+	z-index: 999;
+	background: linear-gradient(180deg, rgba(5, 31, 72, 0.80) 0%, rgba(1, 12, 31, 0.80) 100%);
+	border: 1rem solid #2177f5;
+	color: #fff;
+}
+
+/* 横线 */
+.popup-video2 .rightLine-1 {
+	position: absolute;
+	top: 0;
+	background: #2177f5;
+	width: 4em;
+	right: -4em;
+	height: 0.2em;
+}
+
+/* 斜线 */
+.popup-video2 .rightLine-2 {
+	position: absolute;
+	top: 2.2em;
+	right: -9em;
+	background: #2177f5;
+	width: 6em;
+	height: 0.2em;
+	transform: rotate(47deg);
+	-ms-transform: rotate(47deg);
+	/* IE 9 */
+	-moz-transform: rotate(47deg);
+	/* Firefox */
+	-webkit-transform: rotate(47deg);
+	/* Safari 和 Chrome */
+	-o-transform: rotate(47deg);
+}
+
+/* 圆点 */
+.popup-video2 .rightLine-3 {
+	position: absolute;
+	top: 4em;
+	right: -8.6em;
+	width: 1em;
+	height: 1em;
+	background: #2177f5;
+	background-size: 100% 100%;
+	border: solid 4rem rgb(250, 172, 47);
+	border-radius: 100%;
+}
+
+/*标题*/
+.popup-video2 .popup-header {
+	width: 100%;
+	height: 30rem;
+	line-height: 30rem;
+	text-align: center;
+	background: linear-gradient(180deg, rgba(5, 31, 72, 0.80) 0%, rgba(1, 12, 31, 0.80) 100%);
+}
+
+.popup-video2 .popup-header .popup-title {
+	float: left;
+	padding-left: 10rem;
+}
+
+.popup-video2 .popup-header .popup-video2-close-button {
+	float: right;
+	padding-right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.popup-video2 .popup-content {
+	padding: 0rem;
+	width: 400rem;
+}

+ 66 - 0
packages/Assets/styles/PopupWindow/VideoWindow3.css

@@ -0,0 +1,66 @@
+.popup-video3 {
+	position: absolute;
+	z-index: 999;
+	background: linear-gradient(180deg, rgba(5, 31, 72, 0.80) 0%, rgba(1, 12, 31, 0.80) 100%);
+	border-bottom: 3rem solid rgb(250, 172, 47);
+	color: #fff;
+}
+
+/* 斜线 */
+.popup-video3 .leftLine-1 {
+	position: absolute;
+	bottom: -2.55em;
+	left: -4.6em;
+	background: rgb(250, 172, 47);
+	width: 6em;
+	height: 0.2em;
+	transform: rotate(125deg);
+	-ms-transform: rotate(125deg);
+	/* IE 9 */
+	-moz-transform: rotate(125deg);
+	/* Firefox */
+	-webkit-transform: rotate(125deg);
+	/* Safari 和 Chrome */
+	-o-transform: rotate(125deg);
+}
+
+/* 圆点 */
+.popup-video3 .leftLine-2 {
+	position: absolute;
+	bottom: -5.6em;
+	left: -4em;
+	width: 1em;
+	height: 1em;
+	background: #fff;
+	background-size: 100% 100%;
+	border: 4rem solid rgb(250, 172, 47);
+	border-radius: 100%;
+}
+
+/*标题*/
+.popup-video3 .popup-header {
+	width: 100%;
+	height: 30rem;
+	line-height: 30rem;
+	text-align: center;
+	background: rgba(31, 63, 142, 1);
+}
+
+.popup-video3 .popup-header .popup-title {
+	float: left;
+	padding-left: 10rem;
+}
+
+.popup-video3 .popup-header .popup-video3-close-button {
+	float: right;
+	padding-right: 10rem;
+	cursor: pointer;
+}
+
+/*内容*/
+.popup-video3 .popup-content {
+	padding: 5rem;
+	width: 360rem;
+	height: 200rem;
+	overflow: auto;
+}

+ 41 - 0
packages/Assets/styles/StatusBar.css

@@ -0,0 +1,41 @@
+.lk-status-bar {
+	position: absolute;
+	bottom: 0;
+	width: 100%;
+	background-color: rgba(58, 57, 57, 0.8);
+	text-align: right;
+	font-size: 14rem;
+	color: white;
+	padding: 3rem 0;
+}
+
+.lk-status-bar .status-all {
+	float: left;
+	padding: 0 10rem;
+	color: rgb(8, 223, 8);
+}
+
+.lk-status-bar .status-position {
+	padding: 0 5rem;
+}
+
+.lk-status-bar .status-position span {
+	padding: 0 5rem;
+}
+
+.lk-status-bar .status-scale {
+	display: inline-flex;
+	align-items: flex-end;
+	margin-left: 10rem;
+	float: left;
+}
+
+.lk-status-bar .status-scale .scale-border {
+	border: 2rem solid rgb(243, 242, 242);
+	border-top: 0;
+	height: 6rem;
+	line-height: 1rem;
+	padding: 0rem 5rem;
+	margin: 3rem 0;
+	font-size: 12rem;
+}

+ 62 - 0
packages/Assets/styles/base.css

@@ -0,0 +1,62 @@
+/* 右上角按钮组 */
+.cesium-viewer-toolbar,
+/* 左下角动画控件(时间圆盘) */
+.cesium-viewer-animationContainer,
+/* 下方时间线 */
+.cesium-viewer-timelineContainer,
+/* logo信息 */
+.cesium-viewer-bottom {
+	display: none;
+}
+
+/**cesium 任务栏的FPS信息*/
+.cesium-performanceDisplay-defaultContainer {
+	top: auto;
+	bottom: 30rem;
+	right: 10rem;
+}
+
+.cesium-performanceDisplay-ms,
+.cesium-performanceDisplay-fps {
+	/* color: #fff; */
+}
+
+.cesium-performanceDisplay-throttled {
+	display: none;
+}
+
+/* 自带帧率窗口移除到地图窗口外 */
+.cesium-performanceDisplay {
+	position: absolute;
+	float: right;
+	right: -1000rem;
+}
+
+
+/* 全屏按钮 */
+.cesium-viewer-fullscreenContainer {
+	position: absolute;
+	top: -999rem;
+}
+
+/* app绘图工具按钮 */
+#drawButtonDiv {
+	width: 160rem !important;
+	background-color: rgba(5, 45, 155, 0) !important;
+	border-radius: 5rem !important;
+	display: flex !important;
+	flex-direction: row !important;
+	justify-content: space-evenly !important;
+	padding: 8rem !important;
+	position: absolute !important;
+	bottom: 40rem !important;
+	right: 10rem !important;
+}
+
+#drawButtonDiv #btnDrawBackout,#btnDrawComplete {
+	width: 60rem !important;
+	height: 30rem !important;
+	margin-bottom: 8rem !important;
+	border-radius: 5rem !important;
+	font-size: 13rem !important;
+}

+ 99 - 0
packages/Assets/styles/tooltip.css

@@ -0,0 +1,99 @@
+.twipsy {
+    display: block;
+    position: absolute;
+    visibility: visible;
+    max-width: 200px;
+    min-width: 100px;
+    padding: 5px;
+    font-size: 11px;
+    z-index: 1000;
+    opacity: 0.8;
+    -khtml-opacity: 0.8;
+    -moz-opacity: 0.8;
+    filter: alpha(opacity=80);
+}
+.twipsy.left .twipsy-arrow {
+    top: 50%;
+    right: 0;
+    margin-top: -5px;
+    border-top: 5px solid transparent;
+    border-bottom: 5px solid transparent;
+    border-left: 5px solid #000000;
+}
+.twipsy.right .twipsy-arrow {
+    top: 50%;
+    left: 0;
+    margin-top: -5px;
+    border-top: 5px solid transparent;
+    border-bottom: 5px solid transparent;
+    border-right: 5px solid #000000;
+}
+.twipsy-inner {
+    padding: 3px 8px;
+    background-color: #000000;
+    color: white;
+    text-align: center;
+    max-width: 200px;
+    text-decoration: none;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+}
+.twipsy-arrow {
+    position: absolute;
+    width: 0;
+    height: 0;
+}
+
+/*
+css rules for the draw helper components
+*/
+
+.toolbar {
+    margin: 0px;
+    padding: 0px;
+    background: white;
+}
+
+.toolbar > .button {
+    margin: 5px;
+    padding: 5px;
+    border: 1px solid #eee;
+    cursor: pointer;
+}
+
+.toolbar > .button:hover {
+    background: #eee;
+}
+
+/*
+css rules for the infowindow
+*/
+
+.infoWindow {
+    position: absolute;
+    min-width: 100px;
+    max-width: 300px;
+}
+.infoWindow #frame {
+    padding: 10px;
+    border: 1px solid black;
+    background: white;
+}
+.infoWindow #close {
+    float: right;
+    margin: 5px 2px;
+    font-size: small;
+    color: gray;
+    cursor: pointer;
+}
+.infoWindow #arrow {
+    position: absolute;
+    bottom: -8px;
+    left: 50%;
+    margin-left: -10px;
+    border-right: 10px solid transparent;
+    border-left: 10px solid transparent;
+    border-top: 10px solid white;
+}
+

+ 230 - 0
packages/Core/SkyBoxOnGround.js

@@ -0,0 +1,230 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+const BoxGeometry = Cesium.BoxGeometry;
+const Cartesian3 = Cesium.Cartesian3;
+const defaultValue = Cesium.defaultValue;
+const defined = Cesium.defined;
+const destroyObject = Cesium.destroyObject;
+const DeveloperError = Cesium.DeveloperError;
+const GeometryPipeline = Cesium.GeometryPipeline;
+const Matrix3 = Cesium.Matrix3;
+const Matrix4 = Cesium.Matrix4;
+const Transforms = Cesium.Transforms;
+const VertexFormat = Cesium.VertexFormat;
+const BufferUsage = Cesium.BufferUsage;
+const CubeMap = Cesium.CubeMap;
+const DrawCommand = Cesium.DrawCommand;
+const loadCubeMap = Cesium.loadCubeMap;
+const RenderState = Cesium.RenderState;
+const VertexArray = Cesium.VertexArray;
+const BlendingState = Cesium.BlendingState;
+const SceneMode = Cesium.SceneMode;
+const ShaderProgram = Cesium.ShaderProgram;
+const ShaderSource = Cesium.ShaderSource;
+
+//片元着色器,直接从源码复制
+const SkyBoxFS =
+	"uniform samplerCube u_cubeMap;\n\
+  varying vec3 v_texCoord;\n\
+  void main()\n\
+  {\n\
+  vec4 color = textureCube(u_cubeMap, normalize(v_texCoord));\n\
+  gl_FragColor = vec4(czm_gammaCorrect(color).rgb, czm_morphTime);\n\
+  }\n\
+  ";
+
+//顶点着色器有修改,主要是乘了一个旋转矩阵
+const SkyBoxVS =
+	"attribute vec3 position;\n\
+  varying vec3 v_texCoord;\n\
+  uniform mat3 u_rotateMatrix;\n\
+  void main()\n\
+  {\n\
+  vec3 p = czm_viewRotation * u_rotateMatrix * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position));\n\
+  gl_Position = czm_projection * vec4(p, 1.0);\n\
+  v_texCoord = position.xyz;\n\
+  }\n\
+  ";
+
+/**
+ * 为了兼容高版本的Cesium,因为新版cesium中getRotation被移除
+ */
+if (!Cesium.defined(Cesium.Matrix4.getRotation)) {
+	Cesium.Matrix4.getRotation = Cesium.Matrix4.getMatrix3;
+}
+
+/**
+ * 近景天空盒
+ * @ignore 忽略注释,注释不生成Doc
+ */
+class SkyBoxOnGround {
+
+	/**
+	 * 近景天空盒 初始化
+	 * @ignore
+	 */
+	constructor(options) {
+
+		/**
+		 * 近景天空盒
+		 * @type Object
+		 * @default undefined
+		 */
+		this.sources = options.sources;
+		this._sources = undefined;
+
+		/**
+		 * Determines if the sky box will be shown.
+		 * @ignore 忽略注释,注释不生成Doc
+		 * @type {Boolean}
+		 * @default true
+		 */
+		this.show = defaultValue(options.show, true);
+
+		this._command = new DrawCommand({
+			modelMatrix: Matrix4.clone(Matrix4.IDENTITY),
+			owner: this
+		});
+		this._cubeMap = undefined;
+
+		this._attributeLocations = undefined;
+		this._useHdr = undefined;
+	}
+}
+
+const skyboxMatrix3 = new Matrix3();
+SkyBoxOnGround.prototype.update = function(frameState, useHdr) {
+	const that = this;
+
+	if (!this.show) {
+		return undefined;
+	}
+
+	if (
+		frameState.mode !== SceneMode.SCENE3D &&
+		frameState.mode !== SceneMode.MORPHING
+	) {
+		return undefined;
+	}
+
+	if (!frameState.passes.render) {
+		return undefined;
+	}
+
+	const context = frameState.context;
+
+	if (this._sources !== this.sources) {
+		this._sources = this.sources;
+		const sources = this.sources;
+
+		if (
+			!defined(sources.positiveX) ||
+			!defined(sources.negativeX) ||
+			!defined(sources.positiveY) ||
+			!defined(sources.negativeY) ||
+			!defined(sources.positiveZ) ||
+			!defined(sources.negativeZ)
+		) {
+			throw new DeveloperError(
+				"this.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties."
+			);
+		}
+
+		if (
+			typeof sources.positiveX !== typeof sources.negativeX ||
+			typeof sources.positiveX !== typeof sources.positiveY ||
+			typeof sources.positiveX !== typeof sources.negativeY ||
+			typeof sources.positiveX !== typeof sources.positiveZ ||
+			typeof sources.positiveX !== typeof sources.negativeZ
+		) {
+			throw new DeveloperError(
+				"this.sources properties must all be the same type."
+			);
+		}
+
+		if (typeof sources.positiveX === "string") {
+			// Given urls for cube-map images.  Load them.
+			loadCubeMap(context, this._sources).then(function(cubeMap) {
+				that._cubeMap = that._cubeMap && that._cubeMap.destroy();
+				that._cubeMap = cubeMap;
+			});
+		} else {
+			this._cubeMap = this._cubeMap && this._cubeMap.destroy();
+			this._cubeMap = new CubeMap({
+				context: context,
+				source: sources
+			});
+		}
+	}
+
+	const command = this._command;
+
+	command.modelMatrix = Transforms.eastNorthUpToFixedFrame(
+		frameState.camera._positionWC
+	);
+	if (!defined(command.vertexArray)) {
+		command.uniformMap = {
+			u_cubeMap: function() {
+				return that._cubeMap;
+			},
+			u_rotateMatrix: function() {
+				return Matrix4.getRotation(command.modelMatrix, skyboxMatrix3);
+			}
+		};
+
+		const geometry = BoxGeometry.createGeometry(
+			BoxGeometry.fromDimensions({
+				dimensions: new Cartesian3(2.0, 2.0, 2.0),
+				vertexFormat: VertexFormat.POSITION_ONLY
+			})
+		);
+		const attributeLocations = (this._attributeLocations = GeometryPipeline.createAttributeLocations(
+			geometry
+		));
+
+		command.vertexArray = VertexArray.fromGeometry({
+			context: context,
+			geometry: geometry,
+			attributeLocations: attributeLocations,
+			bufferUsage: BufferUsage._DRAW
+		});
+
+		command.renderState = RenderState.fromCache({
+			blending: BlendingState.ALPHA_BLEND
+		});
+	}
+
+	if (!defined(command.shaderProgram) || this._useHdr !== useHdr) {
+		const fs = new ShaderSource({
+			defines: [useHdr ? "HDR" : ""],
+			sources: [SkyBoxFS]
+		});
+		command.shaderProgram = ShaderProgram.fromCache({
+			context: context,
+			vertexShaderSource: SkyBoxVS,
+			fragmentShaderSource: fs,
+			attributeLocations: this._attributeLocations
+		});
+		this._useHdr = useHdr;
+	}
+
+	if (!defined(this._cubeMap)) {
+		return undefined;
+	}
+
+	return command;
+};
+SkyBoxOnGround.prototype.isDestroyed = function() {
+	return false;
+};
+SkyBoxOnGround.prototype.destroy = function() {
+	const command = this._command;
+	command.vertexArray = command.vertexArray && command.vertexArray.destroy();
+	command.shaderProgram =
+		command.shaderProgram && command.shaderProgram.destroy();
+	this._cubeMap = this._cubeMap && this._cubeMap.destroy();
+	return destroyObject(this);
+};
+
+export default SkyBoxOnGround;

+ 67 - 0
packages/Widgets/AroundPoint.js

@@ -0,0 +1,67 @@
+/*
+ * @Description: 相机绕点旋转
+ * @Version: 1.0
+ * @Author: joy
+ * @Date: 2023-04-11 21:42:26
+ * @LastEditors: joy
+ * @LastEditTime: 2023-04-12 16:32:25
+ */
+class AroundPoint {
+	constructor(viewer, amount, position) {
+		this._viewer = viewer;
+		this._amount = amount;
+		this._position = position;
+		this._range = this._viewer.camera.positionCartographic.height;
+	}
+
+	_bindEvent() {
+		let _self = this;
+
+		this._viewer.clock.onTick.addEventListener(this._aroundPoint, this);
+		//监听点击事件
+		var handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
+		handler.setInputAction(function(click) {
+			_self.stop();
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+	}
+
+	_unbindEvent() {
+		this._viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
+		this._viewer.clock.onTick.removeEventListener(this._aroundPoint, this);
+	}
+
+	start() {
+		this._viewer.clock.shouldAnimate = true;
+		this._unbindEvent();
+		this._bindEvent();
+		return this;
+	}
+
+	stop() {
+		this._unbindEvent();
+		return this;
+	}
+
+	// 相机绕点旋转函数
+	_aroundPoint() {
+		let heading = this._viewer.camera.heading;
+		let pitch = this._viewer.camera.pitch;
+		let range = this._range;
+
+		heading += Cesium.Math.toRadians(this._amount);
+		if (heading >= Math.PI * 2 || heading <= -Math.PI * 2) {
+			heading = 0;
+		}
+
+		this._viewer.camera.lookAt(
+			this._position,
+			new Cesium.HeadingPitchRange(
+				heading,
+				pitch,
+				range,
+			)
+		)
+	}
+}
+
+export default AroundPoint

+ 70 - 0
packages/Widgets/AroundView.js

@@ -0,0 +1,70 @@
+/*
+ * @Description: 相机绕地旋转
+ * @Version: 1.0
+ * @Author: joy
+ * @Date: 2023-04-11 21:42:26
+ * @LastEditors: joy
+ * @LastEditTime: 2023-04-12 16:32:25
+ */
+class AroundView {
+	constructor(viewer, amount) {
+		this._viewer = viewer;
+		this._amount = amount;
+	}
+
+	// 绑定事件
+	_bindEvent() {
+		let _self = this;
+		
+		this._viewer.clock.onTick.addEventListener(this._aroundView, this);
+
+		//监听点击事件
+		var handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
+		handler.setInputAction(function(click) {
+			_self.stop();
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+	}
+
+	// 解除绑定
+	_unbindEvent() {
+		this._viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
+		this._viewer.clock.onTick.removeEventListener(this._aroundView, this);
+	}
+
+	// 开始
+	start() {
+		this._viewer.clock.shouldAnimate = true;
+		this._unbindEvent();
+		this._bindEvent();
+		return this;
+	}
+
+	// 停止
+	stop() {
+		this._unbindEvent();
+		return this;
+	}
+
+
+	// 相机绕地旋转函数
+	_aroundView() {
+		let heading = this._viewer.camera.heading;
+		let pitch = this._viewer.camera.pitch;
+		let roll = this._viewer.camera.roll;
+
+		heading += Cesium.Math.toRadians(this._amount);
+		if (heading >= Math.PI * 2 || heading <= -Math.PI * 2) {
+			heading = 0;
+		}
+
+		this._viewer.camera.setView({
+			orientation: {
+				heading: heading,
+				pitch: pitch,
+				roll: roll
+			}
+		})
+	}
+}
+
+export default AroundView

+ 160 - 0
packages/Widgets/CircleObject.js

@@ -0,0 +1,160 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	setSessionid
+} from "./common/common.js";
+
+/**
+ *流动纹理
+ */
+import CircleMaterialProperty from "./CircleObject/CircleMaterialProperty.js";
+import CircleRippleMaterialProperty from "./CircleObject/CircleRippleMaterialProperty.js";
+
+/**
+ * 墙体对象
+ */
+class CircleObject {
+	/**
+	 * 默认初始化
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(CircleObject.prototype, /** @lends CircleObject.prototype */ {
+
+	/**
+	 * @description 绘制动态圆
+	 * @param {String} centerPoint 圆心坐标
+	 * @param {String} radius 圆半径
+	 * @param {Object} [options] 圆的样式,具有以下属性:
+	 * @param {Number} [options.id] 用于移除
+	 * @param {Number} [options.clampToGround=true] 是否贴地
+	 * @param {String} [options.color="#FF0000"] 指定圆的颜色
+
+	 * @param {String} [options.outlineColor="#FFFF00"] 指定点轮廓的颜色
+	 * @param {Number} [options.outlineWidth=0] 指定点轮廓的宽度
+	 * 
+	 * @param {Number} [options.CircleType='ColorCircle'] ColorCircle / DynamicCircle
+	 * @param {Number} [options.duration=3000] 持续时间 毫秒,越小越快
+	 * @param {Number} [options.count=1] 重复次数
+	 */
+	drawCircle: function(centerPoint, radius, options) {
+		return new Promise((resolve, reject) => {
+			let _self = this;
+			let viewer = this._viewer;
+
+			if (!Cesium.defined(centerPoint)) {
+				throw new Cesium.DeveloperError("centerPoint is required.");
+			}
+
+			if (!Cesium.defined(radius)) {
+				throw new Cesium.DeveloperError("radius is required.");
+			}
+
+			//坐标位置
+			let position;
+			if (centerPoint instanceof Cesium.Cartesian3) {
+				position = centerPoint;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(centerPoint[0], centerPoint[1], centerPoint[2] || 0);
+			}
+
+			//半径
+			if (typeof radius === 'number' && radius > 0) {
+				radius = radius;
+			} else {
+				radius = 100
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+			options.clampToGround = Cesium.defaultValue(options.clampToGround, true);
+			options.CircleType = Cesium.defaultValue(options.CircleType, 'ColorCircle');
+
+			options.duration = Cesium.defaultValue(options.duration, 3000);
+			options.count = Cesium.defaultValue(options.count, 1);
+
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+
+			if (options.outlineColor) {
+				if (options.outlineColor instanceof Array) {
+					options.outlineColor = new Cesium.Color(options.outlineColor[0] / 255, options.outlineColor[1] / 255, options.outlineColor[2] / 255, options.outlineColor[3]);
+				} else if (typeof(options.outlineColor) === 'string') {
+					options.outlineColor = new Cesium.Color.fromCssColorString(options.outlineColor);
+				} else {
+					options.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			options.outlineWidth = Cesium.defaultValue(options.outlineWidth, 0);
+
+
+			/* 创建面材质 */
+			let polygonMaterial = options.color;
+			/* 创建线材质 */
+			// let outlineMaterial = new Cesium.PolylineDashMaterialProperty({//虚线
+			// 	dashLength: 16,
+			// 	color: options.outlineColor
+			// });
+			let outlineMaterial = options.outlineColor;
+
+			if (options.CircleType === 'DynamicCircle') {
+				// polygonMaterial = new CircleMaterialProperty({
+				// 	viewer: viewer,
+				// 	duration: options.duration,
+				// 	color: options.color,
+				// 	count: options.count,
+				// });
+
+				polygonMaterial = new Cesium.CircleRippleMaterialProperty({
+					color: options.color,
+					speed: options.duration/1000,
+					count: options.count,
+					gradient: 0.2
+				})
+			}
+
+			let entity = new Cesium.Entity({
+				id: options.id,
+				//位置
+				position: position,
+				//椭圆
+				ellipse: {
+					//半短轴(画圆:半短轴和半长轴一致即可)
+					semiMinorAxis: radius,
+					// 半长轴
+					semiMajorAxis: radius,
+					// 填充色
+					material: polygonMaterial,
+					// 是否有边框
+					outline: true,
+					// 边框颜色
+					outlineColor: options.outlineColor,
+					// 边框宽度
+					outlineWidth: options.outlineWidth
+				}
+			});
+
+			let flyEntity = viewer.entities.add(entity);
+
+			resolve(entity, flyEntity)
+
+		});
+	},
+});
+
+export default CircleObject;

+ 181 - 0
packages/Widgets/CircleObject/CircleMaterialProperty.js

@@ -0,0 +1,181 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2022年12月29日
+ * 描述:动态扩散圆材质
+ */
+class CircleMaterialProperty {
+	/**
+	 * 构造方法
+	 * @ignore 无需公开
+	 * @param {JSON} options 配置项
+	 * @param {Cesium.Viewer} options.viewer 着色器运行所需的视图
+	 * @param {Cesium.Color} options.color [圆环的颜色,默认蓝色] 可选
+	 * @param {Number} options.duration [循环时间 默认1000] 可选
+	 * @param {Number} options.count [圆环的数量 可选 默认为1]
+	 */
+	constructor(options) {
+		/* 着色器运行依赖的视图 */
+		this._viewer = options.viewer;
+		/* 变更事件 */
+		this._definitionChanged = new Cesium.Event();
+		this._color = undefined;
+		/* 扩算圆环的颜色 */
+		this.color = options.color || Cesium.Color.BLUE;
+		/* 扩散圆环的数量 */
+		this.count = options.count || 1.0;
+		/* 动态循环周期 */
+		this.duration = options.duration || 1000;
+		/* 默认时间 */
+		this._time = (new Date()).getTime();
+		/* 材质类型名称 */
+		this._materialTypeName = 'jtCircleMaterial'
+		/* 存储相关参数的属性 以便后期进行追踪修改 */
+		this._param = {
+			color: this.color._value.toCssColorString(),
+			duration: this.duration,
+			count: this.count,
+		}
+		/* 将材质加入缓存 以便重复利用 */
+		Cesium.Material._materialCache.addMaterial(this._materialTypeName, {
+			fabric: {
+				type: this._materialTypeName,
+				uniforms: {
+					time: 0,
+					color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
+					count: 1.0,
+				},
+				source: this._getCircleMaterial(),
+			},
+			translucent: function(material) {
+				/* 材质是否半透明 */
+				return true;
+			}
+		});
+	}
+
+	/**
+	 * @ignore 无需公开
+	 * 获取材质着色器Shader
+	 */
+	_getCircleMaterial() {
+		let circleMaterial = "czm_material czm_getMaterial(czm_materialInput materialInput)\n" +
+			"{\n" +
+			"  czm_material material = czm_getDefaultMaterial(materialInput);\n" +
+			"  material.diffuse = 1.5 * color.rgb;\n" +
+			"  vec2 st = materialInput.st;\n" +
+			"  vec3 str = materialInput.str;\n" +
+			"  float dis = distance(st, vec2(0.5, 0.5));\n" +
+			"  float per = fract(time);\n" +
+			"  if (abs(str.z) > 0.001)\n" +
+			"  {\n" +
+			"     //着色器渲染停止,不在绘制内容  \n" +
+			"     discard;\n" +
+			"  }\n" +
+			"  if (dis > 0.5)\n" +
+			"  {\n" +
+			"     //超出半径范围时,着色器渲染停止  \n" +
+			"     discard;\n" +
+			"  } else {\n" +
+			"     //把半径分成count份,每两份之间的间隔距离  \n" +
+			"     float perDis = 0.5 / count;\n" +
+			"     float disNum;\n" +
+			"     float bl = 0.0;\n" +
+			"     //循环,最多999个环  \n" +
+			"     for (int i = 0; i <= 999; i++)\n" +
+			"     {\n" +
+			"        //判断是否属于数量内的环  \n" +
+			"        if (float(i) <= count)\n" +
+			"        {\n" +
+			"           disNum = perDis * float(i) - dis + per / count;\n" +
+			"           if (disNum > 0.0)\n" +
+			"           {\n" +
+			"               if (disNum < perDis)\n" +
+			"               {\n" +
+			"                  bl = 1.0 - disNum / perDis;\n" +
+			"               } else if (disNum - perDis < perDis) {\n" +
+			"                  bl = 1.0 - abs(1.0 - disNum / perDis);\n" +
+			"               }\n" +
+			"               material.alpha = color.a * pow(bl, 3.0);\n" +
+			"           }\n" +
+			"        }\n" +
+			"     }\n" +
+			"  }\n" +
+			"  return material;\n" +
+			"}\n";
+		return circleMaterial;
+	}
+}
+
+/**
+ * @ignore 无需公开
+ * 必须重写的方法
+ */
+Object.assign(CircleMaterialProperty.prototype, {
+	/**
+	 * 重新获取类型方法
+	 * @ignore 无需公开
+	 * @param {Cesium.JulianDate} time 时间
+	 */
+	getType: function(time) {
+		return this._materialTypeName;
+	},
+
+	/**
+	 * 重写获取值方法
+	 * @ignore 无需公开
+	 * @param {Cesium.JulianDate} time
+	 * @param {JSON} result 
+	 */
+	getValue: function(time, result) {
+		if (!Cesium.defined(result)) {
+			result = {};
+		}
+		result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.BLUE, result
+			.color);
+		result.count = this.count;
+		if (this.duration) {
+			result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
+		}
+		this._viewer.scene.requestRender();
+		return result;
+	},
+
+	/**
+	 * 重写对比函数
+	 * @ignore 无需公开
+	 * @param {Object} other 传入对比对象
+	 */
+	equals: function(other) {
+		return (this === other || (other instanceof CircleMaterialProperty && Cesium.Property.equals(this
+			._color, other._color)));
+	}
+})
+
+/**
+ * 默认属性
+ */
+Object.defineProperties(CircleMaterialProperty.prototype, {
+	/**
+	 * 判断是否相等,返回false表示属性一直在变化中
+	 * @ignore 无需公开
+	 */
+	isConstant: {
+		get: function() {
+			return false;
+		}
+	},
+	/**
+	 * 事件变更
+	 * @ignore 无需公开
+	 */
+	definitionChanged: {
+		get: function() {
+			return this._definitionChanged;
+		}
+	},
+	/* 颜色属性 */
+	color: Cesium.createPropertyDescriptor('color')
+})
+
+export default CircleMaterialProperty;

+ 132 - 0
packages/Widgets/CircleObject/CircleRippleMaterialProperty.js

@@ -0,0 +1,132 @@
+/*
+ * @Description: 波纹圆效果(和水波纹扩散类似,参考开源代码)
+ * @Version: 1.0
+ * @Author: Julian
+ * @Date: 2022-03-03 21:59:17
+ * @LastEditors: Julian
+ * @LastEditTime: 2022-03-03 23:09:02
+ */
+class CircleRippleMaterialProperty {
+    constructor(options) {
+        this._definitionChanged = new Cesium.Event();
+        this._color = undefined;
+        this._speed = undefined;
+        this.color = options.color;
+        this.speed = options.speed;
+        this.count = options.count;
+        this.gradient = options.gradient;
+    };
+
+    get isConstant() {
+        return false;
+    }
+
+    get definitionChanged() {
+        return this._definitionChanged;
+    }
+
+    getType(time) {
+        return Cesium.Material.CircleRippleMaterialType;
+    }
+
+    getValue(time, result) {
+        if (!Cesium.defined(result)) {
+            result = {};
+        }
+
+        result.color = Cesium.Property.getValueOrDefault(this._color, time, Cesium.Color.RED, result.color);
+        result.speed = Cesium.Property.getValueOrDefault(this._speed, time, 10, result.speed);
+        result.count = this.count;
+        result.gradient = this.gradient;
+        return result
+    }
+
+    equals(other) {
+        return (this === other ||
+            (other instanceof CircleRippleMaterialProperty &&
+                Cesium.Property.equals(this._color, other._color) &&
+                Cesium.Property.equals(this._speed, other._speed) &&
+                Cesium.Property.equals(this.count, other.count) &&
+                Cesium.Property.equals(this.gradient, other.gradient))
+        )
+    }
+}
+
+Object.defineProperties(CircleRippleMaterialProperty.prototype, {
+    color: Cesium.createPropertyDescriptor('color'),
+    speed: Cesium.createPropertyDescriptor('speed'),
+    count: Cesium.createPropertyDescriptor('count'),
+    gradient: Cesium.createPropertyDescriptor('gradient')
+})
+
+Cesium.CircleRippleMaterialProperty = CircleRippleMaterialProperty;
+Cesium.Material.CircleRippleMaterialProperty = 'CircleRippleMaterialProperty';
+Cesium.Material.CircleRippleMaterialType = 'CircleRippleMaterialType';
+Cesium.Material.CircleRippleMaterialSource = `
+                                            uniform vec4 color;
+                                            uniform float speed;
+                                            uniform float count;
+                                            uniform float gradient;
+
+                                            czm_material czm_getMaterial(czm_materialInput materialInput)
+                                            {
+                                            czm_material material = czm_getDefaultMaterial(materialInput);
+                                            material.diffuse = 1.5 * color.rgb;
+                                            vec2 st = materialInput.st;
+                                            float dis = distance(st, vec2(0.5, 0.5));
+                                            float per = fract(czm_frameNumber * speed / 1000.0);
+                                            if(count == 1.0){
+                                                if(dis > per * 0.5){
+                                                discard;
+                                                }else {
+                                                material.alpha = color.a  * dis / per / 2.0;
+                                                }
+                                            } else {
+                                                vec3 str = materialInput.str;
+                                                if(abs(str.z)  > 0.001){
+                                                discard;
+                                                }
+                                                if(dis > 0.5){
+                                                discard;
+                                                } else {
+                                                float perDis = 0.5 / count;
+                                                float disNum;
+                                                float bl = 0.0;
+                                                for(int i = 0; i <= 999; i++){
+                                                    if(float(i) <= count){
+                                                    disNum = perDis * float(i) - dis + per / count;
+                                                    if(disNum > 0.0){
+                                                        if(disNum < perDis){
+                                                        bl = 1.0 - disNum / perDis;
+                                                        }
+                                                        else if(disNum - perDis < perDis){
+                                                        bl = 1.0 - abs(1.0 - disNum / perDis);
+                                                        }
+                                                        material.alpha = pow(bl,(1.0 + 10.0 * (1.0 - gradient)));
+                                                    }
+                                                    }
+                                                }
+                                                }
+                                            }
+                                            return material;
+                                            }
+                                            `
+
+Cesium.Material._materialCache.addMaterial(Cesium.Material.CircleRippleMaterialType, {
+    fabric: {
+        type: Cesium.Material.CircleRippleMaterialType,
+        uniforms: {
+            color: new Cesium.Color(1.0, 0.0, 0.0, 1.0),
+            speed: 3.0,
+            count: 4,
+            gradient: 0.2
+        },
+        source: Cesium.Material.CircleRippleMaterialSource
+    },
+    translucent: function(material) {
+        return true;
+    }
+})
+
+
+export default CircleRippleMaterialProperty;

+ 627 - 0
packages/Widgets/CrImageServerLayer.js

@@ -0,0 +1,627 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2023年1月30日
+ * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
+ */
+
+/* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
+Date.prototype.Format = function(fmt) { // author: meizz 
+	var o = {
+		"M+": this.getMonth() + 1, // 月份 
+		"d+": this.getDate(), // 日 
+		"h+": this.getHours(), // 小时 
+		"m+": this.getMinutes(), // 分 
+		"s+": this.getSeconds(), // 秒 
+		"q+": Math.floor((this.getMonth() + 3) / 3), // 季度 
+		"S": this.getMilliseconds() // 毫秒 
+	};
+	if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	for (var k in o)
+		if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((
+			"00" + o[k]).substr(("" + o[k]).length)));
+	return fmt;
+}
+
+/* 引入Cesium */
+// import * as Cesium from 'cesium';
+// import Worker from '../../../public/worker/download.js?worker';
+
+/* 创建类 */
+class CrImageServerLayer {
+	/**
+	 * 构造函数
+	 * @param {Cesium.Viewer} options.viewer 地图视图容器
+	 * @param {String} options.url 服务地址
+	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
+	 */
+	constructor({
+		viewer,
+		url,
+		opacity = 0.75,
+		show = true,
+	} = {}) {
+		/* 地图视图 外部传入 必须参数 */
+		this._viewer = viewer;
+		/* 服务地址 外部传入 */
+		this._url = url;
+		/* 透明度 外部传入 */
+		this._opacity = opacity;
+		/* 图层随机标识 */
+		this._renderName = this._guid();
+		/* 实体集合 */
+		/* 用DataSource 方式 以便进行多图层管理 */
+		let dataSource = new Cesium.CustomDataSource(this._renderName);
+		this._viewer.dataSources.add(dataSource);
+		this._entities = dataSource.entities;
+		/* 渲染集合 */
+		this._renderEntities = new Map();
+		/* 是否渲染标志 */
+		this._isUpdateTile = show;
+		/* 是否输出测试信息 */
+		this._isDebug = false;
+		/* 初始化 */
+		this._init();
+	}
+
+	/**
+	 * 初始化
+	 */
+	_init() {
+		let _self = this;
+		/* 创建服务提供者 */
+		this._provider = new Cesium.ArcGisMapServerImageryProvider({
+			url: _self._url,
+		})
+		/* 激活服务提供者 注册刷帧事件 */
+		this._provider.readyPromise.then(function(result) {
+			/* 服务提供者的数据范围 */
+			_self._rectangle = _self._provider.rectangle;
+			/* 输出调试信息 */
+			if (_self._isDebug) _self._printDebug();
+			/* 注册事件 */
+			_self._viewer.scene.postRender.addEventListener(() => {
+				if (_self._isUpdateTile) {
+					/* 设置运行标志为false 等待计算完成 */
+					_self._isUpdateTile = false;
+					/* 投影瓦片集合 */
+					_self._renderTiles();
+				}
+			});
+		})
+	}
+
+	/**
+	 * 生成GUID随机数
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 输出调试信息
+	 */
+	_printDebug() {
+		/* 数据提供者的切片方案 */
+		let tiling = this._provider.tilingScheme;
+		/* WGS84坐标系的切片方案 */
+		let tiling84 = new Cesium.GeographicTilingScheme();
+		/* 绘制数据提供者的数据范围 */
+		this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
+		/* 根据行列号和等级创建调试矩形 */
+		let rect = tiling84.tileXYToRectangle(1696, 312, 10);
+		/* 绘制调试矩形 */
+		// this._drawDebugRectangle(rect, Cesium.Color.YELLOW);
+
+		// let rect11 = Cesium.Rectangle.subsection(rect, 0, 0, 0.5, 0.5);
+		// let rect12 = Cesium.Rectangle.subsection(rect, 0.5, 0, 1.0, 0.5);
+		// let rect21 = Cesium.Rectangle.subsection(rect, 0, 0.5, 0.5, 1.0);
+		// let rect22 = Cesium.Rectangle.subsection(rect, 0.5, 0.5, 1.0, 1.0);
+		// this._drawDebugRectangle(rect11, Cesium.Color.RED);
+		// this._drawDebugRectangle(rect12, Cesium.Color.GREEN);
+		// this._drawDebugRectangle(rect21, Cesium.Color.BLUE);
+		// this._drawDebugRectangle(rect22, Cesium.Color.WHITE);
+	}
+
+	/**
+	 * 绘制调试矩形
+	 * @param {Cesium.Rectangle} rectangle 绘制的矩形
+	 * @param {Cesium.Color} color 矩形边框颜色
+	 */
+	_drawDebugRectangle(rectangle, color) {
+		/* 计算矩形的外包范围 */
+		let positions = this._calculateRectangleOutlineCoordinates(rectangle);
+		/* 创建矩形实体 */
+		let rectEntity = new Cesium.Entity({
+			name: this._renderName,
+			polyline: {
+				positions: positions,
+				material: color,
+				width: 10,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		/* 加入数据集 */
+		this._entities.add(rectEntity);
+	}
+
+	/**
+	 * 输出消息
+	 * @param {Object} res
+	 */
+	_console(...rest) {
+		if (this._isDebug)
+			console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
+	}
+
+	/**
+	 * 渲染瓦片集合
+	 */
+	_renderTiles() {
+		let _self = this;
+		/* 获取当前视图渲染的瓦片集合 */
+		let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
+		if (tilesToRender === undefined || tilesToRender.length === 0) {
+			this._isUpdateTile = true;
+			return;
+		} else {
+			new Promise((resolve, reject) => {
+				/* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
+				tilesToRender.sort(function(obj1, obj2) {
+					let level1 = parseInt(obj1.level);
+					let level2 = parseInt(obj2.level);
+					return level1 - level2;
+				})
+				/* 返回排序后的渲染瓦片数据集 开始异步计算 */
+				resolve(tilesToRender);
+			}).then(tiles => {
+				/* 异步重投影瓦片数据集 */
+				_self._asyncProjectionTiles(tiles);
+			})
+		}
+	}
+
+	/**
+	 * 根据行列和等级生成key
+	 * @param {Number} x 行
+	 * @param {Number} y 列
+	 * @param {Number} level 等级
+	 */
+	_createKey(x, y, level) {
+		let key = `${this._renderName}_${x}_${y}_${level}`;
+		return key;
+	}
+
+	/**
+	 * 投影瓦片集合
+	 * @param {Object} tiles 原始渲染瓦片集合
+	 */
+	_asyncProjectionTiles(tiles) {
+		let renderTiles = [];
+		/* 循环投影 */
+		for (let tile of tiles) {
+			/* 对单个瓦片进行重投影 */
+			let proTiles = this._projectionTile(tile);
+			for (let proTile of proTiles) {
+				/* 瓦片实体唯一标识 */
+				let key = this._createKey(proTile.x, proTile.y, proTile.level);
+				/* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
+				let subTile = renderTiles.find(obj => {
+					return obj.x === proTile.x && obj.y === proTile.y;
+				})
+				if (subTile === undefined) {
+					/* 重投影瓦片范围与数据范围的叠合计算 */
+					let isExists = false;
+					for (let eTile of renderTiles) {
+						if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
+							/* 追加子集 方便后期进行层级处理 */
+							eTile.childTiles.push(key);
+							isExists = true;
+							break;
+						}
+					}
+					/* 加入渲染集合 */
+					if (!isExists) {
+						renderTiles.push({
+							key: key,
+							x: proTile.x,
+							y: proTile.y,
+							level: proTile.level,
+							rectangle: proTile.rectangle,
+							childTiles: [],
+						});
+					}
+				}
+			}
+		}
+		/* 清理低层级元素 */
+		let i = renderTiles.length;
+		let appendTiles = [];
+		while (i--) {
+			let findTile = renderTiles[i];
+			if (findTile.childTiles.length >= 1) {
+				/* 创建高层级的瓦片 */
+				let tiles = this._createFourTiles(findTile);
+				for (let tile of tiles) {
+					appendTiles.push(tile);
+				}
+				/* 如果存在高层级 则删除低层级 */
+				renderTiles.splice(i, 1);
+			}
+		}
+		/* 将四叉树追加的层级数据加入到渲染集合中 */
+		for (let appendTile of appendTiles) {
+			renderTiles.push(appendTile);
+		}
+		/* 对数组进行排序 */
+		renderTiles.sort(function(obj1, obj2) {
+			let level1 = parseInt(obj1.level);
+			let level2 = parseInt(obj2.level);
+			return level1 - level2;
+		})
+		/* 渲染数据到视图中 */
+		this._renderTilesToViewer(renderTiles);
+	}
+
+	/**
+	 * 根据矩形和登记查询高一等级的行列号
+	 * @param {Cesium.Rectangle} rectangle 
+	 */
+	_createTileByRectangleAndLevel(rectangle, level) {
+		/* 获取矩形中心点 */
+		let center = Cesium.Rectangle.center(rectangle);
+		/* 新层级 */
+		let nLevel = parseInt(level) + 1;
+		/* 查询高一层级的行列号 */
+		let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
+		if (query === undefined) return undefined;
+		/* 返回结果 */
+		return {
+			key: this._createKey(query.x, query.y, nLevel),
+			x: query.x,
+			y: query.y,
+			level: nLevel,
+			rectangle: rectangle,
+			childTiles: [],
+		}
+	}
+
+	/**
+	 * 创建四个高层级的瓦片
+	 * @param {Object} tile 当前瓦片
+	 */
+	_createFourTiles(tile) {
+		let rects = [];
+		let results = [];
+		let rectangle = tile.rectangle;
+		/* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
+		for (let rect of rects) {
+			/* 判断高层级的矩形是否与谁范围存在交集 */
+			if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
+				/* 查询高一层级的Tile */
+				let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
+				/* 如果存在加入到返回集合中 */
+				if (newTile !== undefined) results.push(newTile);
+			}
+		}
+		return results;
+	}
+
+	/**
+	 * 渲染瓦片到视图中
+	 * @param {Object} tiles
+	 */
+	_renderTilesToViewer(tiles) {
+		let _self = this;
+		/* 确定哪些渲染实体已失效 对失效的实体进行清理 */
+		let deleteKeys = [];
+		for (let [key, tile] of this._renderEntities) {
+			let findTile = tiles.find(obj => {
+				return obj.key === key;
+			})
+			if (findTile === undefined) {
+				deleteKeys.push(key);
+			}
+		}
+		for (let key of deleteKeys) {
+			/* 移除元素 */
+			this._renderEntities.delete(key);
+			/* 移除渲染元素 */
+			this._entities.removeById(key);
+		}
+		/* 对过滤后的数据集进行渲染 */
+		for (let tile of tiles) {
+			/* 判断当前渲染的数据是否已经渲染且有效 */
+			if (!this._renderEntities.has(tile.key)) {
+				/* 将数据渲染到视图中 */
+				let entity = this._renderSimpleTileToViewer(tile);
+				/* 将渲染的数据加入到集合中 */
+				this._renderEntities.set(tile.key, entity);
+				/* 创建下载线程 */
+				let workBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
+				// let workBlob = new Blob([downloadWorker.toLocaleString().match(
+				// 	/(?:\/\*[\s\S]*?\*\/|\/\/.*?\r?\n|[^{])+\{([\s\S]*)\}$/)[1]]) // 把函数的主体内容拿出来进行转换
+				let worker = new Worker(URL.createObjectURL(workBlob));
+				/* 发送下载任务 */
+				worker.postMessage({
+					key: tile.key,
+					url: this._url,
+					x: tile.x,
+					y: tile.y,
+					level: tile.level,
+				})
+				/* 接收下载任务 */
+				worker.onmessage = function(event) {
+					_self._console(`render x:${event.data.x} y:${event.data.y} level:${event.data.level}`);
+					/* 判断是否存在 */
+					let renderEntity = _self._entities.getById(event.data.key);
+					if (renderEntity !== undefined) {
+						let key = event.data.key;
+						const canvas = _self._createCanvas(event.data, event.data.image, _self._isDebug);
+						renderEntity.rectangle.material = canvas;
+					}
+					worker.terminate();
+				}
+			}
+		}
+		/* 重启计算标志 */
+		this._isUpdateTile = true;
+	}
+
+	/**
+	 * 渲染单个瓦片到视图中
+	 * @param {Object} tile
+	 */
+	_renderSimpleTileToViewer(tile) {
+		/* 创建画布 */
+		const canvas = this._createCanvas(tile, undefined, this._isDebug);
+		let bjPositions = this._calculateRectangleOutlineCoordinates(tile
+			.rectangle);
+		let tileEntity = new Cesium.Entity({
+			name: this._renderName,
+			id: tile.key,
+			rectangle: {
+				coordinates: tile.rectangle,
+				material: canvas,
+			},
+			polyline: {
+				positions: bjPositions,
+				material: Cesium.Color.YELLOW.withAlpha(this._isDebug ? 1 : 0),
+				width: 1,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		return this._entities.add(tileEntity);
+	}
+
+	/**
+	 * 根据瓦片创建画布
+	 * @param {Object} tile 瓦片
+	 * @param {Object} image 绘制的图片
+	 * @param {boolean} islabel 是否绘制标签 
+	 */
+	_createCanvas(tile, image, islabel) {
+		/* 获取服务提供者的切片方案 */
+		let provider = this._provider;
+		const canvas = document.createElement("canvas");
+		canvas.width = provider.tileWidth;
+		canvas.height = provider.tileHeight;
+		const context = canvas.getContext("2d");
+		if (image !== undefined) {
+			context.globalAlpha = this._opacity;
+			context.drawImage(event.data.image, 0, 0, canvas.width, canvas.height);
+		}
+		if (islabel !== undefined && islabel === true) {
+			context.globalAlpha = 1.0;
+			/* 创建标签 */
+			context.font = "20px Arial";
+			context.textAlign = "center";
+			context.fillStyle = 'rgba(255,255,0)';
+			context.strokeStyle = 'rgba(255,255,255,1)';
+			context.lineWidth = 2;
+			context.strokeText(`L: ${tile.level}`, 126, 86);
+			context.fillText(`L: ${tile.level}`, 126, 86);
+			context.strokeText(`X: ${tile.x}`, 126, 136);
+			context.fillText(`X: ${tile.x}`, 126, 136);
+			context.strokeText(`Y: ${tile.y}`, 126, 186);
+			context.fillText(`Y: ${tile.y}`, 126, 186);
+		}
+		/* 返回画布 */
+		return canvas;
+	}
+
+	/**
+	 * 投影当前瓦片
+	 * @param {Object} tile
+	 */
+	_projectionTile(tile) {
+		/* 获取矩形 */
+		let rectangle = tile._rectangle;
+		// let imageryLevel = parseInt(tile.level) + 1;
+		let imageryLevel = parseInt(tile.level);
+		let mercatorTilingScheme = this._provider.tilingScheme;
+		let res = [];
+		/* 先判断当前的切片范围是否与提供者的数据范围有交集 */
+		let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
+		/* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
+		if (interRectangle === undefined) return res;
+		/* 判断北西角点的墨卡托投影瓦片信息 */
+		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.northwest(rectangle),
+			imageryLevel
+		);
+		/* 判断南东角点的墨卡托投影瓦片信息 */
+		let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.southeast(rectangle),
+			imageryLevel
+		);
+		/* 根据不同类型分别进行计算 */
+		if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
+			for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
+				for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
+					let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
+					if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+						res.push({
+							x: i,
+							y: j,
+							level: imageryLevel,
+							rectangle: _webRectangle,
+						});
+					}
+				}
+			}
+		} else if (northwestTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
+				northwestTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: northwestTileCoordinates.x,
+					y: northwestTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		} else if (southeastTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
+				southeastTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: southeastTileCoordinates.x,
+					y: southeastTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		}
+		return res;
+	}
+
+	/**
+	 * 计算矩形的外围坐标串
+	 * @param {Cesium.Rectangle} rectangle 矩形
+	 * @return {Array<Cesium.Cartesian3>} 坐标串集合
+	 */
+	_calculateRectangleOutlineCoordinates(rectangle) {
+		/* 计算东南角 */
+		let south_east = Cesium.Rectangle.southeast(rectangle);
+		let se = Cesium.Cartographic.toCartesian(south_east);
+		/* 计算西南角 */
+		let south_west = Cesium.Rectangle.southwest(rectangle);
+		let sw = Cesium.Cartographic.toCartesian(south_west);
+		/* 计算东北角 */
+		let north_east = Cesium.Rectangle.northeast(rectangle);
+		let ne = Cesium.Cartographic.toCartesian(north_east);
+		/* 计算西北角 */
+		let north_west = Cesium.Rectangle.northwest(rectangle);
+		let nw = Cesium.Cartographic.toCartesian(north_west);
+		return [sw, se, ne, nw, sw];
+	}
+
+	/**
+	 * 根据Entity的名称批量删除Entity
+	 * @param {String} entityName 实体名称
+	 */
+	_removeEntityByName(entityName) {
+		/* 获取实体集合 */
+		var entities = this._entities;
+		/* 如果不存在实体集合或集合中没有数据 则返回 */
+		if (!entities || !entities.values) return;
+		var delEntitys = [];
+		/* 循环获取当前集合中的所有实体 */
+		for (var i = 0; i < entities.values.length; i++) {
+			if (entities.values[i].name == entityName) {
+				delEntitys.push(entities.values[i]);
+			}
+		}
+		/* 删除符合条件的所有实体 */
+		for (var i = 0; i < delEntitys.length; i++) {
+			entities.remove(delEntitys[i]);
+		}
+	}
+}
+
+/* 对外方法 */
+Object.assign(CrImageServerLayer.prototype, /** @lends CrImageServerLayer.prototype */ {
+	/**
+	 * 隐藏
+	 */
+	hide: function() {
+		this._console('隐藏');
+		this._isUpdateTile = false;
+		/* 清理资源 */
+		this._removeEntityByName(this._renderName);
+		/* 清理渲染 */
+		this._renderEntities.clear();
+	},
+
+	/**
+	 * 显示
+	 */
+	show: function() {
+		this._console('显示');
+		this._isUpdateTile = true;
+	},
+
+	/**
+	 * 设置透明度
+	 * @param {Number} opacity [0-1]
+	 */
+	setOpacity: function(opacity) {
+		if (opacity === undefined || typeof opacity !== 'number') return;
+		if (opacity >= 1) this._opacity = 1.0;
+		if (opacity <= 0) this._opacity = 0.0;
+		this._opacity = parseFloat(opacity);
+	}
+
+})
+
+/* 下载线程函数 */
+function downloadWorker() {
+	/* 接收主线程发送的文件下载请求 */
+	onmessage = function(event) {
+		let data = event.data;
+		/* 创建下载数据链接 */
+		let url = data.url + '/tile/' + data.level + '/' + data.y + '/' + data.x;
+		/* 创建下载相关 并下载 */
+		let xhr = new XMLHttpRequest();
+		xhr.open('get', url, true);
+		xhr.responseType = "blob"; //设置返回类型,此处我用于下载文件 所以返回blob
+		xhr.onload = function() {
+			// 请求完成
+			if (this.status === 200) {
+				var blob = this.response;
+				var bmpPromise = createImageBitmap(blob, {
+					imageOrientation: "none",
+					premultiplyAlpha: "none",
+					colorSpaceConversion: "default",
+				});
+				bmpPromise.then(function(image) {
+					let outObj = {
+						key: data.key,
+						x: data.x,
+						y: data.y,
+						level: data.level,
+						image: image,
+					}
+					postMessage(outObj);
+				})
+			} else {
+				console.log('===>>>', url + ' Not found');
+			}
+		}
+		/* 发送请求 */
+		xhr.send();
+	}
+}
+
+/* 输出类 */
+export default CrImageServerLayer

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 79 - 0
packages/Widgets/DrawTools/CommonTools.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 684 - 0
packages/Widgets/DrawTools/CrEditProperty.ce.vue


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 388 - 0
packages/Widgets/DrawTools/CrEditProperty_MilitaryPlot.ce.vue


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 779 - 0
packages/Widgets/DrawTools/CrEditProperty_Point.ce.vue


+ 609 - 0
packages/Widgets/DrawTools/DrawMilitaryPlot.js

@@ -0,0 +1,609 @@
+import MilitaryPlot from './/MilitaryPlot/drawingMethod/index.js'
+
+//编辑类
+import EntityEdit from './MilitaryPlot/EntityEdit.js';
+
+/* 引入属性编辑框 */
+import DialogEditProperty from './CrEditProperty_MilitaryPlot.ce.vue'
+/* 引入组件注册 */
+import {
+	defineCustomElement
+} from 'vue'
+
+/**
+ * 设置附加参数
+ * @ignore 生成方法时不对外公开
+ * @param {JSON} params 参数
+ */
+Cesium.Entity.prototype.setParams = function(params) {
+	this._params = params;
+}
+
+/**
+ * 获取附加参数
+ * @ignore 生成方法时不对外公开
+ */
+Cesium.Entity.prototype.getParams = function() {
+	return this._params;
+}
+
+
+/**
+ * 设置实体是否可编辑
+ * @ignore 生成方法时不对外公开
+ * @param {Boolean} isEdit 是否可编辑
+ */
+Cesium.Entity.prototype.setIsEdit = function(isEdit) {
+	this._isEdit = isEdit;
+}
+
+/**
+ * 获取实体是否可编辑
+ * @ignore 生成方法时不对外公开
+ * @return {Boolean} isEdit
+ */
+Cesium.Entity.prototype.getIsEdit = function() {
+	return this._isEdit;
+}
+
+/**
+ * 军事标绘
+ */
+class DrawMilitaryPlot {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(options) {
+		if (!options.viewer) throw new DeveloperError('no options.viewer object!');
+		if (!options.Cesium) throw new DeveloperError('no options.Cesium object!');
+
+		this._viewer = options.viewer;
+		this.cesium = options.Cesium;
+
+		this.drawArr = [];
+		this.Draw = '';
+		// 鼠标点击获取实体修改事件
+		this.edit = new EntityEdit(this._viewer);
+		this.edit.activate(); //激活编辑
+		//获取得到实体 cesium回调机制
+		this.edit.EditEndEntity.addEventListener((result) => {
+			if (result.Type) {
+				this.handleFirstPosition(result.Type);
+				this.edit.DrawExample = this.Draw;
+			}
+			this._editEntity = result; //选中的实体
+		})
+	}
+
+	/**
+	 * 静态方法 初始化并获取属性编辑参数
+	 */
+	static initEditPropertyParams() {
+		return {
+			id: undefined, //用于标识及传递当前编辑的实体类型 内容为DrawTools.DrawType
+			color: 'rgba(0,255,0,0.75)', //用于颜色标识
+			outlineWidth: 0, //用于标识描边线宽度
+			outlineColor: 'rgba(255,255,255,1)', //用于标识描边线颜色
+		}
+	}
+
+	// 编辑时获取到实体时调用
+	editActivate() {
+		return this.edit
+	}
+
+	handleFirstPosition(type) {
+		/* 开启地形检测 必须开启 否则会导致获取地形高度时异常 导致鼠标移动时位置哆嗦 */
+		this._viewer.scene.globe.depthTestAgainstTerrain = true;
+		
+		switch (type) {
+			case "DrawStraightArrow":
+				// 绘制直线箭头
+				this.Draw = new MilitaryPlot.DrawStraightArrow({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawAttackArrow":
+				// 绘制攻击箭头
+				this.Draw = new MilitaryPlot.DrawAttackArrow({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawPincerArrow":
+				//绘制钳击箭头
+				this.Draw = new MilitaryPlot.DrawPincerArrow({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawGatheringPlace":
+				this.Draw = new MilitaryPlot.DrawGatheringPlace({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawClosedCurve":
+				this.Draw = new MilitaryPlot.DrawClosedCurve({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawSector":
+				this.Draw = new MilitaryPlot.DrawSector({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawBowLine":
+				this.Draw = new MilitaryPlot.DrawBowLine({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawBowPlane":
+				this.Draw = new MilitaryPlot.DrawBowPlane({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawCurve":
+				//绘制曲线
+				this.Draw = new MilitaryPlot.DrawCurve({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawCurveFlag":
+				//绘制曲线旗帜
+				this.Draw = new MilitaryPlot.DrawCurveFlag({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawRectFlag":
+				//绘制矩形直角旗帜
+				this.Draw = new MilitaryPlot.DrawRectFlag({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawTriangleFlag":
+				//绘制三角旗帜
+				this.Draw = new MilitaryPlot.DrawTriangleFlag({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+
+			case "DrawPoint":
+				//绘制点
+				this.Draw = new MilitaryPlot.DrawPoint({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawPolyline":
+				// 绘制线
+				this.Draw = new MilitaryPlot.DrawPolyline({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawPolygon":
+				// 多边形
+				this.Draw = new MilitaryPlot.DrawPolygon({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawRectangle":
+				// 绘制矩形
+				this.Draw = new MilitaryPlot.DrawRectangle({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				})
+				break;
+			case "DrawCircle":
+				//绘制圆
+				this.Draw = new MilitaryPlot.DrawCircle({
+					viewer: this._viewer,
+					Cesium: this.cesium
+				});
+				break;
+		}
+	}
+
+	// 加载数据
+	addEntity(data) {
+		this.handleFirstPosition(data.type);
+		if (this.Draw) {
+			let entity = this.Draw.addload(data.position);
+			entity._id = data.id
+			return entity
+		}
+	}
+}
+
+/**
+ * 通用对外公开函数-鼠标事件 
+ */
+Object.assign(DrawMilitaryPlot.prototype, /** @lends DrawMilitaryPlot.prototype */ {
+	/**
+	 * 设置鼠标为十字样式
+	 * @ignore 生成方法时不对外公开
+	 */
+	_setMousePointerStyle() {
+		document.querySelector('body').style.cursor = 'crosshair';
+	},
+
+	/**
+	 * 恢复鼠标指针为默认样式
+	 * @ignore 生成方法时不对外公开
+	 */
+	_setMouseDefaultStyle() {
+		document.querySelector('body').style.cursor = 'default';
+	},
+
+	/**
+	 * 注册鼠标左键点击事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerLeftClickEvent(handler, callChange) {
+		let _self = this;
+		if (!handler) return;
+
+		handler.setInputAction(function(event) {
+			/* 锁定点击事件 以免和移动事件冲突 */
+			_self._lock = true;
+			clearTimeout(_self._timer);
+			_self._timer = setTimeout(function() {
+				if (callChange) callChange(event);
+				/* 解除锁定 */
+				_self._lock = false;
+			}, 200);
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+	},
+
+	/**
+	 * 注册鼠标移动事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerMouseMoveEvent(handler, callChange) {
+		let _self = this;
+		if (!handler) return;
+
+		handler.setInputAction(function(event) {
+			if (_self._lock === undefined || _self._lock === false) {
+				if (callChange) callChange(event);
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	},
+
+	/**
+	 * 注册鼠标左键按下事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerLeftDownEvent(handler, callChange) {
+		if (!handler) return;
+		handler.setInputAction(function(event) {
+			if (callChange) callChange(event);
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+	},
+
+	/**
+	 * 注册鼠标左键抬起事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerLeftUpEvent(handler, callChange) {
+		if (!handler) return;
+		handler.setInputAction(function(event) {
+			if (callChange) callChange(event);
+		}, Cesium.ScreenSpaceEventType.LEFT_UP);
+	},
+
+	/**
+	 * 清除事件
+	 * @ignore
+	 * @param {Cesium.ScreenSpaceEventHandler} handler
+	 */
+	_clearEvent(handler) {
+		if (!handler) return;
+
+		/* 干掉事件句柄 释放资源 */
+		handler.destroy();
+		handler = null;
+	}
+
+});
+
+/**
+ * 属性编辑相关
+ */
+Object.assign(DrawMilitaryPlot.prototype, {
+
+	/**
+	 * 设置实体可编辑,编辑的实体必须包含编辑类型
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Entity} entity 编辑的实体
+	 */
+	_setEntityIsEdit(entity) {
+		let _self = this;
+
+		/* 关闭属性编辑框 */
+		this._closePropertyEditDialog();
+
+		/* 设置实体要素可编辑 */
+		entity.setIsEdit(true);
+		this.edit.handlePickEditEntity(entity);
+
+		/* 激活编辑 并显示属性编辑框 */
+		this._sendShowPropertyDialog(entity);
+
+		/* 注册统一事件 用于单击拾取实体 */
+		let handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 只要点击 关闭属性编辑框 */
+			_self._closePropertyEditDialog();
+
+			let feature = _self._viewer.scene.pick(event.position);
+			if (feature !== undefined && feature.id instanceof Cesium.Entity) {
+				let editEntity = feature.id;
+				if (
+					editEntity.Type == 'DrawStraightArrow' ||
+					editEntity.Type == 'DrawAttackArrow' ||
+					editEntity.Type == 'DrawPincerArrow' ||
+					editEntity.Type == 'DrawGatheringPlace' ||
+					editEntity.Type == 'DrawClosedCurve' ||
+					editEntity.Type == "DrawSector" ||
+					editEntity.Type == "DrawBowLine" ||
+					editEntity.Type == "DrawBowPlane" ||
+					editEntity.Type == 'DrawCurve' ||
+					editEntity.Type == 'DrawCurveFlag' ||
+					editEntity.Type == 'DrawRectFlag' ||
+					editEntity.Type == 'DrawTriangleFlag' ||
+
+					editEntity.Type == 'DrawPoint' ||
+					editEntity.Type == 'DrawPolyline' ||
+					editEntity.Type == 'DrawPolygon' ||
+					editEntity.Type == 'DrawRectangle' ||
+					editEntity.Type == 'DrawCircle'
+				) {
+					_self._sendShowPropertyDialog(feature.id);
+				}
+			}
+		});
+	},
+
+	/**
+	 * 打开实体编辑对话框
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Entity} entity
+	 */
+	_sendShowPropertyDialog(entity) {
+
+		let _self = this;
+		/* 获取可编辑实体的类型 */
+		let editEntityType = entity.Type;
+		if (entity.getIsEdit() === undefined || entity.getIsEdit() === false || editEntityType === undefined) {
+			/* 选择的实体不可编辑 */
+			return;
+		}
+
+		/* 编辑属性 */
+		let editProperty = entity.getParams();
+		if (editProperty !== undefined && this.onEditProperty !== undefined) {
+			editProperty.id = editEntityType;
+
+			/* 更改测试 */
+			_self._openPropertyEditDialog(editProperty,
+				//编辑回调
+				function(params) {
+					_self.updateEditEntityProperty(params);
+				},
+				//移除回调
+				function() {
+					// _self.Draw.clear();
+					_self._viewer.entities.remove(entity);
+					_self.edit.clearAllEditVertex(); //禁用编辑
+				}
+			);
+		}
+	},
+	
+	/**
+	 * 更新当前编辑的实体属性
+	 * @param {JSON} params
+	 */
+	updateEditEntityProperty: function(params) {
+		let _self = this;
+		
+		if (this._editEntity === undefined) return;
+		if (this._editEntity.getIsEdit() === undefined || this._editEntity.getIsEdit() === false) return;
+		let editEntityType = this._editEntity.Type;
+		if (editEntityType === undefined) return;
+		
+		let material = this._editEntity.polygon.material;
+		if (material instanceof Cesium.ColorMaterialProperty) {
+			let newMaterial = this._materialColorProperty({
+				color: params.color,
+			});
+			this._editEntity.polygon.material = newMaterial;
+		}
+		if (this._editEntity.polyline !== undefined) {
+			let newMaterial = this._materialColorProperty({
+				color: params.outlineColor,
+			});
+			this._editEntity.polyline.material = newMaterial;
+			this._editEntity.polyline.width = parseFloat(params.outlineWidth);
+		}
+		/* 重新关联墙实体的属性 */
+		this._editEntity.setParams(params);
+	},
+	
+	/**
+	 * 颜色材质
+	 * @ignore 生成方法时不对外公开
+	 * @param {JSON} options 配置项
+	 * @param {String} options.color 文字颜色 rgba(r,g,b,a)
+	 */
+	_materialColorProperty(options) {
+		let mColor = 'rgba(0,255,0,1)';
+		if (options !== undefined && options.color !== undefined) mColor = options.color;
+		/* 创建材质 */
+		let colorMaterial = new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString(mColor));
+		colorMaterial._param = {
+			color: mColor,
+		}
+		/* 返回材质 */
+		return colorMaterial;
+	}
+})
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(DrawMilitaryPlot.prototype, /** @lends DrawMilitaryPlot.prototype */ {
+
+	/**
+	 * 开始绘制
+	 * @param {String} type 绘制类型 鼠标点击绘制时调用
+	 */
+	drawActivate(type) {
+		/* 设置鼠标样式为十字 */
+		this._setMousePointerStyle();
+
+		this.handleFirstPosition(type);
+		this.Draw.startCreate(type)
+
+		// 标绘完成返回数据
+		this.Draw.DrawEndEvent.addEventListener((entity, positions, drawType) => {
+			console.log({
+				entity,
+				positions,
+				drawType
+			});
+
+			// 恢复鼠标指针为默认样式
+			this._setMouseDefaultStyle();
+
+			if (entity) {
+
+
+				let entityParam = DrawMilitaryPlot.initEditPropertyParams();
+				entity.setParams(entityParam);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				this._setEntityIsEdit(entity);
+			}
+		});
+
+		this.drawArr.push(this.Draw);
+
+		return this.Draw
+	},
+
+	/**
+	 * 删除选定图形
+	 */
+	clearOne: function() {
+
+		this.Draw.clear();
+		// this.edit.deactivate(); //禁用编辑
+	},
+
+	/**
+	 * 删除所有图形
+	 */
+	clearAll: function() {
+
+		for (var i = 0; i < this.drawArr.length; i++) {
+			this.drawArr[i].clear();
+		}
+		this.edit.deactivate(); //禁用编辑
+
+		/* 关闭属性编辑框 */
+		this._closePropertyEditDialog();
+		/* 移除操作容器 */
+		let buttonDiv = document.getElementById("drawButtonDiv");
+		if (buttonDiv) {
+			//从页面移除
+			document.body.removeChild(buttonDiv);
+		}
+	},
+});
+
+/**
+ * 属性编辑相关(UI)
+ */
+Object.assign(DrawMilitaryPlot.prototype, {
+	/**
+	 * 打开属性编辑窗口
+	 * @ignore
+	 * @param {JSON} params 参数
+	 * @param {Function} callEdit 编辑回调
+	 * @param {Function} callRemove 移除回调
+	 */
+	_openPropertyEditDialog: function(params, callEdit, callRemove) {
+		this._editPropertyDialogDomId = 'dialog-property-dom-militaryplot';
+		this._registerDOMPropertyEdit = 'dialog-edit-property-militaryplot'
+		/* 获取一个属性编辑组件 */
+		let PropertyEditComponent = customElements.get(this._registerDOMPropertyEdit);
+		/* 如果组件还未注册 则进行注册 否则不在注册 避免重复注册的BUG */
+		if (PropertyEditComponent === undefined) {
+			PropertyEditComponent = defineCustomElement(DialogEditProperty);
+			customElements.define(this._registerDOMPropertyEdit, PropertyEditComponent);
+		}
+
+		/* 先关闭编辑框 */
+		this._closePropertyEditDialog();
+		/* 创建组件 */
+		let dialogPropertyElement = new PropertyEditComponent({
+			params: params,
+		})
+		dialogPropertyElement.id = this._editPropertyDialogDomId;
+		dialogPropertyElement.showDialog = true;
+		document.body.appendChild(dialogPropertyElement);
+
+		/* 监听修改事件 */
+		dialogPropertyElement.addEventListener(
+			"submit",
+			(e) => {
+				if (callEdit) callEdit(e.detail[0]);
+			},
+			false
+		);
+		/* 监听移除事件 */
+		dialogPropertyElement.addEventListener(
+			"remove",
+			(e) => {
+				if (callRemove) callRemove();
+			},
+			false
+		);
+	},
+
+	/**
+	 * 关闭属性编辑框
+	 * @ignore
+	 */
+	_closePropertyEditDialog() {
+		let dom = document.getElementById(this._editPropertyDialogDomId);
+		if (dom !== null && dom !== undefined) {
+			document.body.removeChild(dom);
+		}
+	},
+
+})
+
+export default DrawMilitaryPlot;

+ 1141 - 0
packages/Widgets/DrawTools/DrawPoint.js

@@ -0,0 +1,1141 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import CreateRemindertip from "../common/ReminderTip.js";
+
+//点对象
+import PointObject from "../PointObject.js";
+
+/* 引入属性编辑框 */
+import DialogEditProperty from './CrEditProperty_Point.ce.vue';
+/* 引入组件注册 */
+import {
+	defineCustomElement
+} from 'vue';
+
+/**
+ * 设置附加参数
+ * @ignore 生成方法时不对外公开
+ * @param {JSON} params 参数
+ */
+Cesium.Entity.prototype.setParams = function(params) {
+	this._params = params;
+}
+
+/**
+ * 获取附加参数
+ * @ignore 生成方法时不对外公开
+ */
+Cesium.Entity.prototype.getParams = function() {
+	return this._params;
+}
+
+/**
+ * 设置实体挂接的数据类型
+ * @ignore 生成方法时不对外公开
+ * @param {DrawPoint.DrawType} entityType 实体挂接的数据类型
+ */
+Cesium.Entity.prototype.setEntityType = function(entityType) {
+	this._entityType = entityType;
+}
+
+/**
+ * 获取实体挂接的数据类型
+ * @ignore 生成方法时不对外公开
+ * @@return {DrawPoint.DrawType} 实体挂接的数据类型
+ */
+Cesium.Entity.prototype.getEntityType = function(entityType) {
+	return this._entityType;
+}
+
+/**
+ * 设置实体是否可编辑
+ * @ignore 生成方法时不对外公开
+ * @param {Boolean} isEdit 是否可编辑
+ */
+Cesium.Entity.prototype.setIsEdit = function(isEdit) {
+	this._isEdit = isEdit;
+}
+
+/**
+ * 获取实体是否可编辑
+ * @ignore 生成方法时不对外公开
+ * @return {Boolean} isEdit
+ */
+Cesium.Entity.prototype.getIsEdit = function() {
+	return this._isEdit;
+}
+
+/**
+ * 绘制点文字小模型
+ */
+class DrawPoint {
+	/**
+	 * 默认初始化
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+
+		/* 开启地形检测 必须开启 否则会导致获取地形高度时异常 导致鼠标移动时位置哆嗦 */
+		this._viewer.scene.globe.depthTestAgainstTerrain = true;
+		/* 取消地图右键点击事件 */
+		this._viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
+
+		/* 实体数据集 */
+		this._entities = [];
+
+		//绘制点
+		this._pointObject = new PointObject(viewer);
+	}
+
+	/**
+	 * 静态方法 初始化并获取属性编辑参数
+	 */
+	static initEditPropertyParams() {
+		return {
+			id: undefined, //用于标识及传递当前编辑的实体类型 内容为DrawPoint.DrawType
+			label: {
+				text: '金田CIM三维基础平台', //文字内容
+				font: 'Helvetica', //文字字体
+				fontSize: 24, //文字字体大小
+				bolder: false, //文字是否加粗
+				italic: false, //文字是否倾斜
+				fillColor: 'rgba(0,255,0,0.75)', //文字颜色
+				showOutline: false, //是否显示描边线
+				outlineWidth: 0, //描边线宽度
+				outlineColor: 'rgba(255,255,255,1)', //描边线颜色
+				showBackground: false, //是否显示背景
+				backgroundPadding: 0, //以像素为单位指定水平和垂直背景填充。
+				backgroundColor: 'rgba(255,255,255,1)', //背景颜色
+				pixelOffsetX: 0, //横向偏移像素
+				pixelOffsetY: 0 //纵向偏移像素
+			},
+			point: {
+				color: 'rgba(0,255,0,0.75)', //点颜色
+				pixelSize: 10, //点像素大小
+				showOutline: false, //是否显示描边线
+				outlineWidth: 0, //描边线宽度
+				outlineColor: 'rgba(255,255,255,1)', //描边线颜色
+			},
+			billboard: {
+				imgUrl: 'jt3dSDK/imgs/point/point3.png', //图片路径
+				alpha: 1, //透明度
+				scale: 1, //放大比例
+			},
+			model: {
+				url: 'jt3dSDK/gltf/pyramid.glb', //模型路径
+				alpha: 1, // 模型透明度
+
+				showSilhouette: false, //是否显示模型轮廓
+				silhouetteColor: 'rgba(255,255,255,1)', // 模型轮廓颜色[0~255,0~255,0~255,0~1]
+				silhouetteSize: 0, //模型轮廓宽度
+
+				minimumPixelSize: 128, // 模型最小刻度
+				maximumScale: 20000, // 模型的最大比例尺大小,设置模型最大放大大小
+				heading: 0.0, // 以弧度为单位的航向分量
+				pitch: 0.0, //以弧度为单位的螺距分量
+				roll: 0.0, // 以弧度为单位的滚动分量
+			}
+		}
+	}
+
+	/**
+	 * 世界坐标转换为经纬度坐标
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Cartesian3} position 点
+	 */
+	_cartesian3ToGeo(position) {
+		let g = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
+		return {
+			longitude: Cesium.Math.toDegrees(g.longitude),
+			latitude: Cesium.Math.toDegrees(g.latitude),
+			height: g.height,
+		}
+	}
+
+	/**
+	 * 弧度转度
+	 * @ignore
+	 * @param {Number} arc 弧度
+	 * @return {Number} 角度
+	 */
+	_arcToDegree(arc) {
+		return arc / Math.PI * 180;
+	}
+
+	/**
+	 * 根据地形或实景或模型检测当前屏幕位置的经纬度及高度
+	 * @ignore
+	 * @param {JSON} screenPoint 屏幕坐标
+	 * @param {Number} screenPoint.x 屏幕坐标x
+	 * @param {Number} screenPoint.y 屏幕坐标y
+	 * @return {JSON} 位置信息{lng,lat,height}
+	 */
+	_getScreenClickPositionAndHeight(screenPoint) {
+		var lng = undefined,
+			lat = undefined,
+			height = undefined;
+
+		/* 从相机位置到 windowPosition 处的像素创建射线在世界坐标系中 */
+		var ray = this._viewer.scene.camera.getPickRay(screenPoint);
+		/* 找到射线与渲染的地球表面之间的交点 */
+		var position = this._viewer.scene.globe.pick(ray, this._viewer.scene);
+		/* 获取地理位置的制图表达 */
+		var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
+
+		/* 查询屏幕位置的要素 */
+		var feature = this._viewer.scene.pick(screenPoint);
+		if (feature == undefined) {
+			lng = this._arcToDegree(cartographic.longitude);
+			lat = this._arcToDegree(cartographic.latitude);
+			height = cartographic.height;
+		} else {
+			var cartesian = this._viewer.scene.pickPosition(screenPoint);
+			if (Cesium.defined(cartesian)) {
+				var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
+				lng = this._arcToDegree(cartographic.longitude);
+				lat = this._arcToDegree(cartographic.latitude);
+				height = cartographic.height;
+			}
+		}
+		/* 返回结果 */
+		return {
+			lng: lng,
+			lat: lat,
+			height: height,
+		}
+	}
+
+	/**
+	 * 屏幕位置转换为经纬度位置及空间位置
+	 * @ignore
+	 * @param {Cesium.Cartesian2} screenPosition 屏幕位置
+	 * @return {JSON} 经纬度位置及空间位置
+	 */
+	_transfromFromScreenPoint(screenPosition) {
+		/* 根据屏幕位置获取经度、纬度和高度信息 */
+		let location = this._getScreenClickPositionAndHeight(screenPosition);
+		/* 经纬度位置转换为三维坐标 */
+		var cartesian = Cesium.Cartesian3.fromDegrees(location.lng, location.lat, location.height);
+		/* 返回 */
+		return {
+			gLocation: location,
+			sLocation: cartesian,
+		}
+	}
+}
+
+/**
+ * 通用对外公开函数-鼠标事件 
+ */
+Object.assign(DrawPoint.prototype, /** @lends DrawPoint.prototype */ {
+	/**
+	 * 设置鼠标为十字样式
+	 * @ignore 生成方法时不对外公开
+	 */
+	_setMousePointerStyle() {
+		document.querySelector('body').style.cursor = 'crosshair';
+	},
+
+	/**
+	 * 恢复鼠标指针为默认样式
+	 * @ignore 生成方法时不对外公开
+	 */
+	_setMouseDefaultStyle() {
+		document.querySelector('body').style.cursor = 'default';
+	},
+
+	/**
+	 * 注册鼠标左键点击事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerLeftClickEvent(handler, callChange) {
+		let _self = this;
+		if (!handler) return;
+
+		handler.setInputAction(function(event) {
+			/* 锁定点击事件 以免和移动事件冲突 */
+			_self._lock = true;
+			clearTimeout(_self._timer);
+			_self._timer = setTimeout(function() {
+				if (callChange) callChange(event);
+				/* 解除锁定 */
+				_self._lock = false;
+			}, 200);
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+	},
+
+	/**
+	 * 注册鼠标移动事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerMouseMoveEvent(handler, callChange) {
+		let _self = this;
+		if (!handler) return;
+
+		handler.setInputAction(function(event) {
+			if (_self._lock === undefined || _self._lock === false) {
+				if (callChange) callChange(event);
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	},
+
+	/**
+	 * 注册鼠标左键按下事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerLeftDownEvent(handler, callChange) {
+		if (!handler) return;
+		handler.setInputAction(function(event) {
+			if (callChange) callChange(event);
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+	},
+
+	/**
+	 * 注册鼠标左键抬起事件
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.ScreenSpaceEventHandler} handler 事件句柄
+	 * @param {Function} callChange 回调callChange(event)
+	 */
+	_registerLeftUpEvent(handler, callChange) {
+		if (!handler) return;
+		handler.setInputAction(function(event) {
+			if (callChange) callChange(event);
+		}, Cesium.ScreenSpaceEventType.LEFT_UP);
+	},
+
+	/**
+	 * 清除事件
+	 * @ignore
+	 * @param {Cesium.ScreenSpaceEventHandler} handler
+	 */
+	_clearEvent(handler) {
+		if (!handler) return;
+
+		/* 干掉事件句柄 释放资源 */
+		handler.destroy();
+		handler = null;
+	}
+
+});
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(DrawPoint.prototype, /** @lends DrawPoint.prototype */ {
+
+	draw: function(type, options) {
+		/* 定义自身 */
+		let _self = this;
+
+		/*撤销编辑*/
+		_self._unActivateEdit();
+
+		/* 注册事件 */
+		this._drawEventHandler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
+		this._drawType = type;
+
+		/* 分类型注册事件 */
+		switch (type) {
+			case DrawPoint.DrawType.Model: //模型
+				_self._sketchDrawModel(_self._drawEventHandler, options);
+				break;
+			case DrawPoint.DrawType.Label: //文字
+				_self._sketchDrawLabel(_self._drawEventHandler, options);
+				break;
+			case DrawPoint.DrawType.Point: //点
+				_self._sketchDrawPoint(_self._drawEventHandler, options);
+				break;
+			case DrawPoint.DrawType.Point2Label: //点及文字
+				_self._sketchDrawPoint2Label(_self._drawEventHandler, options);
+				break;
+			case DrawPoint.DrawType.Billboard: //广告牌
+				_self._sketchDrawBillboard(_self._drawEventHandler, options);
+				break;
+			case DrawPoint.DrawType.Billboard2Label: //广告牌及文字
+				_self._sketchDrawBillboard2Label(_self._drawEventHandler, options);
+				break;
+		}
+	},
+
+	/**
+	 * 清理所有资源
+	 */
+	clearAll() {
+		for (var i = 0; i < this._entities.length; i++) {
+			var getById = viewer.entities.getById(this._entities[i]);
+			if (getById) {
+				this._viewer.entities.remove(getById);
+			}
+		}
+
+		/* 关闭属性编辑框 */
+		this._closePropertyEditDialog();
+	},
+
+	/**
+	 * 绘制文字工具
+	 * @ignore 生成方法时不对外公开
+	 * @param {Object} handler 事件句柄
+	 * @param {JSON} options 配置项
+	 * @param {Function} [options.onComplete(cPoint, gPoint)] 完成回调 可选
+	 * @param {Function} [options.onError(message)] 错误回到 可选
+	 */
+	_sketchDrawLabel(handler, options) {
+		let _self = this;
+		/* 注册鼠标左键点击事件 */
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 识别屏幕位置 */
+			let loc = _self._transfromFromScreenPoint(event.position);
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let entityParam = DrawPoint.initEditPropertyParams();
+			entityParam.label.font = entityParam.label.fontSize + "px " + entityParam.label.font;
+			entityParam.label.pixelOffset = {
+				x: entityParam.label.pixelOffsetX,
+				y: entityParam.label.pixelOffsetY
+			}
+
+			/* 绘制文字 */
+			_self._pointObject.addLabel(loc.sLocation, {
+				label: entityParam.label
+			}).then((entity) => {
+				_self._entities.push(entity.id);
+
+				entityParam = DrawPoint.initEditPropertyParams();
+
+				_self._drawEntity = entity;
+				/* 挂接参数到实体上 */
+				_self._drawEntity.setParams(entityParam);
+				/* 设置实体类型 */
+				_self._drawEntity.setEntityType(DrawPoint.DrawType.Label);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				_self._setEntityIsEdit(_self._drawEntity);
+
+				/* 干掉事件句柄 释放资源 */
+				_self._clearEvent(handler);
+				/* 监听输出 */
+				if (options.onComplete) options.onComplete(loc.sLocation, loc.gLocation);
+
+			});
+		})
+	},
+
+	/**
+	 * 绘制点工具
+	 * @ignore 生成方法时不对外公开
+	 * @param {Object} handler 事件句柄
+	 * @param {JSON} options 配置项
+	 * @param {Function} [options.onComplete(cPoint, gPoint)] 完成回调 可选
+	 * @param {Function} [options.onError(message)] 错误回到 可选
+	 */
+	_sketchDrawPoint(handler, options) {
+		let _self = this;
+		/* 注册鼠标左键点击事件 */
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 识别屏幕位置 */
+			let loc = _self._transfromFromScreenPoint(event.position);
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let entityParam = DrawPoint.initEditPropertyParams();
+
+			/* 绘制文字 */
+			_self._pointObject.addPoint(loc.sLocation, {
+				point: entityParam.point
+			}).then((entity) => {
+				_self._entities.push(entity.id);
+
+				entityParam = DrawPoint.initEditPropertyParams();
+
+				_self._drawEntity = entity;
+				/* 挂接参数到实体上 */
+				_self._drawEntity.setParams(entityParam);
+				/* 设置实体类型 */
+				_self._drawEntity.setEntityType(DrawPoint.DrawType.Point);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				_self._setEntityIsEdit(_self._drawEntity);
+
+				/* 干掉事件句柄 释放资源 */
+				_self._clearEvent(handler);
+				/* 监听输出 */
+				if (options.onComplete) options.onComplete(loc.sLocation, loc.gLocation);
+
+			});
+		})
+	},
+
+	/**
+	 * 绘制点及文字工具
+	 * @ignore 生成方法时不对外公开
+	 * @param {Object} handler 事件句柄
+	 * @param {JSON} options 配置项
+	 * @param {Function} [options.onComplete(cPoint, gPoint)] 完成回调 可选
+	 * @param {Function} [options.onError(message)] 错误回到 可选
+	 */
+	_sketchDrawPoint2Label(handler, options) {
+		let _self = this;
+		/* 注册鼠标左键点击事件 */
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 识别屏幕位置 */
+			let loc = _self._transfromFromScreenPoint(event.position);
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let entityParam = DrawPoint.initEditPropertyParams();
+			entityParam.label.font = entityParam.label.fontSize + "px " + entityParam.label.font;
+			entityParam.label.pixelOffset = {
+				x: entityParam.label.pixelOffsetX,
+				y: entityParam.label.pixelOffsetY - 10
+			}
+
+			/* 绘制文字 */
+			_self._pointObject.addPoint(loc.sLocation, {
+				point: entityParam.point,
+				label: entityParam.label
+			}).then((entity) => {
+				_self._entities.push(entity.id);
+
+				entityParam = DrawPoint.initEditPropertyParams();
+				entityParam.label.pixelOffsetY = -10;
+
+				_self._drawEntity = entity;
+				/* 挂接参数到实体上 */
+				_self._drawEntity.setParams(entityParam);
+				/* 设置实体类型 */
+				_self._drawEntity.setEntityType(DrawPoint.DrawType.Point2Label);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				_self._setEntityIsEdit(_self._drawEntity);
+
+				/* 干掉事件句柄 释放资源 */
+				_self._clearEvent(handler);
+				/* 监听输出 */
+				if (options.onComplete) options.onComplete(loc.sLocation, loc.gLocation);
+			});
+		})
+	},
+
+	/**
+	 * 绘制广告牌工具
+	 * @ignore 生成方法时不对外公开
+	 * @param {Object} handler 事件句柄
+	 * @param {JSON} options 配置项
+	 * @param {Function} [options.onComplete(cPoint, gPoint)] 完成回调 可选
+	 * @param {Function} [options.onError(message)] 错误回到 可选
+	 */
+	_sketchDrawBillboard(handler, options) {
+		let _self = this;
+		/* 注册鼠标左键点击事件 */
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 识别屏幕位置 */
+			let loc = _self._transfromFromScreenPoint(event.position);
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let entityParam = DrawPoint.initEditPropertyParams();
+
+			/* 绘制文字 */
+			_self._pointObject.addBillboard(loc.sLocation, {
+				billboard: entityParam.billboard
+			}).then((entity) => {
+				_self._entities.push(entity.id);
+
+				entityParam = DrawPoint.initEditPropertyParams();
+				entityParam.label.pixelOffsetY = -50;
+
+				_self._drawEntity = entity;
+				/* 挂接参数到实体上 */
+				_self._drawEntity.setParams(entityParam);
+				/* 设置实体类型 */
+				_self._drawEntity.setEntityType(DrawPoint.DrawType.Billboard);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				_self._setEntityIsEdit(_self._drawEntity);
+
+				/* 干掉事件句柄 释放资源 */
+				_self._clearEvent(handler);
+				/* 监听输出 */
+				if (options.onComplete) options.onComplete(loc.sLocation, loc.gLocation);
+			});
+		})
+	},
+
+	/**
+	 * 绘制广告牌及文字工具
+	 * @ignore 生成方法时不对外公开
+	 * @param {Object} handler 事件句柄
+	 * @param {JSON} options 配置项
+	 * @param {Function} [options.onComplete(cPoint, gPoint)] 完成回调 可选
+	 * @param {Function} [options.onError(message)] 错误回到 可选
+	 */
+	_sketchDrawBillboard2Label(handler, options) {
+		let _self = this;
+		/* 注册鼠标左键点击事件 */
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 识别屏幕位置 */
+			let loc = _self._transfromFromScreenPoint(event.position);
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let entityParam = DrawPoint.initEditPropertyParams();
+			entityParam.label.font = entityParam.label.fontSize + "px " + entityParam.label.font;
+			entityParam.label.pixelOffset = {
+				x: entityParam.label.pixelOffsetX,
+				y: entityParam.label.pixelOffsetY - 50
+			}
+
+			/* 绘制文字 */
+			_self._pointObject.addBillboard(loc.sLocation, {
+				billboard: entityParam.billboard,
+				label: entityParam.label
+			}).then((entity) => {
+				_self._entities.push(entity.id);
+
+				entityParam = DrawPoint.initEditPropertyParams();
+				entityParam.label.pixelOffsetY = -50;
+
+				_self._drawEntity = entity;
+				/* 挂接参数到实体上 */
+				_self._drawEntity.setParams(entityParam);
+				/* 设置实体类型 */
+				_self._drawEntity.setEntityType(DrawPoint.DrawType.Billboard2Label);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				_self._setEntityIsEdit(_self._drawEntity);
+
+				/* 干掉事件句柄 释放资源 */
+				_self._clearEvent(handler);
+				/* 监听输出 */
+				if (options.onComplete) options.onComplete(loc.sLocation, loc.gLocation);
+			});
+		})
+	},
+
+	/**
+	 * gltf
+	 * @ignore 生成方法时不对外公开
+	 * @param {Object} handler 事件句柄
+	 * @param {JSON} options 配置项
+	 * @param {Function} [options.onComplete(cPoint, gPoint)] 完成回调 可选
+	 * @param {Function} [options.onError(message)] 错误回到 可选
+	 */
+	_sketchDrawModel(handler, options) {
+		let _self = this;
+		/* 注册鼠标左键点击事件 */
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 识别屏幕位置 */
+			let loc = _self._transfromFromScreenPoint(event.position);
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let entityParam = DrawPoint.initEditPropertyParams();
+
+			/* 绘制文字 */
+			_self._pointObject.addModel(loc.sLocation, {
+				model: entityParam.model
+			}).then((entity) => {
+				_self._entities.push(entity.id);
+
+				entityParam = DrawPoint.initEditPropertyParams();
+
+				_self._drawEntity = entity;
+				/* 挂接参数到实体上 */
+				_self._drawEntity.setParams(entityParam);
+				/* 设置实体类型 */
+				_self._drawEntity.setEntityType(DrawPoint.DrawType.Model);
+
+				// 设置实体可编辑,编辑的实体必须包含编辑类型
+				_self._setEntityIsEdit(_self._drawEntity);
+
+				/* 干掉事件句柄 释放资源 */
+				_self._clearEvent(handler);
+				/* 监听输出 */
+				if (options.onComplete) options.onComplete(loc.sLocation, loc.gLocation);
+			});
+		})
+	},
+
+
+	/**
+	 * 更新当前编辑的实体属性
+	 * @param {JSON} params
+	 */
+	updateEditEntityProperty: function(params) {
+		let _self = this;
+		if (this._editEntity === undefined) return;
+		if (this._editEntity.getIsEdit() === undefined || this._editEntity.getIsEdit() === false) return;
+		let editEntityType = this._editEntity.getEntityType();
+		if (editEntityType === undefined) return;
+
+		if (editEntityType === DrawPoint.DrawType.Label) {
+			this._updateLabelProperty(params);
+		} else if (editEntityType === DrawPoint.DrawType.Point) {
+			this._updatePointProperty(params);
+		} else if (editEntityType === DrawPoint.DrawType.Point2Label) {
+			this._updatePoint2LabelProperty(params);
+		} else if (editEntityType === DrawPoint.DrawType.Billboard) {
+			this._updateBillboardProperty(params);
+		} else if (editEntityType === DrawPoint.DrawType.Billboard2Label) {
+			this._updateBillboard2LabelProperty(params);
+		} else if (editEntityType === DrawPoint.DrawType.Model) {
+			this._updateModelProperty(params);
+		}
+	},
+
+	/**
+	 * 更新文字的属性
+	 * @ignore 不公开方法
+	 * @param {Object} params
+	 */
+	_updateLabelProperty(params) {
+
+		let label = params.label;
+		
+		this._editEntity.label.text=label.text;
+
+		//组合字体
+		// /*font:font-style font-weight font-size/line-height font-family;*/
+		// font:italic bolder 20px/10px Arial;
+		let font = "";
+		if (label.italic) {
+			font += 'italic '
+		}
+		if (label.bolder) {
+			font += ' bolder '
+		}
+		font += label.fontSize + "px " + label.font;
+		this._editEntity.label.font = font; //字体样式
+		this._editEntity.label.fillColor = Cesium.Color.fromCssColorString(label.fillColor);
+
+		this._editEntity.label.outlineColor = Cesium.Color.fromCssColorString(label.outlineColor);
+		this._editEntity.label.outlineWidth = parseFloat(label.outlineWidth);
+
+		this._editEntity.label.showBackground = label.showBackground;
+		this._editEntity.label.backgroundColor = Cesium.Color.fromCssColorString(label.backgroundColor);
+		this._editEntity.label.backgroundPadding = new Cesium.Cartesian2(parseFloat(label.backgroundPadding), parseFloat(label.backgroundPadding));
+
+		this._editEntity.label.pixelOffset = new Cesium.Cartesian2(parseFloat(label.pixelOffsetX), parseFloat(label.pixelOffsetY));
+
+		/* 重新关联实体的属性 */
+		this._editEntity.setParams(params);
+	},
+
+	/**
+	 * 更新点的属性
+	 * @ignore 不公开方法
+	 * @param {Object} params
+	 */
+	_updatePointProperty(params) {
+		let point = params.point;
+		this._editEntity.point.color = Cesium.Color.fromCssColorString(point.color);
+		this._editEntity.point.pixelSize = parseFloat(point.pixelSize);
+		this._editEntity.point.outlineColor = Cesium.Color.fromCssColorString(point.outlineColor);
+		this._editEntity.point.outlineWidth = parseFloat(point.outlineWidth);
+
+		/* 重新关联实体的属性 */
+		this._editEntity.setParams(params);
+	},
+
+	/**
+	 * 更新点及文字的属性
+	 * @ignore 不公开方法
+	 * @param {Object} params
+	 */
+	_updatePoint2LabelProperty(params) {
+
+		let label = params.label;
+		
+		this._editEntity.label.text=label.text;
+
+		let font = "";
+		if (label.italic) {
+			font += 'italic '
+		}
+		if (label.bolder) {
+			font += ' bolder '
+		}
+		font += label.fontSize + "px " + label.font;
+		this._editEntity.label.font = font; //字体样式
+
+		this._editEntity.label.fillColor = Cesium.Color.fromCssColorString(label.fillColor);
+
+		this._editEntity.label.outlineColor = Cesium.Color.fromCssColorString(label.outlineColor);
+		this._editEntity.label.outlineWidth = parseFloat(label.outlineWidth);
+
+		this._editEntity.label.showBackground = label.showBackground;
+		this._editEntity.label.backgroundColor = Cesium.Color.fromCssColorString(label.backgroundColor);
+		this._editEntity.label.backgroundPadding = new Cesium.Cartesian2(parseFloat(label.backgroundPadding), parseFloat(label.backgroundPadding));
+
+		let point = params.point;
+		this._editEntity.point.color = Cesium.Color.fromCssColorString(point.color);
+		this._editEntity.point.pixelSize = parseFloat(point.pixelSize);
+
+		this._editEntity.point.outlineColor = Cesium.Color.fromCssColorString(point.outlineColor);
+		this._editEntity.point.outlineWidth = parseFloat(point.outlineWidth);
+
+		/* 重新关联实体的属性 */
+		this._editEntity.setParams(params);
+	},
+
+	/**
+	 * 更新广告牌的属性
+	 * @ignore 不公开方法
+	 * @param {Object} params
+	 */
+	_updateBillboardProperty(params) {
+		let billboard = params.billboard;
+
+		this._editEntity.billboard.image = billboard.imgUrl;
+		this._editEntity.billboard.scale = billboard.scale;
+
+		/* 重新关联实体的属性 */
+		this._editEntity.setParams(params);
+	},
+
+	/**
+	 * 更新广告牌及文字的属性
+	 * @ignore 不公开方法
+	 * @param {Object} params
+	 */
+	_updateBillboard2LabelProperty(params) {
+
+		let label = params.label;
+		
+		this._editEntity.label.text=label.text;
+		
+		let font = "";
+		if (label.italic) {
+			font += 'italic '
+		}
+		if (label.bolder) {
+			font += ' bolder '
+		}
+		font += label.fontSize + "px " + label.font;
+		this._editEntity.label.font = font; //字体样式
+		this._editEntity.label.fillColor = Cesium.Color.fromCssColorString(label.fillColor);
+
+		this._editEntity.label.outlineColor = Cesium.Color.fromCssColorString(label.outlineColor);
+		this._editEntity.label.outlineWidth = parseFloat(label.outlineWidth);
+
+		this._editEntity.label.showBackground = label.showBackground;
+		this._editEntity.label.backgroundColor = Cesium.Color.fromCssColorString(label.backgroundColor);
+		this._editEntity.label.backgroundPadding = new Cesium.Cartesian2(parseFloat(label.backgroundPadding), parseFloat(label.backgroundPadding));
+
+		this._editEntity.label.pixelOffset = new Cesium.Cartesian2(parseFloat(label.pixelOffsetX), parseFloat(label.pixelOffsetY));
+
+		let billboard = params.billboard;
+		this._editEntity.billboard.image = billboard.imgUrl;
+		this._editEntity.billboard.scale = billboard.scale;
+
+		/* 重新关联实体的属性 */
+		this._editEntity.setParams(params);
+	},
+
+});
+
+/**
+ * 属性编辑相关
+ */
+Object.assign(DrawPoint.prototype, {
+
+	/**
+	 * 设置实体可编辑,编辑的实体必须包含编辑类型
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Entity} entity 编辑的实体
+	 */
+	_setEntityIsEdit(entity) {
+		let _self = this;
+		/* 先撤销编辑 */
+		this._unActivateEdit();
+
+		/* 设置实体要素可编辑 */
+		entity.setIsEdit(true);
+
+		/* 激活编辑 并显示属性编辑框 */
+		this._sendShowPropertyDialog(entity);
+
+		/* 注册统一事件 用于单击拾取实体 */
+		let handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
+		this._registerLeftClickEvent(handler, function(event) {
+			/* 只要点击 就清除选中状态 */
+			_self._unActivateEdit();
+			let feature = _self._viewer.scene.pick(event.position);
+			if (feature !== undefined && feature.id instanceof Cesium.Entity) {
+				let editEntityType = feature.id.getEntityType();
+				if (editEntityType === DrawPoint.DrawType.Label ||
+					editEntityType === DrawPoint.DrawType.Point ||
+					editEntityType === DrawPoint.DrawType.Point2Label ||
+					editEntityType === DrawPoint.DrawType.Billboard ||
+					editEntityType === DrawPoint.DrawType.Billboard2Label ||
+					editEntityType === DrawPoint.DrawType.Model) {
+						
+					feature.id.setIsEdit(true);
+					_self._sendShowPropertyDialog(feature.id);
+				}
+			}
+		});
+
+		this._registerMouseMoveEvent(handler, function(event) {
+			let toolTip = "单击修改属性,单击拖动修改位置";
+
+			let feature = _self._viewer.scene.pick(event.endPosition);
+			if (feature !== undefined && feature.id instanceof Cesium.Entity) {
+				let editEntityType = feature.id.getEntityType();
+				if (editEntityType === DrawPoint.DrawType.Label ||
+					editEntityType === DrawPoint.DrawType.Point ||
+					editEntityType === DrawPoint.DrawType.Point2Label ||
+					editEntityType === DrawPoint.DrawType.Billboard ||
+					editEntityType === DrawPoint.DrawType.Billboard2Label ||
+					editEntityType === DrawPoint.DrawType.Model) {
+
+					if (feature.id.getIsEdit()) {
+						toolTip = "单击修改属性,单击拖动修改位置";
+						CreateRemindertip(toolTip, event.endPosition, true);
+					} else {
+						toolTip = "单击修改属性";
+						CreateRemindertip(toolTip, event.endPosition, true);
+					}
+				}
+			} else {
+				CreateRemindertip(toolTip, event.endPosition, false);
+			}
+		});
+	},
+
+	/**
+	 * 取消实体编辑激活状态
+	 * @ignore 生成方法时不对外公开
+	 */
+	_unActivateEdit: function() {
+		/* 清理事件句柄 */
+		if (this._sketchEditHandler != undefined) {
+			this._sketchEditHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
+			this._sketchEditHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP);
+			this._sketchEditHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+		}
+		this._editEntity = undefined;
+
+		for (var i = 0; i < this._entities.length; i++) {
+			var getById = this._viewer.entities.getById(this._entities[i]);
+			if (getById) {
+				getById.setIsEdit(false);
+			}
+		}
+
+		/* 关闭属性编辑框 */
+		this._closePropertyEditDialog();
+	},
+
+
+	/**
+	 * 打开实体编辑对话框
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Entity} entity
+	 */
+	_sendShowPropertyDialog(entity) {
+
+		let _self = this;
+		/* 获取可编辑实体的类型 */
+		let editEntityType = entity.getEntityType();
+		if (entity.getIsEdit() === undefined || entity.getIsEdit() === false || editEntityType === undefined) {
+			/* 选择的实体不可编辑 */
+			this._unActivateEdit();
+			return;
+		}
+
+		/* 编辑属性 */
+		let editProperty = entity.getParams();
+		if (editProperty !== undefined && this.onEditProperty !== undefined) {
+			editProperty.id = editEntityType;
+
+			/* 更改测试 */
+			_self._openPropertyEditDialog(editProperty,
+				//编辑回调
+				function(params) {
+					_self.updateEditEntityProperty(params);
+				},
+				//移除回调
+				function() {
+					_self._viewer.entities.remove(entity);
+					_self._editEntity = undefined;
+				}
+			);
+		}
+
+		this._activeteNormalEdit(entity);
+	},
+
+	/**
+	 * 激活编辑单实体
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Entity} editEntity 编辑实体
+	 */
+	_activeteNormalEdit: function(editEntity) {
+		let _self = this;
+
+		/* 获取编辑类型 */
+		let entityType = editEntity.getEntityType();
+		/* 赋值可编辑对象 */
+		this._editEntity = editEntity;
+
+		/* 创建事件句柄 */
+		if (this._sketchEditHandler === undefined) {
+			this._sketchEditHandler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
+		}
+		/* 注册鼠标左键按下事件 */
+		this._registerLeftDownEvent(this._sketchEditHandler, function(event) {
+			const pickInfo = _self._viewer.scene.pick(event.position);
+			console.log(pickInfo)
+
+			if (!pickInfo) {
+				return;
+			}
+
+			console.log("按下")
+
+			// 如果点击空白区域,则不往下执行
+			_self._viewer.scene.screenSpaceCameraController.enableRotate = false; // 将相机锁定,不然后续移动实体时相机也会动
+
+			/* 注册鼠标移动事件 */
+			_self._registerMouseMoveEvent(_self._sketchEditHandler, function(event) {
+				console.log("移动")
+				const position = event.endPosition; // event有startPosition与endPosition两个属性,即移动前后的位置信息:Cartesian2对象
+				const cartesian = _self._viewer.scene.globe.pick(_self._viewer.camera.getPickRay(position), _self._viewer.scene); //将Cartesian2转为Cartesian3
+				const selectedEntity = _self._editEntity; // 实体
+				if (!selectedEntity) {
+					return false;
+				}
+
+				//注意需要赋值三维坐标,// 更新实体位置为当前鼠标位置
+				selectedEntity.position = cartesian;
+
+			});
+			/* 注册鼠标抬起事件 */
+			_self._registerLeftUpEvent(_self._sketchEditHandler, function(event) {
+				_self._sketchEditHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE); // 解除viewer的MOUSE_MOVE事件监听器
+				_self._sketchEditHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP); // 解除viewer的LEFT_UP事件监听器
+				_self._viewer.scene.screenSpaceCameraController.enableRotate = true; // 取消相机锁定
+				console.log("抬起")
+			});
+		});
+	},
+
+	/**
+	 * 更新模型的属性
+	 * @ignore 不公开方法
+	 * @param {Object} params
+	 */
+	_updateModelProperty(params) {
+
+		let model = params.model;
+		this._editEntity.model.uri = model.url;
+
+		this._editEntity.model.color = Cesium.Color.WHITE.withAlpha(model.alpha);
+
+		this._editEntity.model.minimumPixelSize = model.minimumPixelSize;
+		this._editEntity.model.maximumScale = model.maximumScale;
+
+		this._editEntity.model.silhouetteSize = model.silhouetteSize;
+		this._editEntity.model.silhouetteColor = new Cesium.Color.fromCssColorString(model.silhouetteColor);
+
+		//弧度的航向分量。
+		var heading = Cesium.Math.toRadians(model.heading);
+		//弧度的螺距分量。
+		var pitch = model.pitch;
+		//滚动分量(以弧度为单位)
+		var roll = model.roll;
+		//HeadingPitchRoll旋转表示为航向,俯仰和滚动。围绕Z轴。节距是绕负y轴的旋转。滚动是关于正x轴。
+		var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
+		// this._editEntity.orientation = Cesium.Transforms.headingPitchRollQuaternion(this._editEntity.position, hpr); // 模型方向
+
+		/* 重新关联实体的属性 */
+		this._editEntity.setParams(params);
+	},
+})
+
+
+/**
+ * 属性编辑相关(UI)
+ */
+Object.assign(DrawPoint.prototype, {
+
+	/**
+	 * 打开属性编辑窗口
+	 * @ignore
+	 * @param {JSON} params 参数
+	 * @param {Function} callEdit 编辑回调
+	 * @param {Function} callRemove 移除回调
+	 */
+	_openPropertyEditDialog: function(params, callEdit, callRemove) {
+
+		this._editPropertyDialogDomId = 'dialog-property-dom-point';
+		this._registerDOMPropertyEdit = 'dialog-edit-property-point';
+
+		/* 获取一个属性编辑组件 */
+		let PropertyEditComponent = customElements.get(this._registerDOMPropertyEdit);
+		/* 如果组件还未注册 则进行注册 否则不在注册 避免重复注册的BUG */
+		if (PropertyEditComponent === undefined) {
+			PropertyEditComponent = defineCustomElement(DialogEditProperty);
+			customElements.define(this._registerDOMPropertyEdit, PropertyEditComponent);
+		}
+
+		/* 先关闭编辑框 */
+		this._closePropertyEditDialog();
+		/* 创建组件 */
+		let dialogPropertyElement = new PropertyEditComponent({
+			params: params,
+		})
+		dialogPropertyElement.id = this._editPropertyDialogDomId;
+		dialogPropertyElement.showDialog = true;
+		document.body.appendChild(dialogPropertyElement);
+
+		/* 监听修改事件 */
+		dialogPropertyElement.addEventListener(
+			"submit",
+			(e) => {
+				if (callEdit) callEdit(e.detail[0]);
+			},
+			false
+		);
+		/* 监听移除事件 */
+		dialogPropertyElement.addEventListener(
+			"remove",
+			(e) => {
+				if (callRemove) callRemove();
+			},
+			false
+		);
+	},
+
+	/**
+	 * 关闭属性编辑框
+	 * @ignore
+	 */
+	_closePropertyEditDialog() {
+		let dom = document.getElementById(this._editPropertyDialogDomId);
+		if (dom !== null && dom !== undefined) {
+			document.body.removeChild(dom);
+		}
+	},
+})
+
+/**
+ * 绘制类型
+ */
+DrawPoint.DrawType = Object.freeze({
+	Model: 'model', //模型
+	Label: 'label', //文字
+	Point: 'point', //点
+	Point2Label: 'point2Label', //点及文字
+	Billboard: 'billboard', //广告牌
+	Billboard2Label: 'billboard2Label', //广告牌及文字
+
+})
+
+
+export default DrawPoint;

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 200 - 0
packages/Widgets/DrawTools/DrawTools.js


+ 672 - 0
packages/Widgets/DrawTools/MilitaryPlot/EntityEdit.js

@@ -0,0 +1,672 @@
+import * as turf from "@turf/turf"
+
+export default class EntityEdit {
+	constructor(viewer) {
+		this.viewer = viewer;
+		this.DrawExample = '';
+		this.midVertexEntities = [];
+		this.initEventHandler();
+	}
+
+	//鼠标事件
+	initEventHandler() {
+		this.eventHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+		this.EditEndEvent = new Cesium.Event();
+		this.EditEndEntity = new Cesium.Event();
+	}
+
+	//激活编辑
+	activate() {
+		this.deactivate();
+		//鼠标左键点击事件 鼠标左键点击拾取需要编辑的对象
+		this.initLeftClickEventHandler();
+	}
+
+	//禁用编辑
+	deactivate() {
+		this.DrawExample = '';
+		this.eventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
+		this.unRegisterEvents();
+		this.clearAllEditVertex();
+	}
+
+	//清空编辑节点
+	clearAllEditVertex() {
+		this.clearEditVertex();
+		this.clearMidVertex();
+	}
+
+	//左键点击事件
+	initLeftClickEventHandler() {
+		this.eventHandler.setInputAction(e => {
+
+			let id = this.viewer.scene.pick(e.position);
+			if (!id || !id.id) {
+				this.handleEditEntity();
+				return; // 没有拾取到对象 直接返回 不做任何操作
+			}
+
+			// 拾取到对象 判断拾取到的对象类型
+			if (!id.id || !id.id.Type) return;
+			//重复点击同一个对象
+			if (this.editEntity && this.editEntity.id == id.id.id) return;
+			// if (this.editEntity) return
+			//拾取到新的GeoPlot对象
+			this.handleEditEntity(); //处理上一个编辑对象
+			this.handlePickEditEntity(id.id);
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+	}
+
+	//处理编辑对象
+	handleEditEntity() {
+		this.unRegisterEvents();
+		this.clearAllEditVertex();
+		let editEntity = this.editEntity;
+		if (!editEntity) return;
+		this.closeEntityEditMode();
+		this.editEntity = undefined;
+		if (!this.isEdited) return; //没有任何编辑 直接返回   
+
+		// console.log("对象被编辑过是否需要保存操作??");
+
+		//触发编辑事件  
+		this.EditEndEvent.raiseEvent(editEntity);
+		this.isEdited = false;
+		this.isEditing = false;
+	}
+
+	//处理拾取到的对象
+	handlePickEditEntity(pickId) {
+		const EditableTypes = ["DrawAttackArrow", "DrawCircle", "DrawCurve", 'DrawPincerArrow', 'DrawPoint', 'DrawPolygon', 'DrawPolyline', 'DrawRectangle', 'DrawStraightArrow', 'DrawGatheringPlace', 'DrawSector', 'DrawClosedCurve', 'DrawBowLine', 'DrawBowPlane', 'DrawRectFlag', 'DrawTriangleFlag', 'DrawCurveFlag'];
+		if (EditableTypes.indexOf(pickId.Type) == -1) return;
+		this.editEntity = pickId;
+		this.EditEndEntity.raiseEvent(this.editEntity);
+		this.isEditing = false;
+		this.isEdited = false;
+
+		this.editPositions = this.getEditEntityPositions();
+		this.EditMoveCenterPositoin = this.getCenterPosition();
+
+		this.openEntityEditModel();
+
+		this.clearAllEditVertex();
+		this.unRegisterEvents();
+		this.createEditVertex();
+		this.createMidVertex();
+		this.registerEvents();
+	}
+
+	openEntityEditModel() {
+		if (this.DrawExample == '') return
+		switch (this.editEntity.Type) {
+			case "DrawStraightArrow":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawAttackArrow":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawPincerArrow":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawGatheringPlace":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawClosedCurve":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions).PolygonHierarchy;
+				}, false);
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions).pList;
+				}, false);
+				break;
+			case "DrawCircle":
+				this.editEntity.position = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions).position
+				}, false)
+				this.editEntity.ellipse.semiMinorAxis = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions).r
+				}, false);
+				this.editEntity.ellipse.semiMajorAxis = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions).r
+				}, false);
+				break;
+			case "DrawCurve":
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+
+			case "DrawPoint":
+				this.editEntity.position = new Cesium.CallbackProperty(e => {
+					return this.editPositions[0];
+				}, false);
+				break;
+			case "DrawPolygon":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawPolyline":
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawRectangle":
+				this.editEntity.rectangle.coordinates = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+
+			case "DrawSector":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+
+			case "DrawBowLine":
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawBowPlane":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions);
+				}, false);
+				break;
+			case "DrawRectFlag":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions)[0]
+				}, false);
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions)[1];
+				}, false);
+				break;
+
+			case "DrawTriangleFlag":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions)[0]
+				}, false);
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions)[1];
+				}, false);
+				break;
+
+			case "DrawCurveFlag":
+				this.editEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions)[0]
+				}, false);
+				this.editEntity.polyline.positions = new Cesium.CallbackProperty(e => {
+					return this.DrawExample.computePosition(this.editPositions)[1];
+				}, false);
+				break;
+		}
+	}
+
+	closeEntityEditMode() {
+		if (this.DrawExample == '') return
+		let position = '';
+		switch (this.editEntity.Type) {
+			case "DrawStraightArrow":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawAttackArrow":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawPincerArrow":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawGatheringPlace":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawClosedCurve":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position.PolygonHierarchy;
+				this.editEntity.polyline.positions = position.pList;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawCircle":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.position = position.position
+				this.editEntity.ellipse.semiMinorAxis = position.r;
+				this.editEntity.ellipse.semiMajorAxis = position.r;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawCurve":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polyline.positions = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+
+			case "DrawPoint":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.position = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawPolygon":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawPolyline":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polyline.positions = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawRectangle":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.rectangle.coordinates = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+
+			case "DrawSector":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+
+			case "DrawBowLine":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polyline.positions = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+			case "DrawBowPlane":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position;
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+
+			case "DrawRectFlag":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position[0];
+				this.editEntity.polyline.positions = position[1];
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+
+			case "DrawTriangleFlag":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position[0];
+				this.editEntity.polyline.positions = position[1];
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+
+			case "DrawCurveFlag":
+				position = this.DrawExample.computePosition(this.editPositions);
+				this.editEntity.polygon.hierarchy = position[0];
+				this.editEntity.polyline.positions = position[1];
+				this.editEntity.Position = this.DrawExample.getData();
+				break;
+		}
+	}
+
+	getEditEntityPositions() {
+		let position = this.editEntity.Position;
+		let positionArr = [];
+		switch (this.editEntity.Type) {
+			case "DrawAttackArrow":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawCircle":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawCurve":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawPincerArrow":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawPoint":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawPolygon":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawPolyline":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawRectangle":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawStraightArrow":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawGatheringPlace":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawSector":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawClosedCurve":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawBowLine":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawBowPlane":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+			case "DrawRectFlag":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+
+			case "DrawTriangleFlag":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+
+			case "DrawCurveFlag":
+				for (let i = 0; i < position.length; i++) {
+					positionArr.push(this.LatlngTocartesian(position[i]))
+				}
+				return positionArr;
+		}
+	}
+
+	//注册事件监听
+	registerEvents() {
+		//鼠标左键按下事件 当有对象被选中时 如果拾取到编辑辅助要素 表示开始改变对象的位置
+		this.initLeftDownEventHandler();
+		//鼠标移动事件 鼠标移动 如果有编辑对象 表示改变编辑对象的位置
+		this.initMouseMoveEventHandler();
+		//鼠标左键抬起事件 当有编辑对象时  
+		this.initLeftUpEventHandler();
+	}
+
+	//取消事件监听
+	unRegisterEvents() {
+		this.eventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
+		this.eventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP);
+		this.eventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	}
+
+	//场景鼠标左键按下事件
+	initLeftDownEventHandler() {
+		this.eventHandler.setInputAction((e) => {
+			let id = this.viewer.scene.pick(e.position);
+			// 拾取到对象 判断拾取到的对象类型 
+			if (!id || !id.id || !id.id.type) return;
+			//拾取到具有type 属性的entity对象 
+			if (id.id.type == "EditVertex" || id.id.type == "EditMove") {
+				this.isEditing = true;
+				//禁用场景的旋转移动功能 保留缩放功能
+				this.viewer.scene.screenSpaceCameraController.enableRotate = false;
+				//改变鼠标状态
+				this.viewer.enableCursorStyle = false;
+				this.viewer._element.style.cursor = '';
+				document.body.style.cursor = "move";
+				this.editVertext = id.id;
+				this.editVertext.show = false;
+				this.clearMidVertex();
+			} else if (id.id.type == "EditMidVertex") {
+				this.editPositions.splice(id.id.vertexIndex, 0, id.id.position._value);
+				this.clearAllEditVertex();
+				this.createEditVertex();
+				this.createMidVertex();
+				this.isEdited = true;
+			} else {
+				return
+			}
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+	}
+
+	//场景鼠标左键抬起事件
+	initLeftUpEventHandler() {
+		this.eventHandler.setInputAction(((e) => {
+			if (!this.isEditing) return;
+			this.viewer.enableCursorStyle = true;
+			document.body.style.cursor = "default";
+			this.viewer.scene.screenSpaceCameraController.enableRotate = true;
+			this.editVertext.show = true;
+			this.isEditing = false;
+			this.clearMidVertex();
+			this.createMidVertex();
+		}), Cesium.ScreenSpaceEventType.LEFT_UP);
+	}
+
+	//场景鼠标移动事件
+	initMouseMoveEventHandler() {
+		this.eventHandler.setInputAction(((e) => {
+			var position = e.endPosition;
+			var ray = this.viewer.scene.camera.getPickRay(position);
+			var cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+			if (!cartesian) return;
+
+			if (!this.isEditing) return;
+			if (this.editVertext.type == "EditMove") {
+				let startPosition = this.EditMoveCenterPositoin;
+				if (!startPosition) return;
+				this.moveEntityByOffset(startPosition, cartesian);
+			} else if (this.editVertext.type == "EditVertex" || this.editVertext.type == "EditMidVertex") {
+				this.editPositions[this.editVertext.vertexIndex] = cartesian;
+			}
+			this.isEdited = true;
+			this.EditMoveCenterPositoin = this.getCenterPosition();
+		}), Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	}
+
+	//获取编辑对象中心点
+	getCenterPosition() {
+		let points = [];
+		let maxHeight = 0;
+		//如果是点 返回第一个点作为移动点
+		if (this.editEntity.Type == "DrawCircle" || this.editEntity.Type == "DrawPoint" || this.editEntity.Type == "DrawSector") {
+			return this.editPositions[0];
+		}
+
+		//获取所有节点的最高位置
+		this.editPositions.forEach(position => {
+			const point3d = this.cartesian3ToPoint3D(position);
+			points.push([point3d.x, point3d.y]);
+			if (maxHeight < point3d.z) maxHeight = point3d.z;
+		})
+
+		//构建turf.js  lineString
+		let geo = turf.lineString(points);
+		let bbox = turf.bbox(geo);
+		let bboxPolygon = turf.bboxPolygon(bbox);
+		let pointOnFeature = turf.center(bboxPolygon);
+		let lonLat = pointOnFeature.geometry.coordinates;
+		return Cesium.Cartesian3.fromDegrees(lonLat[0], lonLat[1], maxHeight);
+	}
+
+	//根据偏移量移动实体
+	moveEntityByOffset(startPosition, endPosition) {
+		let startPoint3d = this.cartesian3ToPoint3D(startPosition);
+		let endPoint3d = this.cartesian3ToPoint3D(endPosition);
+		let offsetX = endPoint3d.x - startPoint3d.x;
+		let offsetY = endPoint3d.y - startPoint3d.y;
+		//设置偏移量
+		let element;
+		for (let i = 0; i < this.editPositions.length; i++) {
+			element = this.cartesian3ToPoint3D(this.editPositions[i]);
+			element.x += offsetX;
+			element.y += offsetY;
+			this.editPositions[i] = Cesium.Cartesian3.fromDegrees(element.x, element.y, element.z)
+		}
+	}
+
+	//创建编辑节点
+	createEditVertex() {
+		this.vertexEntities = [];
+		this.editPositions.forEach((p, index) => {
+			const entity = this.viewer.entities.add({
+				position: new Cesium.CallbackProperty(e => {
+					return this.editPositions[index];
+				}, false),
+				type: "EditVertex",
+				vertexIndex: index, //节点索引 
+				point: {
+					show: true,
+					pixelSize: 10,
+					color: new Cesium.Color(0, 0, 1, 1),
+					outlineWidth: 1,
+					outlineColor: new Cesium.Color(1, 1, 1, 1),
+					disableDepthTestDistance: 1.5e12, //小于该数值后关闭深度检测默认为空
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+				},
+			})
+			this.vertexEntities.push(entity);
+		});
+		// 如果是圆则隐藏中心点
+		if (this.editEntity.Type == 'DrawCircle') {
+			this.vertexEntities[0].show = false
+		}
+		if (this.editPositions.length == 1) { //只有一个节点表示点类型 不需要创建整体移动节点
+			return;
+		}
+		this.createEditMoveCenterEntity();
+	}
+
+	//整体移动
+	createEditMoveCenterEntity() {
+		this.EditMoveCenterEntity = this.viewer.entities.add({
+			position: new Cesium.CallbackProperty(e => {
+				return this.EditMoveCenterPositoin;
+			}, false),
+			type: "EditMove",
+			point: {
+				show: true,
+				pixelSize: 12,
+				color: new Cesium.Color(0, 1, 0, 0.1),
+				outlineWidth: 2,
+				outlineColor: new Cesium.Color(1, 1, 1, 1),
+				disableDepthTestDistance: 1.5e12, //小于该数值后关闭深度检测默认为空
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			},
+		})
+	}
+
+	//清空编辑节点
+	clearEditVertex() {
+		if (this.vertexEntities) {
+			this.vertexEntities.forEach(item => {
+				this.viewer.entities.remove(item);
+			})
+		}
+		this.vertexEntities = [];
+		this.viewer.entities.remove(this.EditMoveCenterEntity);
+	}
+
+	//创建中点节点
+	createMidVertex() {
+		if (this.editEntity.Type == 'DrawCircle' || this.editEntity.Type == 'DrawPincerArrow' || this.editEntity.Type == 'DrawRectangle' || this.editEntity.Type == 'DrawStraightArrow' || this.editEntity.Type == 'DrawGatheringPlace' || this.editEntity.Type == "DrawSector" || this.editEntity.Type == "DrawBowLine" || this.editEntity.Type == "DrawBowPlane" || this.editEntity.Type == "DrawRectFlag" || this.editEntity.Type == "DrawTriangleFlag" || this.editEntity.Type == "DrawCurveFlag") {
+			return
+		}
+		this.midVertexEntities = [];
+		for (let i = 0; i < this.editPositions.length; i++) {
+			const p1 = this.editPositions[i];
+			const p2 = this.editPositions[i + 1];
+			let mideP = this.midPosition(p1, p2);
+			const entity = this.viewer.entities.add({
+				position: mideP,
+				type: "EditMidVertex",
+				vertexIndex: i + 1, //节点索引 
+				point: {
+					show: true,
+					pixelSize: 10,
+					color: new Cesium.Color(0, 1, 0, 1),
+					outlineWidth: 1,
+					outlineColor: new Cesium.Color(1, 1, 1, 1),
+					disableDepthTestDistance: 1.5e12, //小于该数值后关闭深度检测默认为空
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+				},
+			})
+			this.midVertexEntities.push(entity);
+		}
+	}
+
+	//清空中点节点
+	clearMidVertex() {
+		if (this.midVertexEntities) {
+			this.midVertexEntities.forEach(item => {
+				this.viewer.entities.remove(item);
+			})
+		}
+		this.midVertexEntities = [];
+	}
+
+	//笛卡尔坐标转为经纬度xyz
+	cartesian3ToPoint3D(position) {
+		const cartographic = Cesium.Cartographic.fromCartesian(position);
+		const lon = Cesium.Math.toDegrees(cartographic.longitude);
+		const lat = Cesium.Math.toDegrees(cartographic.latitude);
+		return {
+			x: lon,
+			y: lat,
+			z: cartographic.height
+		};
+	}
+
+	//获取两个节点的中心点
+	midPosition(first, second) {
+		if (!first || !second) return null;
+		let point3d1 = this.cartesian3ToPoint3D(first);
+		let point3d2 = this.cartesian3ToPoint3D(second);
+		let midLonLat = {
+			x: (point3d1.x + point3d2.x) / 2,
+			y: (point3d1.y + point3d2.y) / 2,
+			z: (point3d1.z + point3d2.z) / 2
+		}
+		return Cesium.Cartesian3.fromDegrees(midLonLat.x, midLonLat.y, midLonLat.z);
+	}
+
+
+	cartesianToLatlng(cartesian) {
+		let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		let lat = new Cesium.Math.toDegrees(cartographic.latitude);
+		let lng = new Cesium.Math.toDegrees(cartographic.longitude);
+		let alt = cartographic.height;
+		return [lng, lat];
+	}
+
+	LatlngTocartesian(latlng) {
+		let cartesian3 = new Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+		return cartesian3
+	}
+}

+ 576 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawAttackArrow.js

@@ -0,0 +1,576 @@
+import {
+	createTooltip
+} from "../../../common/common.js";
+
+import {
+	isRuntimeApp,
+	isRuntimeWeb,
+	createOperationMainDom,
+	showTooltipMessage
+} from "../../../common/RuntimeEnvironment.js";
+
+/*
+七、绘制攻击箭头
+ */
+class DrawAttackArrow {
+	constructor(arg) {
+		//设置唯一id 备用
+		this.objId = Number((new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0));
+		this.viewer = arg.viewer;
+		this.Cesium = arg.Cesium;
+		// this.callback=arg.callback;
+		this.floatingPoint = null; //标识点
+		this._AttackArrow = null; //活动箭头
+		this._AttackArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_AttackArrow = []; //脏数据
+		this._AttackArrowData = null; //用于构造箭头数据
+		this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+		this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+
+		this._tooltip = createTooltip(this.viewer.container);
+
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+	}
+
+	//返回箭头
+	get AttackArrow() {
+		return this._AttackArrowLast;
+	}
+
+	//返回箭头数据用于加载箭头
+	getData() {
+		return this._AttackArrowData;
+	}
+
+	//加载箭头
+	addload(data) {
+		var $this = this;
+		if (data.length < 3) {
+			return null;
+		}
+		var res = $this.fineArrow(data);
+		var returnData = res.polygonalPoint;
+		var arrowEntity = $this.viewer.entities.add({
+			Type: 'DrawAttackArrow',
+			Position: data,
+			id: data.id || $this.objId,
+			polygon: {
+				hierarchy: new $this.Cesium.PolygonHierarchy(returnData),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		});
+		return arrowEntity
+	}
+
+	// 修改编辑调用计算
+	computePosition(data) {
+		//计算面
+		let $this = this
+		var lnglatArr = [];
+		for (var i = 0; i < data.length; i++) {
+			var lnglat = $this.cartesianToLatlng(data[i]);
+			lnglatArr.push(lnglat)
+		}
+		$this._AttackArrowData = lnglatArr;
+		var res = $this.fineArrow(lnglatArr);
+		var returnData = res.polygonalPoint;
+		return new $this.Cesium.PolygonHierarchy(returnData)
+	}
+
+	//开始创建
+	startCreate(drawType) {
+		if (isRuntimeApp()) {
+			showTooltipMessage("点击开始绘制");
+		}
+
+		var $this = this;
+
+		this.drawType = drawType;
+		this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas);
+
+		//单击开始绘制
+		this.handler.setInputAction(function(evt) {
+
+			if (isRuntimeApp()) {
+
+				//屏幕坐标转地形上坐标
+				var cartesian = $this.getCatesian3FromPX(evt.position);
+				if (!cartesian) {
+					return;
+				}
+
+				$this.createPoint(cartesian); // 绘制点
+				$this._positions.push(cartesian);
+
+				if ($this._positions.length <= 2) {
+					showTooltipMessage("点击添加点");
+				} else {
+					showTooltipMessage("点击添加点,点击完成按钮,结束绘制");
+					if ($this._positions.length === 3) {
+						if (!$this.Cesium.defined($this._AttackArrow)) {
+							$this._AttackArrow = $this.createAttackArrow();
+
+							//创建按钮
+							createOperationMainDom();
+							//隐藏回退按钮
+							document.getElementById("btnDrawBackout").style.display = 'none';
+							//完成绘制
+							document.getElementById("btnDrawComplete").onclick = () => {
+
+								$this._AttackArrowData = $this._positions.concat();
+								$this.viewer.entities.remove($this._AttackArrow); //移除
+								$this._AttackArrow = null;
+								$this._positions = [];
+
+								let lnglatArr = [];
+								for (var i = 0; i < $this._AttackArrowData.length; i++) {
+									var lnglat = $this.cartesianToLatlng($this._AttackArrowData[i]);
+									lnglatArr.push(lnglat)
+								}
+								$this._AttackArrowData = lnglatArr;
+								var straightArrow = $this.addload(lnglatArr); //加载
+								$this._entities_AttackArrow.push(straightArrow);
+								$this._AttackArrowLast = straightArrow;
+								$this.clearPoint();
+								$this.destroy();
+
+								let buttonDiv = document.getElementById("drawButtonDiv");
+								if (buttonDiv) {
+									//从页面移除
+									document.body.removeChild(buttonDiv);
+								}
+							}
+						}
+					}
+				}
+			} else {
+
+				console.log('监听鼠标事件', '单击')
+
+				/* 锁定点击事件 以免和双击事件冲突 */
+				clearTimeout($this._timer);
+				$this._timer = setTimeout(function() {
+					//屏幕坐标转地形上坐标
+					var cartesian = $this.getCatesian3FromPX(evt.position);
+					if (!cartesian) {
+						return;
+					}
+					if ($this._positions.length == 0) {
+						// $this._positions.push(cartesian.clone());
+						$this.floatingPoint = $this.createPoint(cartesian);
+						$this.createPoint(cartesian); // 绘制点
+					}
+					if ($this._positions.length == 1) {
+						$this._positions.push(cartesian.clone());
+						$this.createPoint(cartesian); // 绘制点
+					}
+					$this._positions.push(cartesian);
+
+				}, 200);
+			}
+
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+		//移动时绘制面
+		this.handler.setInputAction(function(evt) {
+
+			/* 如果运行环境是App 则禁止使用鼠标移动事件 */
+			if (isRuntimeApp()) return;
+
+			// console.log('监听鼠标事件', '移动')
+
+			if ($this._positions.length == 0) {
+				$this._tooltip.showAt(evt.endPosition, "点击开始绘制");
+			} else {
+				$this._tooltip.showAt(evt.endPosition, "点击添加点");
+			}
+
+			if ($this._positions.length < 3) return;
+
+			// $this._tooltip.showAt(evt.endPosition, "点击添加点,右键删除点,双击结束绘制");
+			$this._tooltip.showAt(evt.endPosition, "点击添加点,双击结束绘制");
+
+			if (!$this.Cesium.defined($this._AttackArrow)) {
+				$this._AttackArrow = $this.createAttackArrow();
+			}
+
+			var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+			if (!cartesian) {
+				return;
+			}
+
+			$this.floatingPoint.position.setValue(cartesian);
+			if ($this._AttackArrow) {
+				$this._positions.pop();
+				$this._positions.push(cartesian);
+			}
+		}, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+		//右键结束改为双击结束
+		this.handler.setInputAction(function(evt) {
+			// var cartesian = $this.getCatesian3FromPX(evt.position);
+			// $this._positions.pop();
+			// // $this._positions.push(cartesian);
+			// $this._AttackArrowData = $this._positions.concat();
+			// $this.viewer.entities.remove($this._AttackArrow); //移除
+			// $this._AttackArrow = null;
+			// $this._positions = [];
+			// $this.floatingPoint.position.setValue(cartesian);
+			// let lnglatArr = [];
+			// for (var i = 0; i < $this._AttackArrowData.length; i++) {
+			// 	var lnglat = $this.cartesianToLatlng($this._AttackArrowData[i]);
+			// 	lnglatArr.push(lnglat)
+			// }
+			// $this._AttackArrowData = lnglatArr;
+			// var straightArrow = $this.addload(lnglatArr); //加载
+			// $this._entities_AttackArrow.push(straightArrow);
+			// $this._AttackArrowLast = straightArrow;
+			// $this.clearPoint();
+			// $this.destroy()
+		}, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+		//双击结束
+		this.handler.setInputAction(function(evt) {
+
+			/* 如果运行环境是App 则禁止使用鼠标双击事件 */
+			if (isRuntimeApp()) return;
+
+			console.log('监听鼠标事件', '双击')
+
+			/* 解除锁定 */
+			clearTimeout($this._timer);
+
+			var cartesian = $this.getCatesian3FromPX(evt.position);
+			$this._positions.pop();
+			$this._positions.push(cartesian);
+			$this._AttackArrowData = $this._positions.concat();
+			$this.viewer.entities.remove($this._AttackArrow); //移除
+			$this._AttackArrow = null;
+			$this._positions = [];
+			$this.floatingPoint.position.setValue(cartesian);
+			let lnglatArr = [];
+			for (var i = 0; i < $this._AttackArrowData.length; i++) {
+				var lnglat = $this.cartesianToLatlng($this._AttackArrowData[i]);
+				lnglatArr.push(lnglat)
+			}
+			$this._AttackArrowData = lnglatArr;
+			var straightArrow = $this.addload(lnglatArr); //加载
+			$this._entities_AttackArrow.push(straightArrow);
+			$this._AttackArrowLast = straightArrow;
+			$this.clearPoint();
+			$this.destroy();
+
+			$this._tooltip.setVisible(false);
+
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
+	}
+
+	//创建攻击箭头
+	createAttackArrow() {
+		var $this = this;
+		var arrowEntity = $this.viewer.entities.add({
+			polygon: {
+				hierarchy: new $this.Cesium.CallbackProperty(
+					function() {
+						//计算面
+						var lnglatArr = [];
+						for (var i = 0; i < $this._positions.length; i++) {
+							var lnglat = $this.cartesianToLatlng($this._positions[i]);
+							lnglatArr.push(lnglat)
+						}
+						var res = $this.fineArrow(lnglatArr);
+						var returnData = res.polygonalPoint;
+						return new $this.Cesium.PolygonHierarchy(returnData);
+					}, false),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		})
+		$this._entities_AttackArrow.push(arrowEntity);
+		return arrowEntity
+	}
+
+	//创建点
+	createPoint(cartesian) {
+		var $this = this;
+		var point = this.viewer.entities.add({
+			position: cartesian,
+			point: {
+				pixelSize: 10,
+				color: $this.Cesium.Color.RED,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			}
+		});
+		point.objId = this.objId;
+		$this._entities_point.push(point);
+		return point;
+	}
+
+	cartesianToLatlng(cartesian) {
+		let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
+		let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
+		let alt = cartographic.height;
+		return [lng, lat, alt];
+	}
+
+	//销毁
+	destroy() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+	}
+
+	clearPoint() {
+		this.DrawEndEvent.raiseEvent(this._AttackArrowLast, this._AttackArrowData, this.drawType);
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		this._entities_point = []; //脏数据
+	}
+
+	//清空实体对象
+	clear() {
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		for (var i = 0; i < this._entities_AttackArrow.length; i++) {
+			this.viewer.entities.remove(this._entities_AttackArrow[i]);
+		}
+
+		this.floatingPoint = null; //标识点
+		this._AttackArrow = null; //活动箭头
+		this._AttackArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_AttackArrow = []; //脏数据
+		this._AttackArrowData = null; //用于构造箭头数据
+	}
+
+	getCatesian3FromPX(px) {
+		var cartesian;
+		var ray = this.viewer.camera.getPickRay(px);
+		if (!ray) return null;
+		cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+		return cartesian;
+	}
+
+	////////////////////////////////////////求取箭头坐标函数/////////////////////////////////////////////////////
+	//箭头配置函数
+	fineArrowDefualParam() {
+		return {
+			headHeightFactor: .18,
+			headWidthFactor: .3,
+			neckHeightFactor: .85,
+			neckWidthFactor: .15,
+			tailWidthFactor: .1,
+			headTailFactor: .8,
+			swallowTailFactor: 1
+		}
+	}
+
+	fineArrow(inputPoint) {
+		var $this = this;
+		inputPoint = $this.dereplication(inputPoint);
+		let tailWidthFactor = $this.fineArrowDefualParam().tailWidthFactor;
+		let swallowTailFactor = $this.fineArrowDefualParam().swallowTailFactor;
+		let swallowTailPnt = $this.fineArrowDefualParam().swallowTailPnt;
+		//控制点
+		var result = {
+			controlPoint: null,
+			polygonalPoint: null
+		};
+		result.controlPoint = inputPoint;
+		var t = inputPoint.length;
+		if (!(2 > t)) {
+			if (2 == inputPoint.length) {
+				result.polygonalPoint = inputPoint;
+				return result;
+			}
+			var o = inputPoint,
+				e = o[0],
+				r = o[1];
+			$this.isClockWise(o[0], o[1], o[2]) && (e = o[1], r = o[0]);
+			var n = $this.mid(e, r),
+				g = [n].concat(o.slice(2)),
+				i = $this.getAttackArrowHeadPoints(g, e, r, $this.fineArrowDefualParam()),
+				s = i[0],
+				a = i[4],
+				l = $this.distance(e, r),
+				u = $this.getBaseLength(g),
+				c = u * tailWidthFactor * swallowTailFactor;
+			swallowTailPnt = $this.getThirdPoint(g[1], g[0], 0, c, !0);
+			var p = l / u,
+				h = $this.getAttackArrowBodyPoints(g, s, a, p),
+				t = h.length,
+				d = [e].concat(h.slice(0, t / 2));
+			d.push(s);
+			var f = [r].concat(h.slice(t / 2, t));
+			var newArray = [];
+			f.push(a),
+				d = $this.getQBSplinePoints(d),
+				f = $this.getQBSplinePoints(f),
+				newArray = $this.array2Dto1D(d.concat(i, f.reverse(), [swallowTailPnt, d[0]]));
+			result.polygonalPoint = $this.Cesium.Cartesian3.fromDegreesArray(newArray);
+		}
+		return result;
+	}
+
+	getArrowBodyPoints(t, o, e, r) {
+		var $this = this;
+		for (var n = $this.wholeDistance(t), g = $this.getBaseLength(t), i = g * r, s = $this.distance(o, e), a = (i - s) / 2, l = 0, u = [], c = [], p = 1; p < t.length - 1; p++) {
+			var h = $this.getAngleOfThreePoints(t[p - 1], t[p], t[p + 1]) / 2;
+			l += $this.distance(t[p - 1], t[p]);
+			var d = (i / 2 - l / n * a) / Math.sin(h),
+				f = $this.getThirdPoint(t[p - 1], t[p], Math.PI - h, d, !0),
+				E = $this.getThirdPoint(t[p - 1], t[p], h, d, !1);
+			u.push(f),
+				c.push(E)
+		}
+		return u.concat(c)
+	}
+
+	getAttackArrowHeadPoints(t, o, e, defaultParam) {
+		var $this = this;
+		let headHeightFactor = defaultParam.headHeightFactor;
+		let headTailFactor = defaultParam.headTailFactor;
+		let headWidthFactor = defaultParam.headWidthFactor;
+		let neckWidthFactor = defaultParam.neckWidthFactor;
+		let neckHeightFactor = defaultParam.neckHeightFactor;
+		var r = $this.getBaseLength(t),
+			n = r * headHeightFactor,
+			g = t[t.length - 1];
+		r = $this.distance(g, t[t.length - 2]);
+		var i = $this.distance(o, e);
+		n > i * headTailFactor && (n = i * headTailFactor);
+		var s = n * headWidthFactor,
+			a = n * neckWidthFactor;
+		n = n > r ? r : n;
+		var l = n * neckHeightFactor,
+			u = $this.getThirdPoint(t[t.length - 2], g, 0, n, !0),
+			c = $this.getThirdPoint(t[t.length - 2], g, 0, l, !0),
+			p = $this.getThirdPoint(g, u, Math.PI / 2, s, !1),
+			h = $this.getThirdPoint(g, u, Math.PI / 2, s, !0),
+			d = $this.getThirdPoint(g, c, Math.PI / 2, a, !1),
+			f = $this.getThirdPoint(g, c, Math.PI / 2, a, !0);
+		return [d, p, g, h, f]
+	}
+
+	getAttackArrowBodyPoints = function(t, o, e, r) {
+		var $this = this;
+		for (var n = $this.wholeDistance(t), g = $this.getBaseLength(t), i = g * r, s = $this.distance(o, e), a = (i - s) / 2, l = 0, u = [], c = [], p = 1; p < t.length - 1; p++) {
+			var h = $this.getAngleOfThreePoints(t[p - 1], t[p], t[p + 1]) / 2;
+			l += $this.distance(t[p - 1], t[p]);
+			var d = (i / 2 - l / n * a) / Math.sin(h),
+				f = $this.getThirdPoint(t[p - 1], t[p], Math.PI - h, d, !0),
+				E = $this.getThirdPoint(t[p - 1], t[p], h, d, !1);
+			u.push(f),
+				c.push(E)
+		}
+		return u.concat(c)
+	}
+
+	getAngleOfThreePoints(t, o, e) {
+		var r = this.getAzimuth(o, t) - this.getAzimuth(o, e);
+		return 0 > r ? r + Math.PI * 2 : r
+	}
+
+	dereplication(array) {
+		var last = array[array.length - 1];
+		var change = false;
+		var newArray = [];
+		newArray = array.filter(function(i) {
+			if (i[0] != last[0] && i[1] != last[1]) {
+				return i;
+			}
+			change = true;
+		});
+		if (change) newArray.push(last);
+		return newArray;
+	}
+
+	getBaseLength(t) {
+		return Math.pow(this.wholeDistance(t), .99)
+	}
+
+	wholeDistance(t) {
+		for (var o = 0, e = 0; e < t.length - 1; e++) o += this.distance(t[e], t[e + 1]);
+		return o
+	}
+
+	distance(t, o) {
+		return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2))
+	}
+
+	getThirdPoint(t, o, e, r, n) {
+		var g = this.getAzimuth(t, o),
+			i = n ? g + e : g - e,
+			s = r * Math.cos(i),
+			a = r * Math.sin(i);
+		return [o[0] + s, o[1] + a]
+	}
+
+	getAzimuth(t, o) {
+		var e, r = Math.asin(Math.abs(o[1] - t[1]) / this.distance(t, o));
+		return o[1] >= t[1] && o[0] >= t[0] ? e = r + Math.PI : o[1] >= t[1] && o[0] < t[0] ? e = 2 * Math.PI - r : o[1] < t[1] && o[0] < t[0] ? e = r : o[1] < t[1] && o[0] >= t[0] && (e = Math.PI - r), e
+	}
+
+	isClockWise(t, o, e) {
+		return (e[1] - t[1]) * (o[0] - t[0]) > (o[1] - t[1]) * (e[0] - t[0])
+	}
+
+	mid(t, o) {
+		return [(t[0] + o[0]) / 2, (t[1] + o[1]) / 2]
+	}
+
+	getQBSplinePoints = function(t) {
+		if (t.length <= 2) return t;
+		var o = 2,
+			e = [],
+			r = t.length - o - 1,
+			y = 0;
+		e.push(t[0]);
+		for (var n = 0; r >= n; n++)
+			for (var g = 0; 1 >= g; g += .05) {
+				for (var i = y = 0, s = 0; o >= s; s++) {
+					var a = this.getQuadricBSplineFactor(s, g);
+					i += a * t[n + s][0], y += a * t[n + s][1]
+				}
+				e.push([i, y])
+			}
+		return e.push(t[t.length - 1]), e
+	}
+	getQuadricBSplineFactor = function(t, o) {
+		return 0 == t ? Math.pow(o - 1, 2) / 2 : 1 == t ? (-2 * Math.pow(o, 2) + 2 * o + 1) / 2 : 2 == t ? Math.pow(o, 2) / 2 : 0
+	}
+	array2Dto1D = function(array) {
+		var newArray = [];
+		array.forEach(function(elt) {
+			newArray.push(elt[0]);
+			newArray.push(elt[1]);
+		});
+		return newArray;
+	}
+}
+
+export default DrawAttackArrow

+ 534 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawBowLine.js

@@ -0,0 +1,534 @@
+
+/*
+九、绘制弓形线
+ */
+class DrawBowLine {
+	constructor(arg) {
+		this.viewer = arg.viewer;
+		this.Cesium = arg.Cesium;
+		this.tt = 0.4;
+		this.floatingPoint = null; //标识点
+		this.drawHandler = null; //画事件
+		this.DrawBowLine = null; //弓形
+		this._DrawBowLineLast = null; //最后一个弓形
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_PincerArrow = []; //脏数据
+		this._DrawBowLineData = null; //用于构造弓形
+		this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+		this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+		
+	}
+
+	//返回弓形
+	get PincerArrow() {
+		return this._DrawBowLineLast;
+	}
+
+	//返回弓形数据用于加载弓形
+	getData() {
+		return this._DrawBowLineData;
+	}
+
+	// 修改编辑调用计算
+	computePosition(data) {
+		var $this = this;
+		if (data.length < 3) {
+			return;
+		}
+		var DrawBowLine = [];
+		let positions = [];
+		for (var i = 0; i < data.length; i++) {
+			positions.push($this.cartesianToLatlng(data[i]));
+			var cart3 = $this.lonLatToMercator($this.cartesianToLatlng(data[i]));
+			DrawBowLine.push(cart3);
+		}
+		let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowLine[0], DrawBowLine[2], DrawBowLine[1], null, null];
+		let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
+		let radius = $this.MathDistance(pnt1, center)
+		let angle1 = $this.getAzimuth(pnt1, center)
+		let angle2 = $this.getAzimuth(pnt2, center)
+		if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+			startAngle = angle2
+			endAngle = angle1
+		} else {
+			startAngle = angle1
+			endAngle = angle2
+		}
+		let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
+		let pHierarchy = [];
+		for (var l = 0; l < getArcPoint.length; l++) {
+			var cart3 = $this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
+			pHierarchy.push(cart3);
+		}
+		$this._DrawBowLineData = positions
+		return pHierarchy
+	}
+
+	//加载
+	addload(data) {
+		var $this = this;
+		if (data.length < 3) {
+			return;
+		}
+		var DrawBowLine = [];
+		for (var i = 0; i < data.length; i++) {
+			var cart3 = $this.lonLatToMercator(data[i]);
+			DrawBowLine.push(cart3);
+		}
+		let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowLine[0], DrawBowLine[2], DrawBowLine[1], null, null];
+		let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
+		let radius = $this.MathDistance(pnt1, center)
+		let angle1 = $this.getAzimuth(pnt1, center)
+		let angle2 = $this.getAzimuth(pnt2, center)
+		if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+			startAngle = angle2
+			endAngle = angle1
+		} else {
+			startAngle = angle1
+			endAngle = angle2
+		}
+		let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
+		// console.log(getArcPoint)
+		let pHierarchy = [];
+		for (var l = 0; l < getArcPoint.length; l++) {
+			var cart3 = $this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
+			pHierarchy.push(cart3);
+		}
+		var arrowEntity = $this.viewer.entities.add({
+			Type: 'DrawBowLine',
+			Position: data,
+			id: data.id || $this.objId,
+			polyline: {
+				positions: pHierarchy,
+				show: true,
+				material: $this.Cesium.Color.YELLOW,
+				width: 3,
+				clampToGround: true
+			}
+		})
+		return arrowEntity
+	}
+
+
+	// 开始创建
+	startCreate(drawType) {
+		this.drawType = drawType
+		var $this = this;
+		this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas);
+		this.handler.setInputAction(function(event) {
+			//屏幕坐标转世界坐标
+			var position = event.position;
+			if (!$this.Cesium.defined(position)) {
+				return;
+			}
+			var ray = $this.viewer.camera.getPickRay(position);
+			if (!$this.Cesium.defined(ray)) {
+				return;
+			}
+			var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
+			if (!$this.Cesium.defined(cartesian)) {
+				return;
+			}
+
+			if ($this._positions.length == 0) {
+				$this._positions.push(cartesian.clone());
+				$this.floatingPoint = $this.createPoint(cartesian);
+			}
+
+			if ($this._positions.length <= 2) {
+				$this.createPoint(cartesian); // 绘制点
+				$this._positions.push(cartesian);
+			}
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+
+
+		this.handler.setInputAction(function(event) { //移动时绘制面
+			//console.log("_positions",_positions);
+			if ($this._positions.length < 2) {
+				return;
+			}
+
+			//屏幕坐标转世界坐标
+			var position = event.endPosition;
+			if (!$this.Cesium.defined(position)) {
+				return;
+			}
+			var ray = $this.viewer.camera.getPickRay(position);
+			if (!$this.Cesium.defined(ray)) {
+				return;
+			}
+			var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
+			if (!$this.Cesium.defined(cartesian)) {
+				return;
+			}
+			//console.log("点击地图移动采集的点:",cartesian);
+			if (!$this.Cesium.defined($this.DrawBowLine)) {
+				$this.DrawBowLine = $this.createDrawBowLine();
+			}
+			$this.floatingPoint.position.setValue(cartesian);
+			if ($this.DrawBowLine) {
+				//替换最后一个点
+				// _positions.pop();
+				// _positions.push(cartesian);
+				//替换中间点
+				if ($this._positions.length == 3) {
+					$this._positions[1] = cartesian;
+				} else {
+					$this._positions.pop();
+					$this._positions.push(cartesian);
+				}
+
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+
+		//右击停止采集
+		this.handler.setInputAction(function(movement) {
+
+			if ($this._positions.length >= 3) {
+				$this._DrawBowLineData = $this._positions.concat();
+				$this.viewer.entities.remove($this.DrawBowLine); //移除
+				$this.DrawBowLine = null;
+				var lnglatArr = [];
+				for (var i = 0; i < $this._DrawBowLineData.length; i++) {
+					var lnglat = $this.cartesianToLatlng($this._DrawBowLineData[i]);
+					lnglatArr.push(lnglat)
+				}
+				$this._DrawBowLineData = lnglatArr;
+				var pincerArrow = $this.addload(lnglatArr); //加载
+				$this._entities_PincerArrow.push(pincerArrow);
+				$this._DrawBowLineLast = pincerArrow;
+				$this.viewer.entities.remove($this.floatingPoint);
+				$this.floatingPoint = null;
+
+				//删除关键点
+				$this.clearPoint();
+				$this.destroy()
+			}
+		}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+
+	}
+
+	//创建弓形
+	createDrawBowLine() {
+		let $this = this
+		var DrawBowLineEntity = $this.viewer.entities.add({
+			polyline: {
+				positions: new $this.Cesium.CallbackProperty(function() {
+					if ($this._positions.length < 3) {
+						return;
+					}
+					var DrawBowLine = [];
+					for (var i = 0; i < $this._positions.length; i++) {
+						var cart3 = $this.lonLatToMercator($this.cartesianToLatlng($this._positions[i]));
+						DrawBowLine.push(cart3);
+					}
+					let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowLine[0], DrawBowLine[2], DrawBowLine[1], null, null];
+					let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
+					let radius = $this.MathDistance(pnt1, center)
+					let angle1 = $this.getAzimuth(pnt1, center)
+					let angle2 = $this.getAzimuth(pnt2, center)
+					if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+						startAngle = angle2
+						endAngle = angle1
+					} else {
+						startAngle = angle1
+						endAngle = angle2
+					}
+					let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
+					// console.log(getArcPoint)
+					let pHierarchy = [];
+					for (var l = 0; l < getArcPoint.length; l++) {
+						var cart3 = $this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
+						pHierarchy.push(cart3);
+					}
+					return pHierarchy
+				}, false),
+				show: true,
+				material: $this.Cesium.Color.YELLOW,
+				width: 3,
+				clampToGround: true
+			}
+		})
+		//$this._entities_DrawBowLine.push(DrawBowLineEntity);
+		// DrawBowLineEntity.valueFlag = "value";
+		$this._entities_PincerArrow.push(DrawBowLineEntity);
+		return DrawBowLineEntity
+	}
+
+	//创建点
+	createPoint(cartesian) {
+		var $this = this;
+		var point = this.viewer.entities.add({
+			position: cartesian,
+			point: {
+				pixelSize: 10,
+				color: $this.Cesium.Color.RED,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			}
+		});
+		$this._entities_point.push(point);
+		return point;
+	}
+
+	cartesianToLatlng(cartesian) {
+		let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
+		let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
+		let alt = cartographic.height;
+		return [lng, lat];
+	}
+
+	//销毁
+	destroy() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+	}
+
+	clearPoint() {
+		this.DrawEndEvent.raiseEvent(this._DrawBowLineLast, this._DrawBowLineData, this.drawType);
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		this._entities_point = []; //脏数据
+	}
+
+	//清空实体对象
+	clear() {
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		for (var i = 0; i < this._entities_PincerArrow.length; i++) {
+			this.viewer.entities.remove(this._entities_PincerArrow[i]);
+		}
+
+		this.floatingPoint = null; //标识点
+		this._PincerArrow = null; //活动弓形
+		this._PincerArrowLast = null; //最后一个弓形
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_PincerArrow = []; //脏数据
+		this._PincerArrowData = null; //用于构造弓形数据
+	}
+
+	getCatesian3FromPX(px) {
+		var cartesian;
+		var ray = this.viewer.camera.getPickRay(px);
+		if (!ray) return null;
+		cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+		return cartesian;
+	}
+
+	_computeTempPositions() {
+		var _this = this;
+
+		var pnts = [].concat(_this._positions);
+		var num = pnts.length;
+		var first = pnts[0];
+		var last = pnts[num - 1];
+		if (_this._isSimpleXYZ(first, last) == false) {
+			pnts.push(first);
+			num += 1;
+		}
+		_this.tempPositions = [];
+		for (var i = 1; i < num; i++) {
+			var p1 = pnts[i - 1];
+			var p2 = pnts[i];
+			var cp = _this._computeCenterPotition(p1, p2);
+			_this.tempPositions.push(p1);
+			_this.tempPositions.push(cp);
+		}
+	}
+
+	_isSimpleXYZ(p1, p2) {
+		if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
+			return true;
+		}
+		return false;
+	}
+
+	_computeCenterPotition(p1, p2) {
+		var _this = this;
+		var c1 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p1);
+		var c2 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p2);
+		var cm = new _this.Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5);
+		var cp = _this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cm);
+		return cp;
+	}
+	/**
+	 * 笛卡尔坐标转经纬度坐标
+	 */
+	getLonLat(cartesian) {
+		var cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		cartographic.height = this.viewer.scene.globe.getHeight(cartographic);
+		var pos = {
+			lon: cartographic.longitude,
+			lat: cartographic.latitude,
+			alt: cartographic.height
+		};
+		pos.lon = this.Cesium.Math.toDegrees(pos.lon);
+		pos.lat = this.Cesium.Math.toDegrees(pos.lat);
+		return pos;
+	}
+
+	LatlngTocartesian(latlng) {
+		let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+		return cartesian3
+	}
+
+	/**
+	 * 经纬度坐标转墨卡托坐标
+	 */
+	// 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
+	// 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
+	lonLatToMercator(Latlng) {
+		var E = Latlng[0];
+		var N = Latlng[1];
+		var x = E * 20037508.34 / 180;
+		var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
+		y = y * 20037508.34 / 180;
+		return [x, y]
+	}
+	/**
+	 * 墨卡托坐标转经纬度坐标转
+	 */
+	WebMercator2lonLat(mercator) {
+		let x = mercator[0] / 20037508.34 * 180;
+		let ly = mercator[1] / 20037508.34 * 180;
+		let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
+		return [x, y];
+	}
+
+	////////////////////////////////////////弓形/////////////////////////////////////////////////////
+	/**
+	 * 通过三个点确定一个圆的中心点
+	 * @param point1
+	 * @param point2
+	 * @param point3
+	 */
+	getCircleCenterOfThreePoints(point1, point2, point3) {
+		let pntA = [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2]
+		let pntB = [pntA[0] - point1[1] + point2[1], pntA[1] + point1[0] - point2[0]]
+		let pntC = [(point1[0] + point3[0]) / 2, (point1[1] + point3[1]) / 2]
+		let pntD = [pntC[0] - point1[1] + point3[1], pntC[1] + point1[0] - point3[0]]
+		return this.getIntersectPoint(pntA, pntB, pntC, pntD)
+	}
+
+	/**
+	 * 获取交集的点
+	 * @param pntA
+	 * @param pntB
+	 * @param pntC
+	 * @param pntD
+	 * @returns {[*,*]}
+	 */
+	getIntersectPoint(pntA, pntB, pntC, pntD) {
+		if (pntA[1] === pntB[1]) {
+			let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
+			let x = f * (pntA[1] - pntC[1]) + pntC[0]
+			let y = pntA[1]
+			return [x, y]
+		}
+		if (pntC[1] === pntD[1]) {
+			let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
+			let x = e * (pntC[1] - pntA[1]) + pntA[0]
+			let y = pntC[1]
+			return [x, y]
+		}
+		let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
+		let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
+		let y = (e * pntA[1] - pntA[0] - f * pntC[1] + pntC[0]) / (e - f)
+		let x = e * y - e * pntA[1] + pntA[0]
+		return [x, y]
+	}
+
+
+	/**
+	 * 计算两个坐标之间的距离
+	 * @ignore
+	 * @param pnt1
+	 * @param pnt2
+	 * @returns {number}
+	 * @constructor
+	 */
+	MathDistance(pnt1, pnt2) {
+		return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2)))
+	}
+
+
+	/**
+	 * 获取方位角(地平经度)
+	 * @param startPoint
+	 * @param endPoint
+	 * @returns {*}
+	 */
+	getAzimuth(startPoint, endPoint) {
+		let azimuth
+		let angle = Math.asin(Math.abs(endPoint[1] - startPoint[1]) / (this.MathDistance(startPoint, endPoint)))
+		if (endPoint[1] >= startPoint[1] && endPoint[0] >= startPoint[0]) {
+			azimuth = angle + Math.PI
+		} else if (endPoint[1] >= startPoint[1] && endPoint[0] < startPoint[0]) {
+			azimuth = Math.PI * 2 - angle
+		} else if (endPoint[1] < startPoint[1] && endPoint[0] < startPoint[0]) {
+			azimuth = angle
+		} else if (endPoint[1] < startPoint[1] && endPoint[0] >= startPoint[0]) {
+			azimuth = Math.PI - angle
+		}
+		return azimuth
+	}
+
+	/**
+	 * 判断是否是顺时针
+	 * @param pnt1
+	 * @param pnt2
+	 * @param pnt3
+	 * @returns {boolean}
+	 */
+	isClockWise(pnt1, pnt2, pnt3) {
+		return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0]))
+	}
+
+
+	/**
+	 * 插值弓形线段点
+	 * @param center
+	 * @param radius
+	 * @param startAngle
+	 * @param endAngle
+	 * @returns {null}
+	 */
+	getArcPoints(center, radius, startAngle, endAngle) {
+		let [x, y, pnts, angleDiff] = [null, null, [], (endAngle - startAngle)]
+		angleDiff = ((angleDiff < 0) ? (angleDiff + (Math.PI * 2)) : angleDiff)
+		for (let i = 0; i <= 100; i++) {
+			let angle = startAngle + angleDiff * i / 100
+			x = center[0] + radius * Math.cos(angle)
+			y = center[1] + radius * Math.sin(angle)
+			pnts.push([x, y])
+		}
+		return pnts
+	}
+
+}
+
+export default DrawBowLine

+ 535 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawBowPlane.js

@@ -0,0 +1,535 @@
+/*
+九、绘制弓形面
+ */
+class DrawBowPlane {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this.tt = 0.4;
+        this.floatingPoint = null;//标识点
+        this.drawHandler = null;//画事件
+        this.DrawBowPlane = null;//弓形
+        this._DrawBowPlaneLast = null; //最后一个弓形
+        this._positions = [];//活动点
+        this._entities_point = [];//脏数据
+        this._entities_PincerArrow = [];//脏数据
+        this._DrawBowPlaneData = null; //用于构造弓形
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+
+    //返回弓形
+    get PincerArrow() {
+        return this._DrawBowPlaneLast;
+    }
+
+    //返回弓形数据用于加载弓形
+    getData() {
+        return this._DrawBowPlaneData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data) {
+        var $this = this;
+        if (data.length < 3) {
+            return;
+        }
+        var DrawBowPlane = [];
+        let positions = [];
+        for (var i = 0; i < data.length; i++) {
+            positions.push($this.cartesianToLatlng(data[i]));
+            var cart3 =$this.lonLatToMercator($this.cartesianToLatlng(data[i]));
+            DrawBowPlane.push(cart3);
+        }
+        let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null];
+        let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
+        let radius = $this.MathDistance(pnt1, center)
+        let angle1 = $this.getAzimuth(pnt1, center)
+        let angle2 = $this.getAzimuth(pnt2, center)
+        if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+            startAngle = angle2
+            endAngle = angle1
+            } else {
+            startAngle = angle1
+            endAngle = angle2
+        }
+        let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
+        let pHierarchy = [];
+        for (var l = 0; l < getArcPoint.length; l++) {
+            var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
+            pHierarchy.push(cart3);
+        }
+        pHierarchy.push(pHierarchy[0])
+        $this._DrawBowPlaneData = positions
+        return new $this.Cesium.PolygonHierarchy(pHierarchy)
+    }
+
+    //加载
+    addload(data) {
+        var $this = this;
+        if (data.length < 3) {
+            return;
+        }
+        var DrawBowPlane = [];
+        for (var i = 0; i < data.length; i++) {
+            var cart3 =$this.lonLatToMercator(data[i]);
+            DrawBowPlane.push(cart3);
+        }
+        let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null];
+        let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
+        let radius = $this.MathDistance(pnt1, center)
+        let angle1 = $this.getAzimuth(pnt1, center)
+        let angle2 = $this.getAzimuth(pnt2, center)
+        if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+            startAngle = angle2
+            endAngle = angle1
+          } else {
+            startAngle = angle1
+            endAngle = angle2
+        }
+        let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
+        let pHierarchy = [];
+        for (var l = 0; l < getArcPoint.length; l++) {
+            var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
+            pHierarchy.push(cart3);
+        }
+        pHierarchy.push(pHierarchy[0])
+        var arrowEntity = $this.viewer.entities.add({
+            Type: 'DrawBowPlane',
+            Position: data,
+            id: data.id || $this.objId,
+            polygon: {
+                hierarchy: new $this.Cesium.PolygonHierarchy(pHierarchy),
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 3,
+                clampToGround: true,
+                outlineWidth:3,
+                outline: true,
+                outlineColor: Cesium.Color.MAGENTA,
+            }
+        }
+        )
+        return arrowEntity
+    }
+
+
+    // 开始创建
+    startCreate(drawType) {
+        this.drawType = drawType
+        var $this = this;
+        this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas);
+        this.handler.setInputAction(function (event) {
+            //屏幕坐标转世界坐标
+            var position = event.position;
+            if (!$this.Cesium.defined(position)) {
+                return;
+            }
+            var ray = $this.viewer.camera.getPickRay(position);
+            if (!$this.Cesium.defined(ray)) {
+                return;
+            }
+            var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
+            if (!$this.Cesium.defined(cartesian)) {
+                return;
+            }
+
+            if ($this._positions.length == 0) {
+                $this._positions.push(cartesian.clone());
+                $this.floatingPoint = $this.createPoint(cartesian);
+            }
+
+            if ($this._positions.length <= 2) {
+                $this.createPoint(cartesian); // 绘制点
+                $this._positions.push(cartesian);
+            }
+        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+
+
+        this.handler.setInputAction(function (event) { //移动时绘制面
+            //console.log("_positions",_positions);
+            if ($this._positions.length < 2) {
+                return;
+            }
+
+            //屏幕坐标转世界坐标
+            var position = event.endPosition;
+            if (!$this.Cesium.defined(position)) {
+                return;
+            }
+            var ray = $this.viewer.camera.getPickRay(position);
+            if (!$this.Cesium.defined(ray)) {
+                return;
+            }
+            var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
+            if (!$this.Cesium.defined(cartesian)) {
+                return;
+            }
+            //console.log("点击地图移动采集的点:",cartesian);
+            if (!$this.Cesium.defined($this.DrawBowPlane)) {
+                $this.DrawBowPlane = $this.createDrawBowPlane();
+            }
+            $this.floatingPoint.position.setValue(cartesian);
+            if ($this.DrawBowPlane) {
+                //替换最后一个点
+                // _positions.pop();
+                // _positions.push(cartesian);
+                //替换中间点
+                if ($this._positions.length == 3) {
+                    $this._positions[1] = cartesian;
+                } else {
+                    $this._positions.pop();
+                    $this._positions.push(cartesian);
+                }
+
+            }
+        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+
+        //右击停止采集
+        this.handler.setInputAction(function (movement) {
+
+            if ($this._positions.length >= 3) {
+                $this._DrawBowPlaneData = $this._positions.concat();
+                $this.viewer.entities.remove($this.DrawBowPlane); //移除
+                $this.DrawBowPlane = null;
+                var lnglatArr = [];
+                for (var i = 0; i < $this._DrawBowPlaneData.length; i++) {
+                    var lnglat = $this.cartesianToLatlng($this._DrawBowPlaneData[i]);
+                    lnglatArr.push(lnglat)
+                }
+                $this._DrawBowPlaneData = lnglatArr;
+                var pincerArrow = $this.addload(lnglatArr); //加载
+                $this._entities_PincerArrow.push(pincerArrow);
+                $this._DrawBowPlaneLast = pincerArrow;
+                $this.viewer.entities.remove($this.floatingPoint);
+                $this.floatingPoint = null;
+
+                //删除关键点
+                $this.clearPoint();
+                $this.destroy()
+            }
+        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+
+    }
+
+    //创建弓形
+    createDrawBowPlane() {
+        let $this = this
+        var DrawBowPlaneEntity = $this.viewer.entities.add({
+            polygon: {
+                hierarchy: new $this.Cesium.CallbackProperty(function () {
+                    if ($this._positions.length < 3) {
+                        return;
+                    }
+                    var DrawBowPlane = [];
+                    for (var i = 0; i < $this._positions.length; i++) {
+                        var cart3 =$this.lonLatToMercator($this.cartesianToLatlng($this._positions[i]));
+                        DrawBowPlane.push(cart3);
+                    }
+                    let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null];
+                    let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
+                    let radius = $this.MathDistance(pnt1, center)
+                    let angle1 = $this.getAzimuth(pnt1, center)
+                    let angle2 = $this.getAzimuth(pnt2, center)
+                    if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+                        startAngle = angle2
+                        endAngle = angle1
+                      } else {
+                        startAngle = angle1
+                        endAngle = angle2
+                    }
+                    let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
+                    let pHierarchy = [];
+                    for (var l = 0; l < getArcPoint.length; l++) {
+                        var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
+                        pHierarchy.push(cart3);
+                    }
+                    pHierarchy.push(pHierarchy[0])
+                    return new $this.Cesium.PolygonHierarchy(pHierarchy)
+                }, false),
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                clampToGround: true
+            }
+        }
+        )
+        $this._entities_PincerArrow.push(DrawBowPlaneEntity);
+        return DrawBowPlaneEntity
+    }
+
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this._entities_point.push(point);
+        return point;
+    }
+
+    cartesianToLatlng(cartesian) {
+        let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
+        let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
+        let alt = cartographic.height;
+        return [lng, lat];
+    }
+
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this._DrawBowPlaneLast, this._DrawBowPlaneData, this.drawType);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        for (var i = 0; i < this._entities_PincerArrow.length; i++) {
+            this.viewer.entities.remove(this._entities_PincerArrow[i]);
+        }
+
+        this.floatingPoint = null;//标识点
+        this._PincerArrow = null; //活动弓形
+        this._PincerArrowLast = null; //最后一个弓形
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_PincerArrow = [];  //脏数据
+        this._PincerArrowData = null; //用于构造弓形数据
+    }
+
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+
+    _computeTempPositions() {
+        var _this = this;
+
+        var pnts = [].concat(_this._positions);
+        var num = pnts.length;
+        var first = pnts[0];
+        var last = pnts[num - 1];
+        if (_this._isSimpleXYZ(first, last) == false) {
+            pnts.push(first);
+            num += 1;
+        }
+        _this.tempPositions = [];
+        for (var i = 1; i < num; i++) {
+            var p1 = pnts[i - 1];
+            var p2 = pnts[i];
+            var cp = _this._computeCenterPotition(p1, p2);
+            _this.tempPositions.push(p1);
+            _this.tempPositions.push(cp);
+        }
+    }
+
+    _isSimpleXYZ(p1, p2) {
+        if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
+            return true;
+        }
+        return false;
+    }
+
+    _computeCenterPotition(p1, p2) {
+        var _this = this;
+        var c1 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p1);
+        var c2 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p2);
+        var cm = new _this.Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5);
+        var cp = _this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cm);
+        return cp;
+    }
+    /**
+     * 笛卡尔坐标转经纬度坐标
+     */
+    getLonLat(cartesian) {
+        var cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        cartographic.height = this.viewer.scene.globe.getHeight(cartographic);
+        var pos = {
+            lon: cartographic.longitude,
+            lat: cartographic.latitude,
+            alt: cartographic.height
+        };
+        pos.lon = this.Cesium.Math.toDegrees(pos.lon);
+        pos.lat = this.Cesium.Math.toDegrees(pos.lat);
+        return pos;
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+     /**
+     * 经纬度坐标转墨卡托坐标
+     */
+    // 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
+    // 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
+    lonLatToMercator(Latlng) {
+        var E = Latlng[0];
+        var N = Latlng[1];
+        var x = E * 20037508.34 / 180;
+        var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
+        y = y * 20037508.34 / 180;
+        return [x, y]
+    }
+    /**
+     * 墨卡托坐标转经纬度坐标转
+     */
+    WebMercator2lonLat(mercator) {
+        let x = mercator[0] / 20037508.34 * 180;
+        let ly = mercator[1] / 20037508.34 * 180;
+        let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
+        return [x, y];
+    }
+
+    ////////////////////////////////////////弓形/////////////////////////////////////////////////////
+    /**
+ * 通过三个点确定一个圆的中心点
+ * @param point1
+ * @param point2
+ * @param point3
+ */
+    getCircleCenterOfThreePoints(point1, point2, point3) {
+        let pntA = [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2]
+        let pntB = [pntA[0] - point1[1] + point2[1], pntA[1] + point1[0] - point2[0]]
+        let pntC = [(point1[0] + point3[0]) / 2, (point1[1] + point3[1]) / 2]
+        let pntD = [pntC[0] - point1[1] + point3[1], pntC[1] + point1[0] - point3[0]]
+        return this.getIntersectPoint(pntA, pntB, pntC, pntD)
+    }
+
+    /**
+   * 获取交集的点
+   * @param pntA
+   * @param pntB
+   * @param pntC
+   * @param pntD
+   * @returns {[*,*]}
+   */
+    getIntersectPoint(pntA, pntB, pntC, pntD) {
+        if (pntA[1] === pntB[1]) {
+            let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
+            let x = f * (pntA[1] - pntC[1]) + pntC[0]
+            let y = pntA[1]
+            return [x, y]
+        }
+        if (pntC[1] === pntD[1]) {
+            let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
+            let x = e * (pntC[1] - pntA[1]) + pntA[0]
+            let y = pntC[1]
+            return [x, y]
+        }
+        let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
+        let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
+        let y = (e * pntA[1] - pntA[0] - f * pntC[1] + pntC[0]) / (e - f)
+        let x = e * y - e * pntA[1] + pntA[0]
+        return [x, y]
+    }
+
+
+    /**
+   * 计算两个坐标之间的距离
+   * @ignore
+   * @param pnt1
+   * @param pnt2
+   * @returns {number}
+   * @constructor
+   */
+    MathDistance(pnt1, pnt2) {
+        return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2)))
+    }
+
+
+    /**
+   * 获取方位角(地平经度)
+   * @param startPoint
+   * @param endPoint
+   * @returns {*}
+   */
+    getAzimuth(startPoint, endPoint) {
+        let azimuth
+        let angle = Math.asin(Math.abs(endPoint[1] - startPoint[1]) / (this.MathDistance(startPoint, endPoint)))
+        if (endPoint[1] >= startPoint[1] && endPoint[0] >= startPoint[0]) {
+            azimuth = angle + Math.PI
+        } else if (endPoint[1] >= startPoint[1] && endPoint[0] < startPoint[0]) {
+            azimuth = Math.PI * 2 - angle
+        } else if (endPoint[1] < startPoint[1] && endPoint[0] < startPoint[0]) {
+            azimuth = angle
+        } else if (endPoint[1] < startPoint[1] && endPoint[0] >= startPoint[0]) {
+            azimuth = Math.PI - angle
+        }
+        return azimuth
+    }
+
+    /**
+     * 判断是否是顺时针
+     * @param pnt1
+     * @param pnt2
+     * @param pnt3
+     * @returns {boolean}
+     */
+    isClockWise (pnt1, pnt2, pnt3) {
+        return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0]))
+    }
+
+
+    /**
+   * 插值弓形线段点
+   * @param center
+   * @param radius
+   * @param startAngle
+   * @param endAngle
+   * @returns {null}
+   */
+    getArcPoints(center, radius, startAngle, endAngle) {
+        let [x, y, pnts, angleDiff] = [null, null, [], (endAngle - startAngle)]
+        angleDiff = ((angleDiff < 0) ? (angleDiff + (Math.PI * 2)) : angleDiff)
+        for (let i = 0; i <= 100; i++) {
+            let angle = startAngle + angleDiff * i / 100
+            x = center[0] + radius * Math.cos(angle)
+            y = center[1] + radius * Math.sin(angle)
+            pnts.push([x, y])
+        }
+        return pnts
+    }
+
+}
+
+export default DrawBowPlane

+ 251 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawCircle.js

@@ -0,0 +1,251 @@
+// 四、圆
+/*
+绘制圆
+ */
+class DrawCircle {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this._cicle = null; //活动圆
+        this.floatingPoint = null;
+        this._cicleLast = null; //最后一个圆
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_cicle = [];  //脏数据
+        this._cicleData = null; //用于构造圆形数据
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    get cicle() {
+        return this._cicleLast;
+    }
+ 
+    //加载圆
+    addload(data) {
+        var that = this;
+        let lnglatArr = [];
+            for (var i = 0; i < data.length; i++) {
+                var lnglat = that.LatlngTocartesian(data[i]);
+                lnglatArr.push(lnglat)
+        }
+        var value = lnglatArr;
+        var r = Math.sqrt(
+            Math.pow(value[0].x - value[value.length - 1].x, 2) +
+            Math.pow(value[0].y - value[value.length - 1].y, 2)
+        );
+        var position = value[0];
+        var shape = that.viewer.entities.add({
+            Type:'DrawCircle',
+            Position:[data[0],data[data.length - 1]],
+            position: position,
+            id:data.id || that.objId,
+            ellipse: {
+                semiMinorAxis: r,
+                semiMajorAxis: r,
+                material: that.Cesium.Color.RED.withAlpha(0.9),
+                // outline: true,
+                show: true,
+                clampToGround: true,
+            }
+        });
+        return shape;
+    }
+ 
+    //返回数据
+    getData() {
+        return this._cicleData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        var that = this;
+        let lnglatArr = [];
+            for (var i = 0; i < data.length; i++) {
+                var lnglat = that.cartesianToLatlng(data[i]);
+                lnglatArr.push(lnglat)
+        }
+        that._cicleData = lnglatArr;
+        var value = data;
+        var r = Math.sqrt(
+            Math.pow(value[0].x - value[value.length - 1].x, 2) +
+            Math.pow(value[0].y - value[value.length - 1].y, 2)
+        );
+        var position = value[0];
+        return   {position,r}
+    }
+ 
+    startCreate(drawType) {
+        this.drawType = drawType
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.viewer.scene.globe.depthTestAgainstTerrain = true;
+        var $this = this;
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            $this.viewer.scene.globe.depthTestAgainstTerrain = true;
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this._positions.length == 0) {
+                $this._positions.push(cartesian.clone());
+                $this.floatingPoint = $this.createPoint(cartesian);
+                $this._positions.push(cartesian);
+            }
+            if (!$this._cicle) {
+                $this.createPoint(cartesian);// 绘制点
+            }
+            
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制圆
+            if ($this._positions.length < 1) return;
+            var cartesian = $this.viewer.scene.pickPosition(evt.endPosition);// $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this._cicle)) {
+                $this._cicle = $this.createCicle();
+            }
+            $this.floatingPoint.position.setValue(cartesian);
+            if ($this._cicle) {
+                $this._positions.pop();
+                $this._positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this._cicle) return;
+            $this.viewer.scene.globe.depthTestAgainstTerrain = false;
+            var cartesian = $this.viewer.scene.pickPosition(evt.position); // $this.getCatesian3FromPX(evt.position);
+            $this._positions.pop();
+            $this._positions.push(cartesian);
+            $this._cicleData = $this._positions.concat();
+            $this.viewer.entities.remove($this._cicle); //移除
+            $this._cicle = null;
+            $this._positions = [];
+            $this.floatingPoint.position.setValue(cartesian);
+            let lnglatArr = [];
+            for (var i = 0; i < $this._cicleData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this._cicleData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this._cicleData = lnglatArr;
+            var cicle = $this.addload($this._cicleData); //加载
+            $this._entities_cicle.push(cicle);
+            $this._cicleLast = cicle;
+            $this.clearPoint();
+            // if(typeof $this.callback=="function"){
+            //     $this.callback(cicle);
+            // }
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+ 
+    //创建圆
+    createCicle() {
+        var that = this;
+        var shape = this.viewer.entities.add({
+            position: that._positions[0],
+            ellipse: {
+                semiMinorAxis: new that.Cesium.CallbackProperty(function () {
+                    //半径 两点间距离
+                    var r = Math.sqrt(
+                        Math.pow(that._positions[0].x - that._positions[that._positions.length - 1].x, 2) +
+                        Math.pow(that._positions[0].y - that._positions[that._positions.length - 1].y, 2)
+                    );
+                    return r ? r : r + 1;
+                }, false),
+                semiMajorAxis: new that.Cesium.CallbackProperty(function () {
+                    var r = Math.sqrt(
+                        Math.pow(that._positions[0].x - that._positions[that._positions.length - 1].x, 2) +
+                        Math.pow(that._positions[0].y - that._positions[that._positions.length - 1].y, 2)
+                    );
+                    return r ? r : r + 1;
+                }, false),
+                material: that.Cesium.Color.RED.withAlpha(0.5),
+                outline: true
+            }
+        });
+        that._entities_cicle.push(shape);
+        return shape;
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });;
+        $this._entities_point.push(point);
+        return point;
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+
+    cartesianToLatlng(cartesian) {
+        let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
+        let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
+        let alt = cartographic.height;
+        return [lng, lat];
+    }
+    LatlngTocartesian(latlng){
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0],latlng[1],0);
+        return cartesian3
+    }
+ 
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    clearPoint(){
+        this.DrawEndEvent.raiseEvent(this._cicleLast, this._cicleData, this.drawType);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+    clear() {
+ 
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+ 
+        for (var i = 0; i < this._entities_cicle.length; i++) {
+            this.viewer.entities.remove(this._entities_cicle[i]);
+        }
+        this._cicle = null; //活动圆
+        this.floatingPoint = null;
+        this._cicleLast = null; //最后一个圆
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_cicle = [];  //脏数据
+        this._cicleData = null; //用于构造圆形数据
+    }
+}
+ 
+export default DrawCircle

+ 599 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawClosedCurve.js

@@ -0,0 +1,599 @@
+import {
+	createTooltip
+} from "../../../common/common.js";
+
+import {
+	isRuntimeApp,
+	isRuntimeWeb,
+	createOperationMainDom,
+	showTooltipMessage
+} from "../../../common/RuntimeEnvironment.js";
+
+
+// 闭合曲面
+class DrawClosedCurve {
+	constructor(arg) {
+		this.viewer = arg.viewer;
+		this.Cesium = arg.Cesium;
+		this.floatingPoint = null; //标识点
+		this._ClosedCurve = null; //活动闭合曲面
+		this._ClosedCurveLast = null; //最后一个闭合曲面
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_ClosedCurve = []; //脏数据
+		this._ClosedCurveData = null; //用于构造闭合曲面数据
+		this.ZERO_TOLERANCE = 0.0001;
+		this.FITTING_COUNT = 100;
+		this.t = 0.3
+		this.objId = Number((new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0));
+		this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+		this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+
+		this._tooltip = createTooltip(this.viewer.container);
+
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+	}
+
+	//返回闭合曲面
+	get ClosedCurve() {
+		return this._ClosedCurveLast;
+	}
+
+	//返回闭合曲面数据用于加载闭合曲面
+	getData() {
+		return this._ClosedCurveData;
+	}
+
+	// 修改编辑调用计算
+	computePosition(data) {
+		let $this = this;
+		if (data.length < 2) return
+		let pnts = []
+		for (let p = 0; p < data.length; p++) {
+			pnts.push($this.cartesianToLatlng(data[p]))
+		}
+		this._ClosedCurveData = Array.from(pnts);
+		pnts.push(pnts[0], pnts[1])
+		let [normals, pList] = [
+			[],
+			[]
+		]
+		for (let i = 0; i < pnts.length - 2; i++) {
+			let normalPoints = $this.getBisectorNormals($this.t, pnts[i], pnts[i + 1], pnts[i + 2])
+			normals = normals.concat(normalPoints)
+		}
+		let count = normals.length
+		normals = [normals[count - 1]].concat(normals.slice(0, count - 1))
+		for (let i = 0; i < pnts.length - 2; i++) {
+			let pnt1 = pnts[i]
+			let pnt2 = pnts[i + 1]
+			pList.push($this.LatlngTocartesian(pnt1))
+			for (let t = 0; t <= $this.FITTING_COUNT; t++) {
+				let pnt = $this.getCubicValue(t / $this.FITTING_COUNT, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
+				pList.push($this.LatlngTocartesian(pnt))
+			}
+			pList.push($this.LatlngTocartesian(pnt2))
+		}
+		let PolygonHierarchy = new $this.Cesium.PolygonHierarchy(pList);
+		return {
+			PolygonHierarchy,
+			pList
+		}
+	}
+
+	//加载闭合曲面
+	addload(data) {
+		let $this = this
+		if (data.length < 2) return
+		let pnts = Array.from(data);
+		pnts.push(pnts[0], pnts[1])
+		let [normals, pList] = [
+			[],
+			[]
+		]
+		for (let i = 0; i < pnts.length - 2; i++) {
+			let normalPoints = $this.getBisectorNormals($this.t, pnts[i], pnts[i + 1], pnts[i + 2])
+			normals = normals.concat(normalPoints)
+		}
+		let count = normals.length
+		normals = [normals[count - 1]].concat(normals.slice(0, count - 1))
+		for (let i = 0; i < pnts.length - 2; i++) {
+			let pnt1 = pnts[i]
+			let pnt2 = pnts[i + 1]
+			pList.push($this.LatlngTocartesian(pnt1))
+			for (let t = 0; t <= $this.FITTING_COUNT; t++) {
+				let pnt = $this.getCubicValue(t / $this.FITTING_COUNT, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
+				pList.push($this.LatlngTocartesian(pnt))
+			}
+			pList.push($this.LatlngTocartesian(pnt2))
+		}
+		console.log(data, pnts)
+		var arrowEntity = $this.viewer.entities.add({
+			Type: 'DrawClosedCurve',
+			Position: data,
+			id: data.id || $this.objId,
+			polygon: {
+				hierarchy: new $this.Cesium.PolygonHierarchy(pList),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			},
+			polyline: {
+				positions: pList,
+				show: true,
+				material: new Cesium.PolylineDashMaterialProperty({
+					color: Cesium.Color.YELLOW,
+				}),
+				width: 3,
+				clampToGround: true
+			}
+
+		});
+		return arrowEntity;
+	}
+
+	//开始创建
+	startCreate(drawType) {
+
+		if (isRuntimeApp()) {
+			showTooltipMessage("点击开始绘制");
+		}
+
+		var $this = this;
+
+		this.drawType = drawType;
+		this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+		//单击开始绘制
+		this.handler.setInputAction(function(evt) {
+			if (isRuntimeApp()) {
+
+				//屏幕坐标转地形上坐标
+				var cartesian = $this.getCatesian3FromPX(evt.position);
+				if (!cartesian) {
+					return;
+				}
+
+				$this.createPoint(cartesian); // 绘制点
+				$this._positions.push(cartesian);
+
+				if ($this._positions.length > 2) {
+					showTooltipMessage("点击添加点,点击完成按钮,结束绘制");
+					if ($this._positions.length === 3) {
+						
+						if (!$this.Cesium.defined($this._ClosedCurve)) {
+							$this._ClosedCurve = $this.createClosedCurve();
+
+							//创建按钮
+							createOperationMainDom();
+							//隐藏回退按钮
+							document.getElementById("btnDrawBackout").style.display = 'none';
+							//完成绘制
+							document.getElementById("btnDrawComplete").onclick = () => {
+
+								$this._ClosedCurveData = $this._positions.concat();
+								$this.viewer.entities.remove($this._ClosedCurve); //移除
+								$this._ClosedCurve = null;
+								$this._positions = [];
+								var lnglatArr = [];
+								for (var i = 0; i < $this._ClosedCurveData.length; i++) {
+									var lnglat = $this.cartesianToLatlng($this._ClosedCurveData[i]);
+									lnglatArr.push(lnglat)
+								}
+								$this._ClosedCurveData = lnglatArr;
+								var ClosedCurve = $this.addload(lnglatArr); //加载
+								$this._entities_ClosedCurve.push(ClosedCurve);
+								$this._ClosedCurveLast = ClosedCurve;
+								$this.clearPoint();
+								$this.destroy();
+
+								let buttonDiv = document.getElementById("drawButtonDiv");
+								if (buttonDiv) {
+									//从页面移除
+									document.body.removeChild(buttonDiv);
+								}
+							}
+						}
+					}
+
+				} else {
+					showTooltipMessage("点击添加点");
+				}
+
+			} else {
+				console.log('监听鼠标事件', '单击')
+
+				/* 锁定点击事件 以免和双击事件冲突 */
+				clearTimeout($this._timer);
+				$this._timer = setTimeout(function() {
+					//屏幕坐标转地形上坐标
+					var cartesian = $this.getCatesian3FromPX(evt.position);
+					if ($this._positions.length == 0) {
+						$this.floatingPoint = $this.createPoint(cartesian);
+					}
+					$this._positions.push(cartesian);
+					$this.createPoint(cartesian);
+				}, 200);
+			}
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+		//移动时绘制面
+		this.handler.setInputAction(function(evt) {
+
+			/* 如果运行环境是App 则禁止使用鼠标移动事件 */
+			if (isRuntimeApp()) return;
+
+			if ($this._positions.length == 0) {
+				$this._tooltip.showAt(evt.endPosition, "点击开始绘制");
+			} else {
+				$this._tooltip.showAt(evt.endPosition, "点击添加点");
+			}
+
+			if ($this._positions.length < 2) return;
+
+			$this._tooltip.showAt(evt.endPosition, "点击添加点,双击结束绘制");
+
+			var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+			if ($this._positions.length == 2) {
+				$this._positions.push(cartesian);
+			}
+			$this._positions.pop();
+			$this._positions.push(cartesian);
+			if (!$this.Cesium.defined($this._ClosedCurve)) {
+				$this._ClosedCurve = $this.createClosedCurve();
+			}
+
+		}, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+		//右击停止采集改为双击结束
+		this.handler.setInputAction(function(evt) {
+			// if (!$this._ClosedCurve) return;
+			// var cartesian = $this.getCatesian3FromPX(evt.position);
+			// $this._positions.pop();
+			// $this._positions.push(cartesian);
+			// $this._ClosedCurveData = $this._positions.concat();
+			// $this.viewer.entities.remove($this._ClosedCurve); //移除
+			// $this._ClosedCurve = null;
+			// $this._positions = [];
+			// $this.floatingPoint.position.setValue(cartesian);
+			// var lnglatArr = [];
+			// for (var i = 0; i < $this._ClosedCurveData.length; i++) {
+			// 	var lnglat = $this.cartesianToLatlng($this._ClosedCurveData[i]);
+			// 	lnglatArr.push(lnglat)
+			// }
+			// $this._ClosedCurveData = lnglatArr;
+			// var ClosedCurve = $this.addload(lnglatArr); //加载
+			// $this._entities_ClosedCurve.push(ClosedCurve);
+			// $this._ClosedCurveLast = ClosedCurve;
+			// $this.clearPoint();
+			// $this.destroy()
+		}, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+		//双击结束
+		this.handler.setInputAction(function(evt) {
+			/* 如果运行环境是App 则禁止使用鼠标双击事件 */
+			if (isRuntimeApp()) return;
+
+			console.log('监听鼠标事件', '双击')
+
+			/* 解除锁定 */
+			clearTimeout($this._timer);
+
+			if (!$this._ClosedCurve) return;
+
+			var cartesian = $this.getCatesian3FromPX(evt.position);
+			$this._positions.pop();
+			$this._positions.push(cartesian);
+			$this._ClosedCurveData = $this._positions.concat();
+			$this.viewer.entities.remove($this._ClosedCurve); //移除
+			$this._ClosedCurve = null;
+			$this._positions = [];
+			$this.floatingPoint.position.setValue(cartesian);
+			var lnglatArr = [];
+			for (var i = 0; i < $this._ClosedCurveData.length; i++) {
+				var lnglat = $this.cartesianToLatlng($this._ClosedCurveData[i]);
+				lnglatArr.push(lnglat)
+			}
+			$this._ClosedCurveData = lnglatArr;
+			var ClosedCurve = $this.addload(lnglatArr); //加载
+			$this._entities_ClosedCurve.push(ClosedCurve);
+			$this._ClosedCurveLast = ClosedCurve;
+			$this.clearPoint();
+			$this.destroy();
+
+			$this._tooltip.setVisible(false);
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
+	}
+
+	//创建直线闭合曲面
+	createClosedCurve() {
+		// console.log(this._positions)
+		var $this = this;
+		$this.pLists = ''
+		var arrowEntity = $this.viewer.entities.add({
+			polygon: {
+				hierarchy: new $this.Cesium.CallbackProperty(
+					function() {
+						if ($this._positions.length < 2) return
+						let pnts = []
+						for (let p = 0; p < $this._positions.length; p++) {
+							pnts.push($this.cartesianToLatlng($this._positions[p]))
+						}
+						pnts.push(pnts[0], pnts[1])
+						let [normals, pList] = [
+							[],
+							[]
+						]
+						for (let i = 0; i < pnts.length - 2; i++) {
+							let normalPoints = $this.getBisectorNormals($this.t, pnts[i], pnts[i + 1], pnts[i + 2])
+							normals = normals.concat(normalPoints)
+						}
+						let count = normals.length
+						normals = [normals[count - 1]].concat(normals.slice(0, count - 1))
+						for (let i = 0; i < pnts.length - 2; i++) {
+							let pnt1 = pnts[i]
+							let pnt2 = pnts[i + 1]
+							pList.push($this.LatlngTocartesian(pnt1))
+							for (let t = 0; t <= $this.FITTING_COUNT; t++) {
+								let pnt = $this.getCubicValue(t / $this.FITTING_COUNT, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
+								pList.push($this.LatlngTocartesian(pnt))
+							}
+							pList.push($this.LatlngTocartesian(pnt2))
+						}
+						$this.pLists = pList
+						return new $this.Cesium.PolygonHierarchy(pList);
+					}, false),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			},
+			polyline: {
+				positions: new $this.Cesium.CallbackProperty(
+					function() {
+						return $this.pLists
+					}, false
+				),
+				show: true,
+				material: new Cesium.PolylineDashMaterialProperty({
+					color: Cesium.Color.YELLOW,
+				}),
+				width: 3,
+				clampToGround: true
+			}
+		})
+		$this._entities_ClosedCurve.push(arrowEntity);
+		return arrowEntity
+	}
+
+	//创建点
+	createPoint(cartesian) {
+		var $this = this;
+		var point = this.viewer.entities.add({
+			position: cartesian,
+			point: {
+				pixelSize: 10,
+				color: $this.Cesium.Color.RED,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			}
+		});
+		$this._entities_point.push(point);
+		return point;
+	}
+
+
+	/**
+	 * 世界坐标转经纬度
+	 */
+	cartesianToLatlng(cartesian) {
+		var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+		var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+		return [lng, lat];
+	}
+
+	/**
+	 * 经纬度转世界坐标
+	 */
+	LatlngTocartesian(latlng) {
+		let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+		return cartesian3
+	}
+
+	/**
+	 * 经纬度坐标转墨卡托坐标
+	 */
+	// 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
+	// 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
+	lonLatToMercator(Latlng) {
+		var E = Latlng[0];
+		var N = Latlng[1];
+		var x = E * 20037508.34 / 180;
+		var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
+		y = y * 20037508.34 / 180;
+		return [x, y]
+	}
+	/**
+	 * 墨卡托坐标转经纬度坐标转
+	 */
+	WebMercator2lonLat(mercator) {
+		let x = mercator[0] / 20037508.34 * 180;
+		let ly = mercator[1] / 20037508.34 * 180;
+		let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
+		return [x, y];
+	}
+
+	//销毁
+	destroy() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+	}
+
+	clearPoint() {
+		this.DrawEndEvent.raiseEvent(this._ClosedCurveLast, this._ClosedCurveData);
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		this._entities_point = []; //脏数据
+	}
+
+	//清空实体对象
+	clear() {
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		for (var i = 0; i < this._entities_ClosedCurve.length; i++) {
+			this.viewer.entities.remove(this._entities_ClosedCurve[i]);
+		}
+		this.floatingPoint = null; //标识点
+		this._ClosedCurve = null; //活动闭合曲面
+		this._ClosedCurveLast = null; //最后一个闭合曲面
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_ClosedCurve = []; //脏数据
+		this._ClosedCurveData = null; //用于构造闭合曲面数据
+	}
+
+	getCatesian3FromPX(px) {
+		var cartesian;
+		var ray = this.viewer.camera.getPickRay(px);
+		if (!ray) return null;
+		cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+		return cartesian;
+	}
+
+	// 求取闭合曲面坐标函数/
+	//闭合曲面配置函数
+	/**
+	 * getBisectorNormals
+	 * @param t
+	 * @param pnt1
+	 * @param pnt2
+	 * @param pnt3
+	 * @returns {[*,*]}
+	 */
+	getBisectorNormals(t, pnt1, pnt2, pnt3) {
+		let $this = this
+		let normal = $this.getNormal(pnt1, pnt2, pnt3)
+		let [bisectorNormalRight, bisectorNormalLeft, dt, x, y] = [null, null, null, null, null]
+		let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
+		let uX = normal[0] / dist
+		let uY = normal[1] / dist
+		let d1 = $this.MathDistance(pnt1, pnt2)
+		let d2 = $this.MathDistance(pnt2, pnt3)
+
+		if (dist > $this.ZERO_TOLERANCE) {
+			if ($this.isClockWise(pnt1, pnt2, pnt3)) {
+				dt = t * d1
+				x = pnt2[0] - dt * uY
+				y = pnt2[1] + dt * uX
+				bisectorNormalRight = [x, y]
+				dt = t * d2
+				x = pnt2[0] + dt * uY
+				y = pnt2[1] - dt * uX
+				bisectorNormalLeft = [x, y]
+			} else {
+				dt = t * d1
+				x = pnt2[0] + dt * uY
+				y = pnt2[1] - dt * uX
+				bisectorNormalRight = [x, y]
+				dt = t * d2
+				x = pnt2[0] - dt * uY
+				y = pnt2[1] + dt * uX
+				bisectorNormalLeft = [x, y]
+			}
+		} else {
+			x = pnt2[0] + t * (pnt1[0] - pnt2[0])
+			y = pnt2[1] + t * (pnt1[1] - pnt2[1])
+			bisectorNormalRight = [x, y]
+			x = pnt2[0] + t * (pnt3[0] - pnt2[0])
+			y = pnt2[1] + t * (pnt3[1] - pnt2[1])
+			bisectorNormalLeft = [x, y]
+		}
+		return [bisectorNormalRight, bisectorNormalLeft]
+	}
+
+
+	/**
+	 * 获取默认三点的内切圆
+	 * @param pnt1
+	 * @param pnt2
+	 * @param pnt3
+	 * @returns {[*,*]}
+	 */
+	getNormal(pnt1, pnt2, pnt3) {
+		let dX1 = pnt1[0] - pnt2[0]
+		let dY1 = pnt1[1] - pnt2[1]
+		let d1 = Math.sqrt(dX1 * dX1 + dY1 * dY1)
+		dX1 /= d1
+		dY1 /= d1
+		let dX2 = pnt3[0] - pnt2[0]
+		let dY2 = pnt3[1] - pnt2[1]
+		let d2 = Math.sqrt(dX2 * dX2 + dY2 * dY2)
+		dX2 /= d2
+		dY2 /= d2
+		let uX = dX1 + dX2
+		let uY = dY1 + dY2
+		return [uX, uY]
+	}
+
+	/**
+	 * 计算两个坐标之间的距离
+	 * @ignore
+	 * @param pnt1
+	 * @param pnt2
+	 * @returns {number}
+	 * @constructor
+	 */
+	MathDistance(pnt1, pnt2) {
+		return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2)))
+	}
+
+	/**
+	 * 判断是否是顺时针
+	 * @param pnt1
+	 * @param pnt2
+	 * @param pnt3
+	 * @returns {boolean}
+	 */
+	isClockWise(pnt1, pnt2, pnt3) {
+		return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0]))
+	}
+
+	/**
+	 * 获取立方值
+	 * @param t
+	 * @param startPnt
+	 * @param cPnt1
+	 * @param cPnt2
+	 * @param endPnt
+	 * @returns {[*,*]}
+	 */
+	getCubicValue(t, startPnt, cPnt1, cPnt2, endPnt) {
+		t = Math.max(Math.min(t, 1), 0)
+		let [tp, t2] = [(1 - t), (t * t)]
+		let t3 = t2 * t
+		let tp2 = tp * tp
+		let tp3 = tp2 * tp
+		let x = (tp3 * startPnt[0]) + (3 * tp2 * t * cPnt1[0]) + (3 * tp * t2 * cPnt2[0]) + (t3 * endPnt[0])
+		let y = (tp3 * startPnt[1]) + (3 * tp2 * t * cPnt1[1]) + (3 * tp * t2 * cPnt2[1]) + (t3 * endPnt[1])
+		return [x, y]
+	}
+
+}
+
+export default DrawClosedCurve

+ 510 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawCurve.js

@@ -0,0 +1,510 @@
+// 三、曲线
+// DrawCurve
+/*
+绘制曲线
+ */
+class DrawCurve {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this.floatingPoint = null;//标识点
+        this._curveline = null; //活动曲线
+        this._curvelineLast = null; //最后一条曲线
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_line = [];  //脏数据
+        this._curvelineData = null; //用于构造曲线数据
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+        this.ZERO_TOLERANCE = 0.0001;
+        this.FITTING_COUNT = 100;
+        this.t = 0.3;
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+
+    //返回最后活动曲线
+    get curveline() {
+        return this._curvelineLast;
+    }
+
+    //返回线数据用于加载线
+    getData() {
+        return this._curvelineData;
+    }
+
+    //加载曲线
+    addload(data) {
+        var $this = this;
+        let pnts = []
+        for (let p = 0; p < data.length; p++) {
+            pnts.push($this.lonLatToMercator(data[p]))
+        }
+        let CurvePoints = $this.getCurvePoints(pnts)
+        let point = [];
+        for (let i = 0; i < CurvePoints.length; i++) {
+            point.push($this.LatlngTocartesian($this.WebMercator2lonLat(CurvePoints[i])))
+        }
+        var polyline = this.viewer.entities.add({
+            Type: 'DrawCurve',
+            Position: data,
+            id: data.id || $this.objId,
+            polyline: {
+                positions: point,
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 3,
+                clampToGround: true
+            }
+        });
+        return polyline;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data) {
+        let pnts = [];
+        let position = [];
+        for (let p = 0; p < data.length; p++) {
+            position.push(this.cartesianToLatlng(data[p]));
+            pnts.push(this.lonLatToMercator(this.cartesianToLatlng(data[p])))
+        }
+        this._curvelineData = position;
+        let CurvePoints = this.getCurvePoints(pnts)
+        let point = [];
+        for (let i = 0; i < CurvePoints.length; i++) {
+            point.push(this.LatlngTocartesian(this.WebMercator2lonLat(CurvePoints[i])))
+        }
+        return point;
+    }
+
+    //开始创建
+    startCreate(drawType) {
+        this.drawType = drawType
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this._positions.length == 0) {
+                $this._positions.push(cartesian.clone());
+                $this.floatingPoint = $this.createPoint(cartesian);
+                $this.createPoint(cartesian);// 绘制点
+            }
+            $this._positions.push(cartesian);
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制线
+            if ($this._positions.length < 3) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this._curveline)) {
+                $this._curveline = $this.createCurveline();
+            }
+            $this.floatingPoint.position.setValue(cartesian);
+            if ($this._curveline) {
+                $this._positions.pop();
+                $this._positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this._curveline) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this._positions.pop();
+            $this._positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+            $this._curvelineData = $this._positions.concat();
+            $this.viewer.entities.remove($this._curveline); //移除
+            $this._curveline = null;
+            $this._positions = [];
+            $this.floatingPoint.position.setValue(cartesian);
+            let lnglatArr = [];
+            for (var i = 0; i < $this._curvelineData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this._curvelineData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this._curvelineData = lnglatArr;
+            var line = $this.addload($this._curvelineData); //加载曲线
+            $this._entities_line.push(line);
+            $this._curvelineLast = line;
+            $this.clearPoint()
+            $this.destroy()
+
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+               pixelSize: 10,
+               color: $this.Cesium.Color.RED,
+               heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this._entities_point.push(point);
+        return point;
+    }
+
+    //创建曲线
+    createCurveline() {
+        var $this = this;
+        var polyline = this.viewer.entities.add({
+            polyline: {
+                //使用cesium的peoperty
+                positions: new $this.Cesium.CallbackProperty(function () {
+                    let pnts = []
+                    for (let p = 0; p < $this._positions.length; p++) {
+                        pnts.push($this.lonLatToMercator($this.cartesianToLatlng($this._positions[p])))
+                    }
+                    let CurvePoints = $this.getCurvePoints(pnts)
+                    let point = [];
+                    for (let i = 0; i < CurvePoints.length; i++) {
+                        point.push($this.LatlngTocartesian($this.WebMercator2lonLat(CurvePoints[i])))
+                    }
+                    return point;
+                }, false),
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 3,
+                clampToGround: true
+            }
+        });
+        $this._entities_line.push(polyline);
+        return polyline;
+    }
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this._curvelineLast, this._curvelineData, this.drawType);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        for (var i = 0; i < this._entities_line.length; i++) {
+            this.viewer.entities.remove(this._entities_line[i]);
+        }
+        this.floatingPoint = null;//标识点
+        this._curveline = null; //活动曲线
+        this._curvelineLast = null; //最后一条曲线
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_line = [];  //脏数据
+        this._curvelineData = null; //用于构造曲线数据
+    }
+
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    /**
+     * 经纬度坐标转墨卡托坐标
+     */
+    // 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
+    // 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
+    lonLatToMercator(Latlng) {
+        var E = Latlng[0];
+        var N = Latlng[1];
+        var x = E * 20037508.34 / 180;
+        var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
+        y = y * 20037508.34 / 180;
+        return [x, y]
+    }
+    /**
+     * 墨卡托坐标转经纬度坐标转
+     */
+    WebMercator2lonLat(mercator) {
+        let x = mercator[0] / 20037508.34 * 180;
+        let ly = mercator[1] / 20037508.34 * 180;
+        let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
+        return [x, y];
+    }
+
+
+
+    /**
+     * 插值曲线点
+     * @param t
+     * @param controlPoints
+     * @returns {null}
+     */
+    getCurvePoints( controlPoints) {
+        let leftControl = this.getLeftMostControlPoint(controlPoints, this.t)
+        let [pnt1, pnt2, pnt3, normals, points] = [null, null, null, [leftControl], []]
+        for (let i = 0; i < controlPoints.length - 2; i++) {
+            [pnt1, pnt2, pnt3] = [controlPoints[i], controlPoints[i + 1], controlPoints[i + 2]]
+            let normalPoints = this.getBisectorNormals(this.t, pnt1, pnt2, pnt3)
+            normals = normals.concat(normalPoints)
+        }
+        let rightControl = this.getRightMostControlPoint(controlPoints, this.t)
+        if (rightControl) {
+            normals.push(rightControl)
+        }
+        for (let i = 0; i < controlPoints.length - 1; i++) {
+            pnt1 = controlPoints[i]
+            pnt2 = controlPoints[i + 1]
+            points.push(pnt1)
+            for (let t = 0; t < this.FITTING_COUNT; t++) {
+                let pnt = this.getCubicValue(t / this.FITTING_COUNT, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
+                points.push(pnt)
+            }
+            points.push(pnt2)
+        }
+        return points
+    }
+
+
+
+
+    /**
+     * 获取左边控制点
+     * @param controlPoints
+     * @returns {[*,*]}
+     */
+    getLeftMostControlPoint(controlPoints, t) {
+        let [pnt1, pnt2, pnt3, controlX, controlY] = [controlPoints[0], controlPoints[1], controlPoints[2], null, null]
+        let pnts = this.getBisectorNormals(0, pnt1, pnt2, pnt3)
+        let normalRight = pnts[0]
+        let normal = this.getNormal(pnt1, pnt2, pnt3)
+        let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
+        if (dist > this.ZERO_TOLERANCE) {
+            let mid = this.Mid(pnt1, pnt2)
+            let pX = pnt1[0] - mid[0]
+            let pY = pnt1[1] - mid[1]
+            let d1 = this.MathDistance(pnt1, pnt2)
+            let n = 2.0 / d1
+            let nX = -n * pY
+            let nY = n * pX
+            let a11 = nX * nX - nY * nY
+            let a12 = 2 * nX * nY
+            let a22 = nY * nY - nX * nX
+            let dX = normalRight[0] - mid[0]
+            let dY = normalRight[1] - mid[1]
+            controlX = mid[0] + a11 * dX + a12 * dY
+            controlY = mid[1] + a12 * dX + a22 * dY
+        } else {
+            controlX = pnt1[0] + t * (pnt2[0] - pnt1[0])
+            controlY = pnt1[1] + t * (pnt2[1] - pnt1[1])
+        }
+        return [controlX, controlY]
+    }
+
+
+    /**
+     * getBisectorNormals
+     * @param t
+     * @param pnt1
+     * @param pnt2
+     * @param pnt3
+     * @returns {[*,*]}
+     */
+    getBisectorNormals(t, pnt1, pnt2, pnt3) {
+        let normal = this.getNormal(pnt1, pnt2, pnt3)
+        let [bisectorNormalRight, bisectorNormalLeft, dt, x, y] = [null, null, null, null, null]
+        let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
+        let uX = normal[0] / dist
+        let uY = normal[1] / dist
+        let d1 = this.MathDistance(pnt1, pnt2)
+        let d2 = this.MathDistance(pnt2, pnt3)
+        if (dist > this.ZERO_TOLERANCE) {
+            if (this.isClockWise(pnt1, pnt2, pnt3)) {
+                dt = t * d1
+                x = pnt2[0] - dt * uY
+                y = pnt2[1] + dt * uX
+                bisectorNormalRight = [x, y]
+                dt = t * d2
+                x = pnt2[0] + dt * uY
+                y = pnt2[1] - dt * uX
+                bisectorNormalLeft = [x, y]
+            } else {
+                dt = t * d1
+                x = pnt2[0] + dt * uY
+                y = pnt2[1] - dt * uX
+                bisectorNormalRight = [x, y]
+                dt = t * d2
+                x = pnt2[0] - dt * uY
+                y = pnt2[1] + dt * uX
+                bisectorNormalLeft = [x, y]
+            }
+        } else {
+            x = pnt2[0] + t * (pnt1[0] - pnt2[0])
+            y = pnt2[1] + t * (pnt1[1] - pnt2[1])
+            bisectorNormalRight = [x, y]
+            x = pnt2[0] + t * (pnt3[0] - pnt2[0])
+            y = pnt2[1] + t * (pnt3[1] - pnt2[1])
+            bisectorNormalLeft = [x, y]
+        }
+        return [bisectorNormalRight, bisectorNormalLeft]
+    }
+
+
+
+    /**
+     * 获取默认三点的内切圆
+     * @param pnt1
+     * @param pnt2
+     * @param pnt3
+     * @returns {[*,*]}
+     */
+    getNormal(pnt1, pnt2, pnt3) {
+        let dX1 = pnt1[0] - pnt2[0]
+        let dY1 = pnt1[1] - pnt2[1]
+        let d1 = Math.sqrt(dX1 * dX1 + dY1 * dY1)
+        dX1 /= d1
+        dY1 /= d1
+        let dX2 = pnt3[0] - pnt2[0]
+        let dY2 = pnt3[1] - pnt2[1]
+        let d2 = Math.sqrt(dX2 * dX2 + dY2 * dY2)
+        dX2 /= d2
+        dY2 /= d2
+        let uX = dX1 + dX2
+        let uY = dY1 + dY2
+        return [uX, uY]
+    }
+
+
+
+    /**
+     * 判断是否是顺时针
+     * @param pnt1
+     * @param pnt2
+     * @param pnt3
+     * @returns {boolean}
+     */
+    isClockWise(pnt1, pnt2, pnt3) {
+        return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0]))
+    }
+
+
+    /**
+     * 求取两个坐标的中间值
+     * @param point1
+     * @param point2
+     * @returns {[*,*]}
+     * @constructor
+     */
+    Mid(point1, point2) {
+        return [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2]
+    }
+
+
+    /**
+     * 计算两个坐标之间的距离
+	 * @ignore
+     * @param pnt1
+     * @param pnt2
+     * @returns {number}
+     * @constructor
+     */
+    MathDistance(pnt1, pnt2) {
+        return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2)))
+    }
+
+
+    /**
+     * 获取右边控制点
+     * @param controlPoints
+     * @param t
+     * @returns {[*,*]}
+     */
+    getRightMostControlPoint(controlPoints, t) {
+        let count = controlPoints.length
+        let pnt1 = controlPoints[count - 3]
+        let pnt2 = controlPoints[count - 2]
+        let pnt3 = controlPoints[count - 1]
+        let pnts = this.getBisectorNormals(0, pnt1, pnt2, pnt3)
+        let normalLeft = pnts[1]
+        let normal = this.getNormal(pnt1, pnt2, pnt3)
+        let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
+        let [controlX, controlY] = [null, null]
+        if (dist > this.ZERO_TOLERANCE) {
+            let mid = this.Mid(pnt2, pnt3)
+            let pX = pnt3[0] - mid[0]
+            let pY = pnt3[1] - mid[1]
+            let d1 = this.MathDistance(pnt2, pnt3)
+            let n = 2.0 / d1
+            let nX = -n * pY
+            let nY = n * pX
+            let a11 = nX * nX - nY * nY
+            let a12 = 2 * nX * nY
+            let a22 = nY * nY - nX * nX
+            let dX = normalLeft[0] - mid[0]
+            let dY = normalLeft[1] - mid[1]
+            controlX = mid[0] + a11 * dX + a12 * dY
+            controlY = mid[1] + a12 * dX + a22 * dY
+        } else {
+            controlX = pnt3[0] + t * (pnt2[0] - pnt3[0])
+            controlY = pnt3[1] + t * (pnt2[1] - pnt3[1])
+        }
+        return [controlX, controlY]
+    }
+
+
+    /**
+     * 获取立方值
+     * @param t
+     * @param startPnt
+     * @param cPnt1
+     * @param cPnt2
+     * @param endPnt
+     * @returns {[*,*]}
+     */
+    getCubicValue(t, startPnt, cPnt1, cPnt2, endPnt) {
+        t = Math.max(Math.min(t, 1), 0)
+        let [tp, t2] = [(1 - t), (t * t)]
+        let t3 = t2 * t
+        let tp2 = tp * tp
+        let tp3 = tp2 * tp
+        let x = (tp3 * startPnt[0]) + (3 * tp2 * t * cPnt1[0]) + (3 * tp * t2 * cPnt2[0]) + (t3 * endPnt[0])
+        let y = (tp3 * startPnt[1]) + (3 * tp2 * t * cPnt1[1]) + (3 * tp * t2 * cPnt2[1]) + (t3 * endPnt[1])
+        return [x, y]
+    }
+
+
+
+}
+
+export default DrawCurve

+ 463 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawCurveFlag.js

@@ -0,0 +1,463 @@
+
+// DrawCurveFlag
+/*
+绘制曲线旗标
+ */
+class DrawCurveFlag {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this.identificationPoint = null; //标识点位
+        this.CurveFlag = null; 
+        this.CurveFlagLast = null; // 曲线旗标数据
+        this.positions = [];  // 经纬度
+        this.entitiesPoint = [];   // 实体点位
+        this.entitiesCurveFlag = [];  
+        this.CurveFlagData = null; 
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    //返回曲线旗标数据
+    getData() {
+        return this.CurveFlagData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        //计算面
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        // 取第一个
+        let startPoint = lnglatArr[0]
+        // 取最后一个
+        let endPoint =lnglatArr[lnglatArr.length - 1]
+        // 上曲线起始点
+        let point1 = startPoint
+        // 上曲线第一控制点
+        let point2 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+        // 上曲线第二个点
+        let point3 = [(startPoint[0] + endPoint[0]) / 2, startPoint[1]]
+        // 上曲线第二控制点
+        let point4 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], -(endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+        // 上曲线结束点
+        let point5 = [endPoint[0], startPoint[1]]
+        // 下曲线结束点
+        let point6 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        // 下曲线第二控制点
+        let point7 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 3 / 8 + startPoint[1]]
+        // 下曲线第二个点
+        let point8 = [(startPoint[0] + endPoint[0]) / 2, (startPoint[1] + endPoint[1]) / 2]
+        // 下曲线第一控制点
+        let point9 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 5 / 8 + startPoint[1]]
+        // 下曲线起始点
+        let point10 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        // 旗杆底部点
+        let point11 = [startPoint[0], endPoint[1]]
+        // 计算上曲线
+        let curve1 = $this.getBezierPoints([point1, point2, point3, point4, point5])
+        // 计算下曲线
+        let curve2 = $this.getBezierPoints([point6, point7, point8, point9, point10])
+        // 面合并
+        let componentspolygon = [];
+        componentspolygon = curve1.concat(curve2)
+        let PolygonHierarchy = new $this.Cesium.PolygonHierarchy(componentspolygon)
+        // 线边合并
+        let componentspolyline = [];
+        componentspolyline = curve1.concat(curve2)
+        componentspolyline.push($this.LatlngTocartesian(point1))
+        componentspolyline.push($this.LatlngTocartesian(point11))
+        
+        $this.CurveFlagData = lnglatArr;
+        return [PolygonHierarchy,componentspolyline];
+    }
+ 
+    //加载
+    addload(data) {
+        var $this = this;
+        if (data.length < 2) return;
+        // 取第一个
+        let startPoint = data[0]
+        // 取最后一个
+        let endPoint =data[data.length - 1]
+        // 上曲线起始点
+        let point1 = startPoint
+        // 上曲线第一控制点
+        let point2 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+        // 上曲线第二个点
+        let point3 = [(startPoint[0] + endPoint[0]) / 2, startPoint[1]]
+        // 上曲线第二控制点
+        let point4 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], -(endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+        // 上曲线结束点
+        let point5 = [endPoint[0], startPoint[1]]
+        // 下曲线结束点
+        let point6 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        // 下曲线第二控制点
+        let point7 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 3 / 8 + startPoint[1]]
+        // 下曲线第二个点
+        let point8 = [(startPoint[0] + endPoint[0]) / 2, (startPoint[1] + endPoint[1]) / 2]
+        // 下曲线第一控制点
+        let point9 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 5 / 8 + startPoint[1]]
+        // 下曲线起始点
+        let point10 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        // 旗杆底部点
+        let point11 = [startPoint[0], endPoint[1]]
+        // 计算上曲线
+        let curve1 = $this.getBezierPoints([point1, point2, point3, point4, point5])
+        // 计算下曲线
+        let curve2 = $this.getBezierPoints([point6, point7, point8, point9, point10])
+        // 合并
+        let componentspolygon = [];
+        componentspolygon = curve1.concat(curve2)
+        let componentspolyline = [];
+        componentspolyline = curve1.concat(curve2)
+        componentspolyline.push($this.LatlngTocartesian(point1))
+        componentspolyline.push($this.LatlngTocartesian(point11))
+        
+        var shape = this.viewer.entities.add({
+            Type:'DrawCurveFlag',
+            Position:data,
+            id:data.id || $this.objId,
+            polygon: {
+                hierarchy: new $this.Cesium.PolygonHierarchy(componentspolygon),
+                extrudedHeight: 1,
+                material: $this.Cesium.Color.RED,
+            },
+            polyline: {
+                //使用cesium的peoperty
+                positions: componentspolyline,
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 5,
+                clampToGround: true
+            }
+        });
+        $this.entitiesCurveFlag.push(shape);
+        return shape;
+    }
+ 
+    //开始创建
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this.positions.length == 0) {
+                $this.positions.push(cartesian.clone());
+                $this.identificationPoint = $this.createPoint(cartesian);
+                $this.createPoint(cartesian);// 绘制点
+                $this.positions.push(cartesian);
+            }
+            // if ($this.positions.length == 2) {
+            //     $this.positions.push(cartesian);
+            // }
+            
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制线
+            if ($this.positions.length < 2) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this.CurveFlag)) {
+                $this.CurveFlag = $this.createCurveFlag();
+            }
+            $this.identificationPoint.position.setValue(cartesian);
+            if ($this.CurveFlag) {
+                $this.positions.pop();
+                $this.positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this.CurveFlag) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this.positions.pop();
+            $this.positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+            $this.CurveFlagData = $this.positions.concat();
+            $this.viewer.entities.remove($this.CurveFlag); //移除
+            $this.CurveFlag = null;
+            $this.positions = [];
+            $this.identificationPoint.position.setValue(cartesian);
+            var lnglatArr = [];
+            for (var i = 0; i < $this.CurveFlagData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this.CurveFlagData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this.CurveFlagData = lnglatArr;
+            var CurveFlag = $this.addload([$this.CurveFlagData[0],$this.CurveFlagData[$this.CurveFlagData.length -1 ]]); //加载
+            $this.entitiesCurveFlag.push(CurveFlag);
+            $this.CurveFlagLast = CurveFlag;
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this.entitiesPoint.push(point);
+        return point;
+    }
+ 
+    //创建曲线旗标
+    createCurveFlag() {
+        var $this = this;
+        var polygon = this.viewer.entities.add({
+            polygon: {
+                hierarchy: new $this.Cesium.CallbackProperty(function () {
+                    if($this.positions.length < 2) return 
+                    let lonlat = [];
+                    let components = [];
+                    let length = $this.positions.length
+                    for (let i=0; i<length; i++){
+                        lonlat.push($this.cartesianToLatlng($this.positions[i]))
+                    }
+                    // 取第一个
+                    let startPoint = lonlat[0]
+                    // 取最后一个
+                    let endPoint =lonlat[lonlat.length - 1]
+                    // 上曲线起始点
+                    let point1 = startPoint
+                    // 上曲线第一控制点
+                    let point2 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+                    // 上曲线第二个点
+                    let point3 = [(startPoint[0] + endPoint[0]) / 2, startPoint[1]]
+                    // 上曲线第二控制点
+                    let point4 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], -(endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+                    // 上曲线结束点
+                    let point5 = [endPoint[0], startPoint[1]]
+                    // 下曲线结束点
+                    let point6 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    // 下曲线第二控制点
+                    let point7 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 3 / 8 + startPoint[1]]
+                    // 下曲线第二个点
+                    let point8 = [(startPoint[0] + endPoint[0]) / 2, (startPoint[1] + endPoint[1]) / 2]
+                    // 下曲线第一控制点
+                    let point9 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 5 / 8 + startPoint[1]]
+                    // 下曲线起始点
+                    let point10 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    // 旗杆底部点
+                    let point11 = [startPoint[0], endPoint[1]]
+                    // 计算上曲线
+                    let curve1 = $this.getBezierPoints([point1, point2, point3, point4, point5])
+                    // 计算下曲线
+                    let curve2 = $this.getBezierPoints([point6, point7, point8, point9, point10])
+                    // 合并
+                    components = curve1.concat(curve2)
+                    // components.push(point11)
+                    // let components = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0])
+                    
+                    return new $this.Cesium.PolygonHierarchy(components);
+                }, false),
+                extrudedHeight: 1,
+                material: $this.Cesium.Color.RED,
+            },
+            polyline: {
+                //使用cesium的peoperty
+                positions: new $this.Cesium.CallbackProperty(function () {
+                    if($this.positions.length < 2) return 
+                    let lonlat = [];
+                    let components = [];
+                    let length = $this.positions.length
+                    for (let i=0; i<length; i++){
+                        lonlat.push($this.cartesianToLatlng($this.positions[i]))
+                    }
+                    // 取第一个
+                    let startPoint = lonlat[0]
+                    // 取最后一个
+                    let endPoint =lonlat[lonlat.length - 1]
+                    // 上曲线起始点
+                    let point1 = startPoint
+                    // 上曲线第一控制点
+                    let point2 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+                    // 上曲线第二个点
+                    let point3 = [(startPoint[0] + endPoint[0]) / 2, startPoint[1]]
+                    // 上曲线第二控制点
+                    let point4 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], -(endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+                    // 上曲线结束点
+                    let point5 = [endPoint[0], startPoint[1]]
+                    // 下曲线结束点
+                    let point6 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    // 下曲线第二控制点
+                    let point7 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 3 / 8 + startPoint[1]]
+                    // 下曲线第二个点
+                    let point8 = [(startPoint[0] + endPoint[0]) / 2, (startPoint[1] + endPoint[1]) / 2]
+                    // 下曲线第一控制点
+                    let point9 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 5 / 8 + startPoint[1]]
+                    // 下曲线起始点
+                    let point10 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    // 旗杆底部点
+                    let point11 = [startPoint[0], endPoint[1]]
+                    // 计算上曲线
+                    let curve1 = $this.getBezierPoints([point1, point2, point3, point4, point5])
+                    // 计算下曲线
+                    let curve2 = $this.getBezierPoints([point6, point7, point8, point9, point10])
+                    // 合并
+                    components = curve1.concat(curve2)
+                    components.push($this.LatlngTocartesian(point1))
+                    components.push($this.LatlngTocartesian(point11))
+                    
+                    return components
+                }, false),
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 5,
+                clampToGround: true
+            }
+        });
+        $this.entitiesCurveFlag.push(polygon);
+        return polygon;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this.CurveFlagLast, [this.CurveFlagData[0],this.CurveFlagData[this.CurveFlagData.length -1 ]], this.drawType);
+        for (var i = 0; i < this.entitiesPoint.length; i++) {
+            this.viewer.entities.remove(this.entitiesPoint[i]);
+        }
+        this.entitiesPoint = [];  //脏数据
+    }
+ 
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this.entitiesPoint.length; i++) {
+            this.viewer.entities.remove(this.entitiesPoint[i]);
+        }
+        for (var i = 0; i < this.entitiesCurveFlag.length; i++) {
+            this.viewer.entities.remove(this.entitiesCurveFlag[i]);
+        }
+        this.identificationPoint = null; //标识点位
+        this.CurveFlag = null; 
+        this.CurveFlagLast = null; // 曲线旗标数据
+        this.positions = [];  // 经纬度
+        this.entitiesPoint = [];   // 实体点位
+        this.entitiesCurveFlag = [];  
+        this.CurveFlagData = null; 
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+
+    // 贝塞尔曲线
+    getBezierPoints (points) {
+        let $this = this
+        if (points.length <= 2) {
+          return points
+        } else {
+          let bezierPoints = []
+          let n = points.length - 1
+          for (let t = 0; t <= 1; t += 0.01) {
+            let [x, y] = [0, 0]
+            for (let index = 0; index <= n; index++) {
+              let factor = $this.getBinomialFactor(n, index)
+              let a = Math.pow(t, index)
+              let b = Math.pow((1 - t), (n - index))
+              x += factor * a * b * points[index][0]
+              y += factor * a * b * points[index][1]
+            }
+            bezierPoints.push($this.LatlngTocartesian([x, y]))
+          }
+          bezierPoints.push($this.LatlngTocartesian(points[n]))
+          return bezierPoints
+        }
+    }
+
+
+        /**
+     * 获取二项分布
+     * @param n
+     * @param index
+     * @returns {number}
+     */
+    getBinomialFactor(n, index) {
+        return (this.getFactorial(n) / (this.getFactorial(index) * this.getFactorial(n - index)))
+    }
+
+    /**
+    * 获取阶乘数据
+    * @param n
+    * @returns {number}
+    */
+    getFactorial (n) {
+        let result = 1
+        switch (n) {
+        case (n <= 1):
+            result = 1
+            break
+        case (n === 2):
+            result = 2
+            break
+        case (n === 3):
+            result = 6
+            break
+        case (n === 24):
+            result = 24
+            break
+        case (n === 5):
+            result = 120
+            break
+        default:
+            for (let i = 1; i <= n; i++) {
+            result *= i
+            }
+            break
+        }
+        return result
+    }
+}
+ 
+export default DrawCurveFlag
+

+ 611 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawGatheringPlace.js

@@ -0,0 +1,611 @@
+import {
+	createTooltip
+} from "../../../common/common.js";
+
+import {
+	isRuntimeApp,
+	isRuntimeWeb,
+	createOperationMainDom,
+	showTooltipMessage
+} from "../../../common/RuntimeEnvironment.js";
+
+/*
+九、绘制集结地
+ */
+class DrawGatheringPlace {
+	constructor(arg) {
+		this.viewer = arg.viewer;
+		this.Cesium = arg.Cesium;
+		this.tt = 0.4;
+		this.floatingPoint = null; //标识点
+		this.drawHandler = null; //画事件
+		this.gatheringPlace = null; //集结地
+		this._gatheringPlaceLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_PincerArrow = []; //脏数据
+		this._gatheringPlaceData = null; //用于构造集结地
+		this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+		this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+
+		this._tooltip = createTooltip(this.viewer.container);
+
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+	}
+
+	//返回箭头
+	get PincerArrow() {
+		return this._gatheringPlaceLast;
+	}
+
+	//返回箭头数据用于加载箭头
+	getData() {
+		return this._gatheringPlaceData;
+	}
+
+	// 修改编辑调用计算
+	computePosition(data) {
+		var $this = this;
+		if (data.length < 3) {
+			return;
+		}
+		var gatheringPlace = [];
+		var lonLats = [];
+		var res = $this.fineGatheringPlace(data);
+		for (var i = 0; i < res.length; i++) {
+			var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z);
+			gatheringPlace.push(cart3);
+		}
+		for (let q = 0; q < data.length; q++) {
+			lonLats.push($this.cartesianToLatlng(data[q]));
+		}
+		this._gatheringPlaceData = lonLats;
+		return new $this.Cesium.PolygonHierarchy(gatheringPlace);
+	}
+
+	//加载箭头
+	addload(data) {
+		var $this = this;
+		if (data.length < 3) {
+			return;
+		}
+		var gatheringPlace = [];
+		var lnglatArr = [];
+		for (var i = 0; i < data.length; i++) {
+			var lnglat = $this.LatlngTocartesian(data[i]);
+			lnglatArr.push(lnglat)
+		}
+		var res = $this.fineGatheringPlace(lnglatArr);
+		for (var i = 0; i < res.length; i++) {
+			var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z);
+			gatheringPlace.push(cart3);
+		}
+		var pHierarchy = new $this.Cesium.PolygonHierarchy(gatheringPlace);
+		var arrowEntity = $this.viewer.entities.add({
+			Type: 'DrawGatheringPlace',
+			Position: data,
+			id: data.id || $this.objId,
+			polygon: {
+				hierarchy: pHierarchy,
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		})
+		return arrowEntity
+	}
+
+
+	// 开始创建
+	startCreate(drawType) {
+		if (isRuntimeApp()) {
+			showTooltipMessage("点击开始绘制");
+		}
+
+		var $this = this;
+
+		this.drawType = drawType
+		this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas);
+		//单击开始绘制
+		this.handler.setInputAction(function(event) {
+			if (isRuntimeApp()) {
+				//屏幕坐标转地形上坐标
+				var cartesian = $this.getCatesian3FromPX(event.position);
+				if (!cartesian) {
+					return;
+				}
+
+				$this.createPoint(cartesian); // 绘制点
+				$this._positions.push(cartesian);
+
+				if ($this._positions.length < 3) {
+					showTooltipMessage("点击添加点");
+				}
+
+				if ($this._positions.length === 3) {
+					showTooltipMessage("点击完成按钮,结束绘制");
+					$this.destroy();
+					if (!$this.Cesium.defined($this.gatheringPlace)) {
+						$this.gatheringPlace = $this.createGatheringPlace();
+
+						//创建按钮
+						createOperationMainDom();
+						//隐藏回退按钮
+						document.getElementById("btnDrawBackout").style.display = 'none';
+						//完成绘制
+						document.getElementById("btnDrawComplete").onclick = () => {
+
+							$this._gatheringPlaceData = $this._positions.concat();
+							$this.viewer.entities.remove($this.gatheringPlace); //移除
+							$this.gatheringPlace = null;
+							var lnglatArr = [];
+							for (var i = 0; i < $this._gatheringPlaceData.length; i++) {
+								var lnglat = $this.cartesianToLatlng($this._gatheringPlaceData[i]);
+								lnglatArr.push(lnglat)
+							}
+							$this._gatheringPlaceData = lnglatArr;
+							var pincerArrow = $this.addload(lnglatArr); //加载
+							$this._entities_PincerArrow.push(pincerArrow);
+							$this._gatheringPlaceLast = pincerArrow;
+							$this.viewer.entities.remove($this.floatingPoint);
+							$this.floatingPoint = null;
+
+							//删除关键点
+							$this.clearPoint();
+							$this.destroy();
+
+							let buttonDiv = document.getElementById("drawButtonDiv");
+							if (buttonDiv) {
+								//从页面移除
+								document.body.removeChild(buttonDiv);
+							}
+						}
+					}
+				}
+			} else {
+
+				console.log('监听鼠标事件', '单击')
+
+				/* 锁定点击事件 以免和双击事件冲突 */
+				clearTimeout($this._timer);
+				$this._timer = setTimeout(function() {
+					//屏幕坐标转世界坐标
+					var position = event.position;
+					if (!$this.Cesium.defined(position)) {
+						return;
+					}
+					var ray = $this.viewer.camera.getPickRay(position);
+					if (!$this.Cesium.defined(ray)) {
+						return;
+					}
+					var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
+					if (!$this.Cesium.defined(cartesian)) {
+						return;
+					}
+
+					if ($this._positions.length == 0) {
+						$this._positions.push(cartesian.clone());
+						$this.floatingPoint = $this.createPoint(cartesian);
+					}
+
+					if ($this._positions.length <= 2) {
+						$this.createPoint(cartesian); // 绘制点
+						$this._positions.push(cartesian);
+					}
+
+				}, 200);
+			}
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+		//移动时绘制面
+		this.handler.setInputAction(function(event) {
+			//console.log("_positions",_positions);
+
+			/* 如果运行环境是App 则禁止使用鼠标移动事件 */
+			if (isRuntimeApp()) return;
+
+			if ($this._positions.length == 0) {
+				$this._tooltip.showAt(event.endPosition, "点击开始绘制");
+			} else {
+				$this._tooltip.showAt(event.endPosition, "点击添加点");
+			}
+
+			if ($this._positions.length < 2) {
+				return;
+			}
+
+			if ($this._positions.length == 3) {
+				$this._tooltip.showAt(event.endPosition, "双击结束绘制");
+			}
+
+
+			//屏幕坐标转世界坐标
+			var position = event.endPosition;
+			if (!$this.Cesium.defined(position)) {
+				return;
+			}
+			var ray = $this.viewer.camera.getPickRay(position);
+			if (!$this.Cesium.defined(ray)) {
+				return;
+			}
+			var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
+			if (!$this.Cesium.defined(cartesian)) {
+				return;
+			}
+			//console.log("点击地图移动采集的点:",cartesian);
+			if (!$this.Cesium.defined($this.gatheringPlace)) {
+				$this.gatheringPlace = $this.createGatheringPlace();
+			}
+			$this.floatingPoint.position.setValue(cartesian);
+			if ($this.gatheringPlace) {
+				//替换最后一个点
+				// _positions.pop();
+				// _positions.push(cartesian);
+				//替换中间点
+				if ($this._positions.length == 3) {
+					$this._positions[1] = cartesian;
+				} else {
+					$this._positions.pop();
+					$this._positions.push(cartesian);
+				}
+
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+		//右击停止采集改为双击结束
+		this.handler.setInputAction(function(movement) {
+			// if ($this._positions.length >= 3) {
+			// 	$this._gatheringPlaceData = $this._positions.concat();
+			// 	$this.viewer.entities.remove($this.gatheringPlace); //移除
+			// 	$this.gatheringPlace = null;
+			// 	var lnglatArr = [];
+			// 	for (var i = 0; i < $this._gatheringPlaceData.length; i++) {
+			// 		var lnglat = $this.cartesianToLatlng($this._gatheringPlaceData[i]);
+			// 		lnglatArr.push(lnglat)
+			// 	}
+			// 	$this._gatheringPlaceData = lnglatArr;
+			// 	var pincerArrow = $this.addload(lnglatArr); //加载
+			// 	$this._entities_PincerArrow.push(pincerArrow);
+			// 	$this._gatheringPlaceLast = pincerArrow;
+			// 	$this.viewer.entities.remove($this.floatingPoint);
+			// 	$this.floatingPoint = null;
+
+			// 	//删除关键点
+			// 	$this.clearPoint();
+			// 	$this.destroy()
+			// }
+		}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+		//双击结束
+		this.handler.setInputAction(function(movement) {
+
+			/* 如果运行环境是App 则禁止使用鼠标双击事件 */
+			if (isRuntimeApp()) return;
+
+			console.log('监听鼠标事件', '双击')
+
+			/* 解除锁定 */
+			clearTimeout($this._timer);
+
+			if ($this._positions.length >= 3) {
+				$this._gatheringPlaceData = $this._positions.concat();
+				$this.viewer.entities.remove($this.gatheringPlace); //移除
+				$this.gatheringPlace = null;
+				var lnglatArr = [];
+				for (var i = 0; i < $this._gatheringPlaceData.length; i++) {
+					var lnglat = $this.cartesianToLatlng($this._gatheringPlaceData[i]);
+					lnglatArr.push(lnglat)
+				}
+				$this._gatheringPlaceData = lnglatArr;
+				var pincerArrow = $this.addload(lnglatArr); //加载
+				$this._entities_PincerArrow.push(pincerArrow);
+				$this._gatheringPlaceLast = pincerArrow;
+				$this.viewer.entities.remove($this.floatingPoint);
+				$this.floatingPoint = null;
+
+				//删除关键点
+				$this.clearPoint();
+				$this.destroy();
+
+				$this._tooltip.setVisible(false);
+			}
+		}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
+	}
+
+	//创建集结地
+	createGatheringPlace() {
+		let $this = this
+		var gatheringPlaceEntity = $this.viewer.entities.add({
+			polygon: {
+				hierarchy: new $this.Cesium.CallbackProperty(function() {
+					if ($this._positions.length < 3) {
+						return;
+					}
+					var gatheringPlace = [];
+					var res = $this.fineGatheringPlace($this._positions);
+					for (var i = 0; i < res.length; i++) {
+						var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z);
+						gatheringPlace.push(cart3);
+					}
+					var pHierarchy = new $this.Cesium.PolygonHierarchy(gatheringPlace);
+					var lonLats = $this.cartesianToLatlng($this._positions);
+					pHierarchy.keyPoints = lonLats;
+					return pHierarchy
+				}, false),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		})
+		//$this._entities_gatheringPlace.push(gatheringPlaceEntity);
+		// gatheringPlaceEntity.valueFlag = "value";
+		$this._entities_PincerArrow.push(gatheringPlaceEntity);
+		return gatheringPlaceEntity
+	}
+
+	//创建点
+	createPoint(cartesian) {
+		var $this = this;
+		var point = this.viewer.entities.add({
+			position: cartesian,
+			point: {
+				pixelSize: 10,
+				color: $this.Cesium.Color.RED,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			}
+		});
+		$this._entities_point.push(point);
+		return point;
+	}
+
+	cartesianToLatlng(cartesian) {
+		let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
+		let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
+		let alt = cartographic.height;
+		return [lng, lat, alt];
+	}
+
+	//销毁
+	destroy() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+	}
+
+	clearPoint() {
+		this.DrawEndEvent.raiseEvent(this._gatheringPlaceLast, this._gatheringPlaceData, this.drawType);
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		this._entities_point = []; //脏数据
+	}
+
+	//清空实体对象
+	clear() {
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		for (var i = 0; i < this._entities_PincerArrow.length; i++) {
+			this.viewer.entities.remove(this._entities_PincerArrow[i]);
+		}
+
+		this.floatingPoint = null; //标识点
+		this._PincerArrow = null; //活动箭头
+		this._PincerArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_PincerArrow = []; //脏数据
+		this._PincerArrowData = null; //用于构造箭头数据
+	}
+
+	getCatesian3FromPX(px) {
+		var cartesian;
+		var ray = this.viewer.camera.getPickRay(px);
+		if (!ray) return null;
+		cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+		return cartesian;
+	}
+
+	_computeTempPositions() {
+		var _this = this;
+
+		var pnts = [].concat(_this._positions);
+		var num = pnts.length;
+		var first = pnts[0];
+		var last = pnts[num - 1];
+		if (_this._isSimpleXYZ(first, last) == false) {
+			pnts.push(first);
+			num += 1;
+		}
+		_this.tempPositions = [];
+		for (var i = 1; i < num; i++) {
+			var p1 = pnts[i - 1];
+			var p2 = pnts[i];
+			var cp = _this._computeCenterPotition(p1, p2);
+			_this.tempPositions.push(p1);
+			_this.tempPositions.push(cp);
+		}
+	}
+
+	_isSimpleXYZ(p1, p2) {
+		if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
+			return true;
+		}
+		return false;
+	}
+
+	_computeCenterPotition(p1, p2) {
+		var _this = this;
+		var c1 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p1);
+		var c2 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p2);
+		var cm = new _this.Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5);
+		var cp = _this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cm);
+		return cp;
+	}
+	/**
+	 * 笛卡尔坐标转经纬度坐标
+	 */
+	getLonLat(cartesian) {
+		var cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		cartographic.height = this.viewer.scene.globe.getHeight(cartographic);
+		var pos = {
+			lon: cartographic.longitude,
+			lat: cartographic.latitude,
+			alt: cartographic.height
+		};
+		pos.lon = this.Cesium.Math.toDegrees(pos.lon);
+		pos.lat = this.Cesium.Math.toDegrees(pos.lat);
+		return pos;
+	}
+
+	LatlngTocartesian(latlng) {
+		let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+		return cartesian3
+	}
+
+	////////////////////////////////////////集结地/////////////////////////////////////////////////////
+	fineGatheringPlace(gatherPosition) {
+		let $this = this
+		let points = gatherPosition.length;
+		if (points < 2) {
+			return false
+		} else {
+			let pnts = new Array();
+			gatherPosition.forEach(function(item) {
+				var posLonLat = $this.getLonLat(item);
+				pnts.push([posLonLat.lon, posLonLat.lat]);
+			});
+			//console.log("pnts6666",pnts);
+			// pnts.push(tailPoint);
+			// pnts.push(headerPoint);
+
+			if (pnts.length === 2) {
+				let mid = $this.mid(pnts[0], pnts[1])
+				//let d = utils.MathDistance(pnts[0], mid) / 0.9
+				let d = $this.distance(pnts[0], mid) / 0.9
+				//console.log("d",d);
+				let pnt = $this.getThirdPoint(pnts[0], mid, Math.PI / 2, d, true)
+				pnts = [pnts[0], pnt, pnts[1]];
+				//console.log("pnt",pnt);
+				//createPoint(Cesium.Cartesian3.fromDegrees(pnt[0], pnt[1]));
+			}
+			let mid = $this.mid(pnts[0], pnts[2])
+			pnts.push(mid, pnts[0], pnts[1])
+			//console.log("3333");
+
+			let [normals, pnt1, pnt2, pnt3, pList] = [
+				[], undefined, undefined, undefined, []
+			]
+			for (let i = 0; i < pnts.length - 2; i++) {
+				pnt1 = pnts[i]
+				pnt2 = pnts[i + 1]
+				pnt3 = pnts[i + 2]
+				let normalPoints = $this.getBisectorNormals($this.tt, pnt1, pnt2, pnt3)
+				normals = normals.concat(normalPoints)
+			}
+			let count = normals.length
+			normals = [normals[count - 1]].concat(normals.slice(0, count - 1))
+			for (let i = 0; i < pnts.length - 2; i++) {
+				pnt1 = pnts[i]
+				pnt2 = pnts[i + 1]
+				pList = pList.concat(pnt1)
+				for (let t = 0; t <= 100; t++) {
+					let pnt = $this.getCubicValue(t / 100, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
+					pList = pList.concat(pnt)
+				}
+				pList = pList.concat(pnt2)
+			}
+			return Cesium.Cartesian3.fromDegreesArray(pList);
+		}
+	}
+
+	mid(t, o) {
+		return [(t[0] + o[0]) / 2, (t[1] + o[1]) / 2]
+	}
+
+	distance(t, o) {
+		return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2))
+	}
+
+	getThirdPoint(t, o, e, r, n) {
+		var g = this.getAzimuth(t, o),
+			i = n ? g + e : g - e,
+			s = r * Math.cos(i),
+			a = r * Math.sin(i);
+		return [o[0] + s, o[1] + a]
+	}
+
+	getAzimuth(t, o) {
+		var e, r = Math.asin(Math.abs(o[1] - t[1]) / this.distance(t, o));
+		return o[1] >= t[1] && o[0] >= t[0] ? e = r + Math.PI : o[1] >= t[1] && o[0] < t[0] ? e = 2 * Math.PI - r : o[1] < t[1] && o[0] < t[0] ? e = r : o[1] < t[1] && o[0] >= t[0] && (e = Math.PI - r), e
+	}
+
+	getBisectorNormals(t, o, e, r) {
+		var n = this.getNormal(o, e, r),
+			g = Math.sqrt(n[0] * n[0] + n[1] * n[1]),
+			i = n[0] / g,
+			s = n[1] / g,
+			a = this.distance(o, e),
+			l = this.distance(e, r);
+		if (g > 1e-4)
+			if (this.isClockWise(o, e, r)) {
+				var u = t * a,
+					c = e[0] - u * s,
+					p = e[1] + u * i,
+					h = [c, p];
+				u = t * l, c = e[0] + u * s, p = e[1] - u * i;
+				var d = [c, p]
+			} else u = t * a, c = e[0] + u * s, p = e[1] - u * i, h = [c, p], u = t * l, c = e[0] - u * s, p = e[1] + u * i, d = [c, p];
+		else c = e[0] + t * (o[0] - e[0]), p = e[1] + t * (o[1] - e[1]), h = [c, p], c = e[0] + t * (r[0] - e[0]), p = e[1] + t * (r[1] - e[1]), d = [c, p];
+		return [h, d]
+	}
+
+	getNormal(t, o, e) {
+		var r = t[0] - o[0],
+			n = t[1] - o[1],
+			g = Math.sqrt(r * r + n * n);
+		r /= g, n /= g;
+		var i = e[0] - o[0],
+			s = e[1] - o[1],
+			a = Math.sqrt(i * i + s * s);
+		i /= a, s /= a;
+		var l = r + i,
+			u = n + s;
+		return [l, u]
+	}
+
+	isClockWise(t, o, e) {
+		return (e[1] - t[1]) * (o[0] - t[0]) > (o[1] - t[1]) * (e[0] - t[0])
+	}
+
+	getCubicValue(t, o, e, r, n) {
+		t = Math.max(Math.min(t, 1), 0);
+		var g = 1 - t,
+			i = t * t,
+			s = i * t,
+			a = g * g,
+			l = a * g,
+			u = l * o[0] + 3 * a * t * e[0] + 3 * g * i * r[0] + s * n[0],
+			c = l * o[1] + 3 * a * t * e[1] + 3 * g * i * r[1] + s * n[1];
+		return [u, c]
+	}
+
+}
+
+export default DrawGatheringPlace

+ 659 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPincerArrow.js

@@ -0,0 +1,659 @@
+import {
+	createTooltip
+} from "../../../common/common.js";
+
+import {
+	isRuntimeApp,
+	isRuntimeWeb,
+	createOperationMainDom,
+	showTooltipMessage
+} from "../../../common/RuntimeEnvironment.js";
+
+/*
+九、绘制钳击箭头
+ */
+class DrawPincerArrow {
+	constructor(arg) {
+		this.viewer = arg.viewer;
+		this.Cesium = arg.Cesium;
+		// this.callback=arg.callback;
+		this.floatingPoint = null; //标识点
+		this._PincerArrow = null; //活动箭头
+		this._PincerArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_PincerArrow = []; //脏数据
+		this._PincerArrowData = null; //用于构造箭头数据
+		this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+		this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+
+		this._tooltip = createTooltip(this.viewer.container);
+
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+	}
+
+	//返回箭头
+	get PincerArrow() {
+		return this._PincerArrowLast;
+	}
+
+	//返回箭头数据用于加载箭头
+	getData() {
+		return this._PincerArrowData;
+	}
+
+	//加载箭头
+	addload(data) {
+		var $this = this;
+		if (data.length < 3) {
+			return;
+		}
+		//计算面
+		var res = $this.doubleArrow(data);
+		var returnData = res.polygonalPoint;
+		var arrowEntity = $this.viewer.entities.add({
+			Type: 'DrawPincerArrow',
+			Position: data,
+			id: data.id || $this.objId,
+			polygon: {
+				hierarchy: new $this.Cesium.PolygonHierarchy(returnData),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		})
+		return arrowEntity
+	}
+
+	// 修改编辑调用计算
+	computePosition(data) {
+		let $this = this
+		var lnglatArr = [];
+		for (var i = 0; i < data.length; i++) {
+			var lnglat = $this.cartesianToLatlng(data[i]);
+			lnglatArr.push(lnglat)
+		}
+		$this._PincerArrowData = lnglatArr;
+		var res = $this.doubleArrow(lnglatArr);
+		var returnData = res.polygonalPoint;
+		return new $this.Cesium.PolygonHierarchy(returnData)
+	}
+
+	//开始创建
+	startCreate(drawType) {
+		if (isRuntimeApp()) {
+			showTooltipMessage("点击开始绘制");
+		}
+
+		var $this = this;
+
+		this.drawType = drawType;
+		this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+
+		//单击开始绘制
+		this.handler.setInputAction(function(evt) {
+
+			if (isRuntimeApp()) {
+				//屏幕坐标转地形上坐标
+				var cartesian = $this.getCatesian3FromPX(evt.position);
+				if (!cartesian) {
+					return;
+				}
+
+				$this.createPoint(cartesian); // 绘制点
+				$this._positions.push(cartesian);
+
+				if ($this._positions.length < 3 || $this._positions.length === 4) {
+					showTooltipMessage("点击添加点");
+				}
+
+				if ($this._positions.length === 2) {
+					if (!$this.Cesium.defined($this._PincerArrow)) {
+						$this._PincerArrow = $this.createPincerArrow();
+					}
+				}
+				if ($this._positions.length === 3) {
+					$this._positions.pop();
+					$this._positions.push(cartesian);
+
+					showTooltipMessage("点击添加点,点击完成按钮,结束绘制");
+
+					//创建按钮
+					createOperationMainDom();
+					//隐藏回退按钮
+					document.getElementById("btnDrawBackout").style.display = 'none';
+					//完成绘制
+					document.getElementById("btnDrawComplete").onclick = () => {
+
+
+						$this._PincerArrowData = $this._positions.concat();
+						$this.viewer.entities.remove($this._PincerArrow); //移除
+						$this._PincerArrow = null;
+						$this._positions = [];
+						var lnglatArr = [];
+						for (var i = 0; i < $this._PincerArrowData.length; i++) {
+							var lnglat = $this.cartesianToLatlng($this._PincerArrowData[i]);
+							lnglatArr.push(lnglat)
+						}
+						$this._PincerArrowData = lnglatArr;
+						var pincerArrow = $this.addload(lnglatArr); //加载
+						$this._entities_PincerArrow.push(pincerArrow);
+						$this._PincerArrowLast = pincerArrow;
+						$this.clearPoint();
+						$this.destroy();
+
+						let buttonDiv = document.getElementById("drawButtonDiv");
+						if (buttonDiv) {
+							//从页面移除
+							document.body.removeChild(buttonDiv);
+						}
+					}
+				}
+
+				if ($this._positions.length === 5) {
+					showTooltipMessage("点击完成按钮,结束绘制");
+					$this.destroy();
+				}
+
+			} else {
+				console.log('监听鼠标事件', '单击')
+
+				/* 锁定点击事件 以免和双击事件冲突 */
+				clearTimeout($this._timer);
+				$this._timer = setTimeout(function() {
+					var cartesian = $this.getCatesian3FromPX(evt.position);
+					if (!cartesian) {
+						return;
+					}
+					if ($this._positions.length == 0) {
+						$this.floatingPoint = $this.createPoint(cartesian);
+					}
+					if ($this._positions.length < 5) {
+						$this._positions.push(cartesian);
+						$this.createPoint(cartesian); // 绘制点
+					}
+					if ($this._positions.length == 5) {
+						$this._positions[4] = cartesian;
+						$this.floatingPoint.position.setValue(cartesian);
+					}
+				}, 200);
+			}
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+		//移动时绘制面
+		this.handler.setInputAction(function(evt) {
+
+			/* 如果运行环境是App 则禁止使用鼠标移动事件 */
+			if (isRuntimeApp()) return;
+
+			if ($this._positions.length == 0) {
+				$this._tooltip.showAt(evt.endPosition, "点击开始绘制");
+			} else {
+				$this._tooltip.showAt(evt.endPosition, "点击添加点");
+			}
+
+			var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+			if (!cartesian) return;
+			if ($this._positions.length < 2) return;
+
+			if (!$this.Cesium.defined($this._PincerArrow)) {
+				if ($this._positions.length == 2) {
+					$this._positions.push(cartesian);
+				}
+				$this._PincerArrow = $this.createPincerArrow();
+			}
+			$this.floatingPoint.position.setValue(cartesian);
+			if ($this._positions.length == 3) {
+				$this._positions[2] = cartesian;
+
+				// $this._tooltip.showAt(evt.endPosition, "点击添加点,右键删除点,双击结束绘制");
+				$this._tooltip.showAt(evt.endPosition, "点击添加点,双击结束绘制");
+			}
+
+			if ($this._positions.length > 3) {
+				$this._positions.pop();
+				$this._positions.push(cartesian);
+
+				if ($this._positions === 4) {
+					$this._tooltip.showAt(evt.endPosition, "点击添加点");
+				}
+
+				if ($this._positions.length == 5) {
+					$this._tooltip.showAt(evt.endPosition, "双击结束绘制");
+				}
+			}
+
+			console.log($this._positions.length);
+		}, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+		//右键结束改为双击结束
+		this.handler.setInputAction(function(evt) {
+			// if (!$this._PincerArrow) {
+			// 	return
+			// } else {
+			// 	// if(typeof $this.callback=="function"){
+			// 	//     $this.callback();
+			// 	// }
+			// };
+			// var cartesian = $this.getCatesian3FromPX(evt.position);
+			// if (!cartesian) return;
+			// $this._positions.pop();
+			// $this._positions.push(cartesian);
+			// $this._PincerArrowData = $this._positions.concat();
+			// $this.viewer.entities.remove($this._PincerArrow); //移除
+			// $this._PincerArrow = null;
+			// $this._positions = [];
+			// $this.floatingPoint.position.setValue(cartesian);
+			// var lnglatArr = [];
+			// for (var i = 0; i < $this._PincerArrowData.length; i++) {
+			// 	var lnglat = $this.cartesianToLatlng($this._PincerArrowData[i]);
+			// 	lnglatArr.push(lnglat)
+			// }
+			// $this._PincerArrowData = lnglatArr;
+			// var pincerArrow = $this.addload(lnglatArr); //加载
+			// $this._entities_PincerArrow.push(pincerArrow);
+			// $this._PincerArrowLast = pincerArrow;
+			// $this.clearPoint();
+			// $this.destroy();
+		}, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+		//双击结束
+		this.handler.setInputAction(function(evt) {
+
+			/* 如果运行环境是App 则禁止使用鼠标双击事件 */
+			if (isRuntimeApp()) return;
+
+			console.log('监听鼠标事件', '双击')
+
+			/* 解除锁定 */
+			clearTimeout($this._timer);
+
+			if (!$this._PincerArrow) {
+				return
+			} else {
+				// if(typeof $this.callback=="function"){
+				//     $this.callback();
+				// }
+			};
+			var cartesian = $this.getCatesian3FromPX(evt.position);
+			if (!cartesian) return;
+
+			$this._positions.pop();
+			// $this._positions.push(cartesian);
+			$this._PincerArrowData = $this._positions.concat();
+			$this.viewer.entities.remove($this._PincerArrow); //移除
+			$this._PincerArrow = null;
+			$this._positions = [];
+			$this.floatingPoint.position.setValue(cartesian);
+			var lnglatArr = [];
+			for (var i = 0; i < $this._PincerArrowData.length; i++) {
+				var lnglat = $this.cartesianToLatlng($this._PincerArrowData[i]);
+				lnglatArr.push(lnglat)
+			}
+			$this._PincerArrowData = lnglatArr;
+			var pincerArrow = $this.addload(lnglatArr); //加载
+			$this._entities_PincerArrow.push(pincerArrow);
+			$this._PincerArrowLast = pincerArrow;
+			$this.clearPoint();
+			$this.destroy();
+
+			$this._tooltip.setVisible(false);
+
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
+	}
+
+	//创建钳击箭头
+	createPincerArrow() {
+		var $this = this;
+		$this._computeTempPositions();
+		var arrowEntity = $this.viewer.entities.add({
+			polygon: {
+				hierarchy: new $this.Cesium.CallbackProperty(
+					function() {
+						//计算面
+						var lnglatArr = [];
+						for (var i = 0; i < $this._positions.length; i++) {
+							var lnglat = $this.cartesianToLatlng($this._positions[i]);
+							lnglatArr.push(lnglat)
+						}
+						var res = $this.doubleArrow(lnglatArr);
+						var returnData = res.polygonalPoint;
+						return new $this.Cesium.PolygonHierarchy(returnData);
+					}, false),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		})
+		$this._entities_PincerArrow.push(arrowEntity);
+		return arrowEntity
+	}
+
+	//创建点
+	createPoint(cartesian) {
+		var $this = this;
+		var point = this.viewer.entities.add({
+			position: cartesian,
+			point: {
+				pixelSize: 10,
+				color: $this.Cesium.Color.RED,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			}
+		});
+		$this._entities_point.push(point);
+		return point;
+	}
+
+	cartesianToLatlng(cartesian) {
+		let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
+		let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
+		let alt = cartographic.height;
+		return [lng, lat, alt];
+	}
+
+	//销毁
+	destroy() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+	}
+
+	clearPoint() {
+		this.DrawEndEvent.raiseEvent(this._PincerArrowLast, this._PincerArrowData, this.drawType);
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		this._entities_point = []; //脏数据
+	}
+
+	//清空实体对象
+	clear() {
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		for (var i = 0; i < this._entities_PincerArrow.length; i++) {
+			this.viewer.entities.remove(this._entities_PincerArrow[i]);
+		}
+
+		this.floatingPoint = null; //标识点
+		this._PincerArrow = null; //活动箭头
+		this._PincerArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_PincerArrow = []; //脏数据
+		this._PincerArrowData = null; //用于构造箭头数据
+	}
+
+	getCatesian3FromPX(px) {
+		var cartesian;
+		var ray = this.viewer.camera.getPickRay(px);
+		if (!ray) return null;
+		cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+		return cartesian;
+	}
+
+	_computeTempPositions() {
+		var _this = this;
+
+		var pnts = [].concat(_this._positions);
+		var num = pnts.length;
+		var first = pnts[0];
+		var last = pnts[num - 1];
+		if (_this._isSimpleXYZ(first, last) == false) {
+			pnts.push(first);
+			num += 1;
+		}
+		_this.tempPositions = [];
+		for (var i = 1; i < num; i++) {
+			var p1 = pnts[i - 1];
+			var p2 = pnts[i];
+			var cp = _this._computeCenterPotition(p1, p2);
+			_this.tempPositions.push(p1);
+			_this.tempPositions.push(cp);
+		}
+	}
+
+	_isSimpleXYZ(p1, p2) {
+		if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
+			return true;
+		}
+		return false;
+	}
+
+	_computeCenterPotition(p1, p2) {
+		var _this = this;
+		var c1 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p1);
+		var c2 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p2);
+		var cm = new _this.Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5);
+		var cp = _this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cm);
+		return cp;
+	}
+
+	////////////////////////////////////////求取箭头坐标函数/////////////////////////////////////////////////////
+	//箭头配置函数
+	doubleArrow(inputPoint) {
+		var $this = this;
+		this.connPoint = null;
+		this.tempPoint4 = null;
+		this.points = inputPoint;
+		var result = {
+			controlPoint: null,
+			polygonalPoint: null
+		};
+		//获取已经点击的坐标数
+		var t = inputPoint.length;
+		if (!(2 > t)) {
+			if (2 == t) return inputPoint;
+			var o = this.points[0], //第一个点
+				e = this.points[1], //第二个点
+				r = this.points[2], //第三个点
+				t = inputPoint.length; //获取已经点击的坐标数
+			//下面的是移动点位后的坐标
+			3 == t ? this.tempPoint4 = $this.getTempPoint4(o, e, r) : this.tempPoint4 = this.points[3],
+				3 == t || 4 == t ? this.connPoint = $this.mid(o, e) : this.connPoint = this.points[4];
+			var n, g;
+			$this.isClockWise(o, e, r) ? (n = $this.getArrowPoints(o, this.connPoint, this.tempPoint4, !1), g = $this.getArrowPoints(this.connPoint, e, r, !0)) : (n = $this.getArrowPoints(e, this.connPoint, r, !1), g = $this.getArrowPoints(this.connPoint, o, this.tempPoint4, !0));
+			var i = n.length,
+				s = (i - 5) / 2,
+				a = n.slice(0, s),
+				l = n.slice(s, s + 5),
+				u = n.slice(s + 5, i),
+				c = g.slice(0, s),
+				p = g.slice(s, s + 5),
+				h = g.slice(s + 5, i);
+			c = $this.getBezierPoints(c);
+			var d = $this.getBezierPoints(h.concat(a.slice(1)));
+			u = $this.getBezierPoints(u);
+			var f = c.concat(p, d, l, u);
+			var newArray = $this.array2Dto1D(f);
+			result.controlPoint = [o, e, r, this.tempPoint4, this.connPoint];
+			result.polygonalPoint = $this.Cesium.Cartesian3.fromDegreesArray(newArray);
+		}
+		return result;
+	}
+	getTempPoint4(t, o, e) {
+		var $this = this;
+		var r, n, g, i, s = $this.mid(t, o),
+			a = $this.distance(s, e),
+			l = $this.getAngleOfThreePoints(t, s, e);
+		return l < Math.PI / 2 ? (n = a * Math.sin(l), g = a * Math.cos(l), i = $this.getThirdPoint(t, s, Math.PI / 2, n, !1), r = $this.getThirdPoint(s, i, Math.PI / 2, g, !0)) : l >= Math.PI / 2 && l < Math.PI ? (n = a * Math.sin(Math.PI - l), g = a * Math.cos(Math.PI - l), i = $this.getThirdPoint(t, s, Math.PI / 2, n, !1), r = $this.getThirdPoint(s, i, Math.PI / 2, g, !1)) : l >= Math.PI && l < 1.5 * Math.PI ? (n = a * Math.sin(l - Math.PI), g = a * Math.cos(l - Math.PI), i = $this.getThirdPoint(t, s, Math.PI / 2, n, !0), r = $this.getThirdPoint(s, i, Math.PI / 2, g, !0)) : (n = a * Math.sin(2 * Math.PI - l), g = a * Math.cos(2 * Math.PI - l), i = $this.getThirdPoint(t, s, Math.PI / 2, n, !0), r = $this.getThirdPoint(s, i, Math.PI / 2, g, !1)),
+			r
+	}
+
+	mid(t, o) {
+		return [(t[0] + o[0]) / 2, (t[1] + o[1]) / 2]
+	}
+
+	isClockWise(t, o, e) {
+		return (e[1] - t[1]) * (o[0] - t[0]) > (o[1] - t[1]) * (e[0] - t[0])
+	}
+
+	getArrowPoints(t, o, e, r) {
+		var $this = this;
+		var doubleArrowDefualParam = {
+			type: "doublearrow",
+			headHeightFactor: .25,
+			headWidthFactor: .3,
+			neckHeightFactor: .85,
+			fixPointCount: 4,
+			neckWidthFactor: .15
+		}
+		this.type = doubleArrowDefualParam.type,
+			this.headHeightFactor = doubleArrowDefualParam.headHeightFactor,
+			this.headWidthFactor = doubleArrowDefualParam.headWidthFactor,
+			this.neckHeightFactor = doubleArrowDefualParam.neckHeightFactor,
+			this.neckWidthFactor = doubleArrowDefualParam.neckWidthFactor;
+		var n = $this.mid(t, o),
+			g = $this.distance(n, e),
+			i = $this.getThirdPoint(e, n, 0, .3 * g, !0),
+			s = $this.getThirdPoint(e, n, 0, .5 * g, !0);
+		i = $this.getThirdPoint(n, i, Math.PI / 2, g / 5, r),
+			s = $this.getThirdPoint(n, s, Math.PI / 2, g / 4, r);
+		var a = [n, i, s, e],
+			l = $this.getArrowHeadPoints(a, this.headHeightFactor, this.headWidthFactor, this.neckHeightFactor, this.neckWidthFactor),
+			u = l[0],
+			c = l[4],
+			p = $this.distance(t, o) / $this.getBaseLength(a) / 2,
+			h = $this.getArrowBodyPoints(a, u, c, p),
+			d = h.length,
+			f = h.slice(0, d / 2),
+			E = h.slice(d / 2, d);
+		return f.push(u),
+			E.push(c),
+			f = f.reverse(),
+			f.push(o),
+			E = E.reverse(),
+			E.push(t),
+			f.reverse().concat(l, E)
+	}
+
+	getArrowHeadPoints(t, o, e) {
+		var $this = this;
+		var doubleArrowDefualParam = {
+			type: "doublearrow",
+			headHeightFactor: .25,
+			headWidthFactor: .3,
+			neckHeightFactor: .85,
+			fixPointCount: 4,
+			neckWidthFactor: .15
+		}
+		this.type = doubleArrowDefualParam.type,
+			this.headHeightFactor = doubleArrowDefualParam.headHeightFactor,
+			this.headWidthFactor = doubleArrowDefualParam.headWidthFactor,
+			this.neckHeightFactor = doubleArrowDefualParam.neckHeightFactor,
+			this.neckWidthFactor = doubleArrowDefualParam.neckWidthFactor;
+		var r = $this.getBaseLength(t),
+			n = r * this.headHeightFactor,
+			g = t[t.length - 1],
+			i = ($this.distance(o, e), n * this.headWidthFactor),
+			s = n * this.neckWidthFactor,
+			a = n * this.neckHeightFactor,
+			l = $this.getThirdPoint(t[t.length - 2], g, 0, n, !0),
+			u = $this.getThirdPoint(t[t.length - 2], g, 0, a, !0),
+			c = $this.getThirdPoint(g, l, Math.PI / 2, i, !1),
+			p = $this.getThirdPoint(g, l, Math.PI / 2, i, !0),
+			h = $this.getThirdPoint(g, u, Math.PI / 2, s, !1),
+			d = $this.getThirdPoint(g, u, Math.PI / 2, s, !0);
+		return [h, c, g, p, d];
+	}
+
+	getArrowBodyPoints(t, o, e, r) {
+		var $this = this;
+		for (var n = $this.wholeDistance(t), g = $this.getBaseLength(t), i = g * r, s = $this.distance(o, e), a = (i - s) / 2, l = 0, u = [], c = [], p = 1; p < t.length - 1; p++) {
+			var h = $this.getAngleOfThreePoints(t[p - 1], t[p], t[p + 1]) / 2;
+			l += $this.distance(t[p - 1], t[p]);
+			var d = (i / 2 - l / n * a) / Math.sin(h),
+				f = $this.getThirdPoint(t[p - 1], t[p], Math.PI - h, d, !0),
+				E = $this.getThirdPoint(t[p - 1], t[p], h, d, !1);
+			u.push(f), c.push(E)
+		}
+		return u.concat(c)
+	}
+
+	getBezierPoints(t) {
+		if (t.length <= 2) return t;
+		for (var o = [], e = t.length - 1, r = 0; 1 >= r; r += .01) {
+			for (var n = 0, y = 0, g = 0; e >= g; g++) {
+				var i = this.getBinomialFactor(e, g),
+					s = Math.pow(r, g),
+					a = Math.pow(1 - r, e - g);
+				n += i * s * a * t[g][0], y += i * s * a * t[g][1]
+			}
+			o.push([n, y])
+		}
+		return o.push(t[e]), o
+	}
+
+	getBaseLength(t) {
+		return Math.pow(this.wholeDistance(t), .99)
+	}
+
+	wholeDistance(t) {
+		for (var o = 0, e = 0; e < t.length - 1; e++) o += this.distance(t[e], t[e + 1]);
+		return o
+	}
+
+	getBinomialFactor(t, o) {
+		return this.getFactorial(t) / (this.getFactorial(o) * this.getFactorial(t - o))
+	}
+
+	getFactorial(t) {
+		if (1 >= t) return 1;
+		if (2 == t) return 2;
+		if (3 == t) return 6;
+		if (4 == t) return 24;
+		if (5 == t) return 120;
+		for (var o = 1, e = 1; t >= e; e++) o *= e;
+		return o
+	}
+
+	array2Dto1D(array) {
+		var newArray = [];
+		array.forEach(function(elt) {
+			newArray.push(elt[0]);
+			newArray.push(elt[1]);
+		});
+		return newArray;
+	}
+
+	distance(t, o) {
+		return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2))
+	}
+
+	getAngleOfThreePoints(t, o, e) {
+		var r = this.getAzimuth(o, t) - this.getAzimuth(o, e);
+		return 0 > r ? r + 2 * Math.PI : r
+	}
+
+	getAzimuth(t, o) {
+		var e, r = Math.asin(Math.abs(o[1] - t[1]) / this.distance(t, o));
+		return o[1] >= t[1] && o[0] >= t[0] ? e = r + Math.PI : o[1] >= t[1] && o[0] < t[0] ? e = 2 * Math.PI - r : o[1] < t[1] && o[0] < t[0] ? e = r : o[1] < t[1] && o[0] >= t[0] && (e = Math.PI - r), e
+	}
+
+	getThirdPoint(t, o, e, r, n) {
+		var g = this.getAzimuth(t, o),
+			i = n ? g + e : g - e,
+			s = r * Math.cos(i),
+			a = r * Math.sin(i);
+		return [o[0] + s, o[1] + a]
+	}
+
+}
+
+export default DrawPincerArrow

+ 138 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPoint.js

@@ -0,0 +1,138 @@
+//一、点
+// DrawPoint
+/*
+绘制点
+ */
+class DrawPoint {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        // this.callback=arg.callback;
+        this._point = null;  //最后一个点
+        this._pointData = null;//点数据用于构造点
+        this._entities = []; //脏数据
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    //返回最后活动点
+    get point() {
+        return this._point;
+    }
+ 
+    //加载点
+    addload(data) {
+        return this.createPoint(data);
+    }
+ 
+    //返回点数据用于加载点
+    getData() {
+        return this._pointData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data) {
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        $this._pointData = lnglatArr;
+        let point = lnglatArr[0]
+        return $this.Cesium.Cartesian3.fromDegrees(point[0],point[1])
+    }
+ 
+    //开始绘制
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if (!cartesian) return;
+            let latlon = $this.cartesianToLatlng(cartesian)
+            var point = $this.createPoint(latlon);
+            $this._pointData = cartesian;
+            $this._point = point;
+            // if(typeof $this.callback=="function"){
+            //     $this.callback(point);
+            // }
+            
+            $this.DrawEndEvent.raiseEvent($this._point, latlon, $this.drawType);
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            Type:'DrawPoint',
+            Position:[cartesian],
+            position: $this.Cesium.Cartesian3.fromDegrees(cartesian[0],cartesian[1]),
+            id:cartesian.id || $this.objId,
+            billboard: {
+                image: "./static/poi2.png",
+                // scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4), //设置随图缩放距离和比例
+                // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), //设置可见距离 10000米可见
+                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+                // clampToGround: true
+            },
+        });
+        $this._entities.push(point); //加载脏数据
+        return point;
+    }
+
+    cartesianToLatlng(cartesian) {
+        let ellipsoid = this.viewer.scene.globe.ellipsoid
+        let cartographic = ellipsoid.cartesianToCartographic(cartesian);
+        let lat = Cesium.Math.toDegrees(cartographic.latitude);
+        let lng = Cesium.Math.toDegrees(cartographic.longitude);
+        return [lng, lat];
+    }
+ 
+    //销毁鼠标事件
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities.length; i++) {
+            this.viewer.entities.remove(this._entities[i]);
+        }
+        this._entities = [];
+        this._point = null;
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+}
+ 
+export default DrawPoint;

+ 229 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPolygon.js

@@ -0,0 +1,229 @@
+//   六、多边形
+// DrawPolygon
+/*
+绘制面
+ */
+class DrawPolygon {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        // this.callback=arg.callback;
+        this._polygon = null;  //活动面
+        this._polygonLast = null;  //最后一个面
+        this._positions = []; //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_polygon = [];  //脏数据
+        this._polygonData = null; //用户构造面
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+
+    //返回最后活动面
+    get polygon() {
+        return this._polygonLast;
+    }
+
+    //返回面数据用于加载面
+    getData() {
+        return this._polygonData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        //计算面
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        $this._polygonData = lnglatArr;
+        return new $this.Cesium.PolygonHierarchy(data);
+    }
+
+    //加载面
+    addload(data) {
+        var $this = this;
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.LatlngTocartesian(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        return this.viewer.entities.add({
+            Type: 'DrawPolygon',
+            Position: data,
+            id:data.id || $this.objId,
+            polygon: {
+                hierarchy: new $this.Cesium.PolygonHierarchy(lnglatArr),
+                clampToGround: true,
+                show: true,
+                fill: true,
+                material: $this.Cesium.Color.RED.withAlpha(0.9),
+                width: 3,
+                outlineColor: $this.Cesium.Color.BLACK,
+                outlineWidth: 1,
+                outline: false
+            }
+        });
+    }
+
+    //开始绘制
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this._positions.length == 0) {
+                $this._positions.push(cartesian.clone());
+            }
+            $this.createPoint(cartesian);
+            $this._positions.push(cartesian);
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制面
+            if ($this._positions.length < 1) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if ($this._positions.length == 3) {
+                if (!$this.Cesium.defined($this._polygon)) {
+                    $this._polygon = $this.createPolygon();
+                }
+            }
+            $this._positions.pop();
+            $this._positions.push(cartesian);
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this._polygon) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this._positions.pop();
+            // $this._positions.push(cartesian);
+            $this.createPoint(cartesian);
+            $this._polygonData = $this._positions.concat();
+            $this.viewer.entities.remove($this._positions); //移除
+            $this._positions = null;
+            $this._positions = [];
+            var lnglatArr = [];
+            for (var i = 0; i < $this._polygonData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this._polygonData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this._polygonData = lnglatArr;
+            var Polygon = $this.addload($this._polygonData);
+            $this._entities_polygon.push(Polygon);
+            $this._polygonLast = Polygon;
+            // if(typeof $this.callback=="function"){
+            //     $this.callback(Polygon);
+            // }
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+
+    //创建面
+    createPolygon() {
+        var $this = this;
+        var polygon = this.viewer.entities.add({
+            polygon: {
+                hierarchy: new $this.Cesium.CallbackProperty(function () {
+                    return new $this.Cesium.PolygonHierarchy($this._positions);
+                }, false),
+                clampToGround: true,
+                show: true,
+                fill: true,
+                material: $this.Cesium.Color.RED.withAlpha(0.5),
+                width: 3,
+                outlineColor: $this.Cesium.Color.BLACK,
+                outlineWidth: 1,
+                outline: false
+            }
+        });
+        $this._entities_polygon.push(polygon);
+        return polygon;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this._polygonLast, this._polygonData, this.drawType);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this._entities_point.push(point);
+        return point;
+    }
+
+
+    //销毁事件
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        for (var i = 0; i < this._entities_polygon.length; i++) {
+            this.viewer.entities.remove(this._entities_polygon[i]);
+        }
+        this._polygon = null;  //活动面
+        this._polygonLast = null;  //最后一个面
+        this._positions = []; //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_polygon = [];  //脏数据
+        this._polygonData = null; //用户构造面
+    }
+
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+}
+
+export default DrawPolygon

+ 223 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawPolyline.js

@@ -0,0 +1,223 @@
+//二、折线
+// DrawPolyline
+/*
+绘制线
+ */
+class DrawPolyline {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        // this.callback=arg.callback;
+        this._polyline = null; //活动线
+        this._polylineLast = null; //最后一条线
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_line = [];  //脏数据
+        this._polylineData = null; //用于构造线数据
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    //返回最后活动线
+    get line() {
+        return this._polylineLast;
+    }
+ 
+    //返回线数据用于加载线
+    getData() {
+        return this._polylineData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        //计算面
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        $this._polylineData = lnglatArr;
+        return data;
+    }
+ 
+    //加载线
+    addload(data) {
+        var $this = this;
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.LatlngTocartesian(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        var polyline = this.viewer.entities.add({
+            Type:'DrawPolyline',
+            Position:data,
+            id:data.id || $this.objId,
+            polyline: {
+                positions: lnglatArr,
+                show: true,
+                material: $this.Cesium.Color.RED,
+                width: 3,
+                clampToGround: true
+            }
+        });
+        return polyline;
+    }
+ 
+    //开始创建
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this._positions.length == 0) {
+                $this._positions.push(cartesian.clone());
+            }
+            $this._positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制线
+            if ($this._positions.length < 1) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this._polyline)) {
+                $this._polyline = $this.createPolyline();
+            }
+            if ($this._polyline) {
+                $this._positions.pop();
+                $this._positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this._polyline) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this._positions.pop();
+            // $this._positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+            $this._polylineData = $this._positions.concat();
+            $this.viewer.entities.remove($this._polyline); //移除
+            $this._polyline = null;
+            $this._positions = [];
+            var lnglatArr = [];
+            for (var i = 0; i < $this._polylineData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this._polylineData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this._polylineData = lnglatArr;
+            var line = $this.addload($this._polylineData); //加载线
+            $this._entities_line.push(line);
+            $this._polylineLast=line;
+            // if(typeof $this.callback=="function"){
+            //     $this.callback(line);
+            // }
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this._entities_point.push(point);
+        return point;
+    }
+ 
+    //创建线
+    createPolyline() {
+        var $this = this;
+        var polyline = this.viewer.entities.add({
+            polyline: {
+                //使用cesium的peoperty
+                positions: new $this.Cesium.CallbackProperty(function () {
+                    return $this._positions
+                }, false),
+                show: true,
+                material: $this.Cesium.Color.RED,
+                width: 3,
+                clampToGround: true
+            }
+        });
+        $this._entities_line.push(polyline);
+        return polyline;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this._polylineLast , this._polylineData, this.drawType);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+ 
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        for (var i = 0; i < this._entities_line.length; i++) {
+            this.viewer.entities.remove(this._entities_line[i]);
+        }
+        this._polyline = null;
+        this._positions = [];
+        this._entities_point = [];  //脏数据
+        this._entities_line = [];  //脏数据
+        this._polylineData = null; //用于构造线数据
+        this._polylineLast=null;
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+}
+ 
+export default DrawPolyline

+ 289 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawRectFlag.js

@@ -0,0 +1,289 @@
+
+// DrawRectFlag
+/*
+绘制矩形旗帜旗帜
+ */
+class DrawRectFlag {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this.identificationPoint = null; //标识点位
+        this.RectFlag = null; 
+        this.RectFlagLast = null; // 矩形旗帜数据
+        this.positions = [];  // 经纬度
+        this.entitiesPoint = [];   // 实体点位
+        this.entitiesRectFlag = [];  
+        this.RectFlagData = null; 
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    //返回矩形旗帜数据
+    getData() {
+        return this.RectFlagData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        //计算面
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        let startPoint = lnglatArr[0];
+        // 取最后一个
+        let endPoint =lnglatArr[lnglatArr.length - 1]
+        let point0 = lnglatArr[0];
+        var point1 =[endPoint[0], startPoint[1]];
+        var point2 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point3 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point4 =[startPoint[0], endPoint[1]]
+        let componentspolygon = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point3,...point0,])
+        let componentspolyline = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point3,...point0,...point4])
+        let PolygonHierarchy = new $this.Cesium.PolygonHierarchy(componentspolygon)
+        $this.RectFlagData = lnglatArr;
+        console.log([PolygonHierarchy,componentspolyline])
+        return [PolygonHierarchy,componentspolyline];
+    }
+ 
+    //加载
+    addload(data) {
+        var $this = this;
+        if (data.length < 2) return;
+        let startPoint = data[0];
+        // 取最后一个
+        let endPoint =data[data.length - 1]
+        let point0 = data[0];
+        var point1 =[endPoint[0], startPoint[1]];
+        var point2 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point3 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point4 =[startPoint[0], endPoint[1]]
+        let componentspolygon = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point3,...point0,])
+        let componentspolyline = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point3,...point0,...point4])
+        var shape = this.viewer.entities.add({
+            Type:'DrawRectFlag',
+            Position:data,
+            id:data.id || $this.objId,
+            polygon: {
+                hierarchy: new $this.Cesium.PolygonHierarchy(componentspolygon),
+                extrudedHeight: 1,
+                material: $this.Cesium.Color.RED,
+            },
+            polyline: {
+                //使用cesium的peoperty
+                positions: componentspolyline,
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 5,
+                clampToGround: true
+            }
+        });
+        $this.entitiesRectFlag.push(shape);
+        return shape;
+    }
+ 
+    //开始创建
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this.positions.length == 0) {
+                $this.positions.push(cartesian.clone());
+                $this.identificationPoint = $this.createPoint(cartesian);
+                $this.createPoint(cartesian);// 绘制点
+                $this.positions.push(cartesian);
+            }
+            // if ($this.positions.length == 2) {
+            //     $this.positions.push(cartesian);
+            // }
+            
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制线
+            if ($this.positions.length < 2) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this.RectFlag)) {
+                $this.RectFlag = $this.createRectFlag();
+            }
+            $this.identificationPoint.position.setValue(cartesian);
+            if ($this.RectFlag) {
+                $this.positions.pop();
+                $this.positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this.RectFlag) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this.positions.pop();
+            $this.positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+            $this.RectFlagData = $this.positions.concat();
+            $this.viewer.entities.remove($this.RectFlag); //移除
+            $this.RectFlag = null;
+            $this.positions = [];
+            $this.identificationPoint.position.setValue(cartesian);
+            var lnglatArr = [];
+            for (var i = 0; i < $this.RectFlagData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this.RectFlagData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this.RectFlagData = lnglatArr;
+            var RectFlag = $this.addload([$this.RectFlagData[0],$this.RectFlagData[$this.RectFlagData.length -1 ]]); //加载
+            $this.entitiesRectFlag.push(RectFlag);
+            $this.RectFlagLast = RectFlag;
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this.entitiesPoint.push(point);
+        return point;
+    }
+ 
+    //创建矩形旗帜
+    createRectFlag() {
+        console.log('232323')
+        var $this = this;
+        var polygon = this.viewer.entities.add({
+            polygon: {
+                hierarchy: new $this.Cesium.CallbackProperty(function () {
+                    if($this.positions.length < 2) return 
+                    let lonlat = [];
+                    let length = $this.positions.length
+                    for (let i=0; i<length; i++){
+                        lonlat.push($this.cartesianToLatlng($this.positions[i]))
+                    }
+                    let startPoint = lonlat[0]
+                    // 取最后一个
+                    let endPoint =lonlat[lonlat.length - 1]
+                    let point0 = lonlat[0];
+                    var point1 =[endPoint[0], startPoint[1]];
+                    var point2 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point3 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point4 =[startPoint[0], endPoint[1]]
+
+                    let components = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point3,...point0,])
+                    
+                    return new $this.Cesium.PolygonHierarchy(components);
+                }, false),
+                extrudedHeight: 1,
+                material: $this.Cesium.Color.RED,
+            },
+            polyline: {
+                //使用cesium的peoperty
+                positions: new $this.Cesium.CallbackProperty(function () {
+                    if($this.positions.length < 2) return 
+                    let lonlat = [];
+                    let length = $this.positions.length
+                    for (let i=0; i<length; i++){
+                        lonlat.push($this.cartesianToLatlng($this.positions[i]))
+                    }
+                    let startPoint = lonlat[0]
+                    // 取最后一个
+                    let endPoint =lonlat[lonlat.length - 1]
+                    let point0 = lonlat[0];
+                    var point1 =[endPoint[0], startPoint[1]];
+                    var point2 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point3 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point4 =[startPoint[0], endPoint[1]]
+
+                    let components = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point3,...point0,...point4])
+                    return components
+                }, false),
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 5,
+                clampToGround: true
+            }
+        });
+        $this.entitiesRectFlag.push(polygon);
+        return polygon;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this.RectFlagLast, [this.RectFlagData[0],this.RectFlagData[this.RectFlagData.length -1 ]], this.drawType);
+        for (var i = 0; i < this.entitiesPoint.length; i++) {
+            this.viewer.entities.remove(this.entitiesPoint[i]);
+        }
+        this.entitiesPoint = [];  //脏数据
+    }
+ 
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this.entitiesPoint.length; i++) {
+            this.viewer.entities.remove(this.entitiesPoint[i]);
+        }
+        for (var i = 0; i < this.entitiesRectFlag.length; i++) {
+            this.viewer.entities.remove(this.entitiesRectFlag[i]);
+        }
+        this.identificationPoint = null; //标识点位
+        this.RectFlag = null; 
+        this.RectFlagLast = null; // 矩形旗帜数据
+        this.positions = [];  // 经纬度
+        this.entitiesPoint = [];   // 实体点位
+        this.entitiesRectFlag = [];  
+        this.RectFlagData = null; 
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+}
+ 
+export default DrawRectFlag

+ 228 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawRectangle.js

@@ -0,0 +1,228 @@
+//  五、矩形
+// DrawRectangle
+/*
+绘制矩形
+ */
+class DrawRectangle {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        // this.callback=arg.callback;
+        this.floatingPoint = null;//标识点
+        this._rectangle = null; //活动矩形
+        this._rectangleLast = null; //最后一个矩形
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_rectangle = [];  //脏数据
+        this._rectangleData = null; //用于构造矩形数据
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    //返回最后图形
+    get line() {
+        return this._rectangleLast;
+    }
+ 
+    //返回矩形数据
+    getData() {
+        return this._rectangleData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        //计算面
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        $this._rectangleData = lnglatArr;
+        return new $this.Cesium.Rectangle.fromCartesianArray(data);
+    }
+ 
+    //加载
+    addload(data) {
+        var $this = this;
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.LatlngTocartesian(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        var shape = this.viewer.entities.add({
+            Type:'DrawRectangle',
+            Position:data,
+            id:data.id || $this.objId,
+            rectangle: {
+                coordinates: $this.Cesium.Rectangle.fromCartesianArray(lnglatArr),
+                material: $this.Cesium.Color.RED.withAlpha(0.9)
+            }
+        });
+        $this._entities_rectangle.push(shape);
+        return shape;
+    }
+ 
+    //开始创建
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this._positions.length == 0) {
+                $this._positions.push(cartesian.clone());
+                $this.floatingPoint = $this.createPoint(cartesian);
+                $this.createPoint(cartesian);// 绘制点
+                $this._positions.push(cartesian);
+            }
+            if ($this._positions.length == 2) {
+                $this._positions.push(cartesian);
+            }
+            
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制线
+            if ($this._positions.length < 3) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this._rectangle)) {
+                $this._rectangle = $this.createRectangle();
+            }
+            $this.floatingPoint.position.setValue(cartesian);
+            if ($this._rectangle) {
+                $this._positions.pop();
+                $this._positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this._rectangle) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this._positions.pop();
+            $this._positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+            $this._rectangleData = $this._positions.concat();
+            $this.viewer.entities.remove($this._rectangle); //移除
+            $this._rectangle = null;
+            $this._positions = [];
+            $this.floatingPoint.position.setValue(cartesian);
+            var lnglatArr = [];
+            for (var i = 0; i < $this._rectangleData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this._rectangleData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this._rectangleData = lnglatArr;
+            var rectangle = $this.addload([$this._rectangleData[0],$this._rectangleData[$this._rectangleData.length -1 ]]); //加载
+            $this._entities_rectangle.push(rectangle);
+            $this._rectangleLast = rectangle;
+            // if(typeof $this.callback=="function"){
+            //     $this.callback(rectangle);
+            // }
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this._entities_point.push(point);
+        return point;
+    }
+ 
+    //创建矩形
+    createRectangle() {
+        var $this = this;
+        var shape = this.viewer.entities.add({
+            name: "rectangle",
+            rectangle: {
+                coordinates: new $this.Cesium.CallbackProperty(function() {
+                    var obj = $this.Cesium.Rectangle.fromCartesianArray($this._positions);
+                    return obj;
+                }, false),
+                material: $this.Cesium.Color.RED.withAlpha(0.5)
+            }
+        });
+        $this._entities_rectangle.push(shape);
+        return shape;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this._rectangleLast, [this._rectangleData[0],this._rectangleData[this._rectangleData.length -1 ]], this.drawType);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+ 
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        for (var i = 0; i < this._entities_rectangle.length; i++) {
+            this.viewer.entities.remove(this._entities_rectangle[i]);
+        }
+        this.floatingPoint = null;//标识点
+        this._rectangle = null; //活动矩形
+        this._rectangleLast = null; //最后一个矩形
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_rectangle = [];  //脏数据
+        this._rectangleData = null; //用于构造矩形数据
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+}
+ 
+export default DrawRectangle

+ 327 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawSector.js

@@ -0,0 +1,327 @@
+// DrawSector
+/*
+九、绘制扇形
+ */
+class DrawSector {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this.floatingPoint = null;//标识点
+        this._sector = null; //活动扇形
+        this._sectorLast = null; //最后一个扇形
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_sector = [];  //脏数据
+        this._sectorData = null; //用于构造扇形数据
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+
+    //返回扇形
+    get sector() {
+        return this._sectorLast;
+    }
+
+    //返回扇形数据用于加载扇形
+    getData() {
+        return this._sectorData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        let $this = this;
+        let pnts = data;
+        let center = $this.lonLatToMercator($this.cartesianToLatlng(pnts[0]));
+        let pnt2 = $this.lonLatToMercator($this.cartesianToLatlng(pnts[1]));
+        let pnt3 = $this.lonLatToMercator($this.cartesianToLatlng(pnts[2]));
+        var radius = $this.MathDistance(pnt2, center);
+        var startAngle = $this.getAzimuth(pnt2, center);
+        var endAngle = $this.getAzimuth(pnt3, center);
+        var pList = $this.getArcPoints(center, radius, startAngle, endAngle);
+        pList.push(pnts[0], pList[0]);
+        let arrow = [];
+        for (var i = 0; i < pList.length; i++) {
+            var cart3 = new $this.Cesium.Cartesian3(pList[i].x, pList[i].y, pList[i].z);
+            arrow.push(cart3);
+        }
+        var lnglatArr = [];
+        for (var d = 0; d < data.length; d++){
+            lnglatArr.push($this.cartesianToLatlng(data[d]))
+        }
+        $this._sectorData = lnglatArr;
+        return new $this.Cesium.PolygonHierarchy(arrow)
+    }
+
+    //加载扇形
+    addload(data) {
+        var $this = this;
+        let pnts = data;
+        let center = $this.lonLatToMercator(pnts[0]);
+        let pnt2 = $this.lonLatToMercator(pnts[1]);
+        let pnt3 = $this.lonLatToMercator(pnts[2]);
+        var radius = $this.MathDistance(pnt2, center);
+        var startAngle = $this.getAzimuth(pnt2, center);
+        var endAngle = $this.getAzimuth(pnt3, center);
+        var pList = $this.getArcPoints(center, radius, startAngle, endAngle);
+        let pntsc = $this.Cesium.Cartesian3.fromDegrees(pnts[0][0], pnts[0][1])
+        pList.push(pntsc, pList[0]);
+        let arrow = [];
+        for (var i = 0; i < pList.length; i++) {
+            var cart3 = new $this.Cesium.Cartesian3(pList[i].x, pList[i].y, pList[i].z);
+            arrow.push(cart3);
+        }
+        var arrowEntity = $this.viewer.entities.add({
+            Type: 'DrawSector',
+            Position: data,
+            id: data.id || $this.objId,
+            polygon: {
+                hierarchy: new $this.Cesium.PolygonHierarchy(arrow),
+                show: true,
+                fill: true,
+                clampToGround: true,
+                material: $this.Cesium.Color.AQUA.withAlpha(0.9)
+            }
+        });
+        return arrowEntity;
+    }
+
+    //开始创建
+    startCreate() {
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            // if($this._positions.length == 3) return
+            if ($this._positions.length < 3) {
+                $this.floatingPoint = $this.createPoint(cartesian);
+                $this._positions.push(cartesian);
+            }
+            if (!$this._sector) {
+                // $this.createPoint(cartesian);// 绘制点
+            }
+
+
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制面
+            if ($this._positions.length < 2) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if ($this._positions.length == 2) {
+                $this._positions.push(cartesian);
+            }
+            if ($this._positions.length == 3) {
+                $this._positions.pop();
+                $this._positions.push(cartesian);
+                if (!$this.Cesium.defined($this._sector)) {
+                    $this._sector = $this.createsector();
+                }
+            }
+
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+        this.handler.setInputAction(function (evt) {
+            if (!$this._sector) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this._positions.pop();
+            $this._positions.push(cartesian);
+            $this._sectorData = $this._positions.concat();
+            $this.viewer.entities.remove($this._sector); //移除
+            $this._sector = null;
+            $this._positions = [];
+            $this.floatingPoint.position.setValue(cartesian);
+            var lnglatArr = [];
+            for (var i = 0; i < $this._sectorData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this._sectorData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this._sectorData = lnglatArr;
+            var sector = $this.addload(lnglatArr); //加载
+            $this._entities_sector.push(sector);
+            $this._sectorLast = sector;
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+
+    //创建直线扇形
+    createsector() {
+        // console.log(this._positions)
+        var $this = this;
+        var arrowEntity = $this.viewer.entities.add({
+            polygon: {
+                hierarchy: new $this.Cesium.CallbackProperty(
+                    function () {
+                        // if(this._positions.length < 3) return
+                        let pnts = $this._positions;
+                        let center = $this.lonLatToMercator($this.cartesianToLatlng(pnts[0]));
+                        let pnt2 = $this.lonLatToMercator($this.cartesianToLatlng(pnts[1]));
+                        let pnt3 = $this.lonLatToMercator($this.cartesianToLatlng(pnts[2]));
+                        var radius = $this.MathDistance(pnt2, center);
+                        var startAngle = $this.getAzimuth(pnt2, center);
+                        var endAngle = $this.getAzimuth(pnt3, center);
+                        var pList = $this.getArcPoints(center, radius, startAngle, endAngle);
+                        pList.push(pnts[0], pList[0]);
+                        let arrow = [];
+                        for (var i = 0; i < pList.length; i++) {
+                            var cart3 = new $this.Cesium.Cartesian3(pList[i].x, pList[i].y, pList[i].z);
+                            arrow.push(cart3);
+                        }
+
+                        return new $this.Cesium.PolygonHierarchy(pList);
+
+                    }, false),
+                show: true,
+                fill: true,
+                clampToGround: true,
+                material: $this.Cesium.Color.AQUA.withAlpha(0.5)
+            }
+        }
+        )
+        $this._entities_sector.push(arrowEntity);
+        return arrowEntity
+    }
+
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this._entities_point.push(point);
+        return point;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+    /**
+     * 经纬度坐标转墨卡托坐标
+     */
+    // 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
+    // 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
+    lonLatToMercator(Latlng) {
+        var E = Latlng[0];
+        var N = Latlng[1];
+        var x = E * 20037508.34 / 180;
+        var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
+        y = y * 20037508.34 / 180;
+        return [x, y]
+    }
+
+    WebMercator2lonLat(mercator) {
+        let x = mercator[0] / 20037508.34 * 180;
+        let ly = mercator[1] / 20037508.34 * 180;
+        let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
+        return [x, y];
+    }
+
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this._sectorLast, this._sectorData);
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        this._entities_point = [];  //脏数据
+    }
+
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this._entities_point.length; i++) {
+            this.viewer.entities.remove(this._entities_point[i]);
+        }
+        for (var i = 0; i < this._entities_sector.length; i++) {
+            this.viewer.entities.remove(this._entities_sector[i]);
+        }
+        this.floatingPoint = null;//标识点
+        this._sector = null; //活动扇形
+        this._sectorLast = null; //最后一个扇形
+        this._positions = [];  //活动点
+        this._entities_point = [];  //脏数据
+        this._entities_sector = [];  //脏数据
+        this._sectorData = null; //用于构造扇形数据
+    }
+
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+
+    // 求取扇形坐标函数/
+    //扇形配置函数
+    MathDistance(pnt1, pnt2) {
+        return Math.sqrt(Math.pow(pnt1[0] - pnt2[0], 2) + Math.pow(pnt1[1] - pnt2[1], 2));
+    }
+
+    getAzimuth(startPoint, endPoint) {
+        var azimuth;
+        var angle = Math.asin(Math.abs(endPoint[1] - startPoint[1]) / this.MathDistance(startPoint, endPoint));
+
+        if (endPoint[1] >= startPoint[1] && endPoint[0] >= startPoint[0]) {
+            azimuth = angle + Math.PI;
+        } else if (endPoint[1] >= startPoint[1] && endPoint[0] < startPoint[0]) {
+            azimuth = Math.PI * 2 - angle;
+        } else if (endPoint[1] < startPoint[1] && endPoint[0] < startPoint[0]) {
+            azimuth = angle;
+        } else if (endPoint[1] < startPoint[1] && endPoint[0] >= startPoint[0]) {
+            azimuth = Math.PI - angle;
+        }
+
+        return azimuth;
+    }
+
+
+    getArcPoints(center, radius, startAngle, endAngle) {
+        var x = null,
+            y = null,
+            z = null,
+            pnts = [],
+            angleDiff = endAngle - startAngle;
+        angleDiff = angleDiff < 0 ? angleDiff + Math.PI * 2 : angleDiff;
+
+        for (var i = 0; i <= 100; i++) {
+            var angle = startAngle + angleDiff * i / 100;
+            x = center[0] + radius * Math.cos(angle);
+            y = center[1] + radius * Math.sin(angle);
+            let latlon = this.WebMercator2lonLat([x, y])
+            pnts.push(this.Cesium.Cartesian3.fromDegrees(latlon[0], latlon[1]));
+        }
+        return pnts;
+    }
+}
+
+export default DrawSector

+ 424 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawStraightArrow.js

@@ -0,0 +1,424 @@
+import {
+	createTooltip
+} from "../../../common/common.js";
+
+import {
+	isRuntimeApp,
+	isRuntimeWeb,
+	createOperationMainDom,
+	showTooltipMessage
+} from "../../../common/RuntimeEnvironment.js";
+
+/*
+绘制直线箭头
+ */
+class DrawStraightArrow {
+	constructor(arg) {
+		this.viewer = arg.viewer;
+		this.Cesium = arg.Cesium;
+		this.floatingPoint = null; //标识点
+		this._straightArrow = null; //活动箭头
+		this._straightArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_straightArrow = []; //脏数据
+		this._straightArrowData = null; //用于构造箭头数据
+		this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+		this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+
+		this._tooltip = createTooltip(this.viewer.container);
+
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+	}
+
+	//返回箭头
+	get straightArrow() {
+		return this._straightArrowLast;
+	}
+
+	//返回箭头数据用于加载箭头
+	getData() {
+		return this._straightArrowData;
+	}
+
+	// 修改编辑调用计算
+	computePosition(data) {
+		var $this = this;
+		var length = data.length;
+		var p1 = data[0];
+		var p2 = data[length - 1];
+		var firstPoint = $this.cartesianToLatlng(p1);
+		var endPoints = $this.cartesianToLatlng(p2);
+		var arrow = [];
+		var res = $this.fineArrow([firstPoint[0], firstPoint[1]], [endPoints[0], endPoints[1]]);
+		for (var i = 0; i < res.length; i++) {
+			var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z);
+			arrow.push(cart3);
+		}
+		$this._straightArrowData = [firstPoint, endPoints];
+		return new $this.Cesium.PolygonHierarchy(arrow);
+	}
+
+	//加载箭头
+	addload(data) {
+		var $this = this;
+		if (data.length < 2) {
+			return null;
+		}
+		var length = data.length;
+		var p1 = data[0];
+		var p2 = data[length - 1];
+		var arrow = [];
+		var res = $this.fineArrow([p1[0], p1[1]], [p2[0], p2[1]]);
+		for (var i = 0; i < res.length; i++) {
+			var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z);
+			arrow.push(cart3);
+		}
+		var arrowEntity = $this.viewer.entities.add({
+			Type: 'DrawStraightArrow',
+			Position: data,
+			id: data.id || $this.objId,
+			polygon: {
+				hierarchy: new $this.Cesium.PolygonHierarchy(arrow),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		});
+		return arrowEntity;
+	}
+
+	//开始创建
+	startCreate(drawType) {
+		if (isRuntimeApp()) {
+			showTooltipMessage("点击开始绘制");
+		}
+
+		var $this = this;
+
+		this.drawType = drawType;
+		this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+
+		//单击开始绘制
+		this.handler.setInputAction(function(evt) {
+
+			if (isRuntimeApp()) {
+				//屏幕坐标转地形上坐标
+				var cartesian = $this.getCatesian3FromPX(evt.position);
+				if (!cartesian) {
+					return;
+				}
+
+				$this.createPoint(cartesian); // 绘制点
+				$this._positions.push(cartesian);
+
+				if ($this._positions.length === 2) {
+					showTooltipMessage("点击完成按钮,结束绘制");
+					$this.destroy();
+					if (!$this.Cesium.defined($this._straightArrow)) {
+						$this._straightArrow = $this.createStraightArrow();
+
+						//创建按钮
+						createOperationMainDom();
+						//隐藏回退按钮
+						document.getElementById("btnDrawBackout").style.display='none';
+						
+						//完成绘制
+						document.getElementById("btnDrawComplete").onclick = () => {
+
+							$this._straightArrowData = $this._positions.concat();
+							$this.viewer.entities.remove($this._straightArrow); //移除
+							$this._straightArrow = null;
+							$this._positions = [];
+
+							var lnglatArr = [];
+							for (var i = 0; i < $this._straightArrowData.length; i++) {
+								var lnglat = $this.cartesianToLatlng($this._straightArrowData[i]);
+								lnglatArr.push(lnglat)
+							}
+							$this._straightArrowData = lnglatArr;
+							var straightArrow = $this.addload($this._straightArrowData); //加载
+							$this._entities_straightArrow.push(straightArrow);
+							$this._straightArrowLast = straightArrow;
+
+							//删除关键点
+							$this.clearPoint();
+							$this.destroy();
+
+							let buttonDiv = document.getElementById("drawButtonDiv");
+							if (buttonDiv) {
+								//从页面移除
+								document.body.removeChild(buttonDiv);
+							}
+						}
+					}
+				}
+			} else {
+				/* 锁定点击事件 以免和双击事件冲突 */
+				clearTimeout($this._timer);
+				$this._timer = setTimeout(function() {
+					console.log('监听鼠标事件', '单击')
+
+					//屏幕坐标转地形上坐标
+					var cartesian = $this.getCatesian3FromPX(evt.position);
+					if ($this._positions.length == 0) {
+						$this._positions.push(cartesian.clone());
+						$this.floatingPoint = $this.createPoint(cartesian);
+						$this._positions.push(cartesian);
+					}
+					if (!$this._straightArrow) {
+						$this.createPoint(cartesian); // 绘制点
+					} else {
+						$this._straightArrowData = $this._positions.concat();
+						$this.viewer.entities.remove($this._straightArrow); //移除
+						$this._straightArrow = null;
+						$this._positions = [];
+						$this.floatingPoint.position.setValue(cartesian);
+						var lnglatArr = [];
+						for (var i = 0; i < $this._straightArrowData.length; i++) {
+							var lnglat = $this.cartesianToLatlng($this._straightArrowData[i]);
+							lnglatArr.push(lnglat)
+						}
+						$this._straightArrowData = lnglatArr;
+						var straightArrow = $this.addload($this._straightArrowData); //加载
+						$this._entities_straightArrow.push(straightArrow);
+						$this._straightArrowLast = straightArrow;
+						$this.clearPoint();
+						$this.destroy();
+
+						$this._tooltip.setVisible(false);
+					}
+				}, 200);
+			}
+		}, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+		//移动时绘制面
+		this.handler.setInputAction(function(evt) {
+
+			/* 如果运行环境是App 则禁止使用鼠标移动事件 */
+			if (isRuntimeApp()) return;
+
+			$this._tooltip.showAt(evt.endPosition, "点击开始绘制");
+
+			if ($this._positions.length < 2) return;
+
+			$this._tooltip.showAt(evt.endPosition, "点击结束绘制");
+
+			var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+			if (!$this.Cesium.defined($this._straightArrow)) {
+				$this._straightArrow = $this.createStraightArrow();
+			}
+			$this.floatingPoint.position.setValue(cartesian);
+			if ($this._straightArrow) {
+				$this._positions.pop();
+				$this._positions.push(cartesian);
+			}
+		}, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+		// this.handler.setInputAction(function(evt) {
+		// 	if (!$this._straightArrow) return;
+		// 	var cartesian = $this.getCatesian3FromPX(evt.position);
+		// 	$this._positions.pop();
+		// 	$this._positions.push(cartesian);
+		// 	$this._straightArrowData = $this._positions.concat();
+		// 	$this.viewer.entities.remove($this._straightArrow); //移除
+		// 	$this._straightArrow = null;
+		// 	$this._positions = [];
+		// 	$this.floatingPoint.position.setValue(cartesian);
+		// 	var lnglatArr = [];
+		// 	for (var i = 0; i < $this._straightArrowData.length; i++) {
+		// 		var lnglat = $this.cartesianToLatlng($this._straightArrowData[i]);
+		// 		lnglatArr.push(lnglat)
+		// 	}
+		// 	$this._straightArrowData = lnglatArr;
+		// 	var straightArrow = $this.addload($this._straightArrowData); //加载
+		// 	$this._entities_straightArrow.push(straightArrow);
+		// 	$this._straightArrowLast = straightArrow;
+		// 	$this.clearPoint();
+		// 	$this.destroy()
+		// }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+	}
+
+	//创建直线箭头
+	createStraightArrow() {
+		var $this = this;
+		var arrowEntity = $this.viewer.entities.add({
+			polygon: {
+				hierarchy: new $this.Cesium.CallbackProperty(
+					function() {
+						// return new $this.Cesium.PolygonHierarchy($this._positions);
+						var length = $this._positions.length;
+						var p1 = $this._positions[0];
+						var p2 = $this._positions[length - 1];
+						var firstPoint = $this.cartesianToLatlng(p1);
+						var endPoints = $this.cartesianToLatlng(p2);
+						var arrow = [];
+						var res = $this.fineArrow([firstPoint[0], firstPoint[1]], [endPoints[0], endPoints[1]]);
+						for (var i = 0; i < res.length; i++) {
+							var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z);
+							arrow.push(cart3);
+						}
+						return new $this.Cesium.PolygonHierarchy(arrow);
+
+					}, false),
+				show: true,
+				fill: true,
+				clampToGround: true,
+				material: $this.polygonMaterial
+			}
+		})
+		$this._entities_straightArrow.push(arrowEntity);
+		return arrowEntity
+	}
+
+	//创建点
+	createPoint(cartesian) {
+		var $this = this;
+		var point = this.viewer.entities.add({
+			position: cartesian,
+			point: {
+				pixelSize: 10,
+				color: $this.Cesium.Color.RED,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			}
+		});
+		$this._entities_point.push(point);
+		return point;
+	}
+
+	cartesianToLatlng(cartesian) {
+		var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+		var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+		var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+		return [lng, lat];
+	}
+
+	//销毁
+	destroy() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+	}
+
+	clearPoint() {
+		this.DrawEndEvent.raiseEvent(this._straightArrowLast, this._straightArrowData, this.drawType);
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		this._entities_point = []; //脏数据
+	}
+
+	//清空实体对象
+	clear() {
+		for (var i = 0; i < this._entities_point.length; i++) {
+			this.viewer.entities.remove(this._entities_point[i]);
+		}
+		for (var i = 0; i < this._entities_straightArrow.length; i++) {
+			this.viewer.entities.remove(this._entities_straightArrow[i]);
+		}
+
+		this.floatingPoint = null; //标识点
+		this._straightArrow = null; //活动箭头
+		this._straightArrowLast = null; //最后一个箭头
+		this._positions = []; //活动点
+		this._entities_point = []; //脏数据
+		this._entities_straightArrow = []; //脏数据
+		this._straightArrowData = null; //用于构造箭头数据
+	}
+
+	getCatesian3FromPX(px) {
+		var cartesian;
+		var ray = this.viewer.camera.getPickRay(px);
+		if (!ray) return null;
+		cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+		return cartesian;
+	}
+
+	// 求取箭头坐标函数/
+	//箭头配置函数
+	fineArrowDefualParam() {
+		return {
+			tailWidthFactor: 0.15,
+			neckWidthFactor: 0.20,
+			headWidthFactor: 0.25,
+			headAngle: Math.PI / 8.5,
+			neckAngle: Math.PI / 13
+		}
+	}
+
+	fineArrow(tailPoint, headerPoint) {
+		var $this = this;
+		if ((tailPoint.length < 2) || (headerPoint.length < 2)) return;
+		//画箭头的函数
+		let tailWidthFactor = $this.fineArrowDefualParam().tailWidthFactor;
+		let neckWidthFactor = $this.fineArrowDefualParam().neckWidthFactor;
+		let headWidthFactor = $this.fineArrowDefualParam().headWidthFactor;
+		let headAngle = $this.fineArrowDefualParam().headAngle;
+		let neckAngle = $this.fineArrowDefualParam().neckAngle;
+		var o = [];
+		o[0] = tailPoint;
+		o[1] = headerPoint;
+		var e = o[0],
+			r = o[1],
+			n = $this.getBaseLength(o),
+			g = n * tailWidthFactor,
+			//尾部宽度因子
+			i = n * neckWidthFactor,
+			//脖子宽度银子
+			s = n * headWidthFactor,
+			//头部宽度因子
+			a = $this.getThirdPoint(r, e, Math.PI / 2, g, !0),
+			l = $this.getThirdPoint(r, e, Math.PI / 2, g, !1),
+			u = $this.getThirdPoint(e, r, headAngle, s, !1),
+			c = $this.getThirdPoint(e, r, headAngle, s, !0),
+			p = $this.getThirdPoint(e, r, neckAngle, i, !1),
+			h = $this.getThirdPoint(e, r, neckAngle, i, !0),
+			d = [];
+		d.push(a[0], a[1], p[0], p[1], u[0], u[1], r[0], r[1], c[0], c[1], h[0], h[1], l[0], l[1], e[0], e[1]);
+		return $this.Cesium.Cartesian3.fromDegreesArray(d);
+	}
+
+	getBaseLength(t) {
+		return Math.pow(this.wholeDistance(t), .99)
+	}
+
+	wholeDistance(t) {
+		for (var o = 0, e = 0; e < t.length - 1; e++) o += this.distance(t[e], t[e + 1]);
+		return o
+	}
+
+	distance(t, o) {
+		return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2))
+	}
+
+	getThirdPoint(t, o, e, r, n) {
+		var g = this.getAzimuth(t, o),
+			i = n ? g + e : g - e,
+			s = r * Math.cos(i),
+			a = r * Math.sin(i);
+		return [o[0] + s, o[1] + a]
+	}
+
+	getAzimuth(t, o) {
+		var e, r = Math.asin(Math.abs(o[1] - t[1]) / this.distance(t, o));
+		return o[1] >= t[1] && o[0] >= t[0] ? e = r + Math.PI : o[1] >= t[1] && o[0] < t[0] ? e = 2 * Math.PI - r : o[1] < t[1] && o[0] < t[0] ? e = r : o[1] < t[1] && o[0] >= t[0] && (e = Math.PI - r), e
+	}
+}
+
+export default DrawStraightArrow

+ 286 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/DrawTriangleFlag.js

@@ -0,0 +1,286 @@
+
+// DrawTriangleFlag
+/*
+绘制三角形旗帜
+ */
+class DrawTriangleFlag {
+    constructor(arg) {
+        this.viewer = arg.viewer;
+        this.Cesium = arg.Cesium;
+        this.identificationPoint = null; //标识点位
+        this.TriangleFlag = null; 
+        this.TriangleFlagLast = null; // 三角形旗帜数据
+        this.positions = [];  // 经纬度
+        this.entitiesPoint = [];   // 实体点位
+        this.entitiesTriangleFlag = [];  
+        this.TriangleFlagData = null; 
+        this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
+        this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 
+		
+		/* 通用参数集合 */
+		this._param = {
+			id: "DrawStraightArrow",
+			polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
+			outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
+			outlineWidth: 1, //边框宽度
+		}
+		
+		/* 创建面材质 */
+		this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
+		/* 创建线材质 */
+		// this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
+		// 	dashLength: 16,
+		// 	color: Cesium.Color.fromCssColorString(this._param.outlineColor)
+		// });
+		this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
+    }
+ 
+    //返回三角形旗帜数据
+    getData() {
+        return this.TriangleFlagData;
+    }
+
+    // 修改编辑调用计算
+    computePosition(data){
+        //计算面
+        let $this = this
+        var lnglatArr = [];
+        for (var i = 0; i < data.length; i++) {
+            var lnglat = $this.cartesianToLatlng(data[i]);
+            lnglatArr.push(lnglat)
+        }
+        let startPoint = lnglatArr[0];
+        // 取最后一个
+        let endPoint =lnglatArr[lnglatArr.length - 1]
+        let point0 = lnglatArr[0];
+        var point1 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point2 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point3 =[startPoint[0], endPoint[1]]
+        let componentspolygon = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0])
+        let componentspolyline = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0,...point3])
+        let PolygonHierarchy = new $this.Cesium.PolygonHierarchy(componentspolygon)
+        $this.TriangleFlagData = lnglatArr;
+        console.log([PolygonHierarchy,componentspolyline])
+        return [PolygonHierarchy,componentspolyline];
+    }
+ 
+    //加载
+    addload(data) {
+        var $this = this;
+        if (data.length < 2) return;
+        let startPoint = data[0];
+        // 取最后一个
+        let endPoint =data[data.length - 1]
+        let point0 = data[0];
+        var point1 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point2 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+        var point3 =[startPoint[0], endPoint[1]]
+        let componentspolygon = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0])
+        let componentspolyline = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0,...point3])
+        var shape = this.viewer.entities.add({
+            Type:'DrawTriangleFlag',
+            Position:data,
+            id:data.id || $this.objId,
+            polygon: {
+                hierarchy: new $this.Cesium.PolygonHierarchy(componentspolygon),
+                extrudedHeight: 1,
+                material: $this.Cesium.Color.RED,
+            },
+            polyline: {
+                //使用cesium的peoperty
+                positions: componentspolyline,
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 5,
+                clampToGround: true
+            }
+        });
+        $this.entitiesTriangleFlag.push(shape);
+        return shape;
+    }
+ 
+    //开始创建
+    startCreate(drawType) {
+        this.drawType = drawType;
+        var $this = this;
+        this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
+        this.handler.setInputAction(function (evt) { //单机开始绘制
+            //屏幕坐标转地形上坐标
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            if ($this.positions.length == 0) {
+                $this.positions.push(cartesian.clone());
+                $this.identificationPoint = $this.createPoint(cartesian);
+                $this.createPoint(cartesian);// 绘制点
+                $this.positions.push(cartesian);
+            }
+            // if ($this.positions.length == 2) {
+            //     $this.positions.push(cartesian);
+            // }
+            
+        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
+        this.handler.setInputAction(function (evt) { //移动时绘制线
+            if ($this.positions.length < 2) return;
+            var cartesian = $this.getCatesian3FromPX(evt.endPosition);
+            if (!$this.Cesium.defined($this.TriangleFlag)) {
+                $this.TriangleFlag = $this.createTriangleFlag();
+            }
+            $this.identificationPoint.position.setValue(cartesian);
+            if ($this.TriangleFlag) {
+                $this.positions.pop();
+                $this.positions.push(cartesian);
+            }
+        }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+        this.handler.setInputAction(function (evt) {
+            if (!$this.TriangleFlag) return;
+            var cartesian = $this.getCatesian3FromPX(evt.position);
+            $this.positions.pop();
+            $this.positions.push(cartesian);
+            $this.createPoint(cartesian);// 绘制点
+            $this.TriangleFlagData = $this.positions.concat();
+            $this.viewer.entities.remove($this.TriangleFlag); //移除
+            $this.TriangleFlag = null;
+            $this.positions = [];
+            $this.identificationPoint.position.setValue(cartesian);
+            var lnglatArr = [];
+            for (var i = 0; i < $this.TriangleFlagData.length; i++) {
+                var lnglat = $this.cartesianToLatlng($this.TriangleFlagData[i]);
+                lnglatArr.push(lnglat)
+            }
+            $this.TriangleFlagData = lnglatArr;
+            var TriangleFlag = $this.addload([$this.TriangleFlagData[0],$this.TriangleFlagData[$this.TriangleFlagData.length -1 ]]); //加载
+            $this.entitiesTriangleFlag.push(TriangleFlag);
+            $this.TriangleFlagLast = TriangleFlag;
+            $this.clearPoint();
+            $this.destroy()
+        }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+    }
+ 
+    //创建点
+    createPoint(cartesian) {
+        var $this = this;
+        var point = this.viewer.entities.add({
+            position: cartesian,
+            point: {
+                pixelSize: 10,
+                color: $this.Cesium.Color.RED,
+                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+            }
+        });
+        $this.entitiesPoint.push(point);
+        return point;
+    }
+ 
+    //创建三角形旗帜
+    createTriangleFlag() {
+        console.log('232323')
+        var $this = this;
+        var polygon = this.viewer.entities.add({
+            polygon: {
+                hierarchy: new $this.Cesium.CallbackProperty(function () {
+                    if($this.positions.length < 2) return 
+                    let lonlat = [];
+                    let length = $this.positions.length
+                    for (let i=0; i<length; i++){
+                        lonlat.push($this.cartesianToLatlng($this.positions[i]))
+                    }
+                    let startPoint = lonlat[0]
+                    // 取最后一个
+                    let endPoint =lonlat[lonlat.length - 1]
+                    let point0 = lonlat[0];
+                    var point1 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point2 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point3 =[startPoint[0], endPoint[1]]
+
+                    let components = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0])
+                    
+                    return new $this.Cesium.PolygonHierarchy(components);
+                }, false),
+                extrudedHeight: 1,
+                material: $this.Cesium.Color.RED,
+            },
+            polyline: {
+                //使用cesium的peoperty
+                positions: new $this.Cesium.CallbackProperty(function () {
+                    if($this.positions.length < 2) return 
+                    let lonlat = [];
+                    let length = $this.positions.length
+                    for (let i=0; i<length; i++){
+                        lonlat.push($this.cartesianToLatlng($this.positions[i]))
+                    }
+                    let startPoint = lonlat[0]
+                    // 取最后一个
+                    let endPoint =lonlat[lonlat.length - 1]
+                    let point0 = lonlat[0];
+                    var point1 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point2 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+                    var point3 =[startPoint[0], endPoint[1]]
+
+                    let components = $this.Cesium.Cartesian3.fromDegreesArray([...point0, ...point1, ...point2, ...point0,...point3])
+                    return components
+                }, false),
+                show: true,
+                material: $this.Cesium.Color.YELLOW,
+                width: 5,
+                clampToGround: true
+            }
+        });
+        $this.entitiesTriangleFlag.push(polygon);
+        return polygon;
+    }
+
+    cartesianToLatlng(cartesian) {
+        var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
+        var lat = this.Cesium.Math.toDegrees(latlng.latitude);
+        var lng = this.Cesium.Math.toDegrees(latlng.longitude);
+        return [lng, lat];
+    }
+
+    LatlngTocartesian(latlng) {
+        let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
+        return cartesian3
+    }
+
+    clearPoint() {
+        this.DrawEndEvent.raiseEvent(this.TriangleFlagLast, [this.TriangleFlagData[0],this.TriangleFlagData[this.TriangleFlagData.length -1 ]], this.drawType);
+        for (var i = 0; i < this.entitiesPoint.length; i++) {
+            this.viewer.entities.remove(this.entitiesPoint[i]);
+        }
+        this.entitiesPoint = [];  //脏数据
+    }
+ 
+    //销毁
+    destroy() {
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+    }
+ 
+    //清空实体对象
+    clear() {
+        for (var i = 0; i < this.entitiesPoint.length; i++) {
+            this.viewer.entities.remove(this.entitiesPoint[i]);
+        }
+        for (var i = 0; i < this.entitiesTriangleFlag.length; i++) {
+            this.viewer.entities.remove(this.entitiesTriangleFlag[i]);
+        }
+        this.identificationPoint = null; //标识点位
+        this.TriangleFlag = null; 
+        this.TriangleFlagLast = null; // 三角形旗帜数据
+        this.positions = [];  // 经纬度
+        this.entitiesPoint = [];   // 实体点位
+        this.entitiesTriangleFlag = [];  
+        this.TriangleFlagData = null; 
+    }
+ 
+    getCatesian3FromPX(px) {
+        var cartesian;
+        var ray = this.viewer.camera.getPickRay(px);
+        if (!ray) return null;
+        cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
+        return cartesian;
+    }
+}
+ 
+export default DrawTriangleFlag
+

+ 47 - 0
packages/Widgets/DrawTools/MilitaryPlot/drawingMethod/index.js

@@ -0,0 +1,47 @@
+import DrawStraightArrow from './DrawStraightArrow';
+import DrawAttackArrow from './DrawAttackArrow';
+import DrawPincerArrow from './DrawPincerArrow';
+import DrawGatheringPlace from './DrawGatheringPlace';
+import DrawClosedCurve from './DrawClosedCurve';
+import DrawSector from './DrawSector';
+
+import DrawBowLine from './DrawBowLine';
+import DrawBowPlane from './DrawBowPlane';
+
+import DrawCurve from './DrawCurve';
+import DrawCurveFlag from './DrawCurveFlag';
+import DrawRectFlag from './DrawRectFlag';
+import DrawTriangleFlag from './DrawTriangleFlag';
+
+import DrawPoint from './DrawPoint';
+import DrawPolyline from './DrawPolyline';
+import DrawPolygon from './DrawPolygon';
+import DrawRectangle from './DrawRectangle';
+import DrawCircle from './DrawCircle';
+
+
+let MilitaryPlot = {
+	DrawStraightArrow, // 绘制直线箭头
+	DrawAttackArrow, //绘制攻击箭头
+	DrawPincerArrow, //绘制钳击箭头
+	DrawGatheringPlace, // 绘制集结地
+	DrawClosedCurve, //绘制闭合曲面
+
+	DrawSector, //绘制扇形
+
+	DrawBowLine, // 绘制弓形线
+	DrawBowPlane, // 绘制弓形面
+
+	DrawCurve, //绘制曲线
+	DrawCurveFlag, //绘制曲线旗帜
+	DrawRectFlag, //绘制矩形直角旗帜
+	DrawTriangleFlag, //绘制三角旗帜
+
+	DrawPoint, //绘制点
+	DrawPolyline, // 绘制线
+	DrawPolygon, // 多边形
+	DrawRectangle, // 绘制矩形
+	DrawCircle, //绘制圆
+}
+
+export default MilitaryPlot

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 69 - 0
packages/Widgets/DrawTools/SketchViewModel.js


+ 1094 - 0
packages/Widgets/PointObject.js

@@ -0,0 +1,1094 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	setSessionid,
+	getHeigthByPointsMostDetailed,
+	getHeigthByPointMostDetailed
+} from "./common/common.js";
+
+/**
+ * 点对象
+ */
+class PointObject {
+	/**
+	 * 默认初始化
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(PointObject.prototype, /** @lends PointObject.prototype */ {
+
+	/**
+	 * @description 根据坐标绘制文字
+	 * @param {Array/Cesium.Cartesian3}  points  坐标位置[lng,lat,height]经度,以度为单位,纬度,以度为单位
+	 * @param {Object}  options 
+	 * 
+	 * @param {Object} [options.id] 用于移除
+	 * 
+	 * @param {Object} [options.label] label的样式,具有以下属性:
+	 * @param {Number} [options.label.text=""] 文字
+	 * @param {String} [options.label.font="24px Helvetica"] 组合字体样式
+	 * 	组合字体
+	 *	font:font-style font-weight font-size/line-height font-family;
+	 *	font:italic bolder 20px/10px Arial;
+	 * @param {String} [options.label.fillColor=[255,255,255,0]] 字体颜色
+	 * @param {String} [options.label.outlineColor=[255,255,255,0]] 字体边框颜色
+	 * @param {Number} [options.label.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.label.showBackground=false] 是否显示背景颜色	
+	 * @param {Number} [options.label.backgroundColor=[255,255,255,0]] 背景颜色	
+	 * @param {Number} [options.label.backgroundPadding=0]	背景内边距
+	 * @param {Number} [options.label.pixelOffset] 偏移像素
+	 * @param {Number} [options.label.pixelOffset.x=0] 横向偏移像素
+	 * @param {Number} [options.label.pixelOffset.y=0] 纵向偏移像素
+	 * @param {Number} [options.label.scale=1] 尺寸
+	 * @param {Number} [options.label.scaleByDistance] 相机范围
+	 * @param {Number} [options.label.scaleByDistance.near=1.5e2] 相机范围的下界。
+	 * @param {String} [options.label.scaleByDistance.nearValue=1] 相机范围下界的值。
+	 * @param {String} [options.label.scaleByDistance.far=2400] 相机范围的上限。
+	 * @param {Number} [options.label.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	addLabel(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			//坐标位置
+			let position;
+			if (points instanceof Cesium.Cartesian3) {
+				position = points;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(points[0], points[1], points[2] || 0);
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+			let label = options.label || {};
+
+			//文字内容
+			label.text = Cesium.defaultValue(label.text, "金田CIM三维基础平台");
+			//组合字体样式
+			label.font = Cesium.defaultValue(label.font, "24px Helvetica");
+
+			//字体颜色
+			if (label.fillColor instanceof Array) {
+				label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+			} else if (typeof(label.fillColor) === 'string') {
+				label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+			} else {
+				label.fillColor = new Cesium.Color.fromCssColorString("#FFFF00");
+			}
+
+			//字体边框颜色
+			if (label.outlineColor instanceof Array) {
+				label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+			} else if (typeof(label.outlineColor) === 'string') {
+				label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+			} else {
+				label.outlineColor = new Cesium.Color.fromCssColorString("#FFF");
+			}
+			//字体边框宽度
+			label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+			//是否显示背景颜色
+			label.showBackground = Cesium.defaultValue(label.showBackground, false);
+			//背景颜色
+			if (label.backgroundColor instanceof Array) {
+				label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+			} else if (typeof(label.backgroundColor) === 'string') {
+				label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+			} else {
+				label.backgroundColor = new Cesium.Color.fromCssColorString("#FFF");
+			}
+			//背景内边距
+			if (label.backgroundPadding) {
+				label.backgroundPadding = new Cesium.Cartesian2(label.backgroundPadding, label.backgroundPadding);
+			}
+
+			let entity = new Cesium.Entity({
+				id: options.id,
+				position: position,
+				label: {
+					text: label.text,
+					font: label.font, //字体样式
+					fillColor: label.fillColor, //字体颜色
+					outlineColor: label.outlineColor, //字体边框颜色
+					outlineWidth: label.outlineWidth, //边框宽度	
+					style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+					verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+					showBackground: label.showBackground, //是否显示背景颜色
+					backgroundColor: label.backgroundColor, // 背景颜色
+					backgroundPadding: label.backgroundPadding, //指定以像素为单位的水平和垂直背景填充padding
+					disableDepthTestDistance: Number.POSITIVE_INFINITY,
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+				}
+			});
+
+			//偏移量
+			if (label.pixelOffset) {
+				label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+				label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+				entity.label.pixelOffset = new Cesium.Cartesian2(label.pixelOffset.x, label.pixelOffset.y);
+			}
+
+			if (label.scaleByDistance) {
+				label.scaleByDistance.near = Cesium.defaultValue(label.scaleByDistance.near, 0);
+				label.scaleByDistance.nearValue = Cesium.defaultValue(label.scaleByDistance.nearValue, 0);
+				label.scaleByDistance.far = Cesium.defaultValue(label.scaleByDistance.far, 1);
+				label.scaleByDistance.farValue = Cesium.defaultValue(label.scaleByDistance.farValue, 0);
+
+				entity.label.scaleByDistance = new Cesium.NearFarScalar(label.scaleByDistance.near, label.scaleByDistance.nearValue, label.scaleByDistance.far, label.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+			}
+
+			_self._viewer.entities.add(entity);
+
+			resolve(entity)
+
+		});
+	},
+
+	/**
+	 * @description 根据坐标绘制点及文字
+	 * @param {Array/Cesium.Cartesian3}  points  坐标位置[lng,lat,height]经度,以度为单位,纬度,以度为单位
+	 * @param {Object}  options 
+	 * 
+	 * @param {Object} [options.id] 用于移除
+	 * 
+	 * @param {Object} [options.point] 点的样式,具有以下属性:
+	 * @param {Number} [options.point.pixelSize=10] 指定点的大小,以像素为单位
+	 * @param {Array} [options.point.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {String} [options.point.outlineColor=[255,255,255,0]] 指定点轮廓的颜色,,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明,
+	 * @param {Number} [options.point.outlineWidth=0] 指定点轮廓的宽度
+	 * 
+	 * @param {Object} [options.label] label的样式,具有以下属性:
+	 * @param {Number} [options.label.text=""] 文字
+	 * @param {String} [options.label.font="24px Helvetica"] 字体样式
+	 * @param {String} [options.label.fillColor=[255,255,255,0]] 字体颜色
+	 * @param {String} [options.label.outlineColor=[255,255,255,0]] 字体边框颜色
+	 * @param {Number} [options.label.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.label.showBackground=false] 是否显示背景颜色	
+	 * @param {Number} [options.label.backgroundColor=[255,255,255,0]] 背景颜色		
+	 * @param {Number} [options.label.pixelOffset] 偏移像素
+	 * @param {Number} [options.label.pixelOffset.x=0] 横向偏移像素
+	 * @param {Number} [options.label.pixelOffset.y=0] 纵向偏移像素
+	 * @param {Number} [options.label.scaleByDistance] 相机范围
+	 * @param {Number} [options.label.scaleByDistance.near=1.5e2] 相机范围的下界。
+	 * @param {String} [options.label.scaleByDistance.nearValue=1] 相机范围下界的值。
+	 * @param {String} [options.label.scaleByDistance.far=2400] 相机范围的上限。
+	 * @param {Number} [options.label.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	addPoint(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			//坐标位置
+			let position;
+			if (points instanceof Cesium.Cartesian3) {
+				position = points;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(points[0], points[1], points[2] || 0);
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			let point = options.point || {};
+			//点的大小
+			point.pixelSize = Cesium.defaultValue(point.pixelSize, 10);
+			//点位颜色
+			if (point.color instanceof Array) {
+				point.color = new Cesium.Color(point.color[0] / 255, point.color[1] / 255, point.color[2] / 255, point.color[3]);
+			} else if (typeof(point.color) === 'string') {
+				point.color = new Cesium.Color.fromCssColorString(point.color);
+			} else {
+				point.color = new Cesium.Color.fromCssColorString("#FFF");
+			}
+
+			//点位轮廓颜色
+			if (point.outlineColor instanceof Array) {
+				point.outlineColor = new Cesium.Color(point.outlineColor[0] / 255, point.outlineColor[1] / 255, point.outlineColor[2] / 255, point.outlineColor[3]);
+			} else if (typeof(point.outlineColor) === 'string') {
+				point.outlineColor = new Cesium.Color.fromCssColorString(point.outlineColor);
+			} else {
+				point.outlineColor = new Cesium.Color.fromCssColorString("#FFF");
+			}
+
+			//点位轮廓宽度
+			point.outlineWidth = Cesium.defaultValue(point.outlineWidth, 1);
+
+			let entity = new Cesium.Entity({
+				id: options.id,
+				position: position,
+				point: {
+					pixelSize: point.pixelSize, //点的大小
+					color: point.color, //点位颜色
+					outlineColor: point.outlineColor, //点位轮廓颜色
+					outlineWidth: point.outlineWidth, //点位轮廓宽度
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //指定高度相对于什么的属性。CLAMP_TO_GROUND可使点贴地,地就是地形。NONE是绝对高程.RELATIVE_TO_GROUND是设置距离地形的相对高度。
+					disableDepthTestDistance: Number.POSITIVE_INFINITY, //指定距离相机的距离,在这个距离上禁用深度测试。通过设置相机到圆要素的距离阈值来判断是否开启深度检测,这里设置为1000.0米正常,但是当相机距离超过阈值时,就会开启深度检测,圆还是会只显示一半。将阈值设置为无穷大时:Number.POSITIVE_INFINITY。虽然无论相机距离远近,圆都可以正常显示,但是没有圆的深度检测,不同要素之间的遮挡无法得到有效判断,有的在建筑物后的点会在建筑物前显示,造成视觉误差与干扰。
+
+					// disableDepthTestDistance: updatedPositions[0].height, //指定距离相机的距离,在这个距离上禁用深度测试。通过设置相机到圆要素的距离阈值来判断是否开启深度检测,这里设置为1000.0米正常,但是当相机距离超过阈值时,就会开启深度检测,圆还是会只显示一半。将阈值设置为无穷大时:Number.POSITIVE_INFINITY。虽然无论相机距离远近,圆都可以正常显示,但是没有圆的深度检测,不同要素之间的遮挡无法得到有效判断,有的在建筑物后的点会在建筑物前显示,造成视觉误差与干扰。
+				}
+			});
+
+			/* 判断是否需要绘制文字 */
+			if (options.label) {
+
+				let label = options.label || {};
+
+				label.text = Cesium.defaultValue(label.text, "");
+				label.font = Cesium.defaultValue(label.font, "24px Helvetica"); //字体样式
+
+				//字体颜色
+				if (label.fillColor instanceof Array) {
+					label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+				} else if (typeof(label.fillColor) === 'string') {
+					label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+				} else {
+					label.fillColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+
+				//字体边框颜色
+				if (label.outlineColor instanceof Array) {
+					label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+				} else if (typeof(label.outlineColor) === 'string') {
+					label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+				} else {
+					label.outlineColor = new Cesium.Color.fromCssColorString("#FFF");
+				}
+				//字体边框宽度
+				label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+				//是否显示背景颜色
+				label.showBackground = Cesium.defaultValue(label.showBackground, false);
+				//背景颜色
+				if (label.backgroundColor instanceof Array) {
+					label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+				} else if (typeof(label.backgroundColor) === 'string') {
+					label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+				} else {
+					label.backgroundColor = new Cesium.Color.fromCssColorString("#FFF");
+				}
+
+				if (label.backgroundPadding) {
+					label.backgroundPadding = new Cesium.Cartesian2(label.backgroundPadding, label.backgroundPadding);
+				}
+
+				// label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+				// label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+
+				entity.label = {
+					text: label.text,
+					font: label.font, //字体样式
+					fillColor: label.fillColor, //字体颜色
+					outlineColor: label.outlineColor, //字体边框颜色
+					outlineWidth: label.outlineWidth, //边框宽度	
+					style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+					verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+					showBackground: label.showBackground, //是否显示背景颜色
+					backgroundColor: label.backgroundColor, // 背景颜色
+					backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
+					disableDepthTestDistance: Number.POSITIVE_INFINITY,
+
+					// pixelOffset: new Cesium.Cartesian2(label.pixelOffset.x, label.pixelOffset.y), //偏移量
+				}
+
+				if (label.scaleByDistance) {
+					label.scaleByDistance.near = Cesium.defaultValue(label.scaleByDistance.near, 0);
+					label.scaleByDistance.nearValue = Cesium.defaultValue(label.scaleByDistance.nearValue, 0);
+					label.scaleByDistance.far = Cesium.defaultValue(label.scaleByDistance.far, 1);
+					label.scaleByDistance.farValue = Cesium.defaultValue(label.scaleByDistance.farValue, 0);
+
+					entity.label.scaleByDistance = new Cesium.NearFarScalar(label.scaleByDistance.near, label.scaleByDistance.nearValue, label.scaleByDistance.far, label.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+				}
+			}
+
+			_self._viewer.entities.add(entity);
+
+			resolve(entity)
+		});
+	},
+
+	/**
+	 * 根据坐标绘制广告牌及文字
+	 * @param {Object} points 坐标位置[lng,lat,height]经度,以度为单位,纬度,以度为单位,高程
+	 * @param {Object} options
+	 * @param {String} [options.id] 用于移除
+	 * @param {Object} options.billboard 广告牌的样式,具有以下属性:
+	 * @param {Number} options.billboard.imgUrl 广告牌图片
+	 * @param {Number} [options.billboard.scale=1] 尺寸
+	 * @param {Number} [options.billboard.pixelOffset] 偏移像素
+	 * @param {Number} [options.billboard.pixelOffset.x=0] 横向偏移像素
+	 * @param {Number} [options.billboard.pixelOffset.y=0] 纵向偏移像素
+	 * @param {Object} [options.billboard.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.billboard.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.billboard.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.billboard.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.billboard.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 * 
+	 * @param {Object} [options.label] label的样式,具有以下属性:
+	 * @param {Number} [options.label.text="注记"] 文字
+	 * @param {String} [options.label.font="24px Helvetica"] 指定CSS字体的属性,字体大小及样式
+	 * @param {String} [options.label.fillColor=[255,255,255,1]] 字体颜色
+	 * @param {String} [options.label.outlineColor=[255,255,255,1]] 字体边框颜色
+	 * @param {Number} [options.label.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.label.showBackground=false] 是否显示背景颜色
+	 * @param {Number} [options.label.backgroundColor=[255,255,255,1]] 背景颜色		
+	 * @param {Number} [options.label.pixelOffset] 偏移像素
+	 * @param {Number} [options.label.pixelOffset.x=0] 横向偏移像素
+	 * @param {Number} [options.label.pixelOffset.y=0] 纵向偏移像素
+	 * @param {Object} [options.label.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.label.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.label.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.label.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.label.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	addBillboard(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+			let _self = this;
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			//坐标位置
+			let position;
+			if (points instanceof Cesium.Cartesian3) {
+				position = points;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(points[0], points[1], points[2] || 0);
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			let billboard = options.billboard || {};
+			billboard.image = billboard.imgUrl || "jt3dSDK/imgs/point/point3.png";
+
+			billboard.scale = Cesium.defaultValue(billboard.scale, 1);
+			billboard.pixelOffset = Cesium.defaultValue(billboard.pixelOffset, 0);
+			// label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+			// label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+
+			let entity = new Cesium.Entity({
+				id: options.id,
+				name: "add billboard",
+				//位置
+				position: position,
+				//图片标签
+				billboard: {
+					image: billboard.image,
+					horizontalOrigin: Cesium.HorizontalOrigin.CENTER, //水平
+					verticalOrigin: Cesium.VerticalOrigin.BOTTOM, //垂直位置
+					scale: billboard.scale, //尺寸
+					pixelOffset: new Cesium.Cartesian2(0, billboard.pixelOffset),
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+					disableDepthTestDistance: Number.POSITIVE_INFINITY,
+				}
+			});
+
+			if (billboard.scaleByDistance) {
+				billboard.scaleByDistance.near = Cesium.defaultValue(billboard.scaleByDistance.near, 0);
+				billboard.scaleByDistance.nearValue = Cesium.defaultValue(billboard.scaleByDistance.nearValue, 0);
+				billboard.scaleByDistance.far = Cesium.defaultValue(billboard.scaleByDistance.far, 1);
+				billboard.scaleByDistance.farValue = Cesium.defaultValue(billboard.scaleByDistance.farValue, 0);
+
+				entity.billboard.scaleByDistance = new Cesium.NearFarScalar(billboard.scaleByDistance.near, billboard.scaleByDistance.nearValue, billboard.scaleByDistance.far, billboard.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+			}
+
+			/* 判断是否需要绘制文字 */
+			if (options.label) {
+
+				let label = options.label || {};
+
+				label.text = Cesium.defaultValue(label.text, "");
+				label.font = Cesium.defaultValue(label.font, "24px Helvetica");
+
+				if (label.fillColor instanceof Array) {
+					label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+				} else if (typeof(label.fillColor) === 'string') {
+					label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+				} else {
+					label.fillColor = new Cesium.Color.fromCssColorString("#ff0000");
+				}
+
+				if (label.outlineColor instanceof Array) {
+					label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+				} else if (typeof(label.outlineColor) === 'string') {
+					label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+				} else {
+					label.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+				label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+				//是否显示背景颜色
+				label.showBackground = Cesium.defaultValue(label.showBackground, false);
+				//背景颜色
+				if (label.backgroundColor instanceof Array) {
+					label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+				} else if (typeof(label.backgroundColor) === 'string') {
+					label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+				} else {
+					label.backgroundColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+
+				if (label.backgroundPadding) {
+					label.backgroundPadding = new Cesium.Cartesian2(label.backgroundPadding, label.backgroundPadding);
+				}
+
+				entity.label = {
+					text: label.text,
+					font: label.font,
+					fillColor: label.fillColor, //填充颜色
+					outlineColor: label.outlineColor, //边框颜色
+					outlineWidth: label.outlineWidth, //边框宽度	
+					style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+					verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+					showBackground: label.showBackground, //指定标签后面背景的可见性
+					backgroundColor: label.backgroundColor, // 背景颜色
+					backgroundPadding: label.backgroundPadding, //指定以像素为单位的水平和垂直背景填充padding
+					disableDepthTestDistance: Number.POSITIVE_INFINITY,
+				}
+
+				//偏移量
+				if (label.pixelOffset) {
+					label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+					label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+					entity.label.pixelOffset = new Cesium.Cartesian2(label.pixelOffset.x, label.pixelOffset.y);
+				}
+
+				//相机距离
+				if (label.scaleByDistance) {
+					label.scaleByDistance.near = Cesium.defaultValue(label.scaleByDistance.near, 0);
+					label.scaleByDistance.nearValue = Cesium.defaultValue(label.scaleByDistance.nearValue, 0);
+					label.scaleByDistance.far = Cesium.defaultValue(label.scaleByDistance.far, 1);
+					label.scaleByDistance.farValue = Cesium.defaultValue(label.scaleByDistance.farValue, 0);
+
+					entity.label.scaleByDistance = new Cesium.NearFarScalar(label.scaleByDistance.near, label.scaleByDistance.nearValue, label.scaleByDistance.far, label.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+				}
+			}
+
+			this._viewer.entities.add(entity);
+
+			resolve(entity)
+		});
+	},
+
+	/**
+	 * 加载GLTF/GLB模型数据
+	 * @param {Array/Cesium.Cartesian3}  points  坐标位置[lng,lat,height]经度,以度为单位,纬度,以度为单位
+	 * @param {Object}  options 
+	 * @param {Object} [options.id] 用于移除,模型实体加载ID,加入到整体图层中 以便可以删除对应的图层
+	 * 
+	 * @param {Object} options.model model的样式,具有以下属性:
+	 * @param {String} options.model.url 模型路径
+	 * @param {Number} [options.model.alpha] 模型透明度
+	 * @param {Array<Number>} [options.model.silhouetteColor] 模型轮廓颜色[0~255,0~255,0~255,0~1]
+	 * @param {Number} [options.model.silhouetteSize] 模型轮廓宽度
+	 * @param {Number} [options.model.minimumPixelSize] 模型最小刻度
+	 * @param {Number} [options.model.maximumScale] 模型的最大比例尺大小,设置模型最大放大大小
+	 * @param {Number} [options.model.heading=0.0] 以弧度为单位的航向分量
+	 * @param {Number} [options.model.pitch=0.0] 以弧度为单位的螺距分量
+	 * @param {Number} [options.model.roll=0.0] 以弧度为单位的滚动分量
+	 */
+	addModel: function(points, options) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		//异步函数
+		return new Promise((resolve, reject) => {
+			
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			//坐标位置
+			let position;
+			if (points instanceof Cesium.Cartesian3) {
+				position = points;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(points[0], points[1], points[2] || 0);
+			}
+
+			// 初始化参数默认值
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			let model = options.model || {};
+
+			//透明度
+			model.alpha = Cesium.defaultValue(model.alpha, 1);
+
+			//模型旋转
+			model.heading = Cesium.defaultValue(model.heading, 0.0);
+			model.pitch = Cesium.defaultValue(model.pitch, 0.0);
+			model.roll = Cesium.defaultValue(model.roll, 0.0);
+
+			//弧度的航向分量。
+			var heading = Cesium.Math.toRadians(model.heading);
+			//弧度的螺距分量。
+			var pitch = model.pitch;
+			//滚动分量(以弧度为单位)
+			var roll = model.roll;
+			//HeadingPitchRoll旋转表示为航向,俯仰和滚动。围绕Z轴。节距是绕负y轴的旋转。滚动是关于正x轴。
+			var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
+
+			let entity = new Cesium.Entity({
+				id: options.id, //模型id
+				position: position, // 模型位置
+				// orientation: Cesium.Transforms.headingPitchRollQuaternion(position, hpr), // 模型方向
+				model: { // 模型资源
+					uri: model.url, // 模型路径
+					incrementallyLoadTextures: true, //加载模型后纹理是否能够继续流入
+					colorBlendMode: Cesium.ColorBlendMode['HIGHLIGHT'], //经常使用的有三个HIGHLIGHT,REPLACE,MIX
+					colorBlendAmount: 0.1, //这个属性必须是MIX混合属性才能生效,见colorBlendMode
+
+					color: Cesium.Color.WHITE.withAlpha(model.alpha), //模型颜色,这里可以设置颜色的变化,包含透明度的颜色
+
+					imageBasedLightingFactor: new Cesium.Cartesian2(12.0, 13.0),
+					runAnimations: true, //是否运行模型中的动画效果
+					show: true, // 模型是否可见
+
+					// 仅用于调试,显示魔仙绘制时的线框
+					debugWireframe: false,
+					// 仅用于调试。显示模型绘制时的边界球。
+					debugShowBoundingVolume: false,
+					
+					heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+					disableDepthTestDistance: Number.POSITIVE_INFINITY,
+				},
+			});
+
+			// 模型最小刻度,不管缩放如何,模型的最小最小像素大小。
+			if (model.minimumPixelSize) {
+				entity.model.minimumPixelSize = model.minimumPixelSize;
+			}
+			// 模型最大刻度,模型的最大比例尺大小。 minimumPixelSize的上限。
+			if (model.maximumScale) {
+				entity.model.maximumScale = model.maximumScale;
+			}
+			// 模型轮廓颜色
+			if (model.silhouetteColor) {
+				if (model.silhouetteColor instanceof Array) {
+					entity.model.silhouetteColor = new Cesium.Color(model.silhouetteColor[0] / 255, model.silhouetteColor[1] / 255, model.silhouetteColor[2] / 255, model.silhouetteColor[3]);
+				} else if (typeof(model.silhouetteColor) === 'string') {
+					entity.model.silhouetteColor = new Cesium.Color.fromCssColorString(model.silhouetteColor);
+				}
+			}
+			//模型轮廓宽度
+			model.silhouetteSize = Cesium.defaultValue(model.silhouetteSize, 1);
+
+			_self._viewer.entities.add(entity);
+
+			resolve(entity);
+		});
+	},
+
+	/**
+	 * @description 根据坐标绘制点
+	 * @param {Array/Cesium.Cartesian3}  points  坐标位置[lng,lat,height]经度,以度为单位,纬度,以度为单位
+	 * @param {Object}  options 
+	 * 
+	 * @param {Object} [options.id] 用于移除
+	 * 
+	 * @param {Object} [options.point] 点的样式,具有以下属性:
+	 * @param {Number} [options.point.pixelSize=10] 指定点的大小,以像素为单位
+	 * @param {Array} [options.point.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {String} [options.point.outlineColor=[255,255,255,0]] 指定点轮廓的颜色,,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明,
+	 * @param {Number} [options.point.outlineWidth=0] 指定点轮廓的宽度
+	 * 
+	 * @param {Object} [options.label] label的样式,具有以下属性:
+	 * @param {Number} [options.label.text=""] 文字
+	 * @param {String} [options.label.font="24px Helvetica"] 字体样式
+	 * @param {String} [options.label.fillColor=[255,255,255,0]] 字体颜色
+	 * @param {String} [options.label.outlineColor=[255,255,255,0]] 字体边框颜色
+	 * @param {Number} [options.label.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.label.showBackground=false] 是否显示背景颜色	
+	 * @param {Number} [options.label.backgroundColor=[255,255,255,0]] 背景颜色		
+	 * @param {Number} [options.label.pixelOffset=0] 偏移量
+	 * @param {Number} [options.label.scale=1] 尺寸
+	 * @param {Number} [options.label.scaleByDistance] 相机范围
+	 * @param {Number} [options.label.scaleByDistance.near=1.5e2] 相机范围的下界。
+	 * @param {String} [options.label.scaleByDistance.nearValue=1] 相机范围下界的值。
+	 * @param {String} [options.label.scaleByDistance.far=2400] 相机范围的上限。
+	 * @param {Number} [options.label.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	generatePoint(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			let point = options.point || {};
+			//点的大小
+			point.pixelSize = Cesium.defaultValue(point.pixelSize, 10);
+			//点位颜色
+			if (point.color instanceof Array) {
+				point.color = new Cesium.Color(point.color[0] / 255, point.color[1] / 255, point.color[2] / 255, point.color[3]);
+			} else if (typeof(point.color) === 'string') {
+				point.color = new Cesium.Color.fromCssColorString(point.color);
+			} else {
+				point.color = new Cesium.Color.fromCssColorString("#FFF");
+			}
+
+			//点位轮廓颜色
+			if (point.outlineColor instanceof Array) {
+				point.outlineColor = new Cesium.Color(point.outlineColor[0] / 255, point.outlineColor[1] / 255, point.outlineColor[2] / 255, point.outlineColor[3]);
+			} else if (typeof(point.outlineColor) === 'string') {
+				point.outlineColor = new Cesium.Color.fromCssColorString(point.outlineColor);
+			} else {
+				point.outlineColor = new Cesium.Color.fromCssColorString("#FFF");
+			}
+
+			//点位轮廓宽度
+			point.outlineWidth = Cesium.defaultValue(point.outlineWidth, 1);
+
+			//获取指定坐标的地形高度。
+			let terrainAltitude = getHeigthByPointsMostDetailed(_self._viewer, [points]);
+			terrainAltitude.then(function(updatedPositions) {
+				let position = Cesium.Cartesian3.fromDegrees(points[0], points[1], updatedPositions[0].height)
+
+				let entity = new Cesium.Entity({
+					id: options.id,
+					position: position,
+					point: {
+						pixelSize: point.pixelSize, //点的大小
+						color: point.color, //点位颜色
+						outlineColor: point.outlineColor, //点位轮廓颜色
+						outlineWidth: point.outlineWidth, //点位轮廓宽度
+						heightReference: Cesium.HeightReference.NONE, //指定高度相对于什么的属性。CLAMP_TO_GROUND可使点贴地,地就是地形。NONE是绝对高程.RELATIVE_TO_GROUND是设置距离地形的相对高度。
+						// disableDepthTestDistance: Number.POSITIVE_INFINITY, //指定距离相机的距离,在这个距离上禁用深度测试。通过设置相机到圆要素的距离阈值来判断是否开启深度检测,这里设置为1000.0米正常,但是当相机距离超过阈值时,就会开启深度检测,圆还是会只显示一半。将阈值设置为无穷大时:Number.POSITIVE_INFINITY。虽然无论相机距离远近,圆都可以正常显示,但是没有圆的深度检测,不同要素之间的遮挡无法得到有效判断,有的在建筑物后的点会在建筑物前显示,造成视觉误差与干扰。
+
+						disableDepthTestDistance: updatedPositions[0].height, //指定距离相机的距离,在这个距离上禁用深度测试。通过设置相机到圆要素的距离阈值来判断是否开启深度检测,这里设置为1000.0米正常,但是当相机距离超过阈值时,就会开启深度检测,圆还是会只显示一半。将阈值设置为无穷大时:Number.POSITIVE_INFINITY。虽然无论相机距离远近,圆都可以正常显示,但是没有圆的深度检测,不同要素之间的遮挡无法得到有效判断,有的在建筑物后的点会在建筑物前显示,造成视觉误差与干扰。
+					}
+				});
+
+				/* 判断是否需要绘制文字 */
+				if (options.label) {
+
+					let label = options.label || {};
+
+					label.text = Cesium.defaultValue(label.text, "");
+					label.font = Cesium.defaultValue(label.font, "24px Helvetica"); //字体样式
+
+					//字体颜色
+					if (label.fillColor instanceof Array) {
+						label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+					} else if (typeof(label.fillColor) === 'string') {
+						label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+					} else {
+						label.fillColor = new Cesium.Color.fromCssColorString("#FFFF00");
+					}
+
+					//字体边框颜色
+					if (label.outlineColor instanceof Array) {
+						label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+					} else if (typeof(label.outlineColor) === 'string') {
+						label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+					} else {
+						label.outlineColor = new Cesium.Color.fromCssColorString("#FFF");
+					}
+					//字体边框宽度
+					label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+					//是否显示背景颜色
+					label.showBackground = Cesium.defaultValue(label.showBackground, false);
+					//背景颜色
+					if (label.backgroundColor instanceof Array) {
+						label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+					} else if (typeof(label.backgroundColor) === 'string') {
+						label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+					} else {
+						label.backgroundColor = new Cesium.Color.fromCssColorString("#FFF");
+					}
+
+					label.pixelOffset = Cesium.defaultValue(label.pixelOffset, 0);
+					// label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+					// label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+					label.scale = Cesium.defaultValue(label.scale, 1);
+
+					entity.label = {
+						text: label.text,
+						font: label.font, //字体样式
+						fillColor: label.fillColor, //字体颜色
+						outlineColor: label.outlineColor, //字体边框颜色
+						outlineWidth: label.outlineWidth, //边框宽度	
+						style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+						showBackground: label.showBackground, //是否显示背景颜色
+						backgroundColor: label.backgroundColor, // 背景颜色
+						backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+
+						pixelOffset: new Cesium.Cartesian2(0, label.pixelOffset), //偏移量
+						scale: label.scale, //尺寸
+					}
+				}
+
+				_self._viewer.entities.add(entity);
+
+				resolve(entity)
+			});
+
+		});
+	},
+
+	/**
+	 * 根据GeoJson添加广告牌
+	 * @param {String} geoJsonUrl geoJson文件路径
+	 * @param {Object} options
+	 * @param {String} [options.id] 用于移除
+	 * @param {Object} [options.billboard] 广告牌的样式,具有以下属性:
+	 * @param {Number} [options.billboard.imgUrl] 广告牌图片
+	 * @param {Number} [options.billboard.imgWidth] 广告牌图片宽度
+	 * @param {Number} [options.billboard.imgHeight] 广告牌图片高度
+	 * @param {Number} [options.billboard.scale=1] 尺寸
+	 * @param {Object} [options.billboard.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.billboard.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.billboard.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.billboard.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.billboard.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 * 
+	 * @param {Object} [options.label] label的样式,具有以下属性:
+	 * @param {Number} [options.label.text=""] 文字
+	 * @param {Number} [options.label.textField=""] 文字字段
+	 * @param {String} [options.label.font="24px Helvetica"] 指定CSS字体的属性,字体大小及样式
+	 * @param {String} [options.label.fillColor=[255,255,255,1]] 字体颜色
+	 * @param {String} [options.label.outlineColor=[255,255,255,1]] 字体边框颜色
+	 * @param {Number} [options.label.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.label.showBackground=false] 是否显示背景颜色
+	 * @param {Number} [options.label.backgroundColor=[255,255,255,1]] 背景颜色		
+	 * @param {Number} [options.label.pixelOffset=0] 偏移量
+	 * @param {Number} [options.label.scale=1] 尺寸
+	 * @param {Object} [options.label.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.label.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.label.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.label.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.label.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	addBillboardByGeoJson: function(geoJsonUrl, options) {
+		return new Promise((resolve, reject) => {
+			let _self = this;
+			let viewer = this._viewer;
+
+			if (!Cesium.defined(geoJsonUrl)) {
+				throw new Cesium.DeveloperError("geoJsonUrl is required.");
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			let billboard = options.billboard || {};
+			billboard.imgUrl = Cesium.defaultValue(billboard.imgUrl, 'jt3dSDK/imgs/point/point3.png');
+
+			billboard.scale = Cesium.defaultValue(billboard.scale, 1);
+			billboard.pixelOffset = Cesium.defaultValue(billboard.pixelOffset, 0);
+			// label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+			// label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+
+			let label = options.label || {};
+			label.text = Cesium.defaultValue(label.text, "");
+			label.textField = Cesium.defaultValue(label.textField, "");
+			label.font = Cesium.defaultValue(label.font, "24px Helvetica");
+
+			if (label.fillColor instanceof Array) {
+				label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+			} else if (typeof(label.fillColor) === 'string') {
+				label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+			} else {
+				label.fillColor = new Cesium.Color.fromCssColorString("#ff0000");
+			}
+
+			if (label.outlineColor instanceof Array) {
+				label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+			} else if (typeof(label.outlineColor) === 'string') {
+				label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+			} else {
+				label.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+			}
+			label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+			//是否显示背景颜色
+			label.showBackground = Cesium.defaultValue(label.showBackground, false);
+			//背景颜色
+			if (label.backgroundColor instanceof Array) {
+				label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+			} else if (typeof(label.backgroundColor) === 'string') {
+				label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+			} else {
+				label.backgroundColor = new Cesium.Color.fromCssColorString("#FFFF00");
+			}
+
+			label.pixelOffset = Cesium.defaultValue(label.pixelOffset, 0);
+			// label.pixelOffset.x = Cesium.defaultValue(label.pixelOffset.x, 0);
+			// label.pixelOffset.y = Cesium.defaultValue(label.pixelOffset.y, 0);
+			label.scale = Cesium.defaultValue(label.scale, 1);
+
+			const dataSource = new Cesium.GeoJsonDataSource(options.id); // 创建并取名
+			dataSource.load(geoJsonUrl, {
+				clampToGround: true
+			}).then(function(data) {
+				viewer.dataSources.add(data); // 添加这个datasource
+				const entities = data.entities.values; // 拿到所有实体
+				entities.forEach(entity => {
+
+					entity.billboard = {
+						image: billboard.imgUrl,
+						horizontalOrigin: Cesium.HorizontalOrigin.CENTER, //水平
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM, //垂直位置
+						scale: billboard.scale, //尺寸
+						pixelOffset: new Cesium.Cartesian2(0, billboard.pixelOffset),
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+					};
+
+					let labelText = label.text;
+					if (entity.properties[label.textField]) {
+						labelText = entity.properties[label.textField]._value;
+					}
+					if (labelText === "") {
+						labelText = (i + 1).toString();
+					}
+
+					entity.label = {
+						text: labelText.toString(),
+						font: label.font,
+						fillColor: label.fillColor, //填充颜色
+						outlineColor: label.outlineColor, //边框颜色
+						outlineWidth: label.outlineWidth, //边框宽度	
+						style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+						showBackground: label.showBackground, //指定标签后面背景的可见性
+						backgroundColor: label.backgroundColor, // 背景颜色
+						backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+
+						pixelOffset: new Cesium.Cartesian2(0, label.pixelOffset), //偏移量
+						scale: label.scale, //尺寸
+					}
+
+					if (label.scaleByDistance) {
+						label.scaleByDistance.near = Cesium.defaultValue(label.scaleByDistance.near, 0);
+						label.scaleByDistance.nearValue = Cesium.defaultValue(label.scaleByDistance.nearValue, 0);
+						label.scaleByDistance.far = Cesium.defaultValue(label.scaleByDistance.far, 1);
+						label.scaleByDistance.farValue = Cesium.defaultValue(label.scaleByDistance.farValue, 0);
+
+						entity.label.scaleByDistance = new Cesium.NearFarScalar(label.scaleByDistance.near, label.scaleByDistance.nearValue, label.scaleByDistance.far, label.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+					}
+				})
+			})
+		});
+	},
+
+	/**
+	 * 加载GLTF/GLB模型数据
+	 * @param {Object} options 参数对象
+	 * @param {Array/Cesium.Cartesian3} options.points 模型加载位置 Array[lng,lat,height]经度,以度为单位,纬度,以度为单位,高程
+	 * @param {String} options.url 模型路径
+	 * @param {String} [options.id=guid] 模型实体加载ID,加入到整体图层中 以便可以删除对应的图层
+	 * @param {Number} [options.heading=0.0] 以弧度为单位的航向分量
+	 * @param {Number} [options.pitch=0.0] 以弧度为单位的螺距分量
+	 * @param {Number} [options.roll=0.0] 以弧度为单位的滚动分量
+	 * @param {Number} [options.minimumPixelSize] 模型最小刻度
+	 * @param {Number} [options.maximumScale] 模型的最大比例尺大小,设置模型最大放大大小
+	 * @param {Array<Number>} [options.silhouetteColor] 模型轮廓颜色[0~255,0~255,0~255,0~1]
+	 * @param {Number} [options.alpha] 模型透明度
+	 */
+	addGltf: function(options) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			if (!Cesium.defined(options.points)) {
+				resolve("options.points is required.");
+				throw new Cesium.DeveloperError("options.points is required.");
+			}
+			if (!Cesium.defined(options.url)) {
+				resolve("options.url is required.");
+				throw new Cesium.DeveloperError("options.url is required.");
+			}
+
+			// 初始化参数默认值
+			options.id = options.id || setSessionid();
+			options.heading = Cesium.defaultValue(options.heading, 0.0);
+			options.pitch = Cesium.defaultValue(options.pitch, 0.0);
+			options.roll = Cesium.defaultValue(options.roll, 0.0);
+			options.alpha = Cesium.defaultValue(options.alpha, 1);
+
+			//模型加载位置
+			let position = undefined;
+			if (options.points instanceof Cesium.Cartesian3) {
+				position = options.points;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(options.points[0], options.points[1], options.points[2] || 0);
+			}
+
+			//弧度的航向分量。
+			var heading = Cesium.Math.toRadians(options.heading);
+			//弧度的螺距分量。
+			var pitch = options.pitch;
+			//滚动分量(以弧度为单位)
+			var roll = options.roll;
+			//HeadingPitchRoll旋转表示为航向,俯仰和滚动。围绕Z轴。节距是绕负y轴的旋转。滚动是关于正x轴。
+			var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
+
+			var modelGltf = viewer.entities.add({
+				id: options.id, //模型id
+				position: position, // 模型位置
+				orientation: Cesium.Transforms.headingPitchRollQuaternion(position, hpr), // 模型方向
+				model: { // 模型资源
+					uri: options.url, // 模型路径
+					incrementallyLoadTextures: true, //加载模型后纹理是否能够继续流入
+					colorBlendMode: Cesium.ColorBlendMode['HIGHLIGHT'], //经常使用的有三个HIGHLIGHT,REPLACE,MIX
+					colorBlendAmount: 0.1, //这个属性必须是MIX混合属性才能生效,见colorBlendMode
+
+					color: Cesium.Color.WHITE.withAlpha(options.alpha), //模型颜色,这里可以设置颜色的变化,包含透明度的颜色
+
+					imageBasedLightingFactor: new Cesium.Cartesian2(12.0, 13.0),
+					runAnimations: true, //是否运行模型中的动画效果
+					show: true, // 模型是否可见
+
+					// 仅用于调试,显示魔仙绘制时的线框
+					debugWireframe: false,
+					// 仅用于调试。显示模型绘制时的边界球。
+					debugShowBoundingVolume: false,
+				},
+			});
+
+			// 模型最小刻度,不管缩放如何,模型的最小最小像素大小。
+			if (options.minimumPixelSize) {
+				modelGltf.model.minimumPixelSize = options.minimumPixelSize;
+			}
+			// 模型最大刻度,模型的最大比例尺大小。 minimumPixelSize的上限。
+			if (options.maximumScale) {
+				modelGltf.model.maximumScale = options.maximumScale;
+			}
+			// 模型轮廓颜色
+			if (options.silhouetteColor) {
+				if (options.silhouetteColor instanceof Array) {
+					options.silhouetteColor = new Cesium.Color(options.silhouetteColor[0] / 255, options.silhouetteColor[1] / 255, options.silhouetteColor[2] / 255, options.silhouetteColor[3]);
+				} else if (typeof(options.silhouetteColor) === 'string') {
+					options.silhouetteColor = new Cesium.Color.fromCssColorString(options.silhouetteColor);
+				} else {
+					options.silhouetteColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+
+			window[options.id] = modelGltf;
+
+			resolve(options.id);
+		});
+	},
+
+	/**
+	 * 加载GLTF/GLB模型数据
+	 * @param {Object} options 参数对象
+	 * @param {Array/Cesium.Cartesian3} options.points 模型加载位置 Array[lng,lat,height]经度,以度为单位,纬度,以度为单位,高程
+	 * @param {String} options.url 模型路径
+	 * @param {String} [options.id=guid] 模型实体加载ID,加入到整体图层中 以便可以删除对应的图层
+	 * @param {Number} [options.scale] 放大倍数
+	 */
+	addModelFromGltf(points, options) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			if (!Cesium.defined(options.points)) {
+				resolve("options.points is required.");
+				throw new Cesium.DeveloperError("options.points is required.");
+			}
+			if (!Cesium.defined(options.url)) {
+				resolve("options.url is required.");
+				throw new Cesium.DeveloperError("options.url is required.");
+			}
+
+			options.id = options.id || setSessionid();
+			options.scale = Cesium.defaultValue(options.scale, 1);
+
+			//gltf数据加载位置
+			let position = undefined;
+			if (options.points instanceof Cesium.Cartesian3) {
+				position = options.points;
+			} else {
+				position = Cesium.Cartesian3.fromDegrees(options.points[0], options.points[1], options.points[2] || 0);
+			}
+
+			// options.heading = Cesium.defaultValue(options.heading, 0.0);
+			// options.pitch = Cesium.defaultValue(options.pitch, 0.0);
+			// options.roll = Cesium.defaultValue(options.roll, 0.0);
+			// // 设置模型方向
+			// //弧度的航向分量。
+			// var heading = Cesium.Math.toRadians(options.heading);
+			// //弧度的螺距分量。
+			// var pitch = options.pitch;
+			// //滚动分量(以弧度为单位)
+			// var roll = options.roll;
+			// var hpRoll = new Cesium.HeadingPitchRoll(heading, pitch, roll);
+			// // 生成一个函数,该函数从以提供的原点为中心的参考帧到提供的椭圆体的固定参考帧计算4x4变换矩阵。
+			// var fixedFrame = Cesium.Transforms.localFrameToFixedFrameGenerator('north', 'west');
+
+			const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
+			let model = viewer.scene.primitives.add(
+				Cesium.Model.fromGltf({
+					show: true, //确定是否将显示模型基元
+					url: options.url, // 资源路径
+					modelMatrix: modelMatrix, // 模型矩阵
+					lightColor: new Cesium.Cartesian3(10.0, 10.0, 10.0),
+					// scale: options.scale, // 放大倍数
+
+					// 仅用于调试,显示魔仙绘制时的线框
+					debugWireframe: false,
+					// 仅用于调试。显示模型绘制时的边界球。
+					debugShowBoundingVolume: false,
+				})
+			)
+
+			/** 模型旋转角度 */
+			model.readyPromise.then(function() {
+				//延z轴旋转-90度,其它轴同理
+				var rotationX = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(0)));
+				Cesium.Matrix4.multiply(model.modelMatrix, rotationX, model.modelMatrix);
+			})
+
+			window[options.id] = model;
+
+			resolve(options.id)
+		});
+	},
+});
+
+export default PointObject;

+ 187 - 0
packages/Widgets/PolygonObject.js

@@ -0,0 +1,187 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	setSessionid
+} from "./common/common.js";
+
+/**
+ * 面对象
+ */
+class PolygonObject {
+	/**
+	 * 默认初始化
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+		this._drawEntities = []; //存储entities
+		this._polygonEntity = null;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(PolygonObject.prototype, /** @lends PolygonObject.prototype */ {
+
+	/**
+	 * @description 根据GeoJson绘制面
+	 * @param {Object} geoJsonUrl geoJson文件路径
+	 * @param {Object} [options] 面的样式,具有以下属性:
+	 * @param {Number} [options.id] 用于移除
+	 * @param {Number} [options.clampToGround=true] 是否贴地
+	 * @param {Number} [options.pixelSize=10] 指定点的大小,以像素为单位
+	 * @param {String} [options.color="#FF0000"] 指定点、线、面的颜色
+	 * @param {String} [options.outlineColor="#FFFF00"] 指定点轮廓的颜色
+	 * @param {Number} [options.outlineWidth=0] 指定点轮廓的宽度
+	 */
+	drawPolygonByGeoJson(geoJsonUrl, options) {
+
+		return new Promise((resolve, reject) => {
+			let _self = this;
+			if (!Cesium.defined(geoJsonUrl)) {
+				throw new Cesium.DeveloperError("geoJsonUrl is required.");
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+			options.clampToGround = Cesium.defaultValue(options.clampToGround, true);
+			options.color = Cesium.defaultValue(options.color, "#FF0000");
+			options.outlineColor = Cesium.defaultValue(options.outlineColor, "#FFFF00");
+			options.outlineWidth = Cesium.defaultValue(options.outlineWidth, 1);
+			options.extrudedHeight = Cesium.defaultValue(options.extrudedHeight, 0);
+
+			let promise = Cesium.GeoJsonDataSource.load(geoJsonUrl, {
+				clampToGround: true,
+				stroke: Cesium.Color.WHITE, // 边框颜色
+				strokeWidth: 3, // 边框宽度
+				fill: Cesium.Color.RED.withAlpha(0.5), // 填充颜色
+			});
+			promise.then((dataSource) => {
+				_self._viewer.dataSources.add(dataSource); // 加载整个geojson资源 
+				dataSource.name = options.id
+				let entities = dataSource.entities.values;
+				for (let index = 0; index < entities.length; index++) {
+					let entity = entities[index];
+
+					entity.polygon.material = new Cesium.Color.fromCssColorString(color).withAlpha(0.1);
+					entity.polygon.extrudedHeight = options.extrudedHeight; //拉伸高度,单位是米
+
+					entity.polygon.fill = false;
+					entity.polygon.outline = false;
+					entity.polygon.outlineWidth = options.outlineWidth;
+					entity.polygon.outlineColor = options.outlineColor;
+					entity.polyline = {
+						positions: entity.polygon.hierarchy._value.positions,
+						width: entity.polygon.outlineWidth,
+						material: new Cesium.Color.fromCssColorString(color).withAlpha(0.1),
+						// material: new Cesium.PolylineDashMaterialProperty({
+						// 	color: new Cesium.Color.fromCssColorString(color).withAlpha(0.1),
+						// }),//虚线
+					}
+					
+					if (options.clampToGround) {
+						entity.polyline.clampToGround = true;
+					}
+				}
+
+				resolve(entities);
+
+			});
+		});
+	},
+
+	/**
+	 * 根据坐标点生成面
+	 * @param {Object} [points] 坐标
+	 * @param {Object} [options] 面的样式,具有以下属性:
+	 * @param {Array} [options.color=[255,255,255,0]] 面颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 */
+	generatePolygonByPoints(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+			let _self = this;
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 3) {
+				reject("面对象,点数至少3个");
+			}
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			options.fill = options.fill || true;
+			//面颜色
+			if (options.color) {
+				options.color = new Cesium.Color(options.color[0]/255, options.color[1]/255, options.color[2]/255, options.color[3]);
+			} else {
+				options.color = new Cesium.Color.fromCssColorString("#ff0000");
+			}
+
+			options.outline = options.outline || false;
+			//轮廓颜色
+			if (options.outlineColor) {
+				options.outlineColor = new Cesium.Color(options.outlineColor[0]/255, options.outlineColor[1]/255, options.outlineColor[2]/255, options.outlineColor[3]);
+			} else {
+				options.outlineColor = new Cesium.Color.fromCssColorString("#000");
+			}
+			//轮廓宽度
+			options.outlineWidth = Cesium.defaultValue(options.outlineWidth, 1);
+
+			// let entity = _self._viewer.entities.add({
+			// 	id: options.id,
+			// 	name: "Generate surfaces based on coordinate points",
+			// 	polygon: {
+			// 		hierarchy: positions,
+			// 		material: options.color,
+
+
+			// 		fill:false,
+			// 		outline: true,
+			// 		outlineWidth:5,
+			// 		outlineColor:new Cesium.Color.fromCssColorString("#ddd").withAlpha(0.1)
+			// 	}
+			// });
+
+			let entity = new Cesium.Entity({
+				id: options.id,
+				name: "Generate surfaces based on coordinate points",
+				polygon: {
+					hierarchy: positions,
+					material: options.color,
+					fill: options.fill,
+					outline: options.outline,
+					outlineWidth: options.outlineWidth,
+					outlineColor: options.outlineColor
+				}
+			});
+
+			if (options.outline) {
+				entity.polyline = {
+					positions: entity.polygon.hierarchy._value.positions,
+					width: options.outlineWidth,
+					material: options.outlineColor,
+					// material: new Cesium.PolylineDashMaterialProperty({
+					// 	color: options.outlineColor,
+					// }),//虚线
+					clampToGround: true
+				}
+			}
+
+			_self._viewer.entities.add(entity);
+
+			resolve(entity);
+		})
+	},
+});
+
+export default PolygonObject;

+ 509 - 0
packages/Widgets/PolylineObject.js

@@ -0,0 +1,509 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	setSessionid
+} from "./common/common.js";
+
+/**
+ *流动纹理线
+ */
+import PolylineDirectionMaterialProperty from "./PolylineObject/PolylineDirectionMaterialProperty.js";
+
+/**
+ * 线对象
+ */
+class PolylineObject {
+	/**
+	 * 默认初始化
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(PolylineObject.prototype, /** @lends PolylineObject.prototype */ {
+
+	/**
+	 * @description 根据GeoJson绘制线
+	 * @param {String} geoJsonUrl geoJson文件路径
+	 * @param {Object} [options] 线的样式,具有以下属性:
+	 * @param {Number} [options.id] 用于移除
+	 * @param {Number} [options.clampToGround=true] 是否贴地
+	 * @param {Number} [options.isImageAlpha=true] 是否采用图片颜色
+	 * @param {Number} [options.imgUrl] 精灵线图片
+	 * @param {String} [options.color="#FF0000"] 指定线的颜色
+	 * @param {Number} [options.width=3] 指定线的宽度,以像素为单位
+	 * @param {Number} [options.minHeigh=0] 
+	 * @param {Number} [options.maxHeigh=200000000] 
+	 * @param {Number} [options.duration=3000] 持续时间 毫秒,越小越快
+	 * @param {Number} [options.count] 重复次数
+	 * @param {String} [options.direction='horizontal'] 方向 vertical纵,垂直方向,horizontal横,水平方向
+	 * @param {String} [options.order] 方向正负 
+	 *                                        vertical 纵:'-'(由下到上) , '+"(由上到下)
+	 *                                        horizontal 横:'-'(顺时针) , '+'(逆时针)
+	 */
+	drawPolylineByGeoJson: function(geoJsonUrl, options) {
+		return new Promise((resolve, reject) => {
+			let _self = this;
+			let viewer = this._viewer;
+
+			if (!Cesium.defined(geoJsonUrl)) {
+				throw new Cesium.DeveloperError("geoJsonUrl is required.");
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+			options.clampToGround = Cesium.defaultValue(options.clampToGround, true);
+			options.width = Cesium.defaultValue(options.width, 3);
+			options.minHeigh = Cesium.defaultValue(options.minHeigh, 0);
+			options.maxHeigh = Cesium.defaultValue(options.maxHeigh, 200000000);
+
+			let promise = Cesium.GeoJsonDataSource.load(geoJsonUrl, {
+				clampToGround: options.clampToGround
+			});
+			promise.then((dataSource) => {
+				viewer.dataSources.add(dataSource); // 加载这个geojson资源
+				dataSource.name = options.id
+				let entities = dataSource.entities.values;
+				let distanceDisplayCondition = new Cesium.DistanceDisplayCondition(options.minHeigh, options.maxHeigh);
+				let material = new PolylineDirectionMaterialProperty(options);
+				for (var i = 0; i < entities.length; i++) {
+					var entity = entities[i];
+					entity.polyline.distanceDisplayCondition = distanceDisplayCondition;
+					entity.polyline.material = material;
+					entity.polyline.width = options.width;
+
+					if (options.clampToGround) {
+						entity.polyline.clampToGround = true;
+					}
+				}
+
+				resolve(entities);
+			});
+		});
+	},
+
+	/**
+	 * 脉冲线
+	 * @param {Object} points 坐标位置[[lng,lat],[lng,lat],,,,,]经度,以度为单位,纬度,以度为单位
+	 * @param {Object} options
+	 * @param {Number} [options.id] 指定实体对象的id
+	 * @param {Number} [options.width=5] 指定线的宽度,以像素为单位	
+	 */
+	PolylineLinkPulseMaterialProperty: function(points, options) {
+
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+
+			options.id = options.id || setSessionid();
+			options.width = options.width || 5;
+
+			let material = new PolylineDirectionMaterialProperty(options);
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: "Pulse line",
+				polyline: {
+					positions: positions,
+					width: options.width,
+					material: material,
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+				}
+			});
+
+			resolve(entity);
+		});
+	},
+
+	/**
+	 * 箭头线
+	 * @param {Object} points 坐标位置[[lng,lat],[lng,lat],,,,,]经度,以度为单位,纬度,以度为单位
+	 * @param {Object} options
+	 * @param {Number} [options.id] 指定实体对象的id
+	 * @param {Number} [options.width=5] 指定线的宽度,以像素为单位	
+	 */
+	PolylineArrowMaterialProperty: function(points, options) {
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+
+			options.id = options.id || setSessionid();
+			options.width = options.width || 5;
+
+			let material = new PolylineDirectionMaterialProperty(options);
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: "Pulse line",
+				polyline: {
+					positions: positions,
+					width: options.width,
+					material: material,
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+				}
+			});
+
+			resolve(entity);
+		});
+	},
+
+	/**
+	 * 绘制发光的线
+	 * @param {Object} points 坐标位置[[lng,lat],[lng,lat],,,,,]经度,以度为单位,纬度,以度为单位
+	 * @param {Object} options
+	 * @param {Array} [options.color=[255,255,255,0]] 指定线条颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {Number} [options.taperPower=1] 指定变细效果的强度,以总线长的百分比表示。如果1.0或更高,则不使用锥度效应
+	 * @param {Number} [options.width=5] 指定线的宽度,以像素为单位
+	 * @param {Number} [options.glowPower=0.25] 指定辉光的强度,作为总线宽的百分比。	 
+	 */
+	drawGlowingLine(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			//指定线条颜色
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			options.width = options.width || 5; //指定线条宽度
+			options.glowPower = options.glowPower || 0.25; //一个数值属性,指定辉光的强度,作为总线宽的百分比。
+			options.taperPower = options.taperPower || 1; //一个数值属性,指定变细效果的强度,以总线长的百分比表示。如果1.0或更高,则不使用锥度效应。
+
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: 'Glowing blue line on the surface',
+				polyline: {
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+					positions: positions,
+					width: options.width,
+					followSurface: true,
+					material: new Cesium.PolylineGlowMaterialProperty({
+						color: options.color, //指定线条颜色
+						glowPower: options.glowPower,
+						taperPower: options.taperPower
+					}),
+				},
+			});
+
+			resolve(entity);
+
+		});
+	},
+
+	/**
+	 * 绘制指定颜色的线
+	 * @param {Object} points
+	 * @param {Object} options
+	 * @param {Array} [options.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {Number} [options.width=3] 指定线的宽度,以像素为单位
+	 */
+	drawSpecifyColorLine(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(points)) {
+				reject("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			//指定线条颜色
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//指定线条宽度
+			options.width = options.width || 5;
+
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: 'Red line on the surface',
+				polyline: {
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+					positions: positions,
+					width: options.width,
+					material: options.color,
+				},
+			});
+
+			resolve(entity);
+
+		});
+	},
+
+	/**
+	 * 绘制指定颜色指定边框颜色的线
+	 * @param {Object} points
+	 * @param {Object} options
+	 * @param {Array} [options.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {Number} [options.width=3] 指定线的宽度,以像素为单位
+	 * @param {String} [options.outlineColor=[255,255,255,0]] 指定点轮廓的颜色,,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明,
+	 * @param {Number} [options.outlineWidth=0] 指定点轮廓的宽度
+	 */
+	drawSpecifyColorAndOutlineColorLine(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			//指定线条颜色
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			//指定线条宽度
+			options.width = options.width || 5;
+
+			//指定线条轮廓颜色
+			if (options.outlineColor) {
+				if (options.outlineColor instanceof Array) {
+					options.outlineColor = new Cesium.Color(options.outlineColor[0] / 255, options.outlineColor[1] / 255, options.outlineColor[2] / 255, options.outlineColor[3]);
+				} else if (typeof(options.outlineColor) === 'string') {
+					options.outlineColor = new Cesium.Color.fromCssColorString(options.outlineColor);
+				} else {
+					options.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//指定线条轮廓宽度
+			options.outlineWidth = Cesium.defaultValue(options.outlineWidth, 1);
+
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: 'Orange line with black outline at height and following the surface',
+				polyline: {
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+					positions: positions,
+					width: options.width, // 线宽
+					material: new Cesium.PolylineOutlineMaterialProperty({
+						color: options.color, // 指定颜色
+						outlineWidth: options.outlineWidth, // 边框的宽度
+						outlineColor: options.outlineColor, // 指定边框颜色
+					}),
+				},
+			});
+
+			resolve(entity);
+
+		});
+	},
+
+	/**
+	 * 绘制指定颜色的箭头静态指示线
+	 * @param {Object} points
+	 * @param {Object} options
+	 * @param {Array} [options.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {Number} [options.width=3] 指定线的宽度,以像素为单位
+	 */
+	drawSpecifyColorArrowStaticStateLine(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			//指定线条颜色
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//指定线条宽度
+			options.width = options.width || 5;
+
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: 'Purple straight arrow at height',
+				polyline: {
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+					positions: positions,
+					width: options.width,
+					followSurface: false,
+					material: new Cesium.PolylineArrowMaterialProperty(options.color),
+				},
+			});
+
+			resolve(entity);
+
+		});
+	},
+
+	/**
+	 * 绘制虚线
+	 * @param {Object} points
+	 * @param {Object} options
+	 * @param {Number} [options.width=3] 指定线的宽度,以像素为单位
+	 * @param {Array} [options.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {Array} [options.gapColor=[255,255,255,0]] 指定行中空白颜色的属性,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {Number} [options.dashLength=16] 一个数值属性,以像素为单位指定破折号图案的长度。
+	 * @param {Number} [options.dashPattern=255] 为破折号指定16位模式的数值属性
+	 */
+	drawDashedLine(points, options) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(points)) {
+				throw new Cesium.DeveloperError("points is required.");
+			}
+
+			if (points.length < 2) {
+				reject("线对象,点数至少2个");
+			}
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+
+			//指定线条颜色
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			//指定线条宽度
+			options.width = options.width || 5;
+
+			//指定行中空白颜色的属性
+			if (options.gapColor) {
+				if (options.gapColor instanceof Array) {
+					options.gapColor = new Cesium.Color(options.gapColor[0] / 255, options.gapColor[1] / 255, options.gapColor[2] / 255, options.gapColor[3]);
+				} else if (typeof(options.gapColor) === 'string') {
+					options.gapColor = new Cesium.Color.fromCssColorString(options.gapColor);
+				} else {
+					options.gapColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+
+			options.dashLength = options.dashLength || 16;
+			options.dashPattern = options.dashPattern || 255;
+
+			let entity = this._viewer.entities.add({
+				id: options.id,
+				name: 'CYAN dashed line',
+				polyline: {
+					clampToGround: true, //开启贴地 如果有模型则贴模型
+					positions: positions,
+					width: options.width,
+					material: new Cesium.PolylineDashMaterialProperty({
+						color: options.color,
+						gapColor: options.gapColor, //指定行中空白颜色的属性。
+						dashLength: options.dashLength, //一个数值属性,以像素为单位指定破折号图案的长度。
+						dashPattern: options.dashPattern, //为破折号指定16位模式的数值属性
+					}),
+				},
+			});
+
+			resolve(entity);
+
+		});
+	},
+});
+
+// PolylineObject.prototype.PolylineDirectionMaterialProperty = PolylineDirectionMaterialProperty;
+
+export default PolylineObject;

+ 181 - 0
packages/Widgets/PolylineObject/PolylineDirectionMaterialProperty.js

@@ -0,0 +1,181 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 流动纹理线
+ * @ignore 
+ */
+class PolylineDirectionMaterialProperty {
+
+	/**
+	 * 流动纹理线 初始化
+	 * @author joy/创睿
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.color 颜色
+	 * @param {Number} options.duration 持续时间 毫秒,越小越快
+	 * @param {String} options.imgUrl 材质图片
+	 * @param {Number} [options.count] 重复次数
+	 * @param {String} [options.direction] 方向 vertical纵,垂直方向,horizontal横,水平方向
+	 * @param {String} [options.order] 方向正负 
+	 *                                        纵:'-'(由下到上) , '+"(由上到下)
+	 *                                        横:'-'(顺时针) , '+'(逆时针)
+	 */
+	constructor(options) {
+
+		this.defaultColor = new Cesium.Color(255/255, 0, 0, 0);
+
+		options = options || {};
+		options.isImageAlpha = Cesium.defaultValue(options.isImageAlpha, true);
+		options.imgUrl = Cesium.defaultValue(options.imgUrl, 'jt3dSDK/imgs/polylinematerial/spriteline1.png');
+		options.duration = Cesium.defaultValue(options.duration, 3000);
+		options.count = Cesium.defaultValue(options.count, 1);
+		options.direction = Cesium.defaultValue(options.direction, "horizontal");
+		options.order = Cesium.defaultValue(options.order, "-");
+
+		if (options.isImageAlpha) {
+			options.color = this.defaultColor;
+		} else {
+			if (options.color instanceof Array) {
+				options.color = new Cesium.Color(options.color[0]/255, options.color[1]/255, options.color[2]/255, options.color[3]);
+			} else if (typeof options.color === 'string') {
+				options.color = new Cesium.Color.fromCssColorString(options.color);
+			} else {
+				options.color = this.defaultColor;
+			}
+		}
+
+		/* 变更事件 */
+		this._definitionChanged = new Cesium.Event();
+
+		this._color = undefined;
+		this._image = undefined;
+		this.color = options.color; //颜色
+		this.image = options.imgUrl; //材质图片
+
+		this._isImageAlpha = options.isImageAlpha;
+		this._duration = options.duration; //动态循环周期
+		this._count = options.count; //重复次数
+		this._direction = options.direction; //方向
+		this._order = options.order; //方向正负
+		this._time = performance.now();
+
+		this.addMaterial()
+	}
+
+	addMaterial() {
+		Cesium.Material.PolylineTrailType = 'PolylineTrail';
+		Cesium.Material.Polylineimage = "images/colors.png";
+
+		if (this._direction === "vertical") { //垂直方向
+
+			if (this._isImageAlpha) {
+				Cesium.Material.PolylineTrailSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\
+					            {\n\
+					                czm_material material = czm_getDefaultMaterial(materialInput);\n\
+					                vec2 st = repeat * materialInput.st;\n\
+								    vec4 colorImage = texture2D(image, vec2(fract(st.t " + this._order + " time), st.s));\n\
+								    material.alpha = colorImage.a;\n\
+								    material.diffuse = colorImage.rgb* 1.5 ;\n\
+					                return material;\n\
+					            }";
+			} else {
+				Cesium.Material.PolylineTrailSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\
+					            {\n\
+					                czm_material material = czm_getDefaultMaterial(materialInput);\n\
+					                vec2 st = repeat * materialInput.st;\n\
+								    vec4 colorImage = texture2D(image, vec2(fract(st.t " + this._order + " time), st.s));\n\
+								    material.alpha = colorImage.a * color.a;\n\
+								    material.diffuse = max(color.rgb * material.alpha * 3.0, color.rgb);\n\
+					                return material;\n\
+					            }";
+			}
+
+		} else if (this._direction === "horizontal") { //水平方向
+			if (this._isImageAlpha) {
+				Cesium.Material.PolylineTrailSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\
+				            {\n\
+				                czm_material material = czm_getDefaultMaterial(materialInput);\n\
+				                vec2 st = repeat * materialInput.st;\n\
+							    vec4 colorImage = texture2D(image, vec2(fract(st.s " + this._order + " time), st.t));\n\
+							    material.alpha = colorImage.a;\n\
+							    material.diffuse = colorImage.rgb * 1.5 ;\n\
+				                return material;\n\
+				            }";
+			} else {
+				Cesium.Material.PolylineTrailSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\
+				            {\n\
+				                czm_material material = czm_getDefaultMaterial(materialInput);\n\
+				                vec2 st = repeat * materialInput.st;\n\
+							    vec4 colorImage = texture2D(image, vec2(fract(st.s " + this._order + " time), st.t));\n\
+							    material.alpha = colorImage.a * color.a;\n\
+							    material.diffuse = max(color.rgb * material.alpha * 3.0, color.rgb);\n\
+				                return material;\n\
+				            }";
+			}
+		}
+
+		/* 将材质加入缓存 以便重复利用 */
+		Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailType, {
+			fabric: {
+				type: Cesium.Material.PolylineTrailType,
+				uniforms: {
+					color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
+					image: Cesium.Material.Polylineimage,
+					time: 0,
+					repeat: new Cesium.Cartesian2(5.0, 1.0), // 横纵方向重复的次数
+					order: '-',
+				},
+				source: Cesium.Material.PolylineTrailSource
+			},
+
+			translucent: function(material) {
+				/* 材质是否半透明 */
+				return true;
+			}
+		});
+	}
+}
+
+// 材质类型
+PolylineDirectionMaterialProperty.prototype.getType = function(time) {
+	return 'PolylineTrail';
+}
+
+// 这个方法在每次渲染时被调用,result的参数会传入glsl中。
+PolylineDirectionMaterialProperty.prototype.getValue = function(time, result) {
+
+	if (!Cesium.defined(result)) {
+		result = {};
+	}
+
+	result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, this.defaultColor, result.color);
+	result.image = Cesium.Property.getValueOrUndefined(this._image, time); 
+	result.time = ((performance.now() - this._time) % this._duration) / this._duration;
+	result.repeat = new Cesium.Cartesian2(this._count, 1.0);
+	result.order = this._order;
+
+	return result;
+}
+
+PolylineDirectionMaterialProperty.prototype.equals = function(other) {
+	return this === other ||
+		(other instanceof PolylineDirectionMaterialProperty &&
+			Cesium.Property.equals(this._color, other._color))
+}
+
+Object.defineProperties(PolylineDirectionMaterialProperty.prototype, {
+	isConstant: {
+		get: function() {
+			return false;
+		}
+	},
+	definitionChanged: {
+		get: function() {
+			return this._definitionChanged;
+		}
+	},
+	color: Cesium.createPropertyDescriptor('color'),
+	image: Cesium.createPropertyDescriptor('image')
+});
+
+export default PolylineDirectionMaterialProperty;

+ 25 - 0
packages/Widgets/PopupWindow.js

@@ -0,0 +1,25 @@
+//多字段适配窗口
+import MultiFieldAdaptWindow from "./PopupWindow/MultiFieldAdaptWindow.js";
+//视频弹窗
+import VideoWindow from "./PopupWindow/VideoWindow.js";
+import VideoWindow2 from "./PopupWindow/VideoWindow2.js";
+import VideoWindow3 from "./PopupWindow/VideoWindow3.js";
+//弹框内容,可放任何html
+import HtmlWindow from "./PopupWindow/HtmlWindow.js";
+import HtmlWindow2 from "./PopupWindow/HtmlWindow2.js";
+import HtmlWindow3 from "./PopupWindow/HtmlWindow3.js";
+
+/**
+ * 自定义窗口
+ * @ignore
+ */
+let PopupWindow = {
+	MultiFieldAdaptWindow: MultiFieldAdaptWindow,
+	VideoWindow: VideoWindow,
+	VideoWindow2: VideoWindow2,
+	VideoWindow3: VideoWindow3,
+	HtmlWindow:HtmlWindow,
+	HtmlWindow2:HtmlWindow2,
+	HtmlWindow3:HtmlWindow3,
+}
+export default PopupWindow;

+ 156 - 0
packages/Widgets/PopupWindow/HtmlWindow.js

@@ -0,0 +1,156 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/HtmlWindow1.css';
+
+/**
+ * 弹框内容,可放任何html
+ */
+class HtmlWindow {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {String} title 窗口标题
+	 * @param {Object} html 弹框内容,可放任何html
+	 * @param {Number}offsetHeight 底部偏移高度,弹窗底部偏移高度需要设置一个合适的值,否则很容易导致场景拖动的时候,弹窗存在偏移
+	 */
+	constructor(viewer, position, title, html, offsetHeight) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');
+
+		let _self = this;
+		this.viewer = viewer; //弹窗创建的viewer
+		this.offsetHeight = offsetHeight;
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+
+		//如果有div就移除
+		if (document.getElementsByClassName("popup1").length > 0) {
+			document.getElementsByClassName("popup1")[0].remove();
+
+			viewer.entities.remove(viewer.entities.getById("popupPoint"));
+		}
+
+		this.id = "popup_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("popup1");
+		this.popupDiv.id = this.id;
+
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(title, html);
+
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+		this.initPoint();
+
+		//绑定关闭事件
+		document.getElementsByClassName("popup1-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		let elWidth = this.popupDiv.offsetWidth;
+		let elHeight = this.popupDiv.offsetHeight;
+		//elHeight 值需要设置一个合适的,否则很容易导致场景拖动的时候,弹窗存在偏移
+		if (!!this.offsetHeight) {
+			elHeight += this.offsetHeight;
+		}
+
+		this.popupDiv.style.left = windowPosition.x - elWidth / 2 + "px";
+		this.popupDiv.style.top = windowPosition.y - elHeight + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 创建Html
+	 * @ignore 
+	 * @param {Object} header
+	 * @param {Object} content
+	 */
+	_createHtml(header, content) {
+		let html = `
+			<div class="popup-header">
+					${header }
+				<span class="popup1-close-button">×</span>
+			</div>
+			<div class="popup-content">
+					${content}
+			</div>
+			<div class="popup-tip">
+			</div>
+		`
+		return html;
+	}
+
+	/**
+	 * 用于调试弹窗是否对得上位置,弹窗对上了该点,不然很容易出现弹窗偏移的问题
+	 *  @ignore 
+	 */
+	initPoint() {
+		this.billboard = this.viewer.entities.add({
+			id: "popupPoint",
+			name: "popupPoint",
+			position: this.position, // 点的经纬度坐标
+			billboard: {
+				image: 'jt3dSDK/imgs/point/point.png',
+				horizontalOrigin: Cesium.HorizontalOrigin.center,
+				verticalOrigin: Cesium.VerticalOrigin.bottom,
+				scale: 1,
+				pixelOffset: new Cesium.Cartesian2(0, 0),
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+			},
+		});
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(HtmlWindow.prototype, /** @lends HtmlWindow.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+		this.viewer.entities.remove(this.billboard);
+	}
+});
+
+export default HtmlWindow;

+ 123 - 0
packages/Widgets/PopupWindow/HtmlWindow2.js

@@ -0,0 +1,123 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/HtmlWindow2.css';
+
+/**
+ * 弹框内容,可放任何html
+ */
+class HtmlWindow2 {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {String} title 窗口标题
+	 * @param {String} html 弹框内容,可放任何html
+	 */
+	constructor(viewer, position, title, html) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');	
+
+		this.viewer = viewer; //弹窗创建的viewer
+		this.position = position; //弹窗挂载的位置
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+		
+		//如果有div就移除
+		if (document.getElementsByClassName("popup2").length > 0) {
+			document.getElementsByClassName("popup2")[0].remove();
+		}
+
+		this.id = "popup_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("popup2");
+		this.popupDiv.id = this.id;
+
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(title, html);
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+
+		//绑定关闭事件
+		document.getElementsByClassName("popup2-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		this.popupDiv.style.left = windowPosition.x - this.popupDiv.offsetWidth - 120 + "px";
+		this.popupDiv.style.top = windowPosition.y + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 创建Html
+	 * @ignore 
+	 * @param {Object} title
+	 * @param {Object} content
+	 */
+	_createHtml(title, content) {
+		let html = `
+		<div class="rightLine-1"></div>
+		<div class="rightLine-2"></div>
+		<div class="rightLine-3"></div>
+		<div class="popup-header">
+			<span class="popup-title" >${title}</span>
+			<span class="popup2-close-button" title="关闭" >×</span>
+		</div>
+		<div class="popup-content">
+				${content}
+		</div>
+		`
+		return html;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(HtmlWindow2.prototype, /** @lends HtmlWindow2.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+	}
+});
+
+export default HtmlWindow2;

+ 124 - 0
packages/Widgets/PopupWindow/HtmlWindow3.js

@@ -0,0 +1,124 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/HtmlWindow3.css';
+
+/**
+ * 弹框内容,可放任何html
+ */
+class HtmlWindow3 {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {String} title 窗口标题
+	 * @param {String} html 弹框内容,可放任何html
+	 */
+	constructor(viewer, position, title, html) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');
+
+		this.viewer = viewer; //弹窗创建的viewer
+		this.position = position; //弹窗挂载的位置
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+		
+		//如果有div就移除
+		if (document.getElementsByClassName("popup3").length > 0) {
+			document.getElementsByClassName("popup3")[0].remove();
+		}
+
+		this.id = "popup_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("popup3");
+		this.popupDiv.id = this.id;
+
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(title, html);
+
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+
+		//绑定关闭事件
+		document.getElementsByClassName("popup3-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		this.popupDiv.style.left = windowPosition.x + 70 + "px";
+		this.popupDiv.style.top = windowPosition.y - this.popupDiv.offsetHeight - 20 + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 创建Html
+	 * @ignore 
+	 * @param {Object} title
+	 * @param {Object} content
+	 */
+	_createHtml(title, content) {
+		let html = `
+		<div class="leftLine-1"></div>
+		<div class="leftLine-2"></div>
+		<div class="popup-header">
+			<span class="popup-title" >${title}</span>
+			<span class="popup3-close-button" title="关闭" >×</span>
+		</div>
+		<div class="popup-content">
+				${content}
+		</div>
+		`
+		return html;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(HtmlWindow3.prototype, /** @lends HtmlWindow3.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+	}
+});
+
+export default HtmlWindow3;

+ 177 - 0
packages/Widgets/PopupWindow/MultiFieldAdaptWindow.js

@@ -0,0 +1,177 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/MultiFieldAdaptWindow.css';
+
+/**
+ * 多字段适配窗口
+ */
+class MultiFieldAdaptWindow {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {String} title 窗口标题
+	 * @param {Object} properties 属性
+	 *       {
+	 *           title: title,//标题
+	 *           name: name,//名称
+	 *           num: num, //编号
+	 *           status: true,//在线状态
+	 *       }
+	 */
+	constructor(viewer, position, title, properties, offsetHeight) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');
+
+		this.viewer = viewer; //弹窗创建的viewer
+		this.position = position; //弹窗挂载的位置
+		this.offsetHeight = offsetHeight;
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+		
+		//如果有div就移除
+		if (document.getElementsByClassName("MultiField-popup").length > 0) {
+			document.getElementsByClassName("MultiField-popup")[0].remove();
+			
+			viewer.entities.remove(viewer.entities.getById("MultiFieldPopupPoint"));
+		}
+
+		this.id = "popup_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("MultiField-popup");
+		this.popupDiv.id = this.id;
+
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(title, properties);
+
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+		this.initPoint();
+
+		//绑定关闭事件
+		document.getElementsByClassName("leaflet-popup-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		let elWidth = this.popupDiv.offsetWidth;
+		let elHeight = this.popupDiv.offsetHeight;
+		//elHeight 值需要设置一个合适的,否则很容易导致场景拖动的时候,弹窗存在偏移
+		if (!!this.offsetHeight) {
+			elHeight += this.offsetHeight;
+		}
+
+		this.popupDiv.style.left = windowPosition.x - elWidth / 2 + "px";
+		this.popupDiv.style.top = windowPosition.y - elHeight + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 生成Html
+	 * @ignore 
+	 * @param {Object} header
+	 * @param {Object} content
+	 */
+	_createHtml(header, content) {
+		let html = `
+			<div class="MultiField-popup-header">
+				` + header + `
+				<span class="leaflet-popup-close-button">×</span>
+			</div>
+			<div class="MultiField-popup-content">
+					` + this._createTable(content) + `
+			</div>
+			<div class="MultiField-popup-tip">
+			</div>
+		`
+		return html;
+	}
+
+	/**
+	 * 生成Table
+	 * @ignore 
+	 * @param {Object} content
+	 */
+	_createTable(content) {
+		let html = '<table class="table-popup">';
+		for (let key in content) {
+			html += `<tr><td class="title-popup">${key}</td>
+           <td class="value-popup">${content[key]}</td></tr>`;
+		}
+		html += "</table>";
+		return html;
+	}
+
+	/**
+	 * 用于调试弹窗是否对得上位置,弹窗对上了该点,不然很容易出现弹窗偏移的问题
+	 *  @ignore 
+	 */
+	initPoint() {
+		this.billboard = new Cesium.Entity({
+			id: "MultiFieldPopupPoint",
+			name: "popupPoint",
+			position: this.position, // 点的经纬度坐标
+			billboard: {
+				image: 'jt3dSDK/imgs/point/point.png',
+				horizontalOrigin: Cesium.HorizontalOrigin.center,
+				verticalOrigin: Cesium.VerticalOrigin.bottom,
+				scale: 1,
+				pixelOffset: new Cesium.Cartesian2(0, 0),
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+			},
+		});
+		this.viewer.entities.add(this.billboard);
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(MultiFieldAdaptWindow.prototype, /** @lends MultiFieldAdaptWindow.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+		this.viewer.entities.remove(this.billboard);
+	}
+});
+
+export default MultiFieldAdaptWindow;

+ 204 - 0
packages/Widgets/PopupWindow/VideoWindow.js

@@ -0,0 +1,204 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import Videojs from 'video.js'; //video.js7.0以后版本默认支持hls(m3u8)格式
+import "video.js/dist/video-js.css"; // 引入video.js的css
+// video 6.0及以上版本,需要引入videojs-flash库(5.0及以下版本,flash在其核心库中,高版本分离了flash)
+// rtmp流的视频格式为flv,只有flash能播放
+import "videojs-flash"; // 播放rtmp流需要的插件,flash插件。
+import "videojs-flvjs-es6"; //flv格式
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/VideoWindow.css';
+
+/**
+ * 视频窗口
+ */
+class VideoWindow {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {Object} videoInfo 属性
+	 * @param {String} videoInfo.type 监控类型 hls 、 rtmp 、flv、mp4
+	 * @param {String} videoInfo.name 监控名称
+	 * @param {String} videoInfo.url 监控路径
+	 */
+	constructor(viewer, position, videoInfo, offsetHeight) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');
+
+		this.viewer = viewer; //弹窗创建的viewer
+		this.position = position; //弹窗挂载的位置
+		this.offsetHeight = offsetHeight;
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+
+		//如果有div就移除
+		if (document.getElementsByClassName("popup-video").length > 0) {
+			document.getElementsByClassName("popup-video")[0].remove();
+
+			viewer.entities.remove(viewer.entities.getById("videoPopupPoint"));
+		}
+
+		this.id = "popup_video_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("popup-video");
+		this.popupDiv.id = this.id;
+
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(videoInfo);
+
+		switch (videoInfo.type) {
+			case "hls":
+				this.videotype = "application/x-mpegURL"; // 告诉videojs,这是一个hls流
+				break;
+			case "rtmp":
+				this.videotype = "rtmp/flv"; // 告诉videojs这是一个rtmp流视频
+				// 设置flash路径,用于在videojs发现浏览器不支持HTML5播放器的时候自动唤起flash播放器
+				// Videojs.options.flash.swf = 'https://cdn.bootcss.com/videojs-swf/5.4.1/video-js.swf';
+				break;
+			case "flv":
+				this.videotype = "video/x-flv"; // 告诉videojs这是一个flv
+				break;
+			case "mp4":
+				this.videotype = "video/mp4"; // 告诉videojs这是一个mp4,普通视频
+				break;
+		}
+
+		this.videoPlayer = Videojs(document.querySelector('#myvideo'), {
+			controls: true, //开启交互,即是用户可控。用户可以与之交互的控件
+			autoplay: 'muted', //自动播放
+			loop: true, //视频一结束就重新开始
+			muted: false, //开启视频时是否静音,默认情况下将使所有音频静音
+			fluid: true, //根据外层css样式大小,自动填充宽高!比较实用,可搭配响应式
+			aspectRatio: "16:9", //显示比率
+			reload: "auto", //重载
+			fullscreen: {
+				options: {
+					navigationUI: 'hide'
+				}
+			},
+			sources: [{ //注意,如果是以option方式设置的src,是不能实现 换台的 (即使监听了nowPlayVideoUrl也没实现)
+				src: videoInfo.url,
+				type: this.videotype,
+			}],
+		}, function onPlayerReady() {
+			console.log('onPlayerReady', this);
+		})
+
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+		this.initPoint();
+
+		//绑定关闭事件
+		document.getElementsByClassName("popup-video1-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		let elWidth = this.popupDiv.offsetWidth;
+		let elHeight = this.popupDiv.offsetHeight;
+		//elHeight 值需要设置一个合适的,否则很容易导致场景拖动的时候,弹窗存在偏移
+		if (!!this.offsetHeight) {
+			elHeight += this.offsetHeight;
+		}
+
+		this.popupDiv.style.left = windowPosition.x - elWidth / 2 + "px";
+		this.popupDiv.style.top = windowPosition.y - elHeight + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 生成Html
+	 * @ignore 
+	 * @param {Object} videoInfo
+	 */
+	_createHtml(videoInfo) {
+		let html = `
+			<div class="popup-video-header">
+				${videoInfo.name }
+				<span class="popup-video1-close-button">×</span>
+			</div>
+			<div class="popup-video-content">
+				<video id="myvideo" class="video-js vjs-big-play-centered vjs-fluid" controls preload="auto" width="100%" height="100%"></video>
+			</div>
+			<div class="popup-video-tip">
+			</div>
+		`
+		return html;
+	}
+
+	/**
+	 * 用于调试弹窗是否对得上位置,弹窗对上了该点,不然很容易出现弹窗偏移的问题
+	 *  @ignore 
+	 */
+	initPoint() {
+		this.billboard = new Cesium.Entity({
+			id: "videoPopupPoint",
+			name: "popupPoint",
+			position: this.position, // 点的经纬度坐标
+			billboard: {
+				image: 'jt3dSDK/imgs/point/point.png',
+				horizontalOrigin: Cesium.HorizontalOrigin.center,
+				verticalOrigin: Cesium.VerticalOrigin.bottom,
+				scale: 1,
+				pixelOffset: new Cesium.Cartesian2(0, 0),
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+			},
+		});
+		this.viewer.entities.add(this.billboard);
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(VideoWindow.prototype, /** @lends VideoWindow.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+		this.viewer.entities.remove(this.billboard);
+		Videojs("myvideo").dispose() //销毁video实例,避免出现节点不存在 但是flash一直在执行,报 this.el.......is not function
+		this.videoPlayer.dispose() //销毁video实例
+	}
+});
+
+export default VideoWindow;

+ 170 - 0
packages/Widgets/PopupWindow/VideoWindow2.js

@@ -0,0 +1,170 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import Videojs from 'video.js'; //video.js7.0以后版本默认支持hls(m3u8)格式
+import "video.js/dist/video-js.css"; // 引入video.js的css
+// video 6.0及以上版本,需要引入videojs-flash库(5.0及以下版本,flash在其核心库中,高版本分离了flash)
+// rtmp流的视频格式为flv,只有flash能播放
+import "videojs-flash"; // 播放rtmp流需要的插件,flash插件。
+import "videojs-flvjs-es6"; //flv格式
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/VideoWindow2.css';
+
+/**
+ * 视频窗口
+ */
+class VideoWindow2 {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {Object} videoInfo 属性
+	 * @param {String} videoInfo.type 监控类型 hls 、 rtmp 、flv、mp4
+	 * @param {String} videoInfo.name 监控名称
+	 * @param {String} videoInfo.url 监控路径
+	 */
+	constructor(viewer, position, videoInfo) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');	
+
+		this.viewer = viewer; //弹窗创建的viewer
+		this.position = position; //弹窗挂载的位置
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+		
+		//如果有div就移除
+		if (document.getElementsByClassName("popup-video2").length > 0) {
+			document.getElementsByClassName("popup-video2")[0].remove();
+		}
+
+		this.id = "popup_video_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("popup-video2");
+		this.popupDiv.id = this.id;
+
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(videoInfo);
+
+		switch (videoInfo.type) {
+			case "hls":
+				this.videotype = "application/x-mpegURL"; // 告诉videojs,这是一个hls流
+				break;
+			case "rtmp":
+				this.videotype = "rtmp/flv"; // 告诉videojs这是一个rtmp流视频
+				// 设置flash路径,用于在videojs发现浏览器不支持HTML5播放器的时候自动唤起flash播放器
+				// Videojs.options.flash.swf = 'https://cdn.bootcss.com/videojs-swf/5.4.1/video-js.swf';
+				break;
+			case "flv":
+				this.videotype = "video/x-flv"; // 告诉videojs这是一个flv
+				break;
+			case "mp4":
+				this.videotype = "video/mp4"; // 告诉videojs这是一个mp4,普通视频
+				break;
+		}
+
+		this.videoPlayer = Videojs(document.querySelector('#myvideo'), {
+			controls: true, //开启交互,即是用户可控。用户可以与之交互的控件
+			autoplay: 'muted', //自动播放
+			loop: true, //视频一结束就重新开始
+			muted: false, //开启视频时是否静音,默认情况下将使所有音频静音
+			fluid: true, //根据外层css样式大小,自动填充宽高!比较实用,可搭配响应式
+			aspectRatio: "16:9", //显示比率
+			reload: "auto", //重载
+			fullscreen: {
+				options: {
+					navigationUI: 'hide'
+				}
+			},
+			sources: [{ //注意,如果是以option方式设置的src,是不能实现 换台的 (即使监听了nowPlayVideoUrl也没实现)
+				src: videoInfo.url,
+				type: this.videotype,
+			}],
+		}, function onPlayerReady() {
+			console.log('onPlayerReady', this);
+		})
+
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+
+		//绑定关闭事件
+		document.getElementsByClassName("popup-video2-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		this.popupDiv.style.left = windowPosition.x - this.popupDiv.offsetWidth - 120 + "px";
+		this.popupDiv.style.top = windowPosition.y + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 生成Html
+	 * @ignore 
+	 * @param {Object} videoInfo
+	 */
+	_createHtml(videoInfo) {
+		let html = `
+		<div class="rightLine-1"></div>
+		<div class="rightLine-2"></div>
+		<div class="rightLine-3"></div>
+		<div class="popup-header">
+			<span class="popup-title" >${videoInfo.name }</span>
+			<span class="popup-video2-close-button" title="关闭" >×</span>
+		</div>
+		<div class="popup-content">
+			<video id="myvideo" class="video-js vjs-big-play-centered vjs-fluid" controls preload="auto" width="100%" height="100%"></video>
+		</div>
+		`
+		return html;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(VideoWindow2.prototype, /** @lends VideoWindow2.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+	}
+});
+
+export default VideoWindow2;

+ 170 - 0
packages/Widgets/PopupWindow/VideoWindow3.js

@@ -0,0 +1,170 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import Videojs from 'video.js'; //video.js7.0以后版本默认支持hls(m3u8)格式
+import "video.js/dist/video-js.css"; // 引入video.js的css
+// video 6.0及以上版本,需要引入videojs-flash库(5.0及以下版本,flash在其核心库中,高版本分离了flash)
+// rtmp流的视频格式为flv,只有flash能播放
+import "videojs-flash"; // 播放rtmp流需要的插件,flash插件。
+import "videojs-flvjs-es6"; //flv格式
+
+import {
+	getGuid,
+} from "../common/common.js";
+
+import '../../Assets/styles/PopupWindow/VideoWindow3.css';
+
+/**
+ * 弹框内容,可放任何html
+ */
+class VideoWindow3 {
+
+	/**
+	 * 初始化
+	 * @author joy/创睿
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Cesium.Cartesian3} position 坐标位置
+	 * @param {Object} videoInfo 属性
+	 * @param {String} videoInfo.type 监控类型 hls 、 rtmp 、flv、mp4
+	 * @param {String} videoInfo.name 监控名称
+	 * @param {String} videoInfo.url 监控路径
+	 */
+	constructor(viewer, position, videoInfo) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!position) throw new Cesium.DeveloperError('no position object!');	
+		
+		this.viewer = viewer; //弹窗创建的viewer
+		this.position = position; //弹窗挂载的位置
+		//弹窗挂载的位置
+		if (position instanceof Cesium.Cartesian3) {
+			this.position = position;
+		} else {
+			this.position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2] || 0);
+		}
+		
+		//如果有div就移除
+		if (document.getElementsByClassName("popup-video3").length > 0) {
+			document.getElementsByClassName("popup-video3")[0].remove();
+		}
+		
+		this.id = "popup_video_" + getGuid();
+		this.popupDiv = document.createElement("div");
+		this.popupDiv.classList.add("popup-video3");
+		this.popupDiv.id = this.id;
+		
+		// 将字符串模板生成的内容添加到DOM上
+		this.viewer.container.append(this.popupDiv);
+		// this.viewer.cesiumWidget.container.appendChild(this.popupDiv);
+		
+		//创建Html
+		this.popupDiv.innerHTML = this._createHtml(videoInfo);
+		
+		switch (videoInfo.type) {
+			case "hls":
+				this.videotype = "application/x-mpegURL"; // 告诉videojs,这是一个hls流
+				break;
+			case "rtmp":
+				this.videotype = "rtmp/flv"; // 告诉videojs这是一个rtmp流视频
+				// 设置flash路径,用于在videojs发现浏览器不支持HTML5播放器的时候自动唤起flash播放器
+				// Videojs.options.flash.swf = 'https://cdn.bootcss.com/videojs-swf/5.4.1/video-js.swf';
+				break;
+			case "flv":
+				this.videotype = "video/x-flv"; // 告诉videojs这是一个flv
+				break;
+			case "mp4":
+				this.videotype = "video/mp4"; // 告诉videojs这是一个mp4,普通视频
+				break;
+		}
+		
+		this.videoPlayer = Videojs(document.querySelector('#myvideo'), {
+			controls: true, //开启交互,即是用户可控。用户可以与之交互的控件
+			autoplay: 'muted', //自动播放
+			loop: true, //视频一结束就重新开始
+			muted: false, //开启视频时是否静音,默认情况下将使所有音频静音
+			fluid: true, //根据外层css样式大小,自动填充宽高!比较实用,可搭配响应式
+			aspectRatio: "16:9", //显示比率
+			reload: "auto", //重载
+			fullscreen: {
+				options: {
+					navigationUI: 'hide'
+				}
+			},
+			sources: [{ //注意,如果是以option方式设置的src,是不能实现 换台的 (即使监听了nowPlayVideoUrl也没实现)
+				src: videoInfo.url,
+				type: this.videotype,
+			}],
+		}, function onPlayerReady() {
+			console.log('onPlayerReady', this);
+		})
+		
+		//添加场景事件,实时更新窗口的位置
+		this.viewer.scene.postRender.addEventListener(this.postRender, this);
+		
+		//绑定关闭事件
+		document.getElementsByClassName("popup-video3-close-button")[0].onclick = () => {
+			this.close();
+		};
+	}
+
+
+	/**
+	 * 场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
+	 * @ignore
+	 */
+	postRender() {
+		const canvasHeight = this.viewer.scene.canvas.height;
+		const windowPosition = new Cesium.Cartesian2();
+		Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+			this.viewer.scene,
+			this.position,
+			windowPosition
+		);
+
+		this.popupDiv.style.left = windowPosition.x + 70 + "px";
+		this.popupDiv.style.top = windowPosition.y - this.popupDiv.offsetHeight - 20 + "px";
+
+		const camerPosition = this.viewer.camera.position;
+		let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
+		height += this.viewer.scene.globe.ellipsoid.maximumRadius;
+		if ((!(Cesium.Cartesian3.distance(camerPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
+			this.popupDiv.style.display = "block";
+		} else {
+			this.popupDiv.style.display = "none";
+		}
+	}
+
+	/**
+	 * 创建Html
+	 * @ignore 
+	 * @param {Object} videoInfo
+	 */
+	_createHtml(videoInfo) {
+		let html = `
+		<div class="leftLine-1"></div>
+		<div class="leftLine-2"></div>
+		<div class="popup-header">
+			<span class="popup-title" >${videoInfo.name}</span>
+			<span class="popup-video3-close-button" title="关闭" >×</span>
+		</div>
+		<div class="popup-content">
+				<video id="myvideo" class="video-js vjs-big-play-centered vjs-fluid" controls preload="auto" width="100%" height="100%"></video>
+		</div>
+		`
+		return html;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(VideoWindow3.prototype, /** @lends VideoWindow3.prototype */ {
+	/**
+	 * 关闭按钮
+	 */
+	close() {
+		this.popupDiv.remove();
+		this.viewer.scene.postRender.removeEventListener(this.postRender, this);
+	}
+});
+
+export default VideoWindow3;

+ 546 - 0
packages/Widgets/Roaming/Roaming.js

@@ -0,0 +1,546 @@
+/*
+ * @Description: 漫游
+ * @Version: 1.0
+ * @Author: joy
+ * @Date: 2023-04-12 21:42:26
+ * @LastEditors: joy
+ * @LastEditTime: 2023-04-13 16:32:25
+ */
+export default class Roaming {
+	/**
+	 * 创建一个漫游实例
+	 * @param {Object} viewer 三维场景viewer对象
+	 * @param {Array<Cesium.Cartesian3>/Array<[lng,lat,height]>} positions 坐标串,点集合
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} options.time 漫游时间
+	 * @param {Number} options.speed 速度
+	 * @param {Number} options.followedX 距离运动点的距离(后方) 
+	 * @param {Number} options.followedZ 距离运动点的高度(上方)
+	 * @param {Number} options.height 高度差
+	 * @param {Number} options.role 0自由模式 1跟随模式 2第一视角 3上帝视角
+	 * 第一人称摄像头放置在主角的前面
+	 * 第三人称摄像头放置在主角的背后
+	 * 
+	 * @param {Object} [options.model] model的样式,具有以下属性:
+	 * @param {Number} [options.model.url] 模型的url
+	 * 
+	 * @param {Object} [options.billboard] 广告牌的样式,具有以下属性:
+	 * @param {Number} [options.billboard.imgUrl] 广告牌图片
+	 * @param {Number} [options.billboard.scale=1] 尺寸
+	 * @param {Object} [options.billboard.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.billboard.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.billboard.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.billboard.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.billboard.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 * 
+	 * @param {Object} [options.point] point的样式,具有以下属性:
+	 * @param {Number} [options.point.pixelSize=10] 指定点的大小,以像素为单位
+	 * @param {Array} [options.point.color=[255,255,255,0]] 点位颜色,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明度]
+	 * @param {String} [options.point.outlineColor=[255,255,255,0]] 指定点轮廓的颜色,,颜色数组,[0~255,0~255,0~255,0~1],[red 红色,green 绿色,blue 蓝色,alpha 透明,
+	 * @param {Number} [options.point.outlineWidth=0] 指定点轮廓的宽度
+	 * 
+	 * @param {Object} [options.label] label的样式,具有以下属性:
+	 * @param {Number} [options.label.text=""] 文字
+	 * @param {String} [options.label.font="24px Helvetica"] 字体样式
+	 * @param {String} [options.label.fillColor=[255,255,255,0]] 字体颜色
+	 * @param {String} [options.label.outlineColor=[255,255,255,0]] 字体边框颜色
+	 * @param {Number} [options.label.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.label.showBackground=false] 是否显示背景颜色	
+	 * @param {Number} [options.label.backgroundColor=[255,255,255,0]] 背景颜色		
+	 * @param {Number} [options.label.pixelOffset=0] 偏移量
+	 * @param {Number} [options.label.scale=1] 尺寸
+	 * @param {Number} [options.label.near=1.5e2] 相机范围的下界。
+	 * @param {String} [options.label.nearValue=1] 相机范围下界的值。
+	 * @param {String} [options.label.far=2400] 相机范围的上限。
+	 * @param {Number} [options.label.farValue=0] 该值位于摄像机范围的上界。
+	 * @memberof Roaming
+	 */
+	constructor(viewer, positions, options) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		if (!positions) throw new Cesium.DeveloperError('no positions Array!');
+
+		this.viewer = viewer;
+		this.entity = undefined;
+
+		options = options || {};
+		options.time = Cesium.defaultValue(options.time, 360);
+		options.speed = Cesium.defaultValue(options.speed, 10);
+		options.isPathShow = Cesium.defaultValue(options.isPathShow, true);
+		options.height = Cesium.defaultValue(options.height, 5);
+		options.role = Cesium.defaultValue(options.role, 1);
+		options.followedX = Cesium.defaultValue(options.followedX, 50);
+		options.followedZ = Cesium.defaultValue(options.followedZ, 10);
+
+		this.time = options.time;
+		this.speed = options.speed;
+		this.isPathShow = options.isPathShow;
+		this.height = options.height;
+		this.role = options.role;
+		this.followedX = options.followedX;
+		this.followedZ = options.followedZ;
+
+		this.model = options.model;
+		this.billboard = options.billboard;
+		this.point = options.point;
+		this.label = options.label;
+
+		this.property = this.ComputeRoamingLineProperty(positions, this.time);
+	}
+
+	/**
+	 * @ignore
+	 * @param {*} Lines 点集合
+	 * @param {*} time 漫游时间
+	 * @returns
+	 * @memberof Roaming
+	 */
+	ComputeRoamingLineProperty(Lines, time) {
+		let _self = this;
+
+		let positions = [];
+		if (Lines[0] instanceof Cesium.Cartesian3) {
+			positions = Lines;
+		} else {
+			positions = Lines.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+		}
+
+		//总距离
+		let distance = [];
+		for (let i = 0; i < positions.length - 1; i++) {
+			let dis = Cesium.Cartesian3.distance(positions[i], positions[i + 1])
+			distance.push(dis)
+		}
+
+		//点与点之间间隔时间
+		let times = [Cesium.JulianDate.fromDate(new Date())]
+		times.push(Cesium.JulianDate.addSeconds(times[0], time, new Cesium.JulianDate()))
+		for (let i = 1; i < positions.length - 1; i++) {
+			let s = Cesium.JulianDate.addSeconds(times[i], time * (distance[i] / distance[0]), new Cesium.JulianDate())
+			times.push(s)
+		}
+
+		//一种属性,其值在给定时间内从提供的样本集和指定的插值算法和插值度中插值。
+		let oriSamples = new Cesium.SampledProperty(Cesium.Cartesian3);
+		oriSamples.addSamples(times, positions);
+
+		let startTime = times[0]; // 起始时间
+		let stopTime = times[times.length - 1]; // 结束时间
+		this.viewer.clock.startTime = startTime.clone(); // 设置始时钟始时间
+		this.viewer.clock.stopTime = stopTime.clone(); // 设置始终停止时间
+		this.viewer.clock.currentTime = startTime.clone(); // 设置时钟当前时间
+		this.viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //循环执行
+		this.viewer.clock.multiplier = this.speed; // 时间速率,数字越大时间过的越快
+
+		// 计算提供的实例之间的天数差。
+		let timeOfResolution = 6;
+		let samplesNum = Math.floor(
+			Cesium.JulianDate.secondsDifference(stopTime, startTime) / timeOfResolution
+		);
+
+		let sampledPositions = [];
+		let sampledTimes = [];
+		for (let i = 0; i < samplesNum + 1; i++) {
+			let sampleTime = Cesium.JulianDate.addSeconds(
+				startTime,
+				i * timeOfResolution,
+				new Cesium.JulianDate()
+			);
+			let tmpPos = oriSamples.getValue(sampleTime);
+			sampledPositions.push(Cesium.Cartographic.fromCartesian(tmpPos));
+			sampledTimes.push(sampleTime);
+		}
+
+		let promise = Cesium.sampleTerrainMostDetailed(
+			this.viewer.terrainProvider,
+			sampledPositions
+		).then(updatedPositions => {
+
+			let carPositionProperty = new Cesium.SampledPositionProperty();
+
+			//高度
+			for (let i = 0; i < sampledPositions.length; i++) {
+				sampledPositions[i].height = sampledPositions[i].height + this.height
+			}
+
+			for (let i = 0; i < samplesNum + 1; i++) {
+				carPositionProperty.addSample(
+					sampledTimes[i],
+					Cesium.Ellipsoid.WGS84.cartographicToCartesian(sampledPositions[i])
+				);
+			}
+
+			var position = carPositionProperty;
+			this.InitRoaming(position, startTime, stopTime, this.isPathShow)
+		});
+	}
+
+	/**
+	 * @ignore
+	 * @param {*} position computeRoamingLineProperty计算的属性
+	 * @param {*} start 开始时间节点
+	 * @param {*} stop 结束时间节点
+	 * @param {*} isPathShow path路径是否显示
+	 * @memberof Roaming
+	 */
+	InitRoaming(position, start, stop, isPathShow) {
+		let _self = this;
+		this.entity = this.viewer.entities.add({
+			// 和时间轴关联
+			availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
+				start: start,
+				stop: stop
+			})]),
+			// 位置
+			position: position,
+			//基于位置移动自动计算方向.
+			orientation: new Cesium.VelocityOrientationProperty(position),
+			//路径
+			path: {
+				resolution: 1,
+				//设置航线样式,线条颜色,内发光粗细,航线宽度等
+				material: new Cesium.PolylineGlowMaterialProperty({
+					glowPower: 0.1,
+					color: Cesium.Color.YELLOW
+				}),
+				width: 10,
+				show: isPathShow
+			}
+		})
+
+		if (this.model) {
+			let model = this.model;
+
+			// 加载模型,	模型数据,跨域,模型文件必须放本地
+			this.entity.model = {
+				// 模型路径
+				uri: model.url,
+				// 模型最小刻度
+				minimumPixelSize: 64,
+				maximumSize: 128,
+				// 设置模型最大放大大小
+				maximumScale: 200,
+				// 模型是否可见
+				show: true,
+				// 模型轮廓颜色
+				silhouetteColor: Cesium.Color.WHITE,
+				// 模型颜色  ,这里可以设置颜色的变化
+				// color: color,
+				// 仅用于调试,显示魔仙绘制时的线框
+				debugWireframe: false,
+				// 仅用于调试。显示模型绘制时的边界球。
+				debugShowBoundingVolume: false,
+
+				scale: 20,
+				runAnimations: true // 是否运行模型中的动画效果
+			};
+		} else if (this.billboard) {
+			let billboard = this.billboard;
+
+			billboard.imgUrl = Cesium.defaultValue(billboard.imgUrl, 'jt3dSDK/imgs/point/point3.png');
+
+			this.entity.billboard = {
+				image: billboard.imgUrl, // default: undefined
+				show: true, // default
+				width: 30, // default: undefined
+				scale: 1,
+				height: 30, // default: undefined
+				pixelOffset: new Cesium.Cartesian2(0, -14), // default: (0, 0)
+				// disableDepthTestDistance: 0,
+			}
+
+		} else {
+			let point = {};
+			if (this.point) {
+				point = this.point;
+			}
+
+			//点的大小
+			point.pixelSize = Cesium.defaultValue(point.pixelSize, 10);
+			//点位颜色
+			if (point.color) {
+				if (point.color instanceof Array) {
+					point.color = new Cesium.Color(point.color[0] / 255, point.color[1] / 255, point.color[2] / 255, point.color[3]);
+				} else if (typeof(point.color) === 'string') {
+					point.color = new Cesium.Color.fromCssColorString(point.color);
+				} else {
+					point.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//点位轮廓颜色
+			if (point.outlineColor) {
+				if (point.outlineColor instanceof Array) {
+					point.outlineColor = new Cesium.Color(point.outlineColor[0] / 255, point.outlineColor[1] / 255, point.outlineColor[2] / 255, point.outlineColor[3]);
+				} else if (typeof(point.outlineColor) === 'string') {
+					point.outlineColor = new Cesium.Color.fromCssColorString(point.outlineColor);
+				} else {
+					point.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//点位轮廓宽度
+			point.outlineWidth = Cesium.defaultValue(point.outlineWidth, 2);
+
+			this.entity.point = point
+		}
+
+		/* 判断是否需要绘制文字 */
+		if (this.label) {
+
+			let label = this.label;
+
+			label.text = Cesium.defaultValue(label.text, "");
+			label.font = Cesium.defaultValue(label.font, "24px Helvetica"); //字体样式
+
+			//字体颜色
+			if (label.fillColor) {
+				if (label.fillColor instanceof Array) {
+					label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+				} else if (typeof(label.fillColor) === 'string') {
+					label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+				} else {
+					label.fillColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//字体边框颜色
+			if (label.outlineColor) {
+				if (label.outlineColor instanceof Array) {
+					label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+				} else if (typeof(label.outlineColor) === 'string') {
+					label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+				} else {
+					label.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+			
+			//字体边框宽度
+			label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+			//是否显示背景颜色
+			label.showBackground = Cesium.defaultValue(label.showBackground, false);
+			//背景颜色
+			if (label.backgroundColor) {
+				if (label.backgroundColor instanceof Array) {
+					label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+				} else if (typeof(label.backgroundColor) === 'string') {
+					label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+				} else {
+					label.backgroundColor = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+
+			label.pixelOffset = Cesium.defaultValue(label.pixelOffset, 0);
+			label.scale = Cesium.defaultValue(label.scale, 1);
+
+			label.near = Cesium.defaultValue(label.near, 1.5e2);
+			label.nearValue = Cesium.defaultValue(label.nearValue, 1);
+			label.far = Cesium.defaultValue(label.far, 2400);
+			label.farValue = Cesium.defaultValue(label.farValue, 0);
+
+			this.entity.label = {
+				text: label.text,
+				font: label.font, //字体样式
+				fillColor: label.fillColor, //字体颜色
+				outlineColor: label.outlineColor, //字体边框颜色
+				outlineWidth: label.outlineWidth, //边框宽度	
+				style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+				verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+				showBackground: label.showBackground, //是否显示背景颜色
+				backgroundColor: label.backgroundColor, // 背景颜色
+				backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+
+				pixelOffset: new Cesium.Cartesian2(0, label.pixelOffset), //偏移量
+				scale: label.scale, //尺寸
+				// scaleByDistance: new Cesium.NearFarScalar(label.near, label.nearValue, label.far, label.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+
+			}
+		}
+
+
+		this.entity.position.setInterpolationOptions({ // 点插值
+			interpolationDegree: 5,
+			interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
+		})
+
+		this.initRole(this.role);
+	}
+
+	/**
+	 * @param {Object} role 0自由模式 1跟随模式 2第一视角 3 第三视角  后方、前方、俯视(上帝视角)、左侧、右侧
+	 */
+	initRole(role) {
+		let _self = this;
+
+		if (role == 0) {
+			this.viewer.trackedEntity = undefined;
+
+			//获取被clock监听的全部事件数量
+			let len = _self.viewer.clock.onTick.numberOfListeners;
+			for (let i = 0; i < len; i++) {
+				//将被监听的方法移除来停止方法
+				_self.viewer.clock.onTick.removeEventListener(_self.viewer.clock.onTick._listeners[i]);
+			}
+		} else if (role == 1) {
+
+			this.viewer.trackedEntity = this.entity;
+
+			//获取被clock监听的全部事件数量
+			let len = _self.viewer.clock.onTick.numberOfListeners;
+			for (let i = 0; i < len; i++) {
+				//将被监听的方法移除来停止方法
+				_self.viewer.clock.onTick.removeEventListener(_self.viewer.clock.onTick._listeners[i]);
+			}
+
+		} else if (role == 2) {
+
+			this.viewer.trackedEntity = this.entity;
+
+			let exection = function TimeExecution() {
+				if (_self.viewer.clock.shouldAnimate === true) {
+					//获取位置
+					let center = _self.entity.position.getValue(
+						_self.viewer.clock.currentTime
+					);
+					//获取偏向角
+					let orientation = _self.entity.orientation.getValue(
+						_self.viewer.clock.currentTime
+					)
+					let transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
+					transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation), center);
+
+					var transformX = _self.followedX || 50; //距离运动点的距离(后方) 
+					var transformZ = _self.followedZ || 10; //距离运动点的高度(上方)
+
+					_self.viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(transformX, 0, transformZ))
+				}
+			};
+			//监听时间变化 让cesium的时钟方法来监听该方法
+			this.viewer.clock.onTick.addEventListener(exection);
+
+			// //视角变换
+			// var matrix3Scratch = new Cesium.Matrix3();
+
+			// function getModelMatrix(entity, time, result) {
+			// 	var position = Cesium.Property.getValueOrUndefined(entity.position, time, new Cesium.Cartesian3());
+			// 	if (!Cesium.defined(position)) {
+			// 		return undefined;
+			// 	}
+			// 	var orientation = Cesium.Property.getValueOrUndefined(entity.orientation, time, new Cesium.Quaternion());
+			// 	if (!Cesium.defined(orientation)) {
+			// 		result = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, result);
+			// 	} else {
+			// 		result = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation, matrix3Scratch),
+			// 			position, result);
+			// 	}
+			// 	return result;
+			// }
+
+			// var scratch = new Cesium.Matrix4();
+			// let renderListener = function(e) {
+			// 	var time = _self.viewer.clock.currentTime.secondsOfDay - _self.viewer.clock.startTime.secondsOfDay;
+
+			// 	getModelMatrix(_self.entity, _self.viewer.clock.currentTime, scratch);
+
+			// 	var transformX = _self.followedX || 50; //距离运动点的距离(后方) 
+			// 	var transformZ = _self.followedZ || 10; //距离运动点的高度(上方)
+			// 	_self.viewer.scene.camera.lookAtTransform(scratch, new Cesium.Cartesian3(-transformX, 0, transformZ));
+			// }
+			// this.viewer.scene.preRender.addEventListener(renderListener);
+
+		} else if (role == 3) {
+
+			this.viewer.trackedEntity = this.entity;
+
+			let exection = function TimeExecution() {
+				if (_self.viewer.clock.shouldAnimate === true) {
+					//获取位置
+					let center = _self.entity.position.getValue(
+						_self.viewer.clock.currentTime
+					);
+					// 更新相机位置(上帝视角)
+					_self.viewer.camera.lookAt(center, new Cesium.Cartesian3(0, 0, 1000))
+				}
+			};
+			//监听时间变化 让cesium的时钟方法来监听该方法
+			this.viewer.clock.onTick.addEventListener(exection);
+		}
+	}
+
+	/**
+	 * 漫游的暂停和继续
+	 * @param {Boolean} state bool类型 false为暂停,ture为继续
+	 * @memberof Roaming
+	 */
+	PauseOrContinue(state) {
+		this.viewer.clock.shouldAnimate = state;
+	}
+
+	/**
+	 * 向前飞行
+	 */
+	forwardFly() {
+		// var clockViewModel = this.viewer.clockViewModel;
+		// var multiplier = clockViewModel.multiplier;
+		// if (multiplier < 0) {
+		// 	clockViewModel.multiplier = -multiplier;
+		// }
+		// clockViewModel.shouldAnimate = true;
+		
+		var multiplier=this.viewer.clock.multiplier;
+		if (multiplier < 0) {
+			this.viewer.clock.multiplier = -multiplier;
+		}
+		this.viewer.clock.shouldAnimate = true;
+	}
+
+	/**
+	 * 向后飞行
+	 */
+	backwardsFly() {
+		// var clockViewModel = this.viewer.clockViewModel;
+		// var multiplier = clockViewModel.multiplier;
+		// if (multiplier > 0) {
+		// 	clockViewModel.multiplier = -multiplier;
+		// }
+		// clockViewModel.shouldAnimate = true;
+		
+		var multiplier=this.viewer.clock.multiplier;
+		if (multiplier > 0) {
+			this.viewer.clock.multiplier = -multiplier;
+		}
+		this.viewer.clock.shouldAnimate = true;
+	}
+
+	/**
+	 * 改变飞行的速度
+	 * @param {Number} value  整数类型
+	 * @memberof Roaming
+	 */
+	ChangeRoamingSpeed(value) {
+		this.viewer.clock.multiplier = value;
+	}
+
+	/**
+	 * 取消漫游
+	 * @memberof Roaming
+	 */
+	EndRoaming() {
+		if (this.entity !== undefined) {
+			this.viewer.entities.remove(this.entity);
+		}
+		this.viewer.trackedEntity = undefined;
+		this.viewer.clock.shouldAnimate = false;
+
+		//获取被clock监听的全部事件数量
+		let len = this.viewer.clock.onTick.numberOfListeners;
+		for (let i = 0; i < len; i++) {
+			//将被监听的方法移除来停止方法
+			this.viewer.clock.onTick.removeEventListener(this.viewer.clock.onTick._listeners[i]);
+		}
+	}
+}

+ 320 - 0
packages/Widgets/Roaming/TrackRoam.js

@@ -0,0 +1,320 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 飞行漫游
+ */
+class TrackRoam {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+		this._viewer = viewer;
+
+		this._draw3DObj = null;
+	}
+
+	/**
+	 * 飞行漫游路径
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param pathsData
+	 */
+	_startFly(pathsData, options) {
+		var _self = this;
+
+		options = options || {};
+		options.time = Cesium.defaultValue(options.time, 360);
+		options.isPathShow = Cesium.defaultValue(options.isPathShow, true);
+		options.height = Cesium.defaultValue(options.height, 5);
+		options.role = Cesium.defaultValue(options.role, 1);
+
+		this.url = options.modelUrl;
+		this.time = options.time;
+		this.isPathShow = options.isPathShow;
+		this.height = options.height;
+		this.role = options.role;
+
+		_self.clearFlyPaths();
+		_self._viewer.camera.setView({
+			destination: pathsData.position,
+			orientation: pathsData.orientation,
+		});
+		setTimeout(function() {
+			executeFly3D();
+		}, 200);
+
+		function executeFly3D() {
+			if (pathsData && pathsData.geometry) {
+				var positionA = pathsData.geometry.coordinates;
+
+				/* 转换坐标 */
+				let positions = positionA.map(point => {
+					return Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.height);
+				});
+
+				//总距离
+				let distance = [];
+				for (let i = 0; i < positions.length - 1; i++) {
+					let dis = Cesium.Cartesian3.distance(positions[i], positions[i + 1])
+					distance.push(dis)
+				}
+
+				//点与点之间间隔时间
+				let times = [Cesium.JulianDate.fromDate(new Date())]
+				times.push(Cesium.JulianDate.addSeconds(times[0], _self.time, new Cesium.JulianDate()))
+				for (let i = 1; i < positions.length - 1; i++) {
+					let s = Cesium.JulianDate.addSeconds(times[i], _self.time * (distance[i] / distance[0]), new Cesium.JulianDate())
+					times.push(s)
+				}
+
+				//一种属性,其值在给定时间内从提供的样本集和指定的插值算法和插值度中插值。
+				let oriSamples = new Cesium.SampledProperty(Cesium.Cartesian3);
+				oriSamples.addSamples(times, positions);
+
+				let startTime = times[0]; // 起始时间
+				let stopTime = times[times.length - 1]; // 结束时间
+				_self._viewer.clock.startTime = startTime.clone(); // 设置始时钟始时间
+				_self._viewer.clock.stopTime = stopTime.clone(); // 设置始终停止时间
+				_self._viewer.clock.currentTime = startTime.clone(); // 设置时钟当前时间
+				_self._viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //循环执行
+				_self._viewer.clock.multiplier = 10; // 时间速率,数字越大时间过的越快
+
+				// 计算提供的实例之间的天数差。
+				let timeOfResolution = 6;
+				let samplesNum = Math.floor(
+					Cesium.JulianDate.secondsDifference(stopTime, startTime) / timeOfResolution
+				);
+
+				let sampledPositions = [];
+				let sampledTimes = [];
+				for (let i = 0; i < samplesNum + 1; i++) {
+					let sampleTime = Cesium.JulianDate.addSeconds(
+						startTime,
+						i * timeOfResolution,
+						new Cesium.JulianDate()
+					);
+					let tmpPos = oriSamples.getValue(sampleTime);
+					sampledPositions.push(Cesium.Cartographic.fromCartesian(tmpPos));
+					sampledTimes.push(sampleTime);
+				}
+
+				let promise = Cesium.sampleTerrainMostDetailed(
+					_self._viewer.terrainProvider,
+					sampledPositions
+				).then(() => {
+					let carPositionProperty = new Cesium.SampledPositionProperty();
+
+					//高度
+					for (let i = 0; i < sampledPositions.length; i++) {
+						sampledPositions[i].height = sampledPositions[i].height + _self.height
+					}
+
+					for (let i = 0; i < samplesNum + 1; i++) {
+						carPositionProperty.addSample(
+							sampledTimes[i],
+							Cesium.Ellipsoid.WGS84.cartographicToCartesian(sampledPositions[i])
+						);
+					}
+
+					var position = carPositionProperty;
+					_self.entityFly = _self._viewer.entities.add({
+						// 和时间轴关联
+						availability: new Cesium.TimeIntervalCollection([
+							new Cesium.TimeInterval({
+								start: startTime,
+								stop: stopTime,
+							}),
+						]),
+						// 位置
+						position: position,
+						//基于位置移动自动计算方向.
+						orientation: new Cesium.VelocityOrientationProperty(position),
+						point: {
+							color: Cesium.Color.RED,
+							outlineColor: Cesium.Color.WHITE,
+							outlineWidth: 2,
+							pixelSize: 10,
+						},
+						//路径
+						path: {
+							show: _self.isPathShow,
+							resolution: 1,
+							//设置航线样式,线条颜色,内发光粗细,航线宽度等
+							material: new Cesium.PolylineGlowMaterialProperty({
+								glowPower: 0.1,
+								color: Cesium.Color.YELLOW,
+							}),
+							width: 10,
+						},
+					});
+
+					//  0自由模式 1跟随模式 2第一视角 3 第三视角
+					if (_self.role == 0) {
+
+					} else if (_self.role == 1) {
+
+						_self._viewer.trackedEntity = _self.entityFly;
+
+					} else if (_self.role == 2) {
+
+						_self._viewer.trackedEntity = _self.entityFly;
+
+						let exection = function TimeExecution() {
+							if (_self._viewer.clock.shouldAnimate === true) {
+								//获取位置
+								let center = _self.entity.position.getValue(
+									_self._viewer.clock.currentTime
+								);
+								//获取偏向角
+								let orientation = _self.entity.orientation.getValue(
+									_self._viewer.clock.currentTime
+								)
+								let transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
+								transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation), center);
+								_self._viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(-50, 0, 250))
+							}
+						};
+						//监听时间变化 让cesium的时钟方法来监听该方法
+						_self._viewer.clock.onTick.addEventListener(exection);
+					} else if (_self.role == 3) {
+
+						_self._viewer.trackedEntity = _self.entityFly;
+
+						let exection = function TimeExecution() {
+							if (_self._viewer.clock.shouldAnimate === true) {
+								//获取位置
+								let center = _self.entity.position.getValue(
+									_self._viewer.clock.currentTime
+								);
+								// 更新相机位置(上帝视角)
+								_self._viewer.camera.lookAt(center, new Cesium.Cartesian3(0, 0, 1000))
+							}
+						};
+						//监听时间变化 让cesium的时钟方法来监听该方法
+						_self._viewer.clock.onTick.addEventListener(exection);
+					}
+				});
+			} else {
+				return;
+			}
+		}
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(TrackRoam.prototype, /** @lends TrackRoam.prototype */ {
+
+	/**
+	 * 设定飞行漫游路线
+	 */
+	drawFlyPaths(coordinates, options) {
+
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+			//清除飞行路线
+			_self.clearFlyPaths();
+
+			let position = _self._viewer.camera.position;
+			let heading = _self._viewer.camera.heading;
+			let pitch = _self._viewer.camera.pitch;
+			let roll = _self._viewer.camera.roll;
+
+			var pathsData = {
+				"orientation": {
+					"heading": heading,
+					"pitch": pitch,
+					"roll": roll
+				},
+				"position": position,
+				"clampToGround": true, //开启贴地 如果有模型则贴模型
+				"geometry": {
+					"type": "LineString",
+					"coordinates": coordinates
+				}
+			};
+			_self._draw3DObj = pathsData;
+
+			resolve(true);
+		});
+	},
+
+	/**
+	 * 清空漫游路线
+	 */
+	clearFlyPaths() {
+		this._draw3DObj = null;
+
+		this._viewer.trackedEntity = undefined;
+		this._viewer.entities.remove(this.entityFly); //清空飞行路径模型
+	},
+
+	/**
+	 * 开始飞行
+	 */
+	startFly(options,callError) {
+
+		if (this._draw3DObj) {
+			this._startFly(this._draw3DObj, options);
+		} else {
+				if (callError) callError('漫游路线不存在');
+		}
+	},
+
+	/**
+	 * 暂停飞行
+	 */
+	pauseFly() {
+		var clockViewModel = this._viewer.clockViewModel;
+		if (clockViewModel.shouldAnimate) {
+			clockViewModel.shouldAnimate = false;
+		} else if (this._viewer.clockViewModel.canAnimate) {
+			clockViewModel.shouldAnimate = true;
+		}
+	},
+
+	/**
+	 * 向前飞行
+	 */
+	forwardFly() {
+		var clockViewModel = this._viewer.clockViewModel;
+		var multiplier = clockViewModel.multiplier;
+		if (multiplier < 0) {
+			clockViewModel.multiplier = -multiplier;
+		}
+		clockViewModel.shouldAnimate = true;
+	},
+
+	/**
+	 * 向后飞行
+	 */
+	backwardsFly() {
+		var clockViewModel = this._viewer.clockViewModel;
+		var multiplier = clockViewModel.multiplier;
+		if (multiplier > 0) {
+			clockViewModel.multiplier = -multiplier;
+		}
+		clockViewModel.shouldAnimate = true;
+	},
+
+	/**
+	 * 退出飞行
+	 */
+	outFly() {
+		var start = Cesium.JulianDate.fromDate(new Date());
+		this._viewer.clock.startTime = start.clone();
+
+		var stop = Cesium.JulianDate.addSeconds(start, 300000000, new Cesium.JulianDate());
+		this._viewer.clock.stopTime = stop.clone();
+
+		this.clearFlyPaths();
+	},
+});
+
+export default TrackRoam;

+ 14 - 0
packages/Widgets/SceneControl.js

@@ -0,0 +1,14 @@
+//卷帘
+import ImageLayerSplit from "./SceneControl/ImageLayerSplit.js";
+//分屏
+import ViewerSplitScreen from "./SceneControl/ViewerSplitScreen.js";
+
+/**
+ * 场景控制
+ * @ignore
+ */
+let SceneControl = {
+	ImageLayerSplit: ImageLayerSplit,
+	ViewerSplitScreen: ViewerSplitScreen,
+}
+export default SceneControl;

+ 134 - 0
packages/Widgets/SceneControl/ImageLayerSplit.js

@@ -0,0 +1,134 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 卷帘对
+ * Cesium 影像卷帘对,就是把上层影像卷起来,和下面一层影像做对比。
+ * 可左卷也可右卷
+ */
+class ImageLayerSplit {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(ImageLayerSplit.prototype, /** @lends ImageLayerSplit.prototype */ {
+
+	/**
+	 * 卷帘对比初始化
+	 */
+	initSplit() {
+		let _self = this;
+		this.viewer = this._viewer;
+
+		let sliderDiv = document.getElementById("image_slider");
+		if (sliderDiv == null) {
+			//创建画布
+			sliderDiv = document.createElement('div');
+			sliderDiv.id = "image_slider";
+			sliderDiv.style.position = "absolute";
+			sliderDiv.style.left = "50%";
+			sliderDiv.style.top = "0px";
+			sliderDiv.style.backgroundColor = "#d3d3d3";
+			sliderDiv.style.width = "5px";
+			sliderDiv.style.height = "100%";
+			sliderDiv.style.zIndex = "9999";
+
+			sliderDiv.onmouseover = function() {
+				//设置其背景颜色为黄色
+				this.style.cursor = "ew-resize";
+			};
+
+			/* 加入到页面 */
+			document.body.appendChild(sliderDiv);
+		}
+
+		// 设置图像拆分位置
+		this.slider = sliderDiv;
+		viewer.scene.splitPosition = this.slider.offsetLeft / this.slider.parentElement.offsetWidth; //确定分割点位置,占据父级容器的比例
+
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = null;
+		}
+		//处理用户输入事件。可以添加自定义功能以在用户输入时执行;参数为任意
+		this.handler = new Cesium.ScreenSpaceEventHandler(this.slider);
+		var moveActive = false;
+
+		// 计算拆分
+		function move(movement) {
+			if (!moveActive) {
+				return;
+			}
+
+			//捕获滑动停止的位置
+			var relativeOffset = movement.endPosition.x;
+			var splitPosition = (_self.slider.offsetLeft + relativeOffset) / _self.slider.parentElement.offsetWidth;
+			_self.slider.style.left = `${100.0 * splitPosition}%`;
+			viewer.scene.splitPosition = splitPosition;
+		}
+
+		//对分割条的操作
+		this.handler.setInputAction(function() {
+			moveActive = true;
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+		this.handler.setInputAction(function() {
+			moveActive = true;
+		}, Cesium.ScreenSpaceEventType.PINCH_START);
+
+		this.handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+		this.handler.setInputAction(move, Cesium.ScreenSpaceEventType.PINCH_MOVE);
+
+		this.handler.setInputAction(function() {
+			moveActive = false;
+		}, Cesium.ScreenSpaceEventType.LEFT_UP);
+		this.handler.setInputAction(function() {
+			moveActive = false;
+		}, Cesium.ScreenSpaceEventType.PINCH_END);
+	},
+
+	/**
+	 * 卷帘对比
+	 * @param {Object} earthAtLeft 左侧图层
+	 * @param {Object} earthAtRight 右侧图层
+	 */
+	addSplitLayer(earthAtLeft, earthAtRight) {
+		let _self = this;
+
+		if (this.earthAtLeft) {
+			this._viewer.imageryLayers.remove(this.earthAtLeft); //移除图层
+		}
+		if (this.earthAtRight) {
+			this._viewer.imageryLayers.remove(this.earthAtRight); //移除图层
+		}
+
+		this.earthAtLeft = earthAtLeft;
+		this.earthAtRight = earthAtRight;
+
+		this.earthAtLeft.splitDirection = Cesium.SplitDirection.LEFT;
+		this.earthAtRight.splitDirection = Cesium.SplitDirection.RIGHT;
+	},
+
+	/**
+	 * 移除卷帘
+	 */
+	removeSplitLayer() {
+		document.body.removeChild(this.slider);
+		if (this.earthAtLeft) {
+			this._viewer.imageryLayers.remove(this.earthAtLeft); //移除图层
+		}
+		if (this.earthAtRight) {
+			this._viewer.imageryLayers.remove(this.earthAtRight); //移除图层
+		}
+	},
+});
+
+export default ImageLayerSplit;

+ 106 - 0
packages/Widgets/SceneControl/ViewerSplitScreen.js

@@ -0,0 +1,106 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 分屏
+ */
+class ViewerSplitScreen {
+	/**
+	 * 默认初始化
+	 */
+	constructor() {}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(ViewerSplitScreen.prototype, /** @lends ViewerSplitScreen.prototype */ {
+
+	/**
+	 * 开启分屏
+	 * @param {Object} viewer1 视窗1
+	 * @param {Object} viewer2 视窗2
+	 */
+	initHandler(viewer1, viewer2) {
+		var _self = this;
+		if (_self.handler1 && _self.handler1.getInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)) {
+			return;
+		}
+		_self.handler1 = new Cesium.ScreenSpaceEventHandler(viewer1.scene.canvas);
+		_self.handler2 = new Cesium.ScreenSpaceEventHandler(viewer2.scene.canvas);
+
+		_self.handler1.setInputAction(function(movement) {
+			var _camerca = viewer1.camera;
+			viewer2.camera.setView({
+				destination: _camerca.position,
+				orientation: {
+					direction: _camerca._direction,
+					up: _camerca.up,
+					heading: _camerca.heading,
+					pitch: _camerca.pitch,
+					roll: _camerca.roll
+				}
+			});
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+		_self.handler1.setInputAction(function(movement) {
+			var _camerca = viewer1.camera;
+			viewer2.camera.setView({
+				destination: _camerca.position,
+				orientation: {
+					direction: _camerca._direction,
+					up: _camerca.up,
+					heading: _camerca.heading,
+					pitch: _camerca.pitch,
+					roll: _camerca.roll
+				}
+			});
+		}, Cesium.ScreenSpaceEventType.WHEEL);
+
+
+		_self.handler2.setInputAction(function(movement) {
+			var _camerca = viewer2.camera;
+			viewer1.camera.setView({
+				destination: _camerca.position,
+				orientation: {
+					direction: _camerca._direction,
+					up: _camerca.up,
+					heading: _camerca.heading,
+					pitch: _camerca.pitch,
+					roll: _camerca.roll
+				}
+			});
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+		_self.handler2.setInputAction(function(movement) {
+			var _camerca = viewer2.camera;
+			viewer1.camera.setView({
+				destination: _camerca.position,
+				orientation: {
+					direction: _camerca._direction,
+					up: _camerca.up,
+					heading: _camerca.heading,
+					pitch: _camerca.pitch,
+					roll: _camerca.roll
+				}
+			});
+		}, Cesium.ScreenSpaceEventType.WHEEL);
+	},
+
+	/**
+	 * 移除分屏效果
+	 */
+	clearHandler() {
+		var _self = this;
+		if (_self.handler1) {
+			_self.handler1.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+			_self.handler1.removeInputAction(Cesium.ScreenSpaceEventType.WHEEL);
+		}
+		if (_self.handler2) {
+			_self.handler2.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+			_self.handler2.removeInputAction(Cesium.ScreenSpaceEventType.WHEEL);
+		}
+	}
+});
+
+export default ViewerSplitScreen;

+ 19 - 0
packages/Widgets/SceneEffects.js

@@ -0,0 +1,19 @@
+//天气特效
+import Weather from "./SceneEffects/Weather.js";
+//天空盒子
+import SkyBox from "./SceneEffects/SkyBox.js";
+//粒子系统
+import ParticleSystem from "./SceneEffects/ParticleSystem.js";
+
+
+/**
+ * 场景特效
+ * @ignore
+ */
+let SceneEffects = {
+	Weather: Weather,
+	SkyBox: SkyBox,
+	ParticleSystem:ParticleSystem
+}
+
+export default SceneEffects;

+ 203 - 0
packages/Widgets/SceneEffects/ParticleSystem.js

@@ -0,0 +1,203 @@
+/**
+ * 粒子效果
+ * 火粒子、水粒子
+ */
+class ParticleSystem {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new DeveloperError('no viewer object!');
+		this.viewer = viewer;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(ParticleSystem.prototype, /** @lends ParticleSystem.prototype */ {
+
+	/**
+	 * 创建火焰粒子
+	 * @param {Array} coordinates 粒子位置 [longitude, latitude, height] 
+	 */
+	createParticleFire: function(coordinates) {
+		this.viewer.clock.shouldAnimate = true; //是否允许动画,看到粒子效果
+
+		// 指定喷射地点
+		var position = Cesium.Cartesian3.fromDegrees(coordinates[0], coordinates[1], coordinates[2] || 0);
+		// 使用一个entity来作为粒子载体,比如示例中的小车
+		var entity = this.viewer.entities.add({
+			position: position
+		});
+		// 计算载体位置
+		function computeModelMatrix(entity, time) {
+			var position = Cesium.Property.getValueOrUndefined(entity.position);
+			var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
+			return modelMatrix;
+		}
+
+		var viewModel = {
+			startScale: 3,
+			endScale: 1.5,
+			minimumParticleLife: 1.5,
+			maximumParticleLife: 1.8,
+			minimumSpeed: 7, //粒子发射的最小速度
+			maximumSpeed: 9, //粒子发射的最大速度
+			particleSize: 2,
+			emissionRate: 200
+		};
+
+		var primitive = this.viewer.scene.primitives.add(
+			new Cesium.ParticleSystem({
+				image: "jt3dSDK/imgs/particlesystem/fire.png",
+				imageSize: new Cesium.Cartesian2(viewModel.particleSize, viewModel.particleSize), //如果设置该属性,将会覆盖 minimumImageSize和maximumImageSize属性,以像素为单位缩放image的大小
+
+				startColor: new Cesium.Color(1, 1, 1, 1), //粒子出生时的颜色
+				endColor: new Cesium.Color(0.5, 0, 0, 0), //当粒子死亡时的颜色
+
+				startScale: viewModel.startScale, //粒子出生时的比例,相对于原始大小
+				endScale: viewModel.endScale, //粒子在死亡时的比例
+
+				minimumParticleLife: viewModel.minimumParticleLife, //设置粒子寿命的可能持续时间的最小界限(以秒为单位),粒子的实际寿命将随机生成
+				maximumParticleLife: viewModel.maximumParticleLife, //设置粒子寿命的可能持续时间的最大界限(以秒为单位),粒子的实际寿命将随机生成
+				minimumSpeed: viewModel.minimumSpeed, //设置以米/秒为单位的最小界限,超过该最小界限,随机选择粒子的实际速度。
+				maximumSpeed: viewModel.maximumSpeed, //设置以米/秒为单位的最大界限,超过该最大界限,随机选择粒子的实际速度。
+
+				emissionRate: viewModel.emissionRate, //每秒发射的粒子数。
+				lifetime: 16.0, //多长时间的粒子系统将以秒为单位发射粒子
+				//粒子系统是否应该在完成时循环其爆发
+				loop: true,
+				//设置粒子的大小是否以米或像素为单位
+				sizeInMeters: true, //AAAAAAAAAAAA
+				emitter: new Cesium.ConeEmitter(Cesium.Math.toRadians(45.0)), //此系统的粒子发射器  共有 圆形、锥体、球体、长方体 ( BoxEmitter,CircleEmitter,ConeEmitter,SphereEmitter ) 几类
+				modelMatrix: computeModelMatrix(entity, Cesium.JulianDate.now()), // 4x4转换矩阵,可将粒子系统从模型转换为世界坐标
+			})
+		);
+
+		entity.remove = function() {
+			viewer.entities.remove(entity);
+			viewer.scene.primitives.remove(primitive);
+		};
+
+		return entity;
+	},
+
+	/**
+	 * 创建喷水粒子
+	 * @param {Array} coordinates 粒子位置 [longitude, latitude, height] 
+	 */
+	createParticleWater: function(coordinates) {
+		let viewer = this.viewer;
+		this.viewer.clock.shouldAnimate = true; //是否允许动画,看到粒子效果
+
+		// 指定喷射地点,并实时计算位置
+		var position = Cesium.Cartesian3.fromDegrees(coordinates[0], coordinates[1], coordinates[2] || 0);
+		// 使用一个entity来作为粒子载体,比如示例中的小车
+		var entity = this.viewer.entities.add({
+			position: position
+		});
+
+		//设置该粒子系统的位置
+		// function computeModelMatrix(entity) {
+		// 	var position = Cesium.Property.getValueOrUndefined(entity.position);
+		// 	let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
+		// 	return modelMatrix;
+		// }
+		function computeModelMatrix(entity, time) {
+		  return entity.computeModelMatrix(time, new Cesium.Matrix4());
+		}
+		// 计算粒子发射器的位置姿态
+		function computeEmitterModelMatrix() {
+			let hpr = Cesium.HeadingPitchRoll.fromDegrees(viewModel.heading, viewModel.pitch, viewModel.roll); // 倾斜角度
+			let trs = new Cesium.TranslationRotationScale();
+			trs.translation = Cesium.Cartesian3.fromElements(0, 0, 1); // 发射高度
+
+			trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
+			let Matrix4 = Cesium.Matrix4.fromTranslationRotationScale(trs);
+			return Matrix4
+		}
+		// 更新粒子运动状态
+		function updateCallback(p, dt) {
+			var gravityScratch = new Cesium.Cartesian3();
+			var position = p.position;
+			Cesium.Cartesian3.normalize(position, gravityScratch);
+			// Cesium.Cartesian3.fromElements(20 * dt, gravityScratch.y * dt, -30 * dt, gravityScratch);
+			Cesium.Cartesian3.multiplyByScalar(gravityScratch, viewModel.gravity * dt, gravityScratch);
+			p.velocity = Cesium.Cartesian3.add(p.velocity, gravityScratch, p.velocity);
+		}
+		
+		// 实时计算位置
+		function update(scene, time) {
+		  waterParticleSystem.modelMatrix = computeModelMatrix(entity, time);
+		  waterParticleSystem.emitterModelMatrix = computeEmitterModelMatrix();
+		}
+		viewer.scene.preUpdate.addEventListener(update);
+
+		var viewModel = {
+			startScale: 1,
+			endScale: 7,
+			minimumParticleLife: 6,
+			maximumParticleLife: 7,
+			minimumSpeed: 9,
+			maximumSpeed: 9.5,
+			particleSize: 1,
+			emissionRate: 60.0,
+			gravity: -4, //重力,上下出水方向
+
+			// transX: 2.5,
+			// transY: 4.0,
+			// transZ: 1.0,
+			heading: 110.0,
+			pitch: 30.0,
+			roll: 0.0,
+			// fly: true,
+			// spin: true,
+			// show: true
+		};
+
+		var waterParticleSystem = new Cesium.ParticleSystem({
+			//这里需要改为自己的图片路径
+			image: "jt3dSDK/imgs/particlesystem/water.png",
+			//设置发射出的图像大小
+			imageSize: new Cesium.Cartesian2(viewModel.particleSize, viewModel.particleSize),
+
+			startColor: new Cesium.Color(1, 1, 1, 0.6), //粒子出生时的颜色
+			endColor: new Cesium.Color(0.80, 0.86, 1, 0.4), //当粒子死亡时的颜色
+
+			// 值越大,初始时粒子图的大小越大
+			startScale: viewModel.startScale,
+			endScale: viewModel.endScale,
+			//值越大,尾巴越长
+			minimumParticleLife: viewModel.minimumParticleLife,
+			maximumParticleLife: viewModel.maximumParticleLife,
+			//值越大,尾巴飘的越高
+			minimumSpeed: viewModel.minimumSpeed,
+			maximumSpeed: viewModel.maximumSpeed,
+
+			//每秒发射的粒子数。
+			//数值越大,越浓密
+			emissionRate: viewModel.emissionRate,
+
+			//设置粒子的大小是否以米或像素为单位
+			sizeInMeters: true, //AAAAAAAAAAAA
+			emitter: new Cesium.CircleEmitter(0.2),
+			modelMatrix: computeModelMatrix(entity),
+			emitterModelMatrix: computeEmitterModelMatrix(),
+			updateCallback: updateCallback,
+		});
+		// 将粒子系统添加到场景中
+		viewer.scene.primitives.add(waterParticleSystem);
+
+		entity.remove = function() {
+			viewer.entities.remove(entity);
+			viewer.scene.primitives.remove(waterParticleSystem);
+		};
+
+		return entity;
+	},
+
+});
+
+export default ParticleSystem;

+ 148 - 0
packages/Widgets/SceneEffects/SkyBox.js

@@ -0,0 +1,148 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import SkyBoxOnGround from "../../Core/SkyBoxOnGround.js";
+
+/**
+ * 天空盒子
+ */
+class SkyBox {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+		this._farSkyBox = viewer.scene.skyBox; //默认天空盒子,即远景天空盒子
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(SkyBox.prototype, /** @lends SkyBox.prototype */ {
+	/**
+	 * 自定义天空盒子
+	 * @param {Object} options 具有以下属性:
+	 * @param {Object} [options.type="蓝天"] 默认蓝天,晚霞,阴天,紫色星空,蓝色星空
+	 * @param {Object} [options.sources] 天空盒子6个方向的图片地址(立方体全景图片)
+	 * @param {String} [options.sources.positiveX] 
+	 * @param {String} [options.sources.negativeX] 
+	 * @param {String} [options.sources.positiveY] 
+	 * @param {String} [options.sources.negativeY] 
+	 * @param {String} [options.sources.positiveZ]
+	 * @param {String} [options.sources.negativeZ] 
+	 * @param {Number} [options.height=200000] 开始显示自定义天空盒子高度,默认=200000
+	 * 
+	 * @example
+	 * setGroundSkyBox({
+	 * 	type:"蓝天",
+	 *	height:200000,
+	 * 	sources: { //蓝天
+	 * 		positiveX: 'http://support.supermap.com.cn:8090/webgl/examples/webgl/imgs/SkyBox/bluesky/Right.jpg',
+	 * 		negativeX: 'http://support.supermap.com.cn:8090/webgl/examples/webgl/imgs/SkyBox/bluesky/Left.jpg',
+	 * 		positiveY: 'http://support.supermap.com.cn:8090/webgl/examples/webgl/imgs/SkyBox/bluesky/Front.jpg',
+	 * 		negativeY: 'http://support.supermap.com.cn:8090/webgl/examples/webgl/imgs/SkyBox/bluesky/Back.jpg',
+	 * 		positiveZ: 'http://support.supermap.com.cn:8090/webgl/examples/webgl/imgs/SkyBox/bluesky/Up.jpg',
+	 * 		negativeZ: 'http://support.supermap.com.cn:8090/webgl/examples/webgl/imgs/SkyBox/bluesky/Down.jpg',
+	 * 	},
+	 * });		
+	 */
+	setGroundSkyBox(options) {
+
+		options = options || {};
+		options.height = options.height || 200000;
+		options.type = options.type || "蓝天";
+
+		if (!options.sources) {
+			switch (options.type) {
+				case "晚霞":
+					options.sources = {
+						positiveX: 'jt3dSDK/imgs/skybox/01/px.png',
+						negativeX: 'jt3dSDK/imgs/skybox/01/nx.png',
+						positiveY: 'jt3dSDK/imgs/skybox/01/py.png',
+						negativeY: 'jt3dSDK/imgs/skybox/01/ny.png',
+						positiveZ: 'jt3dSDK/imgs/skybox/01/pz.png',
+						negativeZ: 'jt3dSDK/imgs/skybox/01/nz.png',
+					}
+					break;
+				case "阴天":
+					options.sources = {
+						positiveX: 'jt3dSDK/imgs/skybox/02/px.jpg',
+						negativeX: 'jt3dSDK/imgs/skybox/02/nx.jpg',
+						positiveY: 'jt3dSDK/imgs/skybox/02/py.jpg',
+						negativeY: 'jt3dSDK/imgs/skybox/02/ny.jpg',
+						positiveZ: 'jt3dSDK/imgs/skybox/02/pz.jpg',
+						negativeZ: 'jt3dSDK/imgs/skybox/02/nz.jpg',
+					}
+					break;
+				case "蓝天":
+					options.sources = {
+						positiveX: 'jt3dSDK/imgs/skybox/03/px.jpg',
+						negativeX: 'jt3dSDK/imgs/skybox/03/nx.jpg',
+						positiveY: 'jt3dSDK/imgs/skybox/03/py.jpg',
+						negativeY: 'jt3dSDK/imgs/skybox/03/ny.jpg',
+						positiveZ: 'jt3dSDK/imgs/skybox/03/pz.jpg',
+						negativeZ: 'jt3dSDK/imgs/skybox/03/nz.jpg',
+					}
+					break;
+				case "紫色星空":
+					options.sources = {
+						positiveX: 'jt3dSDK/imgs/skybox/04/px.jpg',
+						negativeX: 'jt3dSDK/imgs/skybox/04/nx.jpg',
+						positiveY: 'jt3dSDK/imgs/skybox/04/py.jpg',
+						negativeY: 'jt3dSDK/imgs/skybox/04/ny.jpg',
+						positiveZ: 'jt3dSDK/imgs/skybox/04/pz.jpg',
+						negativeZ: 'jt3dSDK/imgs/skybox/04/nz.jpg',
+					}
+					break;
+				case "蓝色星空":
+					options.sources = {
+						positiveX: 'jt3dSDK/imgs/skybox/05/px.jpg',
+						negativeX: 'jt3dSDK/imgs/skybox/05/nx.jpg',
+						positiveY: 'jt3dSDK/imgs/skybox/05/py.jpg',
+						negativeY: 'jt3dSDK/imgs/skybox/05/ny.jpg',
+						positiveZ: 'jt3dSDK/imgs/skybox/05/pz.jpg',
+						negativeZ: 'jt3dSDK/imgs/skybox/05/nz.jpg',
+					}
+					break;
+			}
+		} else if (!Cesium.defined(options.sources.positiveX) ||
+			!Cesium.defined(options.sources.negativeX) ||
+			!Cesium.defined(options.sources.positiveY) ||
+			!Cesium.defined(options.sources.negativeY) ||
+			!Cesium.defined(options.sources.positiveZ) ||
+			!Cesium.defined(options.sources.negativeZ)
+		) {
+			throw new Cesium.DeveloperError(
+				"options.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties."
+			);
+		}
+
+		let _self = this;
+
+		//自定义天空盒子(天空盒子需要显示)
+		// let groundSkyBox = new Cesium.SkyBox({//自带的有bug,天空效果出现倾斜
+		// 	sources: options.sources,
+		// 	show: true
+		// });
+
+		let groundSkyBox = new SkyBoxOnGround({ //在源码基础上修改后的
+			sources: options.sources,
+			show: true
+		});
+
+		//如果高度小于某个值 显示近景天空盒 否则显示远景天空盒
+		_self._viewer.scene.postRender.addEventListener(() => {
+			var e = _self._viewer.camera.position;
+			if (Cesium.Cartographic.fromCartesian(e).height < options.height) {
+				_self._viewer.scene.skyBox = groundSkyBox; // 显示自定义的天空盒
+			} else {
+				_self._viewer.scene.skyBox = _self._defaultSkyBox; // 显示原始的天空盒
+			}
+		});
+	}
+});
+
+export default SkyBox;

+ 278 - 0
packages/Widgets/SceneEffects/Weather.js

@@ -0,0 +1,278 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 天气场景
+ */
+class Weather {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+
+	/**
+	 * 雨天特效
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_initRain() {
+		this.rainStage = new Cesium.PostProcessStage({
+			name: 'jt_rain',
+			fragmentShader: this._rain(),
+			uniforms: {
+				tiltAngle: () => {
+					return this.tiltAngle;
+				},
+				rainSize: () => {
+					return this.rainSize;
+				},
+				rainSpeed: () => {
+					return this.rainSpeed;
+				}
+			}
+		});
+		this._viewer.scene.postProcessStages.add(this.rainStage);
+	}
+
+	/**
+	 * 雪天特效
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_initSnow() {
+		this.snowStage = new Cesium.PostProcessStage({
+			name: 'jt_snow',
+			fragmentShader: this._snow(),
+			uniforms: {
+				snowSize: () => {
+					return this.snowSize;
+				},
+				snowSpeed: () => {
+					return this.snowSpeed;
+				}
+			}
+		});
+		this._viewer.scene.postProcessStages.add(this.snowStage);
+	}
+
+	/**
+	 * 雾天特效
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_initFog() {
+		this.fogStage = new Cesium.PostProcessStage({
+			name: 'jt_fog',
+			fragmentShader: this._fog(),
+			uniforms: {
+				visibility: () => {
+					return this.visibility;
+				},
+				fogColor: () => {
+					return this.color;
+				}
+			}
+		});
+		this._viewer.scene.postProcessStages.add(this.fogStage);
+	}
+
+	/**
+	 * 雨天粒子效果
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_rain() {
+		return "uniform sampler2D colorTexture;\n\
+	            varying vec2 v_textureCoordinates;\n\
+	            uniform float tiltAngle;\n\
+	            uniform float rainSize;\n\
+	            uniform float rainSpeed;\n\
+	            float hash(float x) {\n\
+	                return fract(sin(x * 133.3) * 13.13);\n\
+	            }\n\
+	            void main(void) {\n\
+	                float time = czm_frameNumber / rainSpeed;\n\
+	                vec2 resolution = czm_viewport.zw;\n\
+	                vec2 uv = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y);\n\
+	                vec3 c = vec3(.6, .7, .8);\n\
+	                float a = tiltAngle;\n\
+	                float si = sin(a), co = cos(a);\n\
+	                uv *= mat2(co, -si, si, co);\n\
+	                uv *= length(uv + vec2(0, 4.9)) * rainSize + 1.;\n\
+	                float v = 1. - sin(hash(floor(uv.x * 100.)) * 2.);\n\
+	                float b = clamp(abs(sin(20. * time * v + uv.y * (5. / (2. + v)))) - .95, 0., 1.) * 20.;\n\
+	                c *= v * b;\n\
+	                gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c, 1), .5);\n\
+	            }\n\
+	            ";
+	}
+
+	/**
+	 * 雪天粒子效果
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_snow() {
+		return "uniform sampler2D colorTexture;\n\
+            varying vec2 v_textureCoordinates;\n\
+            uniform float snowSpeed;\n\
+                    uniform float snowSize;\n\
+            float snow(vec2 uv,float scale)\n\
+            {\n\
+                float time=czm_frameNumber/snowSpeed;\n\
+                float w=smoothstep(1.,0.,-uv.y*(scale/10.));if(w<.1)return 0.;\n\
+                uv+=time/scale;uv.y+=time*2./scale;uv.x+=sin(uv.y+time*.5)/scale;\n\
+                uv*=scale;vec2 s=floor(uv),f=fract(uv),p;float k=3.,d;\n\
+                p=.5+.35*sin(11.*fract(sin((s+p+scale)*mat2(7,3,6,5))*5.))-f;d=length(p);k=min(d,k);\n\
+                k=smoothstep(0.,k,sin(f.x+f.y)*snowSize);\n\
+                return k*w;\n\
+            }\n\
+            void main(void){\n\
+                vec2 resolution=czm_viewport.zw;\n\
+                vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);\n\
+                vec3 finalColor=vec3(0);\n\
+                //float c=smoothstep(1.,0.3,clamp(uv.y*.3+.8,0.,.75));\n\
+                float c=0.;\n\
+                c+=snow(uv,30.)*.0;\n\
+                c+=snow(uv,20.)*.0;\n\
+                c+=snow(uv,15.)*.0;\n\
+                c+=snow(uv,10.);\n\
+                c+=snow(uv,8.);\n\
+                c+=snow(uv,6.);\n\
+                c+=snow(uv,5.);\n\
+                finalColor=(vec3(c));\n\
+                gl_FragColor=mix(texture2D(colorTexture,v_textureCoordinates),vec4(finalColor,1),.5);\n\
+                }\n\
+                ";
+	}
+
+	/**
+	 * 雾天粒子效果
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_fog() {
+		return "uniform sampler2D colorTexture;\n\
+	     uniform sampler2D depthTexture;\n\
+	     uniform float visibility;\n\
+	     uniform vec4 fogColor;\n\
+	     varying vec2 v_textureCoordinates; \n\
+	     void main(void) \n\
+	     { \n\
+	        vec4 origcolor = texture2D(colorTexture, v_textureCoordinates); \n\
+	        float depth = czm_readDepth(depthTexture, v_textureCoordinates); \n\
+	        vec4 depthcolor = texture2D(depthTexture, v_textureCoordinates); \n\
+	        float f = visibility * (depthcolor.r - 0.3) / 0.2; \n\
+	        if (f < 0.0) f = 0.0; \n\
+	        else if (f > 1.0) f = 1.0; \n\
+	        gl_FragColor = mix(origcolor, fogColor, f); \n\
+	     }\n";
+	}
+
+	/**
+	 * 移除雪天效果
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_removeSnow() {
+		if (!this._viewer || !this.snowStage) return;
+		this._viewer.scene.postProcessStages.remove(this.snowStage);
+		// this.snowStage.destroy();
+		delete this.snowSize;
+		delete this.snowSpeed;
+	}
+
+	/**
+	 * 移除雨天效果
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_removeRain() {
+		if (!this._viewer || !this.rainStage) return;
+		this._viewer.scene.postProcessStages.remove(this.rainStage);
+		// this.rainStage.destroy();
+		delete this.tiltAngle;
+		delete this.rainSize;
+		delete this.rainSpeed;
+	}
+
+	/**
+	 * 移除雾天效果
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_removeFog() {
+		if (!this._viewer || !this.fogStage) return;
+		this._viewer.scene.postProcessStages.remove(this.fogStage);
+		// this.fogStage.destroy();
+		delete this.visibility;
+		delete this.color;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(Weather.prototype, /** @lends Weather.prototype */ {
+
+	/**
+	 * 开启雨天特效
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.tiltAngle=-0.6] 倾斜角度,负数向右,正数向左
+	 * @param {Number} [options.rainSize=0.3] 雨大小
+	 * @param {Number} [options.rainSpeed=-60.0] 雨速
+	 */
+	addRainEffect(options) {
+		options = options || {};
+
+		this.tiltAngle = Cesium.defaultValue(options.tiltAngle, -0.6);
+		this.rainSize = Cesium.defaultValue(options.rainSize, 0.3);
+		this.rainSpeed = Cesium.defaultValue(options.rainSpeed, 60.0);
+
+		this._initRain();
+	},
+
+	/**
+	 * 开启雪天特效
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.snowSize=0.02] 雪大小,最好小于0.02,默认可不写,
+	 * @param {Number} [options.snowSpeed=60.0] 雪速,默认可不写
+	 */
+	addSnowEffect(options) {
+		options = options || {};
+
+		this.snowSize = Cesium.defaultValue(options.snowSize, 0.02);
+		this.snowSpeed = Cesium.defaultValue(options.snowSpeed, 60.0);
+
+		this._initSnow();
+	},
+
+	/**
+	 * 开启雾天特效
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.visibility=-0.1] 
+	 * @param {Number} [options.color=0.3] 
+	 * @param {Number} [options.show] 
+	 */
+	addFogEffect(options) {
+		options = options || {};
+
+		this.visibility = Cesium.defaultValue(options.visibility, 0.1);
+		this.color = Cesium.defaultValue(options.color, new Cesium.Color(0.8, 0.8, 0.8, 0.5));
+		this._show = Cesium.defaultValue(options.show, !0);
+
+		this._initFog();
+	},
+
+	/**
+	 * 移除天气特效
+	 */
+	removeEffect() {
+		if (this.snowStage) {
+			this._removeSnow();
+		}
+		if (this.rainStage) {
+			this._removeRain();
+		}
+		if (this.fogStage) {
+			this._removeFog();
+		}
+	}
+});
+
+export default Weather;

+ 31 - 0
packages/Widgets/SpatialAnalysis.js

@@ -0,0 +1,31 @@
+//视线通视分析
+import SightLine from "./SpatialAnalysis/SightLine.js";
+//视域分析
+import ViewShed from "./SpatialAnalysis/ViewShed.js";
+//光照阴影
+import SunshineShadow from "./SpatialAnalysis/SunshineShadow.js";
+//剖面分析
+import Profile from "./SpatialAnalysis/Profile.js";
+//方量分析
+import CutFill from "./SpatialAnalysis/CutFill.js";
+//限高分析
+import HeightLimit from "./SpatialAnalysis/HeightLimit.js";
+//剖切
+import Cutting from "./SpatialAnalysis/Cutting.js";
+import GeologyClipPlan from "./SpatialAnalysis/GeologyClipPlan.js";
+
+/**
+ * 空间分析
+ * @ignore
+ */
+let SpatialAnalysis = {
+	SightLine: SightLine,
+	ViewShed: ViewShed,
+	SunshineShadow: SunshineShadow,
+	Profile: Profile,
+	CutFill: CutFill,
+	HeightLimit: HeightLimit,
+	Cutting: Cutting,
+	GeologyClipPlan: GeologyClipPlan,
+}
+export default SpatialAnalysis;

+ 214 - 0
packages/Widgets/SpatialAnalysis/CutFill.js

@@ -0,0 +1,214 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 方量分析
+ * 过获取绘制的范围,获取面的坐标,对该面的坐标进行插值,将面等分为一个个的小三角面,求该三角面内定点的平均高度作为该三角面对应的高度。然后 体积 = 三角形面积 x 高度,然后对体积进行累加,即获取了体积。
+ * 填方体积为:当当前点的地形高度低于基准面高度时,用三角面的面积乘以基准面高度减去当前点的地形高度,然后体积求和。
+ * 挖方体积为:当当前点的地形高度高于基准面高度时,用三角面的面积乘以当前点的地形高度减去基准面高度,然后体积求和。
+ */
+class CutFill {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+
+		this.delEntitys = [];
+		this.maxHeigh = -1000000; //用来记录整块区域的最小高程
+	}
+
+	/**
+	 * @ignore 
+	 * @param {Object} options
+	 */
+	_VolumeAnalysis(options) {
+		let _self = this;
+
+		let cutArea = 0,
+			cutVolume = 0,
+			fillArea = 0,
+			fillVolume = 0;
+
+		const indices = options.geom.indices; //获取顶点索引数据
+		const positions = options.geom.attributes.position.values;
+
+		for (let index = 0; index < indices.length; index += 3) {
+			const pos0 = _self._returnPosition(positions, indices[index]);
+			const pos1 = _self._returnPosition(positions, indices[index + 1]);
+			const pos2 = _self._returnPosition(positions, indices[index + 2]);
+
+			let _entities = _self._viewer.entities.add({
+				name: "三角面",
+				polygon: {
+					hierarchy: [pos0.heightPos, pos1.heightPos, pos2.heightPos],
+					perPositionHeight: true,
+					material: Cesium.Color.fromRandom(),
+					extrudedHeight: options.height,
+					outline: true,
+					outlineColor: Cesium.Color.BLACK,
+				},
+			});
+			_self.delEntitys.push(_entities);
+
+			//水平状态下三角形面积
+			const area = _self._computeArea4Triangle(
+				pos0.noHeightPos,
+				pos1.noHeightPos,
+				pos2.noHeightPos
+			);
+
+			//计算三个点的均高
+			//计算三角体的平均高度
+			const height = (pos0.height + pos1.height + pos2.height) / 3;
+
+			//判断是 填方还是挖方
+			//如果三角体低于基准面,则需要填方
+			if (height < options.height) {
+				// 需要填方的部分
+				fillArea += area;
+				const volume = area * (options.height - height);
+				fillVolume += volume;
+			} else {
+				// 需要挖方的部分
+				cutArea += area;
+				const volume = area * (height - options.height);
+				cutVolume += volume;
+			}
+		}
+		let allArea = cutArea + fillArea;
+
+		allArea = allArea.toFixed(2);
+		cutArea = cutArea.toFixed(2);
+		cutVolume = cutVolume.toFixed(2);
+		fillArea = fillArea.toFixed(2);
+		fillVolume = fillVolume.toFixed(2);
+
+		let result = {
+			allArea,
+			cutArea,
+			cutVolume,
+			fillArea,
+			fillVolume,
+		};
+		return result;
+	}
+
+	/**
+	 * 海伦公式求取三角形面积
+	 * @ignore 
+	 * @param {*} pos1
+	 * @param {*} pos2
+	 * @param {*} pos3
+	 * @returns 三角形面积㎡
+	 */
+	_computeArea4Triangle(pos1, pos2, pos3) {
+		let a = Cesium.Cartesian3.distance(pos1, pos2);
+		let b = Cesium.Cartesian3.distance(pos2, pos3);
+		let c = Cesium.Cartesian3.distance(pos3, pos1);
+		let S = (a + b + c) / 2;
+		return Math.sqrt(S * (S - a) * (S - b) * (S - c));
+	}
+
+	/**
+	 * @ignore 
+	 * @param {Object} positions
+	 * @param {Object} index
+	 */
+	_returnPosition(positions, index) {
+		let cartesian = new Cesium.Cartesian3(
+			positions[index * 3],
+			positions[index * 3 + 1],
+			positions[index * 3 + 2]
+		);
+		let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
+		let height = this._viewer.scene.sampleHeightSupported ?
+			this._viewer.scene.sampleHeight(cartographic) :
+			this._viewer.scene.globe.getHeight(cartographic);
+
+		if (height > this.maxHeigh) {
+			this.maxHeigh = height;
+		}
+
+		return {
+			heightPos: Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, height),
+			noHeightPos: Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0),
+			height: height,
+		};
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(CutFill.prototype, /** @lends CutFill.prototype */ {
+
+	/**
+	 * 方量分析
+	 * @param {Object} points
+	 * @param {Object} options
+	 */
+	createPolygonGeo(points, options) {
+
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+			options = options || {};
+			options.precision = Cesium.defaultValue(options.precision, 256);
+			options.height = Cesium.defaultValue(options.height, 10);
+
+			//移除
+			_self.remove();
+
+			/* 转换坐标 */
+			let positions = [];
+			for (let i = 0; i < points.length; i++) {
+				if (points[i] instanceof Cesium.Cartesian3) {
+					positions.push(points[i]);
+				} else {
+					positions.push(Cesium.Cartesian3.fromDegrees(points[i][0], points[i][1], points[i][1] || 0));
+				}
+			}
+
+			//计算网格粒度-精度
+			let granularity = Math.PI / Math.pow(2, 11);
+			granularity = granularity / options.precision;
+
+			let polygonGeometry = new Cesium.PolygonGeometry.fromPositions({
+				positions: positions,
+				vertexFormat: Cesium.PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
+				granularity: granularity,
+			});
+			options.geom = new Cesium.PolygonGeometry.createGeometry(polygonGeometry);
+
+			let result = _self._VolumeAnalysis(options);
+
+			//设置球体背景色
+			//设置地图basecolor为透明色
+			_self._viewer.scene.globe.baseColor = new Cesium.Color(1, 1, 1, 0.9);
+			_self._viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; //相机与地形的碰撞检测,允许相机进入地下
+			_self._viewer.scene.globe.translucency.enabled = true; //地球将被渲染为半透明的球体。
+
+			resolve(result);
+		});
+	},
+
+	/**
+	 * 移除
+	 */
+	remove() {
+		/* 删除符合条件的所有实体 */
+		for (var i = 0; i < this.delEntitys.length; i++) {
+			this._viewer.entities.remove(this.delEntitys[i]);
+		}
+
+		this._viewer.scene.screenSpaceCameraController.enableCollisionDetection = true; //相机与地形的碰撞检测,允许相机进入地下
+		this._viewer.scene.globe.translucency.enabled = false; //地球将被渲染为半透明的球体。
+	},
+
+});
+
+export default CutFill;

+ 528 - 0
packages/Widgets/SpatialAnalysis/Cutting.js

@@ -0,0 +1,528 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/* 引入算法 */
+import * as turf from "@turf/turf";
+
+/**
+ * 剖切
+ * 目前仅支持凸多边形,如果绘制的是凹多边形,可能裁剪结果不正确
+ */
+class Cutting {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+		this._viewer = viewer;
+		this._camera = this._viewer.camera;
+		this._scene = this._viewer.scene;
+
+		this.targetY = 0.0;
+
+		this._mouseHandler();
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_mouseHandler() {
+		let _self = this;
+		let viewer = _self._viewer;
+		let scene = _self._scene;
+		let selectedPlane;
+
+		let downHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+
+		// 监听鼠标按下时,选择平面并设置样式
+		downHandler.setInputAction(function(movement) {
+			let pickedObject = scene.pick(movement.position);
+			if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id.plane)) {
+				// 获取选中平面对象
+				selectedPlane = pickedObject.id.plane;
+				// 选中时修改平面的材质透明度
+				selectedPlane.material = Cesium.Color.RED.withAlpha(0.05);
+				selectedPlane.outlineColor = Cesium.Color.RED;
+				// 当鼠标选中平面后,禁止场景的拖拽
+				scene.screenSpaceCameraController.enableInputs = false;
+			}
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+
+		// 监听鼠标向上释放时,平面设置样式
+		let upHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+		upHandler.setInputAction(function() {
+			if (Cesium.defined(selectedPlane)) {
+				// 鼠标松开时复原平面的材质透明度
+				selectedPlane.material = Cesium.Color.RED.withAlpha(0.1);
+				selectedPlane.outlineColor = Cesium.Color.RED;
+				selectedPlane = undefined;
+			}
+			// 当鼠标松开选中平面后,开启场景的拖拽
+			scene.screenSpaceCameraController.enableInputs = true;
+		}, Cesium.ScreenSpaceEventType.LEFT_UP);
+
+		// 监听鼠标选中移动时,设置平面
+		let moveHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+		moveHandler.setInputAction(function(movement) {
+			//当存在选中平面时执行
+			if (Cesium.defined(selectedPlane)) {
+				// 移动起点的高度减去移动终点的高度
+				let deltaY = movement.startPosition.y - movement.endPosition.y;
+				// 目标高度
+				_self.targetY += deltaY;
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	}
+
+
+	/**
+	 * 修改平面的高度
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_createPlaneUpdateFunction(plane) {
+		let _self = this;
+		return function() {
+			plane.distance = _self.targetY;
+			return plane;
+		};
+	}
+
+	/**
+	 * 创建裁剪面
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param p1 起始点
+	 * @param p2 结束点
+	 * @param inverseTransform 矩阵
+	 * @returns {*} ClippingPlane裁剪面(面法向量,点到面的垂直距离)
+	 */
+	_createPlane(p1, p2, inverseTransform) {
+		let _self = this;
+
+		// 将仅包含经纬度信息的p1,p2,转换为相应坐标系的cartesian3对象
+		let p1C3 = _self._getOriginCoordinateSystemPoint(p1, inverseTransform);
+		let p2C3 = _self._getOriginCoordinateSystemPoint(p2, inverseTransform);
+
+		// 定义一个垂直向上的向量up
+		let up = new Cesium.Cartesian3(0, 0, 10);
+		//  right 实际上就是由p1指向p2的向量 (这里是p2--》p1)
+		let right = Cesium.Cartesian3.subtract(p2C3, p1C3, new Cesium.Cartesian3());
+
+		// 计算normal, right叉乘up,得到平面法向量(垂直于两个向量),这个法向量指向right的右侧
+		let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3());
+		normal = Cesium.Cartesian3.normalize(normal, normal);
+
+		//由于已经获得了法向量和过平面的一点,因此可以直接构造Plane,并进一步构造ClippingPlane
+		let planeTmp = Cesium.Plane.fromPointNormal(p1C3, normal);
+		return Cesium.ClippingPlane.fromPlane(planeTmp);
+	}
+
+	/**
+	 * 对点进行坐标转换
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param point 点坐标 数组形式
+	 * @param inverseTransform 转换举证
+	 * @returns {*} ClippingPlane 裁切面
+	 */
+	_getOriginCoordinateSystemPoint(point, inverseTransform) {
+		let val = Cesium.Cartesian3.fromDegrees(point[0], point[1])
+		return Cesium.Matrix4.multiplyByPoint(
+			inverseTransform, val, new Cesium.Cartesian3(0, 0, 0))
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} tileSet
+	 */
+	_getInverseTransform(tileSet) {
+		let transform;
+
+		// 3dTiles模型加载后的矩阵,可以f12打印查看:tileset.root.transform
+		const tmp = tileSet.root.transform;
+		if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
+			transform = Cesium.Transforms.eastNorthUpToFixedFrame(tileSet.boundingSphere.center);
+		} else {
+			transform = Cesium.Matrix4.fromArray(tileSet.root.transform);
+		}
+
+		//转换矩阵
+		return Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} polygon
+	 * @param {Object} isClockwise
+	 */
+	_isDirRes(polygon, isClockwise) {
+		var lineStringList = [];
+		polygon.forEach((p) => {
+			lineStringList.push([p.lng, p.lat]);
+		});
+
+		var clockwiseRing = turf.lineString(lineStringList);
+		let isR = turf.booleanClockwise(clockwiseRing)
+
+		var points = [];
+		if (isClockwise) {
+			if (!isR) {
+				points = polygon
+			} else {
+				var count = 0;
+				for (var ii = polygon.length - 1; ii >= 0; ii--) {
+					points[count] = polygon[ii];
+					count++;
+				}
+			}
+		} else {
+			if (isR) {
+				points = polygon
+			} else {
+				var count = 0;
+				for (var ii = polygon.length - 1; ii >= 0; ii--) {
+					points[count] = polygon[ii];
+					count++;
+				}
+			}
+		}
+		return points
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(Cutting.prototype, /** @lends Cutting.prototype */ {
+	/**
+	 * 模型剪切
+	 * @param {Object} tileset
+	 */
+	activate(tileset) {
+		let _self = this;
+		let viewer = _self._viewer;
+
+		//转换矩阵
+		let inverseTransform = _self._getInverseTransform(tileset)
+		
+		// clippingPlane集合
+		// _self.polygon = _self._isDirRes(_self.polygon, false)
+		const clippingPlanes1 = []
+		// for (let i = 0; i < _self.polygon.length; i++) {
+		// 	if (i === (_self.polygon.length - 1)) {
+		clippingPlanes1.push(_self._createPlane([121.55814450142213, 37.39658788787028], [121.65814450142213, 37.49658788787028], inverseTransform))
+		// 	} else {
+		// 		clippingPlanes1.push(_self._createPlane(_self.polygon[i], _self.polygon[i + 1], inverseTransform))
+		// 	}
+		// }
+
+
+		// 创建裁剪平面
+		let clippingPlanes = new Cesium.ClippingPlaneCollection({
+			//一组ClippingPlane对象,用于选择性地禁用每个平面外部的渲染。
+			planes: [
+				// 裁剪面两个参数的:第一个为平面法向量,第二个为原点到平面的垂直距离
+				new Cesium.ClippingPlane(
+					//笛卡尔3:表示为三维空间的平面的法向量,x表示为该法向量在x轴上的分量,y表示为该法向量在y轴上的分量,z表示为该法向量在z轴上的分量
+					// new Cesium.Cartesian3(0.0, 0.0, -1.0),
+					// new Cesium.Cartesian3(1, 0, 0),
+					new Cesium.Cartesian3(0.0, 1.0, 0),
+					-10
+				),
+			],
+			// planes: clippingPlanes1,
+			//应用于裁剪对象的边缘的高光的宽度(以像素为单位)
+			edgeWidth: 1.0,
+		});
+
+		_self.tileset = tileset;
+		tileset.clippingPlanes = clippingPlanes; //切割面
+		tileset.debugShowBoundingVolume = false; //打开包围卷
+		// tileset.modelMatrix = new Cesium.Matrix4.fromTranslation(
+		// 	new Cesium.Cartesian3(15.0, -58.6, 50.825)
+		// );
+		// tileset.modelMatrix = new Cesium.Matrix4.fromTranslation(
+		// 	 Cesium.Cartesian3.fromDegrees(121.55814450142213, 37.39658788787028)
+		// );
+		// 当模型准备好时执行
+		return tileset.readyPromise
+			.then(function() {
+
+
+				let boundingSphere = tileset.boundingSphere; //外包球
+				let radius = boundingSphere.radius; //外包球半径
+
+				// 定位到模型,并设置相机的俯仰角和距离
+				viewer.zoomTo(
+					tileset,
+					new Cesium.HeadingPitchRange(0.5, -0.2, radius / 5)
+				);
+
+				// let pointEntity = _self._viewer.entities.add({
+				// 	position: boundingSphere.center,
+				// 	point: {
+				// 		pixelSize: 0,
+				// 	},
+				// });
+				// _self.LocateUtil.flyToEntity(pointEntity);
+
+				if (
+					!Cesium.Matrix4.equals(
+						tileset.root.transform,
+						Cesium.Matrix4.IDENTITY
+					)
+				) {
+					// The clipping plane is initially positioned at the tileset's root transform.
+					// Apply an additional matrix to center the clipping plane on the bounding sphere center.
+					//裁剪平面最初定位于tileset的根变换。
+					//应用一个额外的矩阵使裁剪平面在边界球中心居中。
+					const transformCenter = Cesium.Matrix4.getTranslation(tileset.root.transform, new Cesium.Cartesian3());
+					const transformCartographic = Cesium.Cartographic.fromCartesian(transformCenter);
+					const boundingSphereCartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
+					const height = boundingSphereCartographic.height - transformCartographic.height;
+					clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, 0.0, height));
+				}
+
+				
+				for (let i = 0; i < clippingPlanes.length; ++i) {
+					const plane = clippingPlanes.get(i);
+					// let plane = _self._createPlane([121.55814450142213, 37.39658788787028], [121.65814450142213, 37.49658788787028], inverseTransform)
+					const planeEntity = viewer.entities.add({
+						position: boundingSphere.center, // 笛卡儿坐标系的原点位置为模型外接圆的圆心
+						plane: {
+							dimensions: new Cesium.Cartesian2( // 范围
+								radius / 10,
+								radius / 10
+							),
+							material: Cesium.Color.WHITE.withAlpha(0.1), //设置材质透明度
+							plane: new Cesium.CallbackProperty( //使用回调函数,动态改变模型位置
+								_self._createPlaneUpdateFunction(plane),
+								false
+							),
+							outline: true, // 轮廓
+							outlineColor: Cesium.Color.WHITE, //轮廓颜色
+						},
+					});
+
+					// _self.planeEntities.push(planeEntity);
+				}
+
+				// // 遍历添加裁切面模型
+				// for (let i = 0; i < clippingPlanes.length; ++i) {
+				// 	let plane = clippingPlanes.get(i);
+				// 	let planeEntity = viewer.entities.add({
+				// 		// 笛卡儿坐标系的原点位置为模型外接圆的圆心
+				// 		position: boundingSphere.center,
+				// 		plane: {
+				// 			// 范围
+				// 			dimensions: new Cesium.Cartesian2(
+				// 				radius / 10,
+				// 				radius / 10
+				// 			),
+				// 			//设置材质透明度
+				// 			material: Cesium.Color.RED.withAlpha(0.1),
+				// 			//使用回调函数,动态改变模型位置
+				// 			plane: new Cesium.CallbackProperty(
+				// 				_self._createPlaneUpdateFunction(plane),
+				// 				false
+				// 			),
+				// 			// 轮廓
+				// 			outline: true,
+				// 			//轮廓颜色
+				// 			outlineColor: Cesium.Color.RED,
+				// 		},
+				// 	});
+				// }
+				return tileset;
+			})
+
+	},
+
+	/**
+	 * 添加3dTiles模型
+	 */
+	addTiles(my3dtiles, pointsArray) {
+
+		let _self = this;
+		let viewer = _self._viewer;
+		let tileset = my3dtiles;
+		_self.polygon = pointsArray;
+		_self.tileset = tileset;
+
+		// 当模型准备好时执行
+		return tileset.readyPromise.then(function() {
+			//转换矩阵
+			let inverseTransform = _self._getInverseTransform(tileset)
+			
+			// clippingPlane集合
+			_self.polygon = _self._isDirRes(_self.polygon, false)
+			const clippingPlanes1 = []
+			for (let i = 0; i < _self.polygon.length; i++) {
+				if (i === (_self.polygon.length - 1)) {
+					clippingPlanes1.push(_self._createPlane(_self.polygon[i], _self.polygon[0], inverseTransform))
+				} else {
+					clippingPlanes1.push(_self._createPlane(_self.polygon[i], _self.polygon[i + 1], inverseTransform))
+				}
+			}
+
+			// 创建裁剪平面
+			let clippingPlanes = new Cesium.ClippingPlaneCollection({
+				//一组ClippingPlane对象,用于选择性地禁用每个平面外部的渲染。
+				planes: clippingPlanes1,
+				//应用于裁剪对象的边缘的高光的宽度(以像素为单位)
+				edgeWidth: 1.0,
+				edgeColor: Cesium.Color.RED,
+				unionClippingRegions: false, //true 才能多个切割  
+			});
+
+			_self.clippingPlanes = clippingPlanes;
+
+			tileset.clippingPlanes = clippingPlanes; //切割面
+			tileset.debugShowBoundingVolume = false; //打开包围卷
+
+
+			let boundingSphere = tileset.boundingSphere; //外包球
+			let radius = boundingSphere.radius; //外包球半径
+			
+
+			// 遍历添加裁切面模型
+			for (let i = 0; i < clippingPlanes.length; ++i) {
+				let plane = clippingPlanes.get(i);
+				let planeEntity = viewer.entities.add({
+					// 笛卡儿坐标系的原点位置为模型外接圆的圆心
+					position: boundingSphere.center,
+					plane: {
+						// 范围
+						dimensions: new Cesium.Cartesian2(
+							radius / 10,
+							radius / 10
+						),
+						//设置材质透明度
+						material: Cesium.Color.RED.withAlpha(0.1),
+						//使用回调函数,动态改变模型位置
+						plane: new Cesium.CallbackProperty(
+							_self._createPlaneUpdateFunction(plane),
+							false
+						),
+						// 轮廓
+						outline: true,
+						//轮廓颜色
+						outlineColor: Cesium.Color.RED,
+					},
+				});
+			}
+
+			return tileset;
+		})
+	},
+
+	/**
+	 * 添加3dTiles模型
+	 */
+	addTiles2(my3dtiles, pointsArray) {
+
+		let _self = this;
+		let viewer = _self._viewer;
+		let tileset = my3dtiles;
+		_self.polygon = pointsArray;
+		_self.tileset = tileset;
+
+		// 3dTiles模型初始化位置的矩阵
+		let Matrix4 = Cesium.Matrix4.fromArray(
+			[1, 5.551115123125783e-16, 5.898416033378595e-9, 0,
+				-6.106226635438361e-16, 1, -1.1355608731111744e-8, 0,
+				-5.898416061134171e-9, 1.1355608731111744e-8, 0.9999999999999999, 0,
+				9.912469893228263, -19.08345020748675, -14.613607150502503, 1
+			]
+		);
+
+		// 3dTiles模型加载后的矩阵,可以f12打印查看:tileset.root.transform
+		let transform = Cesium.Matrix4.fromArray(
+			[-0.8874246461620654, -0.46095281470464317, 0, 0,
+				0.2602796082288922, -0.5010893346724129, 0.8253266045740758, 0,
+				-0.3804366214290463, 0.7324151700322881, 0.5646556435405804, 0,
+				-2429070.591483741, 4676437.67731705, 3581165.448379543, 1
+			]);
+
+		//转换矩阵
+		let inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
+		// clippingPlane集合
+		let clippingPlanes1 = [];
+		for (let i = 0; i < _self.polygon.length - 1; i++) {
+			let plane = _self.createPlane(_self.polygon[i], _self.polygon[i + 1], inverseTransform);
+			clippingPlanes1.push(plane);
+		}
+
+		// 创建裁剪平面
+		let clippingPlanes = new Cesium.ClippingPlaneCollection({
+			//一组ClippingPlane对象,用于选择性地禁用每个平面外部的渲染。
+			planes: clippingPlanes1,
+			//应用于裁剪对象的边缘的高光的宽度(以像素为单位)
+			edgeWidth: 1.0,
+			edgeColor: Cesium.Color.RED,
+			unionClippingRegions: false, //true 才能多个切割  
+		});
+
+		_self.clippingPlanes = clippingPlanes;
+
+		// 当模型准备好时执行
+		return tileset.readyPromise.then(function() {
+
+
+			tileset.clippingPlanes = clippingPlanes; //切割面
+			tileset.debugShowBoundingVolume = false; //打开包围卷
+
+
+			let boundingSphere = tileset.boundingSphere; //外包球
+			let radius = boundingSphere.radius; //外包球半径
+			
+
+			// // 遍历添加裁切面模型
+			// for (let i = 0; i < clippingPlanes.length; ++i) {
+			// 	let plane = clippingPlanes.get(i);
+			// 	let planeEntity = viewer.entities.add({
+			// 		// 笛卡儿坐标系的原点位置为模型外接圆的圆心
+			// 		position: boundingSphere.center,
+			// 		plane: {
+			// 			// 范围
+			// 			dimensions: new Cesium.Cartesian2(
+			// 				radius / 10,
+			// 				radius / 10
+			// 			),
+			// 			//设置材质透明度
+			// 			material: Cesium.Color.RED.withAlpha(0.1),
+			// 			//使用回调函数,动态改变模型位置
+			// 			plane: new Cesium.CallbackProperty(
+			// 				_self._createPlaneUpdateFunction(plane),
+			// 				false
+			// 			),
+			// 			// 轮廓
+			// 			outline: true,
+			// 			//轮廓颜色
+			// 			outlineColor: Cesium.Color.RED,
+			// 		},
+			// 	});
+			// }
+
+			return tileset;
+		})
+	},
+
+	/**
+	 * 移除裁切面
+	 */
+	toggleClipping() {
+	
+		let _self = this;
+		// 	if (_self.isShowTileSet) {
+		// _self.tileset.clippingPlanes = null;
+		// 		_self.isShowTileSet = false;
+		// 	} else {
+		// 		_self.tileset._clippingPlanes = _self.clippingPlanes;
+		// 		_self.isShowTileSet = true;
+		// 	}
+		_self.tileset = null;
+	},
+});
+
+export default Cutting;

+ 304 - 0
packages/Widgets/SpatialAnalysis/GeologyClipPlan.js

@@ -0,0 +1,304 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 剖切
+ */
+class GeologyClipPlan {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+		this._camera = this._viewer.camera;
+		this._scene = this._viewer.scene;
+
+		this.tileset = undefined;
+		this.targetY = 0.0;
+		this.planeEntities = [];
+
+		this._mouseHandler();
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_mouseHandler() {
+		let _self = this;
+		let viewer = _self._viewer;
+		let scene = _self._scene;
+		let selectedPlane;
+
+		let downHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+
+		// 监听鼠标按下时,选择平面并设置样式
+		downHandler.setInputAction(function(movement) {
+			let pickedObject = scene.pick(movement.position);
+			if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id.plane)) {
+				// 获取选中平面对象
+				selectedPlane = pickedObject.id.plane;
+				// 选中时修改平面的材质透明度
+				selectedPlane.material = Cesium.Color.RED.withAlpha(0.05);
+				selectedPlane.outlineColor = Cesium.Color.RED;
+				// 当鼠标选中平面后,禁止场景的拖拽
+				scene.screenSpaceCameraController.enableInputs = false;
+			}
+		}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+
+		// 监听鼠标向上释放时,平面设置样式
+		let upHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+		upHandler.setInputAction(function() {
+			if (Cesium.defined(selectedPlane)) {
+				// 鼠标松开时复原平面的材质透明度
+				selectedPlane.material = Cesium.Color.RED.withAlpha(0.1);
+				selectedPlane.outlineColor = Cesium.Color.RED;
+				selectedPlane = undefined;
+			}
+			// 当鼠标松开选中平面后,开启场景的拖拽
+			scene.screenSpaceCameraController.enableInputs = true;
+		}, Cesium.ScreenSpaceEventType.LEFT_UP);
+
+		// 监听鼠标选中移动时,设置平面
+		let moveHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+		moveHandler.setInputAction(function(movement) {
+			//当存在选中平面时执行
+			if (Cesium.defined(selectedPlane)) {
+				// 移动起点的高度减去移动终点的高度
+				let deltaY = movement.startPosition.y - movement.endPosition.y;
+				// 目标高度
+				_self.targetY += deltaY;
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	}
+
+	/**
+	 * 修改平面的高度
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_createPlaneUpdateFunction(plane) {
+		let _self = this;
+		return function() {
+			plane.distance = _self.targetY;
+			return plane;
+		};
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(GeologyClipPlan.prototype, /** @lends GeologyClipPlan.prototype */ {
+
+	/**
+	 * @param {Object} tileset
+	 * @param {Object} options
+	 */
+	activate(tileset, options) {
+		let _self = this;
+
+		options = options || {};
+
+
+		let viewer = _self._viewer;
+
+		// 创建裁剪平面
+		let distance = 100000; //从原点到平面的最短距离。距离的符号决定了原点在平面的哪一边。如果距离为正,原点在法线方向的半空间中;如果是负的,原点在与法线相对的半空间中;如果为零,平面穿过原点。
+
+		// 定义一个ClippingPlaneCollection类,用来存储裁剪面
+		let clippingPlanes = new Cesium.ClippingPlaneCollection({
+			// modelMatrix: Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, -500, Math.abs(2))),
+			// modelMatrix: Cesium.Matrix4.IDENTITY,
+			//一组ClippingPlane对象,用于选择性地禁用每个平面外部的渲染。
+			planes: [ // ClippingPlane对象数组集合
+				// 裁剪面两个参数的:第一个为平面法向量,第二个为原点到平面的垂直距离
+				new Cesium.ClippingPlane( // 裁切面
+					//笛卡尔3:表示为三维空间的平面的法向量,x表示为该法向量在x轴上的分量,y表示为该法向量在y轴上的分量,z表示为该法向量在z轴上的分量
+					new Cesium.Cartesian3(0.0, 0.0, -1.0), // 法线
+					// new Cesium.Cartesian3(1, 0, 0),
+					// new Cesium.Cartesian3(0.0, 1.0, 0),
+					distance, //原点到平面的最短距离,设置0就好
+				),
+			],
+			//应用于裁剪对象的边缘的高光的宽度(以像素为单位)
+			edgeWidth: 1.0, //模型被裁切部分的截面线宽
+		});
+
+		_self.tileset = tileset;
+		tileset.clippingPlanes = clippingPlanes; //切割面
+		tileset.debugShowBoundingVolume = false; //打开包围卷
+		// tileset.modelMatrix = Cesium.Matrix4.fromArray(
+		// 	[0.9972458032561666, 0.04372029028528979, 0.05991113506964879, 0,
+		// 		-0.03623787897545647, 0.9920229449104262, -0.12073646051879428, 0,
+		// 		-0.06471185374661931, 0.11823287609043515, 0.9908750491338749, 0,
+		// 		-663.0794944260269, 1211.490494620055, 2974.1003134818748, 1
+		// 	]);
+
+		// 当模型准备好时执行
+		return tileset.readyPromise
+			.then(function() {
+
+				let boundingSphere = tileset.boundingSphere; //外包球
+				let radius = boundingSphere.radius; //外包球半径
+				
+
+				if (
+					!Cesium.Matrix4.equals( // Cesium.Matrix4.equals(a,b)判断两个四维矩阵是否相等
+						tileset.root.transform, // 整个根节点模型矩阵,该tileSet=>世界坐标系
+						Cesium.Matrix4.IDENTITY // 单位矩阵,对角线值为1.0的4*4矩阵
+					)
+				) {
+					// The clipping plane is initially positioned at the tileset's root transform.
+					// Apply an additional matrix to center the clipping plane on the bounding sphere center.
+
+					// 获取模型的世界坐标(笛卡尔)
+					// Cesium.Matrix4.getTranslation 通过仿射变换矩阵获取该tileSet的世界坐标
+					const transformCenter = Cesium.Matrix4.getTranslation(
+						tileset.root.transform,
+						new Cesium.Cartesian3()
+					);
+
+					// 将笛卡尔坐标转换为WGS84经纬度坐标(模型的)
+					const transformCartographic = Cesium.Cartographic.fromCartesian(
+						transformCenter
+					);
+					// 将笛卡尔坐标转换为WGS84经纬度坐标(截面的)
+					const boundingSphereCartographic = Cesium.Cartographic.fromCartesian(
+						tileset.boundingSphere.center
+					);
+					const height = boundingSphereCartographic.height - transformCartographic.height;
+
+					// 从一个Cartesian3对象生成Matrix4变换矩阵(裁切面的)
+					clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, 0.0, height));
+				}
+
+				//中心点
+				// let entity = viewer.entities.add({
+				// 	position: Cartesian33,
+				// 	point: {
+				// 		pixelSize: 10,
+				// 		color: new Cesium.Color.fromCssColorString("red"),
+				// 		outlineColor: new Cesium.Color.fromCssColorString("blue"),
+				// 		outlineWidth: 2,
+				// 		heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //指定高度相对于什么的属性。
+				// 		disableDepthTestDistance: Number.POSITIVE_INFINITY, //指定距离相机的距离,在这个距离上禁用深度测试。
+				// 	}
+				// });			
+
+				// 定位到模型,并设置相机的俯仰角和距离
+				viewer.zoomTo(
+					tileset,
+					new Cesium.HeadingPitchRange(0.5, -0.2, radius / 10)
+				);
+
+				// Cesium.Matrix4.multiplyByPoint(tileset.root.transform, boundingSphere.center, new Cesium.Cartesian3(0, 0, 0))
+
+				// clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, radius/10, 0));
+
+				// const redPlane = viewer.entities.add({
+				// 	name: "Red plane with black outline",
+				// 	position:Cartesian33,
+				// 	plane: {
+				// 		plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Y, 0.0),
+				// 		dimensions: new Cesium.Cartesian2(200.0, 200.0),
+				// 		material: Cesium.Color.RED.withAlpha(0.5),
+				// 		outline: true,
+				// 		outlineColor: Cesium.Color.BLACK,
+				// 	},
+				// });
+
+				// const outlineOnly = viewer.entities.add({
+				// 	name: "Yellow plane outline",
+				// 	position: Cartesian33,
+				// 	plane: {
+				// 		plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Z, 0.0),
+				// 		dimensions: new Cesium.Cartesian2(200.0, 200.0),
+				// 		fill: false,
+				// 		outline: true,
+				// 		outlineColor: Cesium.Color.YELLOW,
+				// 	},
+				// });
+
+				let cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
+				//将弧度转为度的十进制度表示
+				let lng = Cesium.Math.toDegrees(cartographic.longitude);
+				let lat = Cesium.Math.toDegrees(cartographic.latitude);
+				let alt = cartographic.height; //模型高度
+				var Cartesian33 = Cesium.Cartesian3.fromDegrees(lng, lat, 105)
+				
+
+				// 遍历添加裁切面模型
+				for (let i = 0; i < clippingPlanes.length; ++i) {
+					let plane = clippingPlanes.get(i);
+					let planeEntity = viewer.entities.add({
+						// 笛卡儿坐标系的原点位置为模型外接圆的圆心
+						position: Cartesian33,
+						plane: {
+							// 范围
+							dimensions: new Cesium.Cartesian2(
+								radius / 10,
+								radius / 20
+							),
+							// dimensions: new Cesium.Cartesian2(
+							// 	200,
+							// 	200
+							// ),
+							//设置材质透明度
+							material: Cesium.Color.RED.withAlpha(0.1),
+							//使用回调函数,动态改变模型位置
+							plane: new Cesium.CallbackProperty(
+								_self._createPlaneUpdateFunction(plane),
+								false
+							),
+							// 轮廓
+							outline: true,
+							//轮廓颜色
+							outlineColor: Cesium.Color.RED,
+						},
+					});
+
+					_self.planeEntities.push(planeEntity);
+				}
+				return tileset;
+			})
+
+	},
+	
+	/**
+	 * 移除裁切面
+	 */
+	toggleClipping() {
+		let _self = this;
+		// // if (_self.isShowTileSet) {
+		// _self.tileset._clippingPlanes = null;
+		// // 	_self.isShowTileSet = false;
+		// // } else {
+		// // 	_self.tileset._clippingPlanes = _self.clippingPlanes;
+		// // 	_self.isShowTileSet = true;
+		// // }
+		
+		for (let i = 0; i < _self.planeEntities.length; i++) {
+			_self._viewer.entities.remove(_self.planeEntities[i]);
+		}
+
+		_self.planeEntities = [];
+		_self.targetY = 0.0;
+
+		let boundingSphere = _self.tileset.boundingSphere;
+		_self._camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(Cesium.Math.toRadians(120.0), Cesium.Math.toRadians(-10), boundingSphere.radius * 2.5))
+		_self._camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
+	},
+
+	// Track and create the bindings for the view model
+	reset() {
+		// viewer.entities.removeAll();
+		// viewer.scene.primitives.remove(tileset);
+		this.planeEntities = [];
+		this.targetY = 0.0;
+		// tileset = undefined;
+	}
+
+});
+
+export default GeologyClipPlan;

+ 167 - 0
packages/Widgets/SpatialAnalysis/HeightLimit.js

@@ -0,0 +1,167 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/* 引入算法 */
+import * as turf from "@turf/turf";
+
+/**
+ * 限高分析
+ */
+class HeightLimit {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+
+		this.targetY = 0;
+	}
+
+	/**
+	 * 这里主要是为了添加一个高出地面的 polygon , 用到的经纬度数据和需要校验的建筑物数据一样
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} options
+	 */
+	_setPolygon(options) {
+		let _self = this;
+		_self.HiePolygon = _self._viewer.entities.add({
+			polygon: {
+				hierarchy: new Cesium.PolygonHierarchy(_self.data),
+				material: _self._handleColor('#FFF8DC', options.alpha),
+				height: new Cesium.CallbackProperty(_self._createPolygonUpdateFunction(), false),
+				perPositionHeight: false,
+				outline: true,
+				outlineColor: _self._handleColor('red', options.alpha),
+				outlineWidth: 1.0,
+			}
+		});
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_createPolygonUpdateFunction() {
+		let _self = this;
+		return function() {
+			return _self.targetY;
+		};
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} color
+	 * @param {Object} alpha
+	 */
+	_handleColor(color, alpha) {
+		return Cesium.Color.fromCssColorString(color).withAlpha(alpha || 1);
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * 获取最小高度
+	 */
+	_getMinHeight(points) {
+		let height = 0;
+		let positions = points.map(point => {
+			let _height = point[2] || 0;
+			height = _height;
+			if (_height < height) {
+				height = _height;
+			}
+		});
+		return height;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(HeightLimit.prototype, /** @lends HeightLimit.prototype */ {
+	/**
+	 * 绘制限高区域
+	 */
+	addPrimitive(points, options) {
+
+		this.removePrimitive();
+
+		options = options || {};
+		options.height = Cesium.defaultValue(options.height, 50);
+
+		//图上选点获取最小高度
+		options.baseHeight = Cesium.defaultValue(options.baseHeight, 50);
+		// //根据坐标获取最小高度
+		// options.baseHeight = this._getMinHeight(points);
+
+		options.color = Cesium.defaultValue(options.color, 'red');
+		options.alpha = Cesium.defaultValue(options.alpha, 0.6);
+
+		/* 转换坐标 */
+		let positions = points.map(point => {
+			return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+		});
+
+		let _self = this;
+		_self.data = positions;
+		_self.baseHeight = options.baseHeight;
+		_self.targetY = options.baseHeight + options.height;
+
+		let polygonInstance = new Cesium.GeometryInstance({
+			geometry: new Cesium.PolygonGeometry({
+				polygonHierarchy: new Cesium.PolygonHierarchy(_self.data),
+				height: _self.baseHeight, //分层底部海拔
+				extrudedHeight: _self.baseHeight + 3000, //分层顶部海拔
+			}),
+			attributes: {
+				color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+					Cesium.Color.fromCssColorString(options.color).withAlpha(options.alpha)
+				), //设置高亮颜色
+				show: new Cesium.ShowGeometryInstanceAttribute(true), //设置初始化后是否显示
+			}
+		});
+
+		_self.limitHeightPrimitive = _self._viewer.scene.primitives.add(
+			new Cesium.ClassificationPrimitive({ //ClassificationPrimitive 用来生成可以穿透
+				geometryInstances: polygonInstance,
+				releaseGeometryInstances: false,
+				classificationType: Cesium.ClassificationType.CESIUM_3D_TILE, //只绘制在3dtiles上
+			})
+		);
+
+		// 这里主要是为了添加一个高出地面的 polygon , 用到的经纬度数据和需要校验的建筑物数据一样
+		_self._setPolygon(options)
+	},
+
+	/**
+	 * 移除限高分析
+	 */
+	removePrimitive() {
+		if (this.HiePolygon) {
+			this._viewer.entities.remove(this.HiePolygon); //移除图层
+		}
+		if (this.limitHeightPrimitive) {
+			this._viewer.scene.primitives.remove(this.limitHeightPrimitive); //移除图层
+		}
+	},
+
+	/**
+	 * 高度变化 
+	 * @param {Object} height
+	 */
+	changeHeight(height) {
+
+		if (!this.limitHeightPrimitive) return;
+
+		// this._height = height - this.baseHeight;
+		this.targetY = this.baseHeight + height;
+
+		let cartographic = Cesium.Cartographic.fromCartesian(this.limitHeightPrimitive._primitive._boundingSpheres[0].center);
+		let surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, this.baseHeight);
+		let offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, this.baseHeight + height);
+		let translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
+		this.limitHeightPrimitive._primitive.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
+	},
+});
+
+export default HeightLimit;

+ 142 - 0
packages/Widgets/SpatialAnalysis/Profile.js

@@ -0,0 +1,142 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 剖面分析
+ */
+class Profile {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+		this._profileEntities = [];
+	}
+
+	/**
+	 * 线段插值点
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {*} positions 线段节点集合
+	 * @param {*} objectsToExclude 高度采集时排除的对象集合
+	 * @returns 经纬度点集合,包含距离值
+	 */
+	_interPoints(positions, objectsToExclude) {
+		let positionsCartographic = [];
+		let terrainSamplePositions = [];
+		for (let index = 0; index < positions.length; index++) {
+			const element = positions[index];
+			let ellipsoid = this._viewer.scene.globe.ellipsoid;
+			let cartographic = ellipsoid.cartesianToCartographic(element);
+			positionsCartographic.push(cartographic);
+		}
+		for (let i = 0; i < positionsCartographic.length; i++) {
+			const m_Cartographic0 = positionsCartographic[i];
+			const m_Cartographic1 = positionsCartographic[i + 1];
+			if (m_Cartographic1) {
+				let a = Math.abs(m_Cartographic0.longitude - m_Cartographic1.longitude) * 10000000;
+				let b = Math.abs(m_Cartographic0.latitude - m_Cartographic1.latitude) * 10000000;
+				//等距采样
+				if (a > b) b = a;
+				let length = parseInt(b / 2);
+				if (length > 1000) length = 1000;
+				if (length < 2) length = 2;
+				for (let j = 0; j < length; j++) {
+					terrainSamplePositions.push(
+						new Cesium.Cartographic(
+							Cesium.Math.lerp(
+								m_Cartographic0.longitude,
+								m_Cartographic1.longitude,
+								j / (length - 1)
+							),
+							Cesium.Math.lerp(
+								m_Cartographic0.latitude,
+								m_Cartographic1.latitude,
+								j / (length - 1)
+							)
+						)
+					);
+				}
+				terrainSamplePositions.pop();
+			} else {
+				terrainSamplePositions.push(m_Cartographic0);
+			}
+		}
+		let positions_Inter = [];
+		let distance = 0;
+		for (let n = 0; n < terrainSamplePositions.length; n++) {
+			//地理坐标(弧度)转经纬度坐标
+			let curCartographic = terrainSamplePositions[n];
+			let height = this._viewer.scene.sampleHeight(curCartographic, objectsToExclude);
+			const lon = (curCartographic.longitude / Math.PI) * 180;
+			const lat = (curCartographic.latitude / Math.PI) * 180;
+			let point = Cesium.Cartesian3.fromDegrees(lon, lat, height);
+			let preCartographic = terrainSamplePositions[n - 1];
+			if (preCartographic) {
+				const lon1 = (preCartographic.longitude / Math.PI) * 180;
+				const lat1 = (preCartographic.latitude / Math.PI) * 180;
+				let point1 = Cesium.Cartesian3.fromDegrees(lon1, lat1, height);
+				let curDis = Cesium.Cartesian3.distance(point1, point);
+				distance += curDis;
+			}
+			positions_Inter.push({
+				position: {
+					lon: lon,
+					lat: lat,
+					height: height
+				},
+				distance: distance,
+			});
+		}
+		return positions_Inter;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(Profile.prototype, /** @lends Profile.prototype */{
+
+	/**
+	 * 开启剖面分析
+	 * @param {Object} [points] 坐标:[lng,lat,lng,lat,......]  
+	 * @param {Object} entity 线对象
+	 */
+	startProfileAnalysis(points, entity) {
+		//异步函数
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+
+			/* 转换坐标 */
+			let positions = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			_self.removeProfileAnalysis();
+
+			entity.clampToGround = true;
+			console.log(positions);
+			let pointsList = _self._interPoints(positions, [entity]);
+			console.log(pointsList);
+
+			resolve(pointsList);
+		});
+	},
+
+	/**
+	 * 移除剖面检测
+	 */
+	removeProfileAnalysis() {
+		let _self = this;
+		if (_self._profileEntities && _self._profileEntities.length > 0) {
+			_self._profileEntities.forEach((element) => {
+				_self._viewer.entities.remove(element);
+			});
+		}
+		_self._profileEntities = [];
+	},
+});
+
+export default Profile;

+ 408 - 0
packages/Widgets/SpatialAnalysis/SightLine.js

@@ -0,0 +1,408 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import CreateRemindertip from "../common/ReminderTip.js";
+import CoordTransform from "../common/CoordTransform.js";
+
+/**
+ * 视线分析 通视分析 透视分析
+ */
+class SightLine {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+
+		this._resultObject = {
+			viewPoint: undefined, //通视分析起点
+			targetPoints: [], //通视分析目标点集合
+			targetPoint: undefined, //当前目标点
+			objectExclude: [], //射线排除集合
+			entities: [], //创建的Entity对象
+		};
+	}
+
+	/**
+	 * 空间两点间距离
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} point1
+	 * @param {Object} point2
+	 */
+	_distance(point1, point2) {
+		let point1cartographic = Cesium.Cartographic.fromCartesian(point1);
+		let point2cartographic = Cesium.Cartographic.fromCartesian(point2);
+		/**根据经纬度计算出距离**/
+		let geodesic = new Cesium.EllipsoidGeodesic();
+		geodesic.setEndPoints(point1cartographic, point2cartographic);
+		let s = geodesic.surfaceDistance;
+		//返回两点之间的距离
+		s = Math.sqrt(
+			Math.pow(s, 2) +
+			Math.pow(point2cartographic.height - point1cartographic.height, 2)
+		);
+		return s;
+	}
+
+	/**
+	 * 检测程序运行环境
+	 * @return {SightLine.RuntimeEnvironment}
+	 */
+	_checkAppOrWeb() {
+		if (window.navigator.userAgent.match(
+				/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+			)) {
+			return SightLine.RuntimeEnvironment.App;
+		} else {
+			return SightLine.RuntimeEnvironment.Web;
+		}
+	}
+
+	/**
+	 * 是否是运行于App
+	 * @ignore
+	 */
+	_isRuntimeApp() {
+		if (this._checkAppOrWeb() === SightLine.RuntimeEnvironment.App) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * 是否是运行于App
+	 * @ignore
+	 */
+	_isRuntimeWeb() {
+		if (this._checkAppOrWeb() === SightLine.RuntimeEnvironment.Web) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * @ignore
+	 * 创建操作的主容器
+	 */
+	_createOperationMainDom() {
+		//创建画布
+		let buttonDiv = document.createElement('div');
+		buttonDiv.id = "drawButtonDiv";
+		buttonDiv.style.width = '80px';
+		buttonDiv.style.backgroundColor = 'rgba(5, 45, 155, 0.7)';
+		buttonDiv.style.borderRadius = '5px';
+		buttonDiv.style.display = 'flex';
+		buttonDiv.style.flexDirection = 'column';
+		buttonDiv.style.padding = '8px';
+		buttonDiv.style.justifyContent = 'center';
+		buttonDiv.style.position = 'absolute';
+		buttonDiv.style.bottom = '150px';
+		buttonDiv.style.right = '10px';
+
+		// let btnUndo = document.createElement('button');
+		// btnUndo.id = "btnDrawBackout";
+		// btnUndo.style.height = '30px';
+		// btnUndo.style.marginBottom = '8px';
+		// btnUndo.style.backgroundColor = 'rgba(52, 137, 255, 1.0)';
+		// btnUndo.style.color = 'rgb(255, 255, 255)';
+		// btnUndo.style.border = '0px solid red';
+		// btnUndo.style.borderRadius = '5px';
+		// btnUndo.innerHTML = '回退';
+		// btnUndo.style.fontSize = '13px';
+		// btnUndo.style.cursor = 'pointer';
+		// buttonDiv.appendChild(btnUndo);
+
+		let btnCompletion = document.createElement('button');
+		btnCompletion.id = "btnDrawComplete";
+		btnCompletion.style.height = '30px';
+		btnCompletion.style.backgroundColor = 'rgba(88, 185, 45, 1.0)';
+		btnCompletion.style.color = 'rgb(255, 255, 255)';
+		btnCompletion.style.border = '0px solid red';
+		btnCompletion.style.borderRadius = '5px';
+		btnCompletion.innerHTML = '完成';
+		btnCompletion.style.fontSize = '13px';
+		btnCompletion.style.cursor = 'pointer';
+		buttonDiv.appendChild(btnCompletion);
+
+		/* 加入到页面 */
+		document.body.appendChild(buttonDiv);
+	}
+
+	/**
+	 * 创建顶部弹出提示消息 1秒后自动消失
+	 * @ignore
+	 * @param {String} message 消息内容
+	 */
+	_showTooltipMessage(message) {
+		let msgMainDom = document.getElementById('messageMainDom');
+		if (msgMainDom !== null && msgMainDom !== undefined) {
+			document.body.removeChild(msgMainDom);
+		}
+		msgMainDom = document.createElement('div');
+		msgMainDom.style.width = '30%';
+		msgMainDom.style.backgroundColor = 'rgba(237, 248, 230, 1.0)';
+		msgMainDom.style.height = '45px';
+		msgMainDom.style.border = 'solid 2px rgb(219, 241, 208)';
+		msgMainDom.style.borderRadius = '8px';
+		msgMainDom.style.display = 'flex';
+		msgMainDom.style.alignItems = 'center';
+		msgMainDom.style.paddingLeft = '10px';
+		msgMainDom.style.color = 'rgb(91, 188, 48)';
+		msgMainDom.style.fontSize = '14px';
+		msgMainDom.style.fontWeight = '600';
+		msgMainDom.style.position = 'absolute';
+		msgMainDom.style.left = '35%';
+		msgMainDom.style.transition = 'transform 1s';
+		msgMainDom.style.transform = 'translateY(-90px)';
+		msgMainDom.style.top = '0px';
+		msgMainDom.style.zIndex = 1000;
+		document.body.appendChild(msgMainDom);
+
+		let strHtml = '';
+		strHtml += "<div style='"
+		strHtml += "background-color: rgb(88, 185, 45);";
+		strHtml += "color: rgb(255, 255, 255);";
+		strHtml += "height: 24px;";
+		strHtml += "width: 24px;";
+		strHtml += "border-radius: 20px;";
+		strHtml += "display: flex;";
+		strHtml += "justify-content: center;";
+		strHtml += "align-items: center;";
+		strHtml += "font-size: 14px;";
+		strHtml += "margin-right: 18px;";
+		strHtml += "'>&#10003</div>";
+		strHtml += "<div>" + message + "</div>";
+
+		msgMainDom.innerHTML = strHtml;
+		msgMainDom.addEventListener('transitionend', function() {
+			setTimeout(function() {
+				document.body.removeChild(msgMainDom);
+			}, 1000);
+		}, false);
+
+		setTimeout(function() {
+			msgMainDom.style.transform = 'translateY(50px)';
+		}, 100)
+	}
+}
+
+/**
+ * 通用对外公开函数
+ */
+Object.assign(SightLine.prototype, /** @lends SightLine.prototype */ {
+
+	/**
+	 * 开启通视分析
+	 */
+	startSightLine() {
+		let _self = this;
+		_self.clearAll();
+
+		let toolTip = "左键单击创建视角起点";
+		if (this._isRuntimeApp()) {
+			toolTip = "单击创建视角起点";
+			_self._showTooltipMessage(toolTip);
+		}
+
+		_self.handler = new Cesium.ScreenSpaceEventHandler(_self._viewer.canvas);
+		_self.handler.setInputAction((event) => {
+			let loc = CoordTransform._transfromFromScreenPoint(_self._viewer, event.position);
+			toolTip = "左键创建视角终点,右键结束通视分析";
+			if (this._isRuntimeApp()) {
+				toolTip = "再次单击创建视角终点";
+				_self._showTooltipMessage(toolTip);
+			}
+
+			if (!Cesium.defined(loc.sLocation)) return;
+
+			let cartesian = loc.sLocation;
+
+			if (!_self._resultObject.viewPoint) {
+				_self._resultObject.viewPoint = cartesian;
+				let pointEntity = _self._viewer.entities.add({
+					position: cartesian,
+					point: {
+						color: Cesium.Color.YELLOW,
+						pixelSize: 5,
+					},
+					//文字标签
+					label: {
+						text: "观察位置",
+						font: '12px sans-serif',
+						fillColor: new Cesium.Color(255 / 255, 255 / 255, 255 / 255, 1.0),
+						outlineColor: new Cesium.Color(0, 154 / 255, 94 / 255, 1.0),
+						style: Cesium.LabelStyle.FILL_AND_OUTLINE,
+						outlineWidth: 1.0,
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+						pixelOffset: new Cesium.Cartesian2(0, -28),
+						showBackground: true,
+						backgroundColor: new Cesium.Color(0, 0, 0, 0.6),
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+					},
+				});
+				_self._resultObject.objectExclude.push(pointEntity);
+				_self._resultObject.entities.push(pointEntity);
+			} else {
+				_self._resultObject.targetPoint = cartesian;
+				let pointEntity = _self._viewer.entities.add({
+					position: cartesian,
+					point: {
+						color: Cesium.Color.YELLOW,
+						pixelSize: 5,
+					},
+					//文字标签
+					label: {
+						text: "目标位置",
+						font: '12px sans-serif',
+						fillColor: new Cesium.Color(255 / 255, 255 / 255, 255 / 255, 1.0),
+						outlineColor: new Cesium.Color(0, 154 / 255, 94 / 255, 1.0),
+						style: Cesium.LabelStyle.FILL_AND_OUTLINE,
+						outlineWidth: 1.0,
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+						pixelOffset: new Cesium.Cartesian2(0, -28),
+						showBackground: true,
+						backgroundColor: new Cesium.Color(0, 0, 0, 0.6),
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+					},
+				});
+				_self._resultObject.objectExclude.push(pointEntity);
+				_self._resultObject.entities.push(pointEntity);
+				let direction = Cesium.Cartesian3.normalize(
+					Cesium.Cartesian3.subtract(
+						_self._resultObject.targetPoint,
+						_self._resultObject.viewPoint,
+						new Cesium.Cartesian3()
+					),
+					new Cesium.Cartesian3()
+				);
+
+				let ray = new Cesium.Ray(_self._resultObject.viewPoint, direction);
+				let result = _self._viewer.scene.pickFromRay(ray, _self._resultObject.objectExclude); // 计算交互点,返回第一个
+				if (result) {
+					let dis0 = _self._distance(
+						_self._resultObject.viewPoint,
+						_self._resultObject.targetPoint
+					);
+					let dis1 = _self._distance(
+						_self._resultObject.viewPoint,
+						result.position
+					);
+					let dis2 = _self._distance(
+						result.position,
+						_self._resultObject.targetPoint
+					);
+					console.log(dis0, dis1, dis2);
+					if (dis0 > dis1) {
+						let _poly0 = _self._viewer.entities.add({
+							polyline: {
+								positions: [_self._resultObject.viewPoint, result.position],
+								material: Cesium.Color.GREEN,
+								width: 3,
+							},
+						});
+						_self._resultObject.entities.push(_poly0);
+						let _poly1 = _self._viewer.entities.add({
+							polyline: {
+								positions: [result.position, _self._resultObject.targetPoint],
+								material: Cesium.Color.RED,
+								width: 3,
+							},
+						});
+						_self._resultObject.entities.push(_poly1);
+						_self._resultObject.targetPoints.push({
+							targetPoint: cartesian,
+							visual: false, //如果dis2足够小,其实他是可视的
+							distance: [dis0, dis1, dis2], //[初始点和终点,初始点和交点,交点和终点]
+						});
+					} else {
+						let _poly2 = _self._viewer.entities.add({
+							polyline: {
+								positions: [
+									_self._resultObject.viewPoint,
+									_self._resultObject.targetPoint,
+								],
+								material: Cesium.Color.GREEN,
+								width: 3,
+							},
+						});
+						_self._resultObject.entities.push(_poly2);
+						_self._resultObject.targetPoints.push({
+							targetPoint: cartesian,
+							visual: true, //如果dis2足够小,其实他是可视的
+							distance: [dis0, dis1, dis2], //[初始点和终点,初始点和交点,交点和终点]
+						});
+					}
+				}
+			}
+
+			if (_self._resultObject.objectExclude.length === 2) {
+				if (this._isRuntimeApp()) {
+					//创建按钮
+					_self._createOperationMainDom();
+
+					//完成绘制
+					document.getElementById("btnDrawComplete").onclick = () => {
+						CreateRemindertip(toolTip, event.endPosition, false);
+						_self.handler.destroy();
+
+						let buttonDiv = document.getElementById("drawButtonDiv");
+						if (buttonDiv) {
+							//从页面移除
+							document.body.removeChild(buttonDiv);
+						}
+					}
+				}
+			}
+
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+
+		_self.handler.setInputAction(function(move) {
+			if (_self._isRuntimeApp()) return;
+			CreateRemindertip(toolTip, move.endPosition, true);
+
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+		_self.handler.setInputAction((event) => {
+			CreateRemindertip(toolTip, event.endPosition, false);
+			_self.handler.destroy();
+		}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
+	},
+
+	/**
+	 * 清除视域分析
+	 */
+	clearAll() {
+		this._resultObject.entities.forEach((element) => {
+			this._viewer.entities.remove(element);
+		});
+		this._resultObject = {
+			viewPoint: undefined, //通视分析起点
+			targetPoints: [], //通视分析目标点集合
+			targetPoint: undefined, //当前目标点
+			objectExclude: [], //射线排除集合
+			entities: [], //创建的Entity对象
+		};
+
+		if (this.handler) {
+			this.handler.destroy();
+		}
+
+		let buttonDiv = document.getElementById("drawButtonDiv");
+		if (buttonDiv) {
+			//从页面移除
+			document.body.removeChild(buttonDiv);
+		}
+	}
+});
+
+/**
+ * 运行环境类型
+ */
+SightLine.RuntimeEnvironment = Object.freeze(({
+	App: 'app',
+	Web: 'web'
+}))
+
+export default SightLine;

+ 192 - 0
packages/Widgets/SpatialAnalysis/SunshineShadow.js

@@ -0,0 +1,192 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 光照阴影
+ */
+class SunshineShadow {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+		this._stopTime = null;
+	}
+}
+
+/**
+ * 通用对外公开函数
+ */
+Object.assign(SunshineShadow.prototype, /** @lends SunshineShadow.prototype */ {
+
+	/**
+	 * 开启日照分析
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.startTime] 时钟的开始时间
+	 * @param {Number} [options.stopTime] 时钟的停止时间
+	 * @param {Number} [options.speed] 每一个节拍需要多少时间,确定调用Clock#tick时前进了多少时间,负值允许向后前进。
+	 */
+	startSunShine(options) {
+		options = options || {};
+
+		if (!Cesium.defined(options.startTime)) {
+			options.startTime = new Date().getTime();
+		}
+		if (!Cesium.defined(options.stopTime)) {
+			options.stopTime = new Date().getTime() + 1000;
+		}
+		if (!Cesium.defined(options.speed)) {
+			options.speed = 1600;
+		}
+
+		if (this._stopTime) {
+			this._viewer.clock.shouldAnimate = true;
+			this._viewer.clock.currentTime = this._stopTime;
+		} else {
+			this._viewer.scene.globe.enableLighting = true; //开启全球光照,开启场景光照
+			this._viewer.shadows = true; //开启阴影
+			// this._viewer.terrainShadows = Cesium.ShadowMode.RECEIVE_ONLY;
+
+			this._viewer.clock.startTime = Cesium.JulianDate.fromDate(new Date(options.startTime)); //时钟的开始时间
+			this._viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date(options.startTime)); //当前时间。
+			this._viewer.clock.stopTime = Cesium.JulianDate.fromDate(new Date(options.stopTime)); //时钟的停止时间。
+
+			console.log(this._viewer.clock.currentTime)
+
+			this._viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // 当我们到达结束时间时循环,确定当达到时钟#startTime或时钟#stopTime时,时钟应该如何表现。
+			this._viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER; //确定对Clock#tick的调用是依赖于帧还是依赖于系统时钟。,确定当达到时钟#startTime或时钟#stopTime时,时钟应该如何表现。
+			this._viewer.clock.multiplier = options.speed; // 每一个节拍需要多少时间,确定调用Clock#tick时前进了多少时间,负值允许向后前进。
+			this._viewer.clock.canAnimate = true; //指示Clock#tick是否可以提前时间。例如,如果数据正在被缓冲,这可能是错误的。只有当clock #canAnimate和clock #shouldAnimate都为真时,时钟才会滴答作响。
+			this._viewer.clock.shouldAnimate = true; // 默认打开动画,指示Clock#tick是否应尝试提前时间。只有当clock #canAnimate和clock #shouldAnimate都为真时,时钟才会滴答作响。
+		}
+	},
+
+	/**
+	 * 停止日照分析
+	 */
+	stopSunShine() {
+		this._stopTime = this._viewer.clock.currentTime;
+		console.log(this._viewer.clock.currentTime)
+		this._viewer.clock.shouldAnimate = false;
+	},
+
+	/**
+	 * 移除日照分析
+	 */
+	removeSunShine() {
+		if (this._stopTime) {
+			this._viewer.clock.shouldAnimate = true;
+			this._viewer.clock.currentTime = this._stopTime;
+			console.log(this._viewer.clock.currentTime)
+		}
+		this._viewer.scene.globe.enableLighting = false;
+		this._viewer.shadows = false;
+		this._stopTime = null;
+		// this._viewer.terrainShadows = Cesium.ShadowMode.DISABLED;
+	},
+});
+
+/**
+ * 通用对外公开函数
+ */
+Object.assign(SunshineShadow.prototype, /** @lends SunshineShadow.prototype */ {
+
+
+	/**
+	 * 开启日照分析
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.startTime] 时钟的开始时间
+	 * @param {Number} [options.stopTime] 时钟的停止时间
+	 * @param {Number} [options.speed] 每一个节拍需要多少时间,确定调用Clock#tick时前进了多少时间,负值允许向后前进。
+	 */
+	start(options) {
+		//左下角动画控件(时间圆盘)
+		if (document.getElementsByClassName("cesium-viewer-animationContainer").length > 0) {
+			document.getElementsByClassName("cesium-viewer-animationContainer")[0].style.display = "block";
+		}
+		//下方时间线
+		if (document.getElementsByClassName("cesium-viewer-timelineContainer").length > 0) {
+			document.getElementsByClassName("cesium-viewer-timelineContainer")[0].style.display = "block";
+		}
+
+		// this._viewer.animation.container.style.visibility = 'visible';
+		// this._viewer.timeline.container.style.visibility = 'visible';
+
+		// this._viewer.scene.globe.enableLighting = true; //开启全球光照,开启场景光照
+		this._viewer.shadows = true; //开启阴影
+
+		options = options || {};
+		if (!Cesium.defined(options.startTime)) {
+			options.startTime = new Date(new Date().toLocaleDateString()).getTime(); // 当天凌晨0点
+			console.log("当天凌晨0点", new Date(new Date().toLocaleDateString()));
+		}
+		if (!Cesium.defined(options.stopTime)) {
+			options.stopTime = new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1; // 当天23点59分59秒
+			console.log("当天23点59分59秒", new Date(new Date(new Date().toLocaleDateString()).getTime() + 4 * 60 * 60 * 1000));
+		}
+		if (!Cesium.defined(options.speed)) {
+			options.speed = 1600;
+		}
+
+		// 起始时间
+		let start = Cesium.JulianDate.fromDate(new Date(options.startTime));
+		// 结束时间
+		let stop = Cesium.JulianDate.fromDate(new Date(options.stopTime));
+		// 设置时间轴为模拟边界
+		viewer.timeline.zoomTo(start, stop);
+
+		//定义clock事件
+		let clock = viewer.clock;
+		//控制开始和停止
+		clock.shouldAnimate = false;
+		// 设定clock的起始时间
+		clock.startTime = start;
+		// 设定clock的终止时间
+		clock.stopTime = stop;
+		// 设定clock的当前时间
+		clock.currentTime = start;
+		//表示时间轴达到终点之后的行为
+		//CLAMPED:达到终止时间后停止。
+		//LOOP_STOP:达到终止时间后重新循环。
+		//UNBOUNDED:达到终止时间后继续读秒。时间不仅限于设置的起始日期,可前后拖动(超出该时间轴的范围的可能)
+		clock.clockRange = Cesium.ClockRange.UNBOUNDED;
+		// 时间速率(快速播放与慢速播放),默认1.0,数字越大时间过的越快时间速率
+		//若设置为86400,表示真实世界经过1秒,而在Cesium中时钟经过1天
+		clock.multiplier = options.speed;
+
+		// //时间变化就执行(即使停止时间轴仍然会执行)
+		// clock.onTick.addEventListener(function(clock) {
+		// 	//可以在这里做一些时间的监听
+		// });
+
+		// //停止时间轴执行
+		// clock.onStop.addEventListener(function(clock) {
+		// });
+	},
+
+	/**
+	 * 移除日照分析
+	 */
+	remove() {
+		//左下角动画控件(时间圆盘)
+		if (document.getElementsByClassName("cesium-viewer-animationContainer").length > 0) {
+			document.getElementsByClassName("cesium-viewer-animationContainer")[0].style.display = "none";
+		}
+		//下方时间线
+		if (document.getElementsByClassName("cesium-viewer-timelineContainer").length > 0) {
+			document.getElementsByClassName("cesium-viewer-timelineContainer")[0].style.display = "none";
+		}
+
+		// this._viewer.animation.container.style.visibility = 'hidden';
+		// this._viewer.timeline.container.style.visibility = 'hidden';
+
+		// this._viewer.scene.globe.enableLighting = false;
+		this._viewer.shadows = false;
+		this._viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date(new Date().getTime()));
+		this._viewer.clock.shouldAnimate = false;
+	},
+});
+
+export default SunshineShadow;

+ 582 - 0
packages/Widgets/SpatialAnalysis/ViewShed.js

@@ -0,0 +1,582 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+/* 引入克里金插值 */
+import kriging from '@sakitam-gis/kriging';
+/* 引入算法 */
+import * as turf from "@turf/turf";
+
+import CreateRemindertip from "../common/ReminderTip.js";
+
+/**
+ * 视域分析类
+ */
+class ViewShed {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+		// let canvas = document.getElementById("canvasMap");
+		// if (canvas == null) {
+		// 	//创建画布
+		// 	canvas = document.createElement('canvas');
+		// 	canvas.id = "canvasMap";
+		// 	canvas.style.display = "none";
+		// 	canvas.style.top = "0px";
+		// 	canvas.style.position = "absolute";
+		// 	/* 加入到页面 */
+		// 	document.body.append(canvas);
+		// }
+		// this.canvasEle = canvas;
+
+		this.viewer = viewer;
+		this.handler = undefined;
+		this.lightCamera;
+		this.pyramid;
+		this.frustumPrimitive;
+		this.viewershedPolygon;
+	}
+
+	/**
+	 * 初始化handler
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	initHandler() {
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = undefined;
+		}
+
+		let canvas = document.getElementById("canvasMap");
+		if (canvas == null) {
+			//创建画布
+			canvas = document.createElement('canvas');
+			canvas.id = "canvasMap";
+			canvas.style.display = "none";
+			canvas.style.top = "0px";
+			canvas.style.position = "absolute";
+			/* 加入到页面 */
+			document.body.append(canvas);
+		}
+		this.canvasEle = canvas;
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} pos0
+	 * @param {Object} pos1
+	 */
+	ReturnDistance(pos0, pos1) {
+		let distance = 0;
+		let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
+		let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
+		let geodesic = new Cesium.EllipsoidGeodesic();
+		geodesic.setEndPoints(point1cartographic, point2cartographic);
+		let s = geodesic.surfaceDistance;
+		return s;
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} x
+	 * @param {Object} y
+	 * @param {Object} objectsToExclude
+	 */
+	getHeight(x, y, objectsToExclude) {
+		let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
+		let endHeight = this.viewer.scene.sampleHeight(
+			endCartographic,
+			objectsToExclude
+		);
+		return endHeight;
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} Cartesian3
+	 */
+	cartesian3ToDegree(Cartesian3) {
+		let _ellipsoid = this.viewer.scene.globe.ellipsoid;
+		let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
+		let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
+		let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
+		let _alt = _cartographic.height;
+		return [_lng, _lat, _alt];
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} lng1
+	 * @param {Object} lat1
+	 * @param {Object} lng2
+	 * @param {Object} lat2
+	 */
+	getAngle(lng1, lat1, lng2, lat2) {
+		let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
+		if (lng2 >= lng1) {
+			dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
+		} else {
+			dRotateAngle =
+				lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
+		}
+		dRotateAngle = (dRotateAngle * 180) / Math.PI;
+		return dRotateAngle;
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} pointA
+	 * @param {Object} pointB
+	 */
+	getPitch(pointA, pointB) {
+		let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
+		const vector = Cesium.Cartesian3.subtract(
+			pointB,
+			pointA,
+			new Cesium.Cartesian3()
+		);
+		let direction = Cesium.Matrix4.multiplyByPointAsVector(
+			Cesium.Matrix4.inverse(transfrom, transfrom),
+			vector,
+			vector
+		);
+		Cesium.Cartesian3.normalize(direction, direction);
+		return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	updateViewShed() {
+		this.clear();
+		this.setLightCamera();
+		this.addVisualPyramid();
+		this.createFrustum();
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	clear() {
+		if (this.pyramid) {
+			this.viewer.entities.removeById(this.pyramid.id);
+			this.pyramid = undefined;
+		}
+		if (this.frustumPrimitive) {
+			this.viewer.scene.primitives.remove(this.frustumPrimitive);
+			this.frustumPrimitive = undefined;
+		}
+		if (this.debugModelMatrixPrimitive) {
+			this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
+			this.debugModelMatrixPrimitive = undefined;
+		}
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	addVisualPyramid() {
+		let options = this.ViewShedOptions;
+		let position = options.viewPosition;
+		let visualRange = Number(options.visualRange);
+		let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
+		this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
+			new Cesium.DebugModelMatrixPrimitive({
+				modelMatrix: transform,
+				length: 5.0,
+			})
+		);
+		const halfClock = options.horizontalViewAngle / 2;
+		const halfCone = options.verticalViewAngle / 2;
+		const pitch = Cesium.Math.toDegrees(options.pitch);
+		const ellipsoid = new Cesium.EllipsoidGraphics({
+			radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
+			minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
+			maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
+			minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
+			maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
+			fill: false,
+			outline: true,
+			subdivisions: 256,
+			stackPartitions: 64,
+			slicePartitions: 64,
+			outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
+		});
+		const pyramidEntity = new Cesium.Entity({
+			position: position,
+			ellipsoid,
+		});
+		this.pyramid = this.viewer.entities.add(pyramidEntity);
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	setLightCamera() {
+		if (!this.lightCamera) {
+			this.lightCamera = new Cesium.Camera(this.viewer.scene);
+		}
+		let options = this.ViewShedOptions;
+		let visualRange = Number(options.visualRange);
+		this.lightCamera.position = options.viewPosition;
+		this.lightCamera.frustum.near = 0.1;
+		this.lightCamera.frustum.far = visualRange;
+		const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
+		const vr = Cesium.Math.toRadians(options.verticalViewAngle);
+		this.lightCamera.frustum.aspectRatio =
+			(visualRange * Math.tan(hr / 2) * 2) /
+			(visualRange * Math.tan(vr / 2) * 2);
+		this.lightCamera.frustum.fov = hr > vr ? hr : vr;
+		this.lightCamera.setView({
+			destination: options.viewPosition,
+			orientation: {
+				heading: Cesium.Math.toRadians(options.direction || 0),
+				pitch: options.pitch || 0,
+				roll: 0,
+			},
+		});
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	createFrustum() {
+		const scratchRight = new Cesium.Cartesian3();
+		const scratchRotation = new Cesium.Matrix3();
+		const scratchOrientation = new Cesium.Quaternion();
+		const direction = this.lightCamera.directionWC;
+		const up = this.lightCamera.upWC;
+		let right = this.lightCamera.rightWC;
+		right = Cesium.Cartesian3.negate(right, scratchRight);
+		let rotation = scratchRotation;
+		Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
+		Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
+		Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
+		let orientation = Cesium.Quaternion.fromRotationMatrix(
+			rotation,
+			scratchOrientation
+		);
+		let instanceOutline = new Cesium.GeometryInstance({
+			geometry: new Cesium.FrustumOutlineGeometry({
+				frustum: this.lightCamera.frustum,
+				origin: this.ViewShedOptions.viewPosition,
+				orientation: orientation,
+			}),
+			id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
+			attributes: {
+				color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+					new Cesium.Color(0.0, 1.0, 0.0, 1.0)
+				),
+				show: new Cesium.ShowGeometryInstanceAttribute(true),
+			},
+		});
+		this.frustumPrimitive = this.viewer.scene.primitives.add(
+			new Cesium.Primitive({
+				geometryInstances: instanceOutline,
+				appearance: new Cesium.PerInstanceColorAppearance({
+					flat: true,
+					translucent: false,
+					closed: true,
+				}),
+			})
+		);
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	addViewershedPolygon(positionArr) {
+		let polygon = new Cesium.PolygonGeometry({
+			polygonHierarchy: new Cesium.PolygonHierarchy(
+				Cesium.Cartesian3.fromDegreesArray(positionArr)
+			),
+			height: 0.0,
+			extrudedHeight: 0.0,
+			vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
+			stRotation: 0.0,
+			ellipsoid: Cesium.Ellipsoid.WGS84,
+			granularity: Cesium.Math.RADIANS_PER_DEGREE,
+			perPositionHeight: false,
+			closeTop: true,
+			closeBottom: true,
+			arcType: Cesium.ArcType.GEODESIC,
+		});
+
+		let polygonInstance = new Cesium.GeometryInstance({
+			geometry: polygon,
+			name: "ViewershedPolygon",
+			attributes: {
+				color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+					Cesium.Color.BLUE.withAlpha(0.6)
+				),
+				show: new Cesium.ShowGeometryInstanceAttribute(true),
+			},
+		});
+		this.viewershedPolygon = this.viewer.scene.primitives.add(
+			new Cesium.GroundPrimitive({
+				geometryInstances: polygonInstance,
+				appearance: new Cesium.EllipsoidSurfaceAppearance({
+					aboveGround: true,
+					material: new Cesium.Material({
+						fabric: {
+							type: "Image",
+							uniforms: {
+								image: this.returnImgae(),
+							},
+						},
+					}),
+				}),
+			})
+		);
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	drawViewershed(precision) {
+		const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
+		const radius = this.ViewShedOptions.visualRange;
+		const direction = this.ViewShedOptions.direction;
+		let boundary = this.computeBoundaryOptions(pos, radius, direction);
+		const bbox = boundary.bbox;
+		let mask = turf.polygon([boundary.boundaryPoints]);
+		const dis = this.ViewShedOptions.visualRange / (precision * 1000);
+		let gridPoints = turf.pointGrid(bbox, dis, {
+			mask: mask
+		});
+		console.log(this.ViewShedOptions.visualRange, precision, dis);
+
+		let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
+		let variogram = kriging.train(
+			pointsResult.values,
+			pointsResult.lngs,
+			pointsResult.lats,
+			"exponential",
+			0,
+			100
+		);
+		let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);
+		const colors = [
+			"#ff000080",
+			"#ff000080",
+			"#ff000080",
+			"#ff000080",
+			"#ff000080",
+			"#ff000080",
+			"#00ff0080",
+			"#00ff0080",
+			"#00ff0080",
+			"#00ff0080",
+			"#00ff0080",
+			"#00ff0080",
+		];
+
+		this.canvasEle.width = 3840;
+		this.canvasEle.height = 2160;
+		kriging.plot(
+			this.canvasEle,
+			grid,
+			[bbox[0], bbox[2]],
+			[bbox[1], bbox[3]],
+			colors
+		);
+		this.addViewershedPolygon(boundary.positionArr);
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	computeBoundaryOptions(pos, radius, angle) {
+		let Ea = 6378137; // 赤道半径
+		let Eb = 6356725; // 极半径
+		const lng = pos[0],
+			lat = pos[1];
+		const bbox = [lng, lat, lng, lat];
+		let positionArr = [];
+		let boundaryPoints = [];
+		positionArr.push(lng, lat);
+		boundaryPoints.push([lng, lat]);
+		//正北是0°
+		let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
+		let end = start + 90;
+		for (let i = start; i <= end; i++) {
+			let dx = radius * Math.sin((i * Math.PI) / 180.0);
+			let dy = radius * Math.cos((i * Math.PI) / 180.0);
+			let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
+			let ed = ec * Math.cos((lat * Math.PI) / 180);
+			let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
+			let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
+			positionArr.push(BJD, BWD);
+			boundaryPoints.push([BJD, BWD]);
+			this.refreshBBox(bbox, BJD, BWD);
+		}
+		boundaryPoints.push([lng, lat]);
+		return {
+			positionArr,
+			boundaryPoints,
+			bbox,
+		};
+	}
+
+	/**
+	 * 更新外围矩形 Bbox
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
+	 * @param {Number} x 经度
+	 * @param {Number} y 纬度
+	 */
+	refreshBBox(result, x, y) {
+		result[0] = x < result[0] ? x : result[0];
+		result[1] = y < result[1] ? y : result[1];
+		result[2] = x > result[2] ? x : result[2];
+		result[3] = y > result[3] ? y : result[3];
+	}
+
+	/**
+	 * 插值点用射线判断通视性
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {*} gridPoints 网格点
+	 * @param {*} step 步长,可以理解成是精度
+	 * @param {*} sourcePos 视域分析起点
+	 * @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
+	 */
+	createTargetPoints(gridPoints, step, sourcePos) {
+		let positionArr = [];
+		let objectsToExclude = [
+			this.frustumPrimitive,
+			this.pyramid,
+			this.debugModelMatrixPrimitive,
+		];
+		let values = [],
+			lngs = [],
+			lats = [];
+		let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
+		positionArr.push({
+			x: sourcePos[0],
+			y: sourcePos[1],
+			z: height,
+		});
+		let viewPoint = this.ViewShedOptions.viewPosition;
+		for (let index = 0; index < gridPoints.features.length; index++) {
+			const feature = gridPoints.features[index];
+			const coords = feature.geometry.coordinates;
+			const x = coords[0],
+				y = coords[1];
+			let h = this.getHeight(x, y, objectsToExclude);
+			let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
+			let direction = Cesium.Cartesian3.normalize(
+				Cesium.Cartesian3.subtract(
+					endPoint,
+					viewPoint,
+					new Cesium.Cartesian3()
+				),
+				new Cesium.Cartesian3()
+			);
+			// 建立射线
+			let ray = new Cesium.Ray(viewPoint, direction);
+			let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
+			if (result) {
+				let buffer = this.ReturnDistance(endPoint, result.position);
+				// let M_color = Cesium.Color.GREEN;
+				if (buffer > step) {
+					// M_color = Cesium.Color.RED;
+					values.push(0);
+				} else {
+					values.push(1);
+				}
+				lngs.push(x);
+				lats.push(y);
+			}
+		}
+		return {
+			values,
+			lngs,
+			lats,
+		};
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @returns base64图片
+	 */
+	returnImgae() {
+		return this.canvasEle.toDataURL("image/png");
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(ViewShed.prototype, /** @lends ViewShed.prototype */ {
+	/**
+	 * 开始执行视域分析
+	 * @param {number} precision 精度,值越大创建耗时越长,建议在10~20之间
+	 */
+	createViewshed: function(precision) {
+		let _self = this;
+		let scene = _self.viewer.scene;
+		_self.initHandler();
+		_self.clearAll();
+
+		let count = 0;
+		let toolTip = "左键点击创建起点";
+		_self.handler = new Cesium.ScreenSpaceEventHandler(_self.viewer.canvas);
+		_self.handler.setInputAction((event) => {
+			count++;
+
+			if (count === 1) {
+				toolTip = "左键点击创建终点";
+				let earthPosition = scene.pickPosition(event.position);
+				let pos = _self.cartesian3ToDegree(earthPosition);
+				_self.handler.setInputAction(function(move) {
+					CreateRemindertip(toolTip, move.endPosition, true);
+					let newPosition = scene.pickPosition(move.endPosition);
+					if (Cesium.defined(newPosition)) {
+						let pos1 = _self.cartesian3ToDegree(newPosition);
+						let distance = Cesium.Cartesian3.distance(newPosition, earthPosition);
+						let angle = _self.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
+						let pitch = _self.getPitch(earthPosition, newPosition);
+						_self.ViewShedOptions = {
+							viewPosition: earthPosition,
+							endPosition: newPosition,
+							direction: angle,
+							pitch: pitch,
+							horizontalViewAngle: 90,
+							verticalViewAngle: 60,
+							visibleAreaColor: Cesium.Color.GREEN,
+							invisibleAreaColor: Cesium.Color.RED,
+							visualRange: distance,
+						};
+						_self.updateViewShed();
+					}
+				}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+			}
+
+			if (count === 2) {
+				_self.initHandler();
+				_self.drawViewershed(precision);
+				CreateRemindertip(toolTip, event.endPosition, false);
+			}
+
+		}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+
+		_self.handler.setInputAction(function(move) {
+			CreateRemindertip(toolTip, move.endPosition, true);
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	},
+
+	/**
+	 * 清除视域分析
+	 */
+	clearAll: function() {
+		this.clear();
+		if (this.viewershedPolygon) {
+			this.viewer.scene.primitives.remove(this.viewershedPolygon);
+			this.viewershedPolygon = undefined;
+		}
+	},
+});
+
+export default ViewShed;

+ 309 - 0
packages/Widgets/StatusBar.js

@@ -0,0 +1,309 @@
+import DomUtil from './common/doms.js'
+
+import '../Assets/styles/StatusBar.css';
+
+/**
+ * 状态栏
+ */
+class StatusBar {
+	/**
+	 * 状态栏工具类
+	 * @param {Viewer} viewer - 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Error('viewer is required!');
+		this._viewer = viewer;
+		this._show = false; //初始化显示状态
+		this._handler;
+
+		this._posX;
+		this._posY;
+		this._posZ;
+		this._cameraHeight;
+		this._pitch;
+		this._heading;
+		this._scale;
+
+		this.initListener()
+	}
+	/**
+	 * 状态栏参数
+	 * @readonly
+	 */
+	get params() {
+		return {
+			posX: this._posX, //经度
+			posY: this._posY, //维度
+			posZ: this._posZ, //模型高度
+			cameraHeight: this._cameraHeight, //相机视角高度
+			pitch: this._pitch, //俯仰角
+			heading: this._heading, //方向
+			scale: this._scale //比例尺
+		}
+	}
+	get statusDom() {
+		let innerHtml = `
+		<span class="status-scale">
+			比例尺:
+			<span class="scale-border">
+				${this._scale}
+			</span>
+		</span>
+		<span class="status-position">
+			<span id="status_spaceInfo">空间信息</span>
+			刷帧率:<span id="status_ms"></span>|<span id="status_fps"></span>
+		</span>
+		`
+		return innerHtml
+	}
+	/**
+	 * 控制显示Boolean常量
+	 * @constant
+	 */
+	get show() {
+		return this._show
+	}
+	set show(bool) {
+		bool ? this.createStatusBar() : this.removeStatusBar()
+		this._show = bool
+	}
+	initListener() {
+		const $this = this
+		const scene = this._viewer.scene
+		this._scaleListener = function() {
+			let width = scene.canvas.clientWidth
+			let height = scene.canvas.clientHeight
+			let left = scene.camera.getPickRay(
+				new Cesium.Cartesian2((width / 2) | 0, height - 1)
+			)
+			let right = scene.camera.getPickRay(
+				new Cesium.Cartesian2((1 + width / 2) | 0, height - 1)
+			)
+			let globe = scene.globe
+			let leftPosition = globe.pick(left, scene)
+			let rightPosition = globe.pick(right, scene)
+			if (leftPosition && rightPosition) {
+				let geodesic = new Cesium.EllipsoidGeodesic()
+				let leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition)
+				let rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition)
+				geodesic.setEndPoints(leftCartographic, rightCartographic)
+				let distance = geodesic.surfaceDistance
+				let curScaleNum = $this.closest(distance / 10)
+				if (curScaleNum < 1) {
+					$this._scale = curScaleNum * 1000 + 'm'
+				} else {
+					$this._scale = curScaleNum + 'km'
+				}
+			}
+
+			document.getElementsByClassName("scale-border")[0].innerText = $this._scale;
+
+			if (document.getElementsByClassName("cesium-performanceDisplay-ms").length > 0) {
+				document.getElementById("status_ms").innerText = document.getElementsByClassName("cesium-performanceDisplay-ms")[0].innerText;
+			}
+			if (document.getElementsByClassName("cesium-performanceDisplay-fps").length > 0) {
+				document.getElementById("status_fps").innerText = document.getElementsByClassName("cesium-performanceDisplay-fps")[0].innerText;
+			}
+
+		}
+	}
+	createStatusBar() {
+		const _delegate = this._viewer
+		this.initHandler(_delegate)
+		this.initScale(_delegate, true)
+		this._domContainer = DomUtil.create(
+			'div',
+			'lk-status-bar',
+			document.getElementById(this._viewer._container.id)
+		)
+
+		this._domContainer.innerHTML = this.statusDom;
+
+		// var canvas = this._viewer.canvas; // 获取画布
+		// this._domContainer.style.width = canvas.width + "px";
+		// console.log('画布', canvas.width)
+
+	}
+	removeStatusBar() {
+		this.initScale(this._viewer, false)
+		if (this._handler) {
+			this._handler.destroy()
+		}
+		if (this._domContainer) {
+			DomUtil.remove(this._domContainer)
+		}
+	}
+	initHandler(viewer) {
+		const $this = this
+		this._handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
+		const mouseOverHandler = function(movement) {
+
+			/* 识别屏幕位置 */
+			let loc = $this._getScreenClickPositionAndHeight(movement.endPosition);
+
+			if (!Cesium.defined(loc)) return;
+
+			if (!loc.lng) return;
+
+			$this._posX = loc.lng.toFixed(8);
+			$this._posY = loc.lat.toFixed(8);
+			$this._posZ = loc.height.toFixed(2);
+
+			// const cameraH = viewer.camera.positionCartographic.height
+			// $this._cameraHeight =
+			// 	cameraH < 1000 ?
+			// 	cameraH.toFixed(2) + 'm' :
+			// 	(cameraH / 1000).toFixed(2) + 'km';
+
+			// $this._pitch = Number(viewer.scene.camera.pitch).toFixed(2);
+			// $this._heading = Number(viewer.scene.camera.heading).toFixed(2);
+
+			document.getElementById("status_spaceInfo").innerHTML = `
+				<span>经度:${$this._posX}</span>
+				<span>纬度:${$this._posY}</span>
+				<span>高度:${$this._posZ}</span>
+				`;
+
+		}
+		this._handler.setInputAction(
+			mouseOverHandler,
+			Cesium.ScreenSpaceEventType.MOUSE_MOVE
+		)
+	}
+	initScale(viewer, bool) {
+		const scene = viewer.scene
+		bool
+			?
+			scene.postRender.addEventListener(this._scaleListener) :
+			scene.postRender.removeEventListener(this._scaleListener)
+	}
+	closest(num) {
+		const scaleList = [
+			0.001,
+			0.002,
+			0.003,
+			0.005,
+			0.01,
+			0.015,
+			0.02,
+			0.025,
+			0.03,
+			0.035,
+			0.04,
+			0.045,
+			0.05,
+			0.06,
+			0.07,
+			0.08,
+			0.09,
+			0.1,
+			0.12,
+			0.15,
+			0.2,
+			0.25,
+			0.3,
+			0.5,
+			1,
+			2,
+			3,
+			5,
+			10,
+			15,
+			20,
+			25,
+			30,
+			35,
+			40,
+			45,
+			50,
+			60,
+			70,
+			80,
+			90,
+			100,
+			120,
+			150,
+			200,
+			250,
+			300,
+			500,
+			1000,
+			2000,
+			5000,
+			10000,
+			100000,
+			500000,
+			1000000
+		]
+		let ret = scaleList[0]
+		let distance = Math.abs(ret - num)
+		for (let i = 1; i < scaleList.length; i++) {
+			let newDistance = Math.abs(scaleList[i] - num)
+			if (newDistance < distance) {
+				distance = newDistance
+				ret = scaleList[i]
+			}
+		}
+		return ret
+	}
+
+	/**
+	 * 根据地形或实景或模型检测当前屏幕位置的经纬度及高度
+	 * @ignore 生成方法时不对外公开
+	 * @param {JSON} screenPoint 屏幕坐标
+	 * @param {Number} screenPoint.x 屏幕坐标x
+	 * @param {Number} screenPoint.y 屏幕坐标y
+	 * @return {JSON} 位置信息{lng,lat,height}
+	 */
+	_getScreenClickPositionAndHeight(screenPoint) {
+		var lng = undefined,
+			lat = undefined,
+			height = undefined;
+
+		/* 从相机位置到 windowPosition 处的像素创建射线在世界坐标系中 */
+		var ray = this._viewer.scene.camera.getPickRay(screenPoint);
+		/* 找到射线与渲染的地球表面之间的交点 */
+		var position = this._viewer.scene.globe.pick(ray, this._viewer.scene);
+		if (position) {
+			/* 获取地理位置的制图表达 */
+			var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
+			cartographic = Cesium.Cartographic.fromCartesian(position);
+			/* 查询屏幕位置的要素 */
+			var feature = this._viewer.scene.pick(screenPoint);
+			if (feature === undefined && Cesium.defined(cartographic)) {
+				lng = this._arcToDegree(cartographic.longitude);
+				lat = this._arcToDegree(cartographic.latitude);
+				height = cartographic.height;
+			} else {
+				var cartesian = this._viewer.scene.pickPosition(screenPoint);
+				if (Cesium.defined(cartesian)) {
+					var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
+					if (Cesium.defined(cartographic)) {
+						lng = this._arcToDegree(cartographic.longitude);
+						lat = this._arcToDegree(cartographic.latitude);
+						height = cartographic.height;
+					}
+				}
+			}
+		}
+
+		/* 返回结果 */
+		return {
+			lng: lng,
+			lat: lat,
+			height: height,
+		}
+	}
+
+	/**
+	 * 弧度转度
+	 * @ignore 生成方法时不对外公开
+	 * @param {Number} arc 弧度
+	 * @return {Number} 角度
+	 */
+	_arcToDegree(arc) {
+		return arc / Math.PI * 180;
+	}
+}
+
+export default StatusBar

+ 414 - 0
packages/Widgets/TerrainAnalysis/SlopeAspect.js

@@ -0,0 +1,414 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/* 引入算法 */
+import * as turf from "@turf/turf";
+
+import CreateRemindertip from "../common/ReminderTip.js";
+import CoordTransform from "../common/CoordTransform.js";
+import {
+	setSessionid
+} from "../common/common.js";
+
+/**
+ * 坡度坡向分析类
+ */
+class SlopeAspect {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+
+		this.result = []; //存储创建的坡度分析结果,primitive集合
+		this.handler = undefined;
+		this.toolTip = "";
+	}
+
+	/**
+	 * 坡度提示信息
+	 * @ignore 
+	 */
+	_openTip() {
+		let _self = this;
+		this.handler = new Cesium.ScreenSpaceEventHandler(_self._viewer.canvas);
+		this.handler.setInputAction(function(movement) {
+			let endPos = movement.endPosition;
+			var pick = _self._viewer.scene.pick(endPos);
+			if (pick && pick.id && pick.id.type === "SlopeAspect") {
+				_self.toolTip = pick.id.value.toFixed(2);
+				CreateRemindertip(_self.toolTip, endPos, true);
+			} else {
+				_self.toolTip = "";
+				CreateRemindertip(_self.toolTip, endPos, false);
+			}
+		}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+	}
+
+	/**
+	 * @ignore 
+	 * @param {Object} gridSquare
+	 */
+	_createEllipse(gridSquare) {
+
+		let _self = this;
+
+		let boxResults = [];
+		for (let index = 0; index < gridSquare.features.length; index++) {
+			const feature = gridSquare.features[index];
+			const coordinates = feature.geometry.coordinates[0];
+			const centerdegree = [
+				(coordinates[0][0] + coordinates[2][0]) / 2,
+				(coordinates[0][1] + coordinates[2][1]) / 2,
+			];
+			let centerCartographic = Cesium.Cartographic.fromDegrees(
+				centerdegree[0],
+				centerdegree[1]
+			);
+			boxResults.push(centerCartographic);
+			for (let i = 0; i < coordinates.length; i++) {
+				const coord = coordinates[i];
+				let cartographic = Cesium.Cartographic.fromDegrees(coord[0], coord[1]);
+				boxResults.push(cartographic);
+				const coord1 = coordinates[i + 1];
+				if (coord1) {
+					let newCoord = [(coord[0] + coord1[0]) / 2, (coord[1] + coord1[1]) / 2];
+					let newCartographic = Cesium.Cartographic.fromDegrees(newCoord[0], newCoord[1]);
+					boxResults.push(newCartographic);
+				}
+			}
+		}
+
+		Cesium.sampleTerrainMostDetailed(
+			_self._viewer.scene.terrainProvider,
+			boxResults
+		).then((updatePositions) => {
+			let arrr = [];
+			let ellipseResults = updatePositions.reduce(function(pre, item, index, updatePositions) {
+				var begin = index * 10;
+				var end = begin + 10;
+				var res = updatePositions.slice(begin, end);
+				if (res.length != 0) {
+					arrr[index] = res;
+				}
+				return arrr;
+			}, []);
+
+			_self._calculateSlope(ellipseResults);
+			_self._openTip();
+		});
+	}
+
+	/**
+	 * @ignore 
+	 * @param {Object} points
+	 * @param {Object} color
+	 */
+	_createPolygonInsrance(points, color) {
+		let positions = [];
+		for (let index = 1; index < points.length - 1; index++) {
+			const element = points[index];
+			positions.push(Cesium.Cartographic.toCartesian(element));
+		}
+		let polygon = new Cesium.PolygonGeometry({
+			polygonHierarchy: new Cesium.PolygonHierarchy(positions),
+		});
+
+		let polygonInstance = new Cesium.GeometryInstance({
+			geometry: polygon,
+			attributes: {
+				color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+					Cesium.Color.fromCssColorString(color)
+				),
+				show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
+			},
+		});
+		return polygonInstance;
+	}
+
+	/**
+	 * 箭头
+	 * @ignore 
+	 * @param {Object} targetPoint
+	 * @param {Object} center
+	 * @param {Object} diagonalPoint
+	 * @param {Object} heightDifference
+	 * @param {Object} curSlope
+	 */
+	_createArrowInstance(targetPoint, center, diagonalPoint, heightDifference, curSlope) {
+		let cartographic_0 = new Cesium.Cartographic(
+			(targetPoint.longitude + center.longitude) / 2,
+			(targetPoint.latitude + center.latitude) / 2,
+			(targetPoint.height + center.height) / 2
+		);
+		let cartographic_1 = new Cesium.Cartographic(
+			(diagonalPoint.longitude + center.longitude) / 2,
+			(diagonalPoint.latitude + center.latitude) / 2,
+			(diagonalPoint.height + center.height) / 2
+		);
+
+		//偏移的
+		let positions1 =
+			heightDifference > 0 ? [
+				Cesium.Cartographic.toCartesian(cartographic_0),
+				Cesium.Cartographic.toCartesian(cartographic_1)
+			] : [
+				Cesium.Cartographic.toCartesian(cartographic_1),
+				Cesium.Cartographic.toCartesian(cartographic_0)
+			];
+
+		//箭头线
+		const instance = new Cesium.GeometryInstance({
+			id: {
+				type: "SlopeAspect",
+				value: curSlope,
+			},
+			geometry: new Cesium.GroundPolylineGeometry({
+				positions: positions1,
+				width: this.arrowWidth,
+			}),
+			attributes: {
+				color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+					Cesium.Color.BLUE.withAlpha(0.6)
+				),
+				show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
+			},
+		});
+		return instance;
+	}
+
+	/**
+	 * @ignore 
+	 * @param {Object} ellipseResults
+	 */
+	_calculateSlope(ellipseResults) {
+		let _self = this;
+
+		let instances = [];
+		let polygonInstance = [];
+		for (let index = 0; index < ellipseResults.length; index++) {
+			const ellipse = ellipseResults[index];
+
+			const center = ellipse[0];
+			let heightDifference = 0;
+			let maxIndex = 0;
+			for (let i = 1; i < ellipse.length - 1; i++) {
+				const point = ellipse[i];
+				let curHD = point.height - center.height;
+				if (Math.abs(curHD) > heightDifference) {
+					heightDifference = curHD;
+					maxIndex = i;
+				}
+			}
+			let pos0 = new Cesium.Cartographic(center.longitude, center.latitude, 0);
+			let pos1 = new Cesium.Cartographic(
+				ellipse[maxIndex].longitude,
+				ellipse[maxIndex].latitude,
+				0
+			);
+			let distance = Cesium.Cartesian3.distance(
+				Cesium.Cartographic.toCartesian(pos0),
+				Cesium.Cartographic.toCartesian(pos1)
+			);
+			let curSlope = Math.abs(heightDifference / distance); //坡度的tan值
+			let curColor = _self._calculateSlopeColor(curSlope, 0.4);
+			const curPolygonInstance = _self._createPolygonInsrance(ellipse, curColor);
+			polygonInstance.push(curPolygonInstance);
+
+			let diagonalPoint = maxIndex > 4 ? ellipse[maxIndex - 4] : ellipse[maxIndex + 4]; //对角点
+			let targetPoint = ellipse[maxIndex];
+			const arrowInstance = _self._createArrowInstance(targetPoint, center, diagonalPoint, heightDifference, curSlope);
+			instances.push(arrowInstance);
+		}
+
+		const mapPrimitive = _self._viewer.scene.primitives.add(
+			new Cesium.GroundPrimitive({
+				geometryInstances: polygonInstance,
+				appearance: new Cesium.PerInstanceColorAppearance({
+					translucent: true, //false时透明度无效
+					closed: false,
+				}),
+			})
+		);
+		const arrowPrimitive = _self._viewer.scene.primitives.add(
+			new Cesium.GroundPolylinePrimitive({
+				geometryInstances: instances,
+				appearance: new Cesium.PolylineMaterialAppearance({
+					material: new Cesium.Material({
+						fabric: {
+							type: "PolylineArrow",
+							uniforms: {
+								color: new Cesium.Color(1.0, 1.0, 0.0, 0.8),
+							},
+						},
+					}),
+				}),
+			})
+		);
+		_self.result.push(arrowPrimitive, mapPrimitive);
+	}
+
+	/**
+	 * 根据坡度值赋值颜色
+	 * @ignore 
+	 * @param {Object} value
+	 * @param {Object} alpha
+	 */
+	_calculateSlopeColor(value, alpha) {
+		// 0°~0.5°为平原0.00872686779075879,rgb(85,182,43)
+		// 0.5°~2°为微斜坡0.03492076949174773,rgb(135,211,43)
+		// 2°~5°为缓斜坡0.08748866352592401,rgb(204,244,44)
+		// 5°~15°为斜坡0.2679491924311227,rgb(245,233,44)
+		// 15°~35°为陡坡0.7002075382097097,rgb(255,138,43)
+		// 35°~55°为峭坡1.4281480067421144,rgb(255,84,43)
+		// 55°~90°为垂直壁,rgb(255,32,43)
+
+		if (value < 0.00872686779075879) {
+			return "rgba(85,182,43," + alpha + ")";
+		} else if (value < 0.03492076949174773) {
+			return "rgba(135,211,43," + alpha + ")";
+		} else if (value < 0.08748866352592401) {
+			return "rgba(204,244,44," + alpha + ")";
+		} else if (value < 0.2679491924311227) {
+			return "rgba(245,233,44," + alpha + ")";
+		} else if (value < 0.7002075382097097) {
+			return "rgba(255,138,43," + alpha + ")";
+		} else if (value < 1.4281480067421144) {
+			return "rgba(255,84,43," + alpha + ")";
+		} else {
+			return "rgba(255,32,43," + alpha + ")";
+		}
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(SlopeAspect.prototype, /** @lends SlopeAspect.prototype */ {
+
+	/**
+	 * 等距离切分网格
+	 * @param {Object} points
+	 * @param {Object} polygon
+	 * @param {Object} options
+	 * @param {Object} options.distance 默认0.1km精度
+	 */
+	createNew4Distance(points, polygon, options) {
+		let _self = this;
+
+		options = options || {};
+		options.distance = options.distance || 0.1;//默认0.1km精度
+
+		let width = options.distance * 200 > 35 ? 35 : options.distance * 200;
+		_self.arrowWidth = width < 15 ? 15 : width;
+
+		/* 转换坐标 */
+		let positions = points.map(point => {
+			return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+		});
+
+		_self.clearAll();
+
+		let degrees = CoordTransform.Cartesian3ListToWGS84(positions);
+		// _self._viewer.entities.remove(polygon);
+		let boundary = [];
+		let minX = 10000,
+			minY = 10000,
+			maxX = -10000,
+			maxY = -1000;
+		for (let index = 0; index < degrees.length; index++) {
+			const element = degrees[index];
+			const x = element.lng;
+			const y = element.lat;
+			boundary.push([x, y]);
+			minX = x < minX ? x : minX;
+			minY = y < minY ? y : minY;
+			maxX = x > maxX ? x : maxX;
+			maxY = y > maxY ? y : maxY;
+		}
+		boundary.push(boundary[0]);
+
+		let bbox = [minX, minY, maxX, maxY];
+		let mask = turf.polygon([boundary]);
+		let gridSquare = turf.squareGrid(bbox, options.distance, {
+			// mask: mask,//加上这个参数分析不出来
+		});
+		_self._createEllipse(gridSquare);
+	},
+
+	/**
+	 * 等分切分网格,切分成一个num*num的网格
+	 * @param {Object} points
+	 * @param {Object} polygon
+	 * @param {Object} options.num=10
+	 */
+	createNew4Num(points, polygon, options) {
+		let _self = this;
+
+		options = options || {};
+		options.num = Cesium.defaultValue(options.num, 10);
+
+		/* 转换坐标 */
+		let positions = points.map(point => {
+			return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+		});
+
+
+		_self.clearAll();
+
+		let degrees = CoordTransform.Cartesian3ListToWGS84(positions);
+		// _self._viewer.entities.remove(polygon);
+		let boundary = [];
+		let minX = 10000,
+			minY = 10000,
+			maxX = -10000,
+			maxY = -1000;
+		for (let index = 0; index < degrees.length; index++) {
+			const element = degrees[index];
+			const x = element.lng;
+			const y = element.lat;
+			boundary.push([x, y]);
+			minX = x < minX ? x : minX;
+			minY = y < minY ? y : minY;
+			maxX = x > maxX ? x : maxX;
+			maxY = y > maxY ? y : maxY;
+		}
+		boundary.push(boundary[0]);
+
+		let bbox = [minX, minY, maxX, maxY];
+		let a = maxX - minX;
+		let b = maxY - minY;
+		b = b > a ? b : a;
+
+		const step = b / options.num;
+		let width = step * 2000 > 35 ? 35 : step * 2000;
+		_self.arrowWidth = width < 15 ? 15 : width;
+
+		let mask = turf.polygon([boundary]);
+		let gridSquare = turf.squareGrid(bbox, step, {
+			units: "degrees",
+			// mask: mask,//加上这个参数分析不出来
+		});
+
+		_self._createEllipse(gridSquare);
+	},
+
+	/**
+	 * 清除
+	 */
+	clearAll() {
+		this.result.forEach((element) => {
+			this._viewer.scene.primitives.remove(element);
+		});
+		this.result = [];
+
+		if (this.handler) {
+			this.handler.destroy();
+			this.handler = undefined;
+		}
+	},
+});
+
+export default SlopeAspect;

+ 354 - 0
packages/Widgets/TerrainAnalysis/TerrainExcavation.js

@@ -0,0 +1,354 @@
+//地形开挖
+class TerrainExcavation {
+	constructor(viewer) {
+		if (!viewer) throw new Error("no viewer object!");
+		this.viewer = viewer;
+	}
+
+	//计算并更新wellData
+	prepareWell(activePoints) {
+		let pointLength = activePoints.length;
+		let heightDiff = this.excavateMinHeight - this.height;
+		let no_height_top = [],
+			bottom_pos = [],
+			lerp_pos = [];
+		for (let l = 0; l < pointLength; l++) {
+			let u = l == pointLength - 1 ? 0 : l + 1;
+			let point0 = [
+				Cesium.Cartographic.fromCartesian(activePoints[l]).longitude,
+				Cesium.Cartographic.fromCartesian(activePoints[l]).latitude,
+			];
+			let point1 = [
+				Cesium.Cartographic.fromCartesian(activePoints[u]).longitude,
+				Cesium.Cartographic.fromCartesian(activePoints[u]).latitude,
+			];
+			if (0 == l) {
+				lerp_pos.push(new Cesium.Cartographic(point0[0], point0[1]));
+				bottom_pos.push(
+					Cesium.Cartesian3.fromRadians(point0[0], point0[1], heightDiff)
+				);
+				no_height_top.push(
+					Cesium.Cartesian3.fromRadians(point0[0], point0[1], 0)
+				);
+			}
+			for (let p = 1; p <= this.splitNum; p++) {
+				let m = Cesium.Math.lerp(point0[0], point1[0], p / this.splitNum);
+				let g = Cesium.Math.lerp(point0[1], point1[1], p / this.splitNum);
+				(l == pointLength - 1 && p == this.splitNum) ||
+				(lerp_pos.push(new Cesium.Cartographic(m, g)),
+					bottom_pos.push(Cesium.Cartesian3.fromRadians(m, g, heightDiff)),
+					no_height_top.push(Cesium.Cartesian3.fromRadians(m, g, 0)));
+			}
+		}
+		this.wellData = {
+			lerp_pos: lerp_pos,
+			bottom_pos: bottom_pos,
+			no_height_top: no_height_top,
+		};
+	}
+	//开始创建底面和侧面
+	createWell(wallData) {
+		let $this = this;
+		if (this.viewer.terrainProvider._layers) {
+			this.createBottomSurface(wallData.bottom_pos);
+			let positions = Cesium.sampleTerrainMostDetailed(
+				this.viewer.terrainProvider,
+				wallData.lerp_pos
+			);
+			positions.then(function(pos) {
+				let positionList = [];
+				for (let index = 0; index < pos.length; index++) {
+					const element = pos[index];
+					let curPos = Cesium.Cartesian3.fromRadians(
+						element.longitude,
+						element.latitude,
+						element.height
+					);
+					positionList.push(curPos);
+				}
+
+				$this.createWellWall(wallData.bottom_pos, positionList);
+			});
+			// Cesium.when(positions, function(pos) {
+			// 	let positionList = [];
+			// 	for (let index = 0; index < pos.length; index++) {
+			// 		const element = pos[index];
+			// 		let curPos = Cesium.Cartesian3.fromRadians(
+			// 			element.longitude,
+			// 			element.latitude,
+			// 			element.height
+			// 		);
+			// 		positionList.push(curPos);
+			// 	}
+			// 	$this.createWellWall(wallData.bottom_pos, positionList);
+			// });
+		} else {
+			this.createBottomSurface(wallData.bottom_pos);
+			this.createWellWall(wallData.bottom_pos, wallData.no_height_top);
+		}
+	}
+	//坐标转换,转出经纬度格式
+	ellipsoidToDegree(pos) {
+		let cartesian3 = new Cesium.Cartesian3(pos.x, pos.y, pos.z);
+		let cartographic =
+			this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
+		return {
+			longitude: Cesium.Math.toDegrees(cartographic.longitude),
+			latitude: Cesium.Math.toDegrees(cartographic.latitude),
+			altitude: cartographic.height,
+		};
+	}
+	//创建地形开挖的底面对象
+	createBottomSurface(points) {
+		if (points.length) {
+			let minHeight = this.getMinHeight(points);
+			let positions = [];
+			for (let i = 0; i < points.length; i++) {
+				let curPoint = this.ellipsoidToDegree(points[i]);
+				positions.push(curPoint.longitude, curPoint.latitude, minHeight);
+			}
+			let polygon = new Cesium.PolygonGeometry({
+				polygonHierarchy: new Cesium.PolygonHierarchy(
+					Cesium.Cartesian3.fromDegreesArrayHeights(positions)
+				),
+				perPositionHeight: true,
+			});
+
+			let material = new Cesium.Material({
+				fabric: {
+					type: "Image",
+					uniforms: {
+						image: this.bottomImg,
+					},
+				},
+			});
+			let appearance = new Cesium.MaterialAppearance({
+				translucent: false,
+				flat: true,
+				material: material,
+			});
+			this.bottomSurface = new Cesium.Primitive({
+				geometryInstances: new Cesium.GeometryInstance({
+					geometry: Cesium.PolygonGeometry.createGeometry(polygon),
+				}),
+				appearance: appearance,
+				asynchronous: false,
+			});
+			this.viewer.scene.primitives.add(this.bottomSurface);
+		}
+	}
+	// 创建地形开挖的侧面墙对象
+	createWellWall(bottomPos, positionList) {
+		let minHeight = this.getMinHeight(bottomPos);
+		let maxHeights = [],
+			minHeights = [];
+		for (let i = 0; i < positionList.length; i++) {
+			maxHeights.push(this.ellipsoidToDegree(positionList[i]).altitude);
+			minHeights.push(minHeight);
+		}
+		let wall = new Cesium.WallGeometry({
+			positions: positionList,
+			maximumHeights: maxHeights,
+			minimumHeights: minHeights,
+		});
+		let geometry = Cesium.WallGeometry.createGeometry(wall);
+		let material = new Cesium.Material({
+			fabric: {
+				type: "Image",
+				uniforms: {
+					image: this.wallImg,
+				},
+			},
+		});
+		let appearance = new Cesium.MaterialAppearance({
+			translucent: false,
+			flat: true,
+			material: material,
+		});
+		this.wellWall = new Cesium.Primitive({
+			geometryInstances: new Cesium.GeometryInstance({
+				geometry: geometry,
+				attributes: {
+					color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+						Cesium.Color.GREY
+					),
+				},
+				id: "PitWall",
+			}),
+			appearance: appearance,
+			asynchronous: false,
+		});
+		this.viewer.scene.primitives.add(this.wellWall);
+	}
+	//获取地形开挖最低点高程值
+	getMinHeight(points) {
+		let minHeight = 5000000;
+		let minPoint = null;
+		for (let i = 0; i < points.length; i++) {
+			let height = points[i]["z"];
+			if (height < minHeight) {
+				minHeight = height;
+				minPoint = this.ellipsoidToDegree(points[i]);
+			}
+		}
+		return minPoint.altitude;
+	}
+	switchExcavate(show) {
+		if (show) {
+			this.viewer.scene.globe.material = null;
+			this.wellWall.show = true;
+			this.bottomSurface.show = true;
+		} else {
+			this.viewer.scene.globe.material = null;
+			this.wellWall.show = false;
+			this.bottomSurface.show = false;
+		}
+	}
+
+	updateExcavateDepth(height) {
+		this.viewer.scene.primitives.remove(this.bottomSurface);
+		this.viewer.scene.primitives.remove(this.wellWall);
+		console.log(this.wellData, this.excavateMinHeight);
+		let lerp_pos = this.wellData.lerp_pos;
+		let posList = [];
+		for (let n = 0; n < lerp_pos.length; n++) {
+			posList.push(
+				Cesium.Cartesian3.fromRadians(
+					lerp_pos[n].longitude,
+					lerp_pos[n].latitude,
+					this.excavateMinHeight - height
+				)
+			);
+		}
+		this.wellData.bottom_pos = posList;
+		this.createWell(this.wellData);
+	}
+}
+Object.defineProperties(TerrainExcavation.prototype, {
+	show: {
+		get: function() {
+			return this._show;
+		},
+		set: function(e) {
+			this._show = e;
+			this.switchExcavate(e);
+		},
+	},
+	height: {
+		get: function() {
+			return this._height;
+		},
+		set: function(e) {
+			this._height = e;
+			this.updateExcavateDepth(e);
+		},
+	},
+});
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(TerrainExcavation.prototype, /** @lends TerrainExcavation.prototype */ {
+	/**
+	 * @param {Object} activePoints
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {String} options.url 服务地址
+	 * @param {Number} [options.maximumScreenSpaceError=16] 用于驱动细节细化级别的最大屏幕空间误差
+	 * @return {String} 服务Id
+	 */
+	add(activePoints, options) {
+		options = options || {};
+
+		this._height = options.excavateDepth || 10;
+		this.bottomImg = options.bottomImg || "jt3dSDK/imgs/polygon/ground.png";
+		this.wallImg = options.wallImg || "jt3dSDK/imgs/polygon/ground.png";
+		this.splitNum = Cesium.defaultValue(options.splitNum, 50);
+
+		activePoints = activePoints.map(point => {
+			return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+		});
+
+		let viewer = this.viewer;
+		this.clear();
+		let clippingPlanesList = [];
+		let car3Difference = Cesium.Cartesian3.subtract(
+			activePoints[0],
+			activePoints[1],
+			new Cesium.Cartesian3()
+		); //计算两个笛卡尔函数的分量差异
+		let boolDiff = car3Difference.x > 0;
+		this.excavateMinHeight = 999999999;
+		for (let index = 0; index < activePoints.length; ++index) {
+			let s = (index + 1) % activePoints.length;
+			let curMidPoint = Cesium.Cartesian3.midpoint(
+				activePoints[index],
+				activePoints[s],
+				new Cesium.Cartesian3()
+			);
+			let cartographic = Cesium.Cartographic.fromCartesian(activePoints[index]);
+			let curHeight =
+				viewer.scene.globe.getHeight(cartographic) || cartographic.height;
+			console.log(curHeight);
+			if (curHeight < this.excavateMinHeight) {
+				this.excavateMinHeight = curHeight;
+			}
+			let curMidPointNormal = Cesium.Cartesian3.normalize(
+				curMidPoint,
+				new Cesium.Cartesian3()
+			);
+			let curMidPointDifference = boolDiff ?
+				Cesium.Cartesian3.subtract(
+					activePoints[index],
+					curMidPoint,
+					new Cesium.Cartesian3()
+				) :
+				Cesium.Cartesian3.subtract(
+					activePoints[s],
+					curMidPoint,
+					new Cesium.Cartesian3()
+				);
+			curMidPointDifference = Cesium.Cartesian3.normalize(
+				curMidPointDifference,
+				curMidPointDifference
+			);
+			let curMidPointCross = Cesium.Cartesian3.cross(
+				curMidPointDifference,
+				curMidPointNormal,
+				new Cesium.Cartesian3()
+			);
+			curMidPointCross = Cesium.Cartesian3.normalize(
+				curMidPointCross,
+				curMidPointCross
+			);
+			let plane = new Cesium.Plane(curMidPointCross, 0);
+			let distance = Cesium.Plane.getPointDistance(plane, curMidPoint);
+			clippingPlanesList.push(
+				new Cesium.ClippingPlane(curMidPointCross, distance)
+			);
+		}
+		this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
+			planes: clippingPlanesList,
+			edgeWidth: 1,
+			edgeColor: Cesium.Color.WHITE,
+			enabled: true,
+		});
+		this.prepareWell(activePoints);
+		this.createWell(this.wellData);
+	},
+
+	/**
+	 * 清除开挖
+	 */
+	clear() {
+		if (this.viewer.scene.globe.clippingPlanes) {
+			this.viewer.scene.globe.clippingPlanes.removeAll();
+			this.viewer.scene.primitives.remove(this.bottomSurface);
+			this.viewer.scene.primitives.remove(this.wellWall);
+			this.viewer.scene.render();
+		}
+	}
+});
+
+
+export default TerrainExcavation;

+ 138 - 0
packages/Widgets/WallObject.js

@@ -0,0 +1,138 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import {
+	setSessionid
+} from "./common/common.js";
+
+/**
+ *流动纹理
+ */
+import DynamicWallMaterialProperty from "./WallObject/DynamicWallMaterialProperty.js";
+import WallDiffuseMaterialProperty from "./WallObject/WallDiffuseMaterialProperty.js";
+import WallMaterialProperty from "./WallObject/WallMaterialProperty.js";
+
+/**
+ * 墙体对象
+ */
+class WallObject {
+	/**
+	 * 默认初始化
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(WallObject.prototype, /** @lends WallObject.prototype */ {
+
+	/**
+	 * @description 根据GeoJson绘制墙体对象
+	 * @param {String} geoJsonUrl geoJson文件路径
+	 * @param {Object} [options] 线的样式,具有以下属性:
+	 * @param {Number} [options.id] 用于移除
+	 * @param {Number} [options.clampToGround=true] 是否贴地
+	 * @param {Number} [options.minimunHeights=0] 最低高度
+	 * @param {Number} [options.maximumHeights=100] 最高高度
+	 * @param {Number} [options.imgUrl] 动态墙图片
+	 * @param {String} [options.color="#FF0000"] 指定墙的颜色
+	 * @param {Number} [options.duration=3000] 持续时间 毫秒,越小越快
+	 * @param {Number} [options.count] 重复次数
+	 * @param {String} [options.direction='horizontal'] 方向 vertical纵,垂直方向,horizontal横,水平方向
+	 * @param {String} [options.order] 方向正负 
+	 *                                        vertical 纵:'-'(由下到上) , '+"(由上到下)
+	 *                                        horizontal 横:'-'(顺时针) , '+'(逆时针)
+	 */
+	drawWallByGeoJson: function(geoJsonUrl, options) {
+		return new Promise((resolve, reject) => {
+
+			let _self = this;
+			let viewer = this._viewer;
+
+			if (!Cesium.defined(geoJsonUrl)) {
+				throw new Cesium.DeveloperError("geoJsonUrl is required.");
+			}
+
+			options = options || {};
+			options.id = options.id || setSessionid();
+			options.clampToGround = Cesium.defaultValue(options.clampToGround, true);
+
+			options.minimunHeights = options.minimunHeights !== undefined && typeof options.minimunHeights === 'number' ? options.minimunHeights : 0;
+			options.maximumHeights = options.maximumHeights !== undefined && typeof options.maximumHeights === 'number' ? options.maximumHeights : 1000;
+
+			if (options.color) {
+				if (options.color instanceof Array) {
+					options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+				} else if (typeof(options.color) === 'string') {
+					options.color = new Cesium.Color.fromCssColorString(options.color);
+				} else {
+					options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+				}
+			}
+
+			options.trailImage = Cesium.defaultValue(options.trailImage, 'jt3dSDK/imgs/wallmaterial/wl.png');
+			options.duration = Cesium.defaultValue(options.duration, 3000);
+			options.count = Cesium.defaultValue(options.count, 1);
+			options.direction = Cesium.defaultValue(options.direction, 'vertical');
+			options.order = Cesium.defaultValue(options.order, '-');
+
+			fetch(geoJsonUrl).then(res => {
+				return res.json();
+			}).then(res => {
+
+				for (var i = 0; i < res.features.length; i++) {
+					let coordinates = res.features[i].geometry.coordinates;
+					let positions = coordinates.map(point => {
+						return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+					});
+
+					//先创建一个CustomDataSource源,然后把entity存入这里面
+					let wall = new Cesium.CustomDataSource(options.id);
+					viewer.dataSources.add(wall);
+
+					let entity = new Cesium.Entity({
+						name: "立体墙效果",
+						wall: {
+							positions: positions,
+							// 设置高度
+							maximumHeights: new Array(positions.length).fill(options.maximumHeights),
+							minimunHeights: new Array(positions.length).fill(options.minimunHeights),
+							// 扩散墙材质
+							// material: new Cesium.WallDiffuseMaterialProperty({
+							//     color: new Cesium.Color(1.0, 1.0, 0.0, 1.0)
+							// }),
+							material: new WallMaterialProperty(viewer, {
+								trailImage: options.trailImage,
+								color: options.color,
+								duration: options.duration,
+								param: {
+									count: options.count,
+									direction: options.direction,
+									order: options.order,
+								},
+							}),
+
+							// material: new Cesium.DynamicWallMaterialProperty({
+							// 	trailImage: 'jt3dSDK/imgs/wallmaterial/wl.png',
+							// 	color: Cesium.Color.CYAN,
+							// 	duration: 1500
+							// })
+						}
+					});
+
+					// 绘制墙体
+					wall.entities.add(entity)
+				}
+
+				resolve(options.id);
+			});
+
+		});
+	},
+});
+
+export default WallObject;

+ 107 - 0
packages/Widgets/WallObject/DynamicWallMaterialProperty.js

@@ -0,0 +1,107 @@
+/*
+    动态墙材质
+    color 颜色
+    duration 持续时间 毫秒
+    trailImage 贴图地址
+*/
+function DynamicWallMaterialProperty(options) {
+	this._definitionChanged = new Cesium.Event();
+	this._color = undefined;
+	this._colorSubscription = undefined;
+	this.color = options.color || Color.BLUE;
+	this.duration = options.duration || 1000;
+	this.trailImage = options.trailImage;
+	this._time = (new Date()).getTime();
+}
+
+/**
+ * 带方向的墙体
+ * @param {*} options.get:true/false
+ * @param {*} options.count:数量 
+ * @param {*} options.direction:vertical/standard
+ * @param {*} options.order:+/-
+ */
+function _getDirectionWallShader(options) {
+	if (options && options.get) {
+		var materail = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\
+      {\n\
+          czm_material material = czm_getDefaultMaterial(materialInput);\n\
+          vec2 st = materialInput.st;";
+		if (options.direction == "vertical") { //(由下到上)
+			materail += "vec4 colorImage = texture2D(image, vec2(fract(st.s), fract(float(" + options.count + ")*st.t" + options.order + " time)));\n\ ";
+		} else { //(逆时针)
+			materail += "vec4 colorImage = texture2D(image, vec2(fract(float(" + options.count + ")*st.s " + options.order + " time), fract(st.t)));\n\ ";
+		}
+		//泛光
+		materail += "vec4 fragColor;\n\
+          fragColor.rgb = (colorImage.rgb+color.rgb) / 1.0;\n\
+          fragColor = czm_gammaCorrect(fragColor);\n\
+          material.diffuse = colorImage.rgb;\n\
+          material.alpha = colorImage.a;\n\
+          material.emission = fragColor.rgb;\n\
+          return material;\n\
+      }";
+		return materail
+	}
+}
+
+Object.defineProperties(DynamicWallMaterialProperty.prototype, {
+	isConstant: {
+		get: function() {
+			return false;
+		}
+	},
+	definitionChanged: {
+		get: function() {
+			return this._definitionChanged;
+		}
+	},
+	color: Cesium.createPropertyDescriptor('color')
+});
+
+var MaterialType = 'wallType' + parseInt(Math.random() * 1000);
+DynamicWallMaterialProperty.prototype.getType = function(time) {
+	return MaterialType;
+};
+
+DynamicWallMaterialProperty.prototype.getValue = function(time, result) {
+	if (!Cesium.defined(result)) {
+		result = {};
+	}
+	result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
+	result.image = this.trailImage;
+	if (this.duration) {
+		result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
+	}
+	viewer.scene.requestRender();
+	return result;
+};
+
+DynamicWallMaterialProperty.prototype.equals = function(other) {
+	return this === other ||
+		(other instanceof DynamicWallMaterialProperty &&
+			Cesium.Property.equals(this._color, other._color))
+};
+
+Cesium.Material._materialCache.addMaterial(MaterialType, {
+	fabric: {
+		type: MaterialType,
+		uniforms: {
+			color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
+			image: Cesium.Material.DefaultImageId,
+			time: -20
+		},
+		source: _getDirectionWallShader({
+			get: true,
+			count: 3.0,
+			direction: 'vertical',
+			order: '-'
+		})
+	},
+	translucent: function(material) {
+		return true;
+	}
+});
+Cesium.DynamicWallMaterialProperty = DynamicWallMaterialProperty;
+
+export default DynamicWallMaterialProperty;

+ 79 - 0
packages/Widgets/WallObject/WallDiffuseMaterialProperty.js

@@ -0,0 +1,79 @@
+/*
+ * @Description: 动态扩散墙的墙体效果(参考开源代码)(不同高度透明度不同)
+ * @Version: 1.0
+ * @Author: Julian
+ * @Date: 2022-03-07 19:50:46
+ * @LastEditors: Julian
+ * @LastEditTime: 2022-03-08 13:34:04
+ */
+class WallDiffuseMaterialProperty {
+    constructor(options) {
+        this._definitionChanged = new Cesium.Event();
+        this._color = undefined;
+        this.color = options.color;
+    };
+
+    get isConstant() {
+        return false;
+    }
+
+    get definitionChanged() {
+        return this._definitionChanged;
+    }
+
+    getType(time) {
+        return Cesium.Material.WallDiffuseMaterialType;
+    }
+
+    getValue(time, result) {
+        if (!Cesium.defined(result)) {
+            result = {};
+        }
+
+        result.color = Cesium.Property.getValueOrDefault(this._color, time, Cesium.Color.RED, result.color);
+        return result
+    }
+
+    equals(other) {
+        return (this === other ||
+            (other instanceof WallDiffuseMaterialProperty &&
+                Cesium.Property.equals(this._color, other._color))
+        )
+    }
+}
+
+Object.defineProperties(WallDiffuseMaterialProperty.prototype, {
+    color: Cesium.createPropertyDescriptor('color'),
+})
+
+Cesium.WallDiffuseMaterialProperty = WallDiffuseMaterialProperty;
+Cesium.Material.WallDiffuseMaterialProperty = 'WallDiffuseMaterialProperty';
+Cesium.Material.WallDiffuseMaterialType = 'WallDiffuseMaterialType';
+Cesium.Material.WallDiffuseMaterialSource =
+    `
+    uniform vec4 color;
+    czm_material czm_getMaterial(czm_materialInput materialInput){
+    czm_material material = czm_getDefaultMaterial(materialInput);
+    vec2 st = materialInput.st;
+    material.diffuse = color.rgb * 2.0;
+    material.alpha = color.a * (1.0 - fract(st.t)) * 0.8;
+    return material;
+    }
+                                            
+    `
+
+Cesium.Material._materialCache.addMaterial(Cesium.Material.WallDiffuseMaterialType, {
+    fabric: {
+        type: Cesium.Material.WallDiffuseMaterialType,
+        uniforms: {
+            color: new Cesium.Color(1.0, 0.0, 0.0, 1.0),
+        },
+        source: Cesium.Material.WallDiffuseMaterialSource
+    },
+    translucent: function(material) {
+        return true;
+    }
+})
+
+
+export default WallDiffuseMaterialProperty;

+ 186 - 0
packages/Widgets/WallObject/WallMaterialProperty.js

@@ -0,0 +1,186 @@
+class WallMaterialProperty {
+	/**
+	 * 构造方法
+	 * @ignore 无需公开
+	 * @param {Cesium.Viewer} viewer 着色器运行所需的视图
+	 * @param {JSON} options 配置项
+	 * @param {Cesium.Color} options.color [墙的颜色,默认蓝色] 可选
+	 * @param {Number} options.duration [循环时间 默认1000] 可选
+	 * @param {String} options.trailImage 墙的贴图
+	 * @param {JSON} options.param 着色器参数
+	 * @param {Number} options.param.count [数量 可选 默认为1]
+	 * @param {String} options.param.direction [方向 可选 默认竖直 ] 取值vertical/horizontal
+	 * @param {String} options.param.order [顺序 可选 上下/下上/顺时针/逆时针 与方向配合使用 ] 取值+/-
+	 */
+	constructor(viewer, options) {
+		
+
+		/* 着色器运行依赖的视图 */
+		this._viewer = viewer;
+		options = options || {};
+
+		/* 变更事件 */
+		this._definitionChanged = new Cesium.Event();
+		this._color = undefined;
+		/* 墙的颜色 */
+		this.color = options.color || Cesium.Color.BLUE;
+		/* 动态循环周期 */
+		this.duration = options.duration || 1000;
+		
+		this.count = options.duration || 1;	
+		this.direction = options.duration || 'vertical';
+		this.order = options.duration || '-';
+		
+		
+		
+		/* 墙的贴图 */
+		this.trailImage = Cesium.defaultValue(options.trailImage, 'jt3dSDK/imgs/wallmaterial/wl.png');
+		/* 默认时间 */
+		this._time = (new Date()).getTime();
+		/* 材质类型名称 */
+		this._materialTypeName = 'WallMaterial' + this._guid();
+		/* 存储相关参数的属性 以便后期进行追踪修改 */
+		this._param = {
+			color: this.color._value.toCssColorString(),
+			image: this.trailImage,
+			duration: this.duration,
+			count: this.count,
+			direction: this.direction,
+			order: this.order,
+		}
+		/* 将材质加入缓存 以便重复利用 */
+		Cesium.Material._materialCache.addMaterial(this._materialTypeName, {
+			fabric: {
+				type: this._materialTypeName,
+				uniforms: {
+					time: -20,
+					color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
+					image: options.trailImage,
+				},
+				source: this._getDirectionWallShader(options.param)
+			},
+			translucent: function(material) {
+				/* 材质是否半透明 */
+				return true;
+			}
+		});
+	}
+
+	/**
+	 * 生成GUID随机数
+	 * @ignore 无需公开
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 重新获取类型方法
+	 * @ignore 无需公开
+	 * @param {Cesium.JulianDate} time 时间
+	 */
+	getType(time) {
+		return this._materialTypeName;
+	}
+
+	/**
+	 * 重写获取值方法
+	 * @ignore 无需公开
+	 * @param {Cesium.JulianDate} time
+	 * @param {JSON} result 
+	 */
+	getValue(time, result) {
+		if (!Cesium.defined(result)) {
+			result = {};
+		}
+		result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.BLUE, result.color);
+		result.image = this.trailImage;
+		if (this.duration) {
+			result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
+		}
+		this._viewer.scene.requestRender();
+		return result;
+	}
+
+	/**
+	 * 重写对比函数
+	 * @ignore 无需公开
+	 * @param {Object} other 传入对比对象
+	 */
+	equals(other) {
+		return (this === other || (other instanceof WallMaterialProperty && Cesium.Property.equals(this
+				._color, other._color) && other._param.order === this._param.order && other._param.count ===
+			this._param.count && other._param.direction === this._param.direction && other.duration === this
+			.duration));
+	}
+
+	/**
+	 * 创建着色器资源
+	 * @ignore 无需公开
+	 * @param {JSON} options 配置项
+	 * @param {Number} options.count [数量 可选 默认为1]
+	 * @param {String} options.direction [方向 可选 默认竖直 ] 取值vertical/horizontal
+	 * @param {String} options.order [顺序 可选 上下/下上/顺时针/逆时针 与方向配合使用 ] 取值+/-
+	 */
+	_getDirectionWallShader(options) {
+		let op = Cesium.defaultValue(options, {});
+		// console.log('>>>op===', op);
+		let count = op.count !== undefined && typeof op.count === 'number' && op.count > 0 ? op.count : 1;
+		let direction = op.direction === 'horizontal' ? 'horizontal' : 'vertical';
+		let order = op.order === '+' ? '+' : '-';
+		this._param.count = count;
+		this._param.direction = direction;
+		this._param.order = order;
+		let materail = '';
+		/* 补充参数 */
+		// console.log('_param', this._param);
+		materail += 'czm_material czm_getMaterial(czm_materialInput materialInput){\n' +
+			'  czm_material material = czm_getDefaultMaterial(materialInput);\n' +
+			'  vec2 st = materialInput.st;\n';
+		if (direction === 'vertical') {
+			materail += '  vec4 colorImage = texture2D(image,vec2(st.s,fract(float(' + count + ')*st.t ' + order + ' time)));\n';
+		} else if (direction === 'horizontal') {
+			materail += '  vec4 colorImage = texture2D(image, vec2(fract(float(' + count + ')*st.s ' + order + ' time), st.t));\n'
+		}
+		materail += '  vec4 fragColor;\n' +
+			'  fragColor.rgb = color.rgb / 1.0;\n' +
+			'  fragColor = czm_gammaCorrect(fragColor);\n' +
+			'  material.alpha = colorImage.a * color.a;\n' +
+			'  material.diffuse = color.rgb;\n' +
+			'  material.emission = fragColor.rgb;\n' +
+			'  return material;\n' +
+			'}';
+		return materail;
+	}
+}
+
+/**
+ * 增加默认属性
+ */
+Object.defineProperties(WallMaterialProperty.prototype, {
+	/**
+	 * @ignore 无需公开
+	 * 判断是否相等,返回false表示属性一直在变化中
+	 */
+	isConstant: {
+		get: function() {
+			return false;
+		}
+	},
+	/**
+	 * @ignore 无需公开
+	 * 事件变更
+	 */
+	definitionChanged: {
+		get: function() {
+			return this._definitionChanged;
+		}
+	},
+	/* 颜色属性 */
+	color: Cesium.createPropertyDescriptor('color')
+})
+
+export default WallMaterialProperty;

+ 513 - 0
packages/Widgets/base.js

@@ -0,0 +1,513 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+//状态栏
+import StatusBar from "./StatusBar.js";
+
+import '../Assets/styles/base.css';
+
+/**
+ * 场景视图
+ */
+class jtMap3d {
+	/**
+	 * 
+	 * 初始化三维大球
+	 * @author joy
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.container 包含球体小部件的 DOM 元素ID
+	 * @param {String} [options.imageryProviderType] 默认底图(世界影像)影像类型
+	 * @param {String} [options.imageryProviderUrl] 默认底图(世界影像)影像路径
+	 * 
+	 * @example
+	 * 
+	 * 例1:
+	 * const jtMap3d = new jtMap3d({container: "jtMap3dContainer"});
+	 *
+	 * 例2:
+	 * const jtMap3d = new jtMap3d({
+	 *	 container: "jtMap3dContainer",
+	 *	 imageryProviderType: "SingleTileImageryProvider",
+	 *	 imageryProviderUrl: "img/earth_3.jpg",
+	 * });
+	 *
+	 */
+	constructor(options) {
+
+		if (!Cesium.defined(options) || !Cesium.defined(options.container)) {
+			throw new Cesium.DeveloperError("options.container is required.");
+		}
+
+		/* 设置token 这很重要 否则将导致地图无法加载 */
+		Cesium.Ion.defaultAccessToken =
+			'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxNzM5YjQ3MC03YmMxLTRmMjAtOTk4Yi0yNDMyMDZlOTQzYTYiLCJpZCI6NTU5MjAsImlhdCI6MTYyNDI0NTM5NX0.diydVWFzw5C5rQlHaFYkdDJoSorcdex81KpWcntyICo';
+
+		/* 初始化地图控件 */
+		this._viewer = this._initMap(options);
+
+		/* 初始化变量 地图基础图层集合*/
+		this._imageryLayers = this._viewer.imageryLayers;
+
+		/* 初始化变量 地图原语集合 */
+		this._primitives = this._viewer.scene.primitives;
+
+		/* 初始化变量 地图绘制实体集合 */
+		this._entities = this._viewer.entities;
+
+		/* 初始化变量 数据源集合 */
+		this._dataSources = this._viewer.dataSources; //数据源集合
+
+		//默认天空盒子
+		this._defaultSkyBox = this._viewer.scene.skyBox;
+
+		this.statusBar = new StatusBar(this._viewer);
+
+		console.log(Cesium.buildModuleUrl.getCesiumBaseUrl());
+	}
+
+	/**
+	 * 初始化球体查看小部件
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} options 具有以下属性:
+	 * @param {Element | String} options.container 包含球体小部件的 DOM 元素或 ID
+	 * @param {String} [options.imageryProviderType] 影像类型
+	 * @param {String} [options.imageryProviderUrl] 影像路径
+	 * @return {Viewer} 
+	 */
+	_initMap(options) {
+
+		// //添加默认底图(世界影像)
+		// var imageryProvider = new Cesium.SingleTileImageryProvider({
+		// 	url: 'jt3dSDK/imgs/earth_3.jpg',
+		// });
+
+		// if (Cesium.defined(options.imageryProviderType)) {
+		// 	if (Cesium.defined(options.imageryProviderUrl)) {
+
+		// 		if (options.imageryProviderType == "SingleTileImageryProvider") {
+		// 			imageryProvider = new Cesium.SingleTileImageryProvider({
+		// 				url: options.imageryProviderUrl,
+		// 			});
+		// 		} else if (options.imageryProviderType == "OpenStreetMapImageryProvider") {
+		// 			imageryProvider = new Cesium.OpenStreetMapImageryProvider({
+		// 				url: options.imageryProviderUrl
+		// 			});
+		// 		} else if (options.imageryProviderType == "ArcGisMapServerImageryProvider") {
+		// 			imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
+		// 				url: options.imageryProviderUrl
+		// 			});
+		// 		}
+		// 	} else {
+		// 		throw new Cesium.DeveloperError("imageryProviderType and imageryProviderUrl are required.");
+		// 	}
+		// }
+
+		//球体查看器
+		let viewer = new Cesium.Viewer(options.container, {
+			animation: true, //是否显示动画控件(左下角时间圆盘)
+			timeline: true, //是否显示时间线控件(下方时间条),默认true
+			shadows: false, //阴影,是否让太阳投射阴影
+			shouldAnimate: true, //是否允许动画,是否允许场景中的动画自动播放
+
+			baseLayerPicker: false, //地图切换控件(底图以及地形图)是否显示,默认显示true
+			navigationHelpButton: false, //是否显示帮助信息控件,默认true
+			homeButton: false, //主页按钮,默认true
+			fullscreenButton: false, //全屏按钮,默认显示true
+
+			sceneModePicker: false, //是否显示3D/2D选择器
+			scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
+
+			infoBox: false, //点击要素之后显示的信息,默认true
+			clampToGround: true, //开启贴地
+			geocoder: false, //地名查找,默认true
+			// imageryProvider: imageryProvider,
+			selectionIndicator: false, //选中元素显示,默认true选中元素显示,默认true
+			contextOptions: {
+				webgl: {
+					alpha: true,
+					depth: true,
+					stencil: true,
+					antialias: true,
+					premultipliedAlpha: true,
+					//通过canvas.toDataURL()实现截图需要将该项设置为true
+					preserveDrawingBuffer: true,
+					failIfMajorPerformanceCaveat: true
+				}
+			}
+		});
+
+		//隐藏版本信息
+		viewer._cesiumWidget._creditContainer.style.display = "none";
+
+		//是否显示地球 
+		viewer.scene.globe.show = true;
+		//高程遮挡效果。地形不透明 地形检测,Cesium开启地形检测		
+		/* 此项设置为true可以查看哪些内容掉到地下了 正常情况下设置为false 否则会导致绘制的点只能看见一半 */
+		viewer.scene.globe.depthTestAgainstTerrain = true;
+		// 光照效果
+		viewer.scene.globe.enableLighting = false;
+
+		//启动主动渲染 这样地图加载完成后停止渲染 可节省CPU的开支(开启,以防部分动态效果失效)
+		viewer.scene.requestRenderMode = false;
+		//是否显示帧FPS
+		viewer.scene.debugShowFramesPerSecond = true;
+		//是否隐藏大气圈,如果显示大气圈,自定义天空盒子无效
+		viewer.scene.skyAtmosphere.show = false;
+		//是否显示星空(默认天空盒子)
+		viewer.scene.skyBox.show = true;
+		//是否显示太阳
+		viewer.scene.sun.show = true;
+		//是否显示有月亮
+		viewer.scene.moon.show = false;
+
+		//取消鼠标左键双击
+		viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
+
+		//右侧缺少一块(全屏按钮)
+		// viewer.animation.container.style.visibility = 'hidden';
+		// viewer.timeline.container.style.visibility = 'hidden';
+		// 修改timeline时间  从儒略日改为北京时间
+		viewer.animation.viewModel.dateFormatter = localeDateTimeFormatter;
+		viewer.animation.viewModel.timeFormatter = localeTimeFormatter;
+		viewer.timeline.makeLabel = localeDateTimeFormatter;
+
+		//ignoredate 忽略日期
+		function localeDateTimeFormatter(datetime, viewModel, ignoredate) {
+			var julianDT = new Cesium.JulianDate();
+			Cesium.JulianDate.addHours(datetime, 8, julianDT);
+
+			var gregorianDT = Cesium.JulianDate.toGregorianDate(julianDT);
+
+			var objDT;
+			if (ignoredate) {
+				objDT = '';
+			} else {
+
+				objDT = new Date(gregorianDT.year, gregorianDT.month - 1, gregorianDT.day);
+
+				objDT = gregorianDT.year + '-' + objDT.toLocaleString('zh-cn', {
+					month: 'short'
+				}).split('月').join('-') + gregorianDT.day + ' ';
+
+				if (viewModel || gregorianDT.hour + gregorianDT.minute === 0) {
+					return objDT
+					objDT += '';
+				}
+			}
+
+			let hour, minute, second;
+			if (gregorianDT.hour < 10) {
+				hour = `0${gregorianDT.hour}`
+			} else {
+				hour = gregorianDT.hour
+			}
+			if (gregorianDT.minute < 10) {
+				minute = `0${gregorianDT.minute}`
+			} else {
+				minute = gregorianDT.minute
+			}
+			if (gregorianDT.second < 10) {
+				second = `0${gregorianDT.second}`
+			} else {
+				second = gregorianDT.second
+			}
+			// var millisecond = Math.round(gregorianDT.millisecond);
+
+			// return objDT + hour + ":" + minute + ":" + second+ ":" + millisecond;
+
+			return objDT + hour + ":" + minute + ":" + second;
+		}
+
+		function localeTimeFormatter(time, viewModel) {
+			return localeDateTimeFormatter(time, viewModel, true)
+		}
+
+		return viewer;
+	}
+
+	/**
+	 * 初始化大球视窗范围
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} options.longitude 经度,以度为单位
+	 * @param {Number} options.latitude 纬度,以度为单位
+	 * @param {Number} [options.height=0.0] 椭球的高度,以米为单位
+	 * @param {Number} [options.heading=0.0] 指向,默认值0.0(北)
+	 * @param {Number} [options.pitch=-90] 视角,默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.roll=0.0] 翻滚
+	 */
+	_setView(options) {
+		if (!Cesium.defined(options.longitude) && !Cesium.defined(options.latitude)) {
+			throw new Cesium.DeveloperError("longitude and  latitude are required.");
+		}
+
+		Cesium.Check.typeOf.number("longitude", options.longitude);
+		Cesium.Check.typeOf.number("latitude", options.latitude);
+
+		this._viewer.camera.setView({ //设置视图 设置相机位置、方向和变换。
+			//fromDegrees()将经纬度和高程转为世界坐标     摄像机在 WGS84(世界)坐标中的最终位置,或从自上而下视图可见的矩形。
+			destination: Cesium.Cartesian3.fromDegrees(
+				options.longitude,
+				options.latitude,
+				options.height
+			),
+			orientation: {
+				//此视角为观察者/相机 Math.toRadians() 将角度换成弧度。
+				heading: Cesium.Math.toRadians(Cesium.defaultValue(options.heading, 0.0)),
+				pitch: Cesium.Math.toRadians(Cesium.defaultValue(options.pitch, -90)),
+				roll: options.roll,
+			},
+		});
+	}
+
+	/**
+	 * 获取中国范围坐标 
+	 *  @ignore 忽略注释,注释不生成Doc
+	 */
+	_getChinaPostion() {
+		return Cesium.Cartesian3.fromDegrees(116.435314, 40.960521, 10000000.0);
+	}
+
+	/**
+	 *  初始定位中国
+	 *  @ignore 忽略注释,注释不生成Doc
+	 */
+	_flytoChina() {
+		this._viewer.camera.flyTo({
+			destination: this._getChinaPostion(),
+			duration: 8
+		});
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(jtMap3d.prototype, /** @lends jtMap3d.prototype */ {
+
+	/**
+	 * 初始化大球视窗范围,锁定为中国范围
+	 */
+	setViewChina: function() {
+		this._setView({
+			longitude: 103.84, //经度
+			latitude: 31.15, //维度
+			height: 24000000, //高度
+			heading: 0, // 偏航
+			pitch: -90, // 俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+			roll: 0.0 // 翻滚
+		});
+	},
+
+	/**
+	 * 初始化项目范围(即全图功能)
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} options.west=0.0  最西端的经度范围[-180.0,180.0]
+	 * @param {Number} options.south=0.0 最南端的纬度范围[-90.0,90.0]
+	 * @param {Number} options.east=0.0  最东端的经度范围[-180.0,180.0]
+	 * @param {Number} options.north=0.0 最北端的纬度范围[-90.0,90.0]
+	 * @param {Number} [options.isRemove=true] 定位完成后是否删除
+	 * @param {Number} [options.duration=3] 飞行时间
+	 * @param {Number} [options.heading=0]
+	 * @param {Number} [options.pitch=-90]
+	 * @param {Number} [options.range=0]
+	 */
+	fullMap: function(options) {
+		return new Promise((resolve, reject) => {
+			let _self = this;
+			this._entities.removeById("fullMapRectangle");
+
+			// 初始化参数默认值
+			options.isRemove = Cesium.defaultValue(options.isRemove, true);
+			options.duration = Cesium.defaultValue(options.duration, 3);
+			options.heading = Cesium.defaultValue(options.heading, 0);
+			options.pitch = Cesium.defaultValue(options.pitch, -90);
+			options.range = Cesium.defaultValue(options.range, 0.0);
+
+			//left,bottom,right,top (西,南,东,北)
+			var rectangle = Cesium.Rectangle.fromDegrees(options.west, options.south, options.east,
+				options.north);
+
+			//定义一个实体对象
+			var fullMapEntity = this._entities.add({
+				id: "fullMapRectangle",
+				name: "fullMapRectangle",
+				rectangle: {
+					coordinates: rectangle,
+					material: Cesium.Color.GREEN.withAlpha(0),
+					height: 10.0,
+					outline: false
+				}
+			});
+
+			var flyPromise = this._viewer.flyTo(fullMapEntity, {
+				duration: options.duration, //飞行时间
+				offset: {
+					heading: Cesium.Math.toRadians(options.heading),
+					pitch: Cesium.Math.toRadians(options.pitch),
+					range: options.range
+				},
+			});
+
+			flyPromise.then(function(flyPromise) {
+					if (flyPromise) {
+						//飞行成功后,是否移除该实体
+						if (options.isRemove) {
+							fullMapEntity && (_self._entities.remove(fullMapEntity),
+								fullMapEntity = null);
+						}
+						resolve(true);
+					}
+				})
+				.catch(function(error) {
+					console.log(error);
+				});
+		});
+	},
+
+	/**
+	 *  地图指北
+	 */
+	setMapNorth() {
+		let viewer = this._viewer;
+
+		let pitch = Cesium.Math.toDegrees(viewer.camera.pitch).toFixed(0);
+
+		// 中心点位置
+		var center = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.clientWidth / 2, viewer.canvas.clientHeight / 2));
+		var curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(center);
+		let centerX = curPosition.longitude * 180 / Math.PI;
+		let centerY = curPosition.latitude * 180 / Math.PI;
+
+		//相机姿态信息
+		let cameraPointX = viewer.camera.positionCartographic.longitude * 180 / Math.PI;
+		let cameraPointY = viewer.camera.positionCartographic.latitude * 180 / Math.PI;
+		let cameraPointZ = viewer.camera.positionCartographic.height.toFixed(0);
+
+		// 计算两点之间距离
+		var satrt = Cesium.Cartographic.fromDegrees(cameraPointX, cameraPointY, cameraPointZ);
+		var end = Cesium.Cartographic.fromDegrees(centerX, centerY, 0);
+
+		var geodesic = new Cesium.EllipsoidGeodesic();
+		geodesic.setEndPoints(satrt, end);
+		var distance = geodesic.surfaceDistance;
+		let range = Math.sqrt(Math.pow(distance, 2) + Math.pow(cameraPointZ - 0, 2));
+
+		// 创建旋转中心点
+		if (this.centerEntity) {
+			viewer.entities.remove(this.centerEntity);
+		}
+		this.centerEntity = viewer.entities.add({
+			position: Cesium.Cartesian3.fromDegrees(centerX, centerY, 0),
+			point: {
+				color: Cesium.Color.RED,
+				pixelSize: 1
+			}
+		});
+
+		//更新场景相关旋转、角度距离参数
+		let offset = new Cesium.HeadingPitchRange(Cesium.Math.toRadians(0), Cesium.Math.toRadians(pitch), range);
+		viewer.zoomTo(this.centerEntity, offset);
+	},
+
+	/**
+	 * 地图自旋
+	 * @param {Array/Cartesian3} points  绕点位置[lng,lat,height]经度,以度为单位,纬度,以度为单位
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.speed=30] 设定绕行一周花费时间
+	 * @param {Number} [options.pitch] 设定相机角度,默认相机当前看点的角度,如果大于0那么则是从地底往上看,所以要为负值。-90(向下看,俯仰)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.height] 设定相机距离点的距离,默认相机当前视角高度
+	 */
+	setMapSpinByPoint(points, options) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(points)) {
+			throw new Cesium.DeveloperError("points is required.");
+		}
+
+		options = options || {};
+		options.speed = Cesium.defaultValue(options.speed, 30);
+
+		//绕点位置
+		var position = points;
+		if (points instanceof Cesium.Cartesian3) {
+			position = points;
+		} else {
+			position = Cesium.Cartesian3.fromDegrees(points[0], points[1], points[2] || 0);
+		}
+
+		// 为更直观地展示查询的位置,在点击处添加对应点
+		var entity = viewer.entities.add(
+			new Cesium.Entity({
+				point: new Cesium.PointGraphics({
+					color: new Cesium.Color(1, 1, 0),
+					pixelSize: 6,
+					outlineColor: new Cesium.Color(0, 1, 1)
+				}),
+				position: position
+			})
+		)
+
+		// 给定飞行一周所需时间,比如30s, 那么每秒转动度数
+		var angle = 360 / options.speed;
+
+		// 相机的当前heading
+		var initialHeading = viewer.camera.heading;
+
+		// 相机的当前pitch,相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
+		var pitch = viewer.camera.pitch
+		if (options.pitch) {
+			pitch = Cesium.Math.toRadians(options.pitch);
+		}
+
+		// 给定相机距离点多少距离飞行
+		var distance = viewer.camera.positionCartographic.height;
+		if (options.height) {
+			distance = options.height;
+		}
+
+		// 起始时间
+		var startTime = Cesium.JulianDate.fromDate(new Date());
+		// 结束时间,设置一个结束时间,意思是360秒之后时间结束
+		// var stopTime = Cesium.JulianDate.addSeconds(startTime,angle, new Cesium.JulianDate());
+
+		viewer.clock.startTime = startTime.clone(); // 开始时间
+		// viewer.clock.stopTime = stopTime.clone(); // 结速时间
+		viewer.clock.currentTime = startTime.clone(); // 当前时间
+		viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式
+		viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。
+
+		var Exection = function TimeExecution() {
+			// 当前已经过去的时间,单位s
+			var delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);
+			// 根据过去的时间,计算偏航角的变化
+			var heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;
+
+			viewer.scene.camera.setView({
+				destination: position, // 点的坐标
+				orientation: {
+					heading: heading,
+					pitch: pitch,
+				}
+			});
+			viewer.scene.camera.moveBackward(distance);
+
+			if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
+				viewer.clock.onTick.removeEventListener(Exection);
+			}
+
+			//监听点击事件
+			var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+			handler.setInputAction(function(click) {
+				viewer.clock.onTick.removeEventListener(Exection);
+				viewer.entities.remove(entity);
+			}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+
+		};
+		viewer.clock.onTick.addEventListener(Exection);
+	},
+});
+
+/* 输出 */
+export default jtMap3d;

+ 421 - 0
packages/Widgets/common/CoordTransform.js

@@ -0,0 +1,421 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+const BD_FACTOR = (3.14159265358979324 * 3000.0) / 180.0;
+const PI = 3.1415926535897932384626;
+const RADIUS = 6378245.0;
+const EE = 0.00669342162296594323;
+
+/**
+ * 坐标转换
+ */
+class CoordTransform {
+	/**
+	 * 百度坐标系转||BD-09 To GCJ-02
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number[]}
+	 */
+	static BD09ToGCJ02(lng, lat) {
+		let x = +lng - 0.0065
+		let y = +lat - 0.006
+		let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * BD_FACTOR)
+		let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * BD_FACTOR)
+		let gg_lng = z * Math.cos(theta)
+		let gg_lat = z * Math.sin(theta)
+		return [gg_lng, gg_lat];
+	}
+
+	/**
+	 * GCJ-02 To BD-09
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number[]}
+	 * @constructor
+	 */
+	static GCJ02ToBD09(lng, lat) {
+		lat = +lat
+		lng = +lng
+		let z =
+			Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * BD_FACTOR)
+		let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * BD_FACTOR)
+		let bd_lng = z * Math.cos(theta) + 0.0065
+		let bd_lat = z * Math.sin(theta) + 0.006
+		return [bd_lng, bd_lat]
+	}
+
+	/**
+	 * WGS-84 To GCJ-02
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number[]}
+	 */
+	static WGS84ToGCJ02(lng, lat) {
+		lat = +lat
+		lng = +lng
+		if (this.out_of_china(lng, lat)) {
+			return [lng, lat]
+		} else {
+			let d = this.delta(lng, lat)
+			return [lng + d[0], lat + d[1]]
+		}
+	}
+
+	/**
+	 * GCJ-02 To WGS-84
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number[]}
+	 * @constructor
+	 */
+	static GCJ02ToWGS84(lng, lat) {
+		lat = +lat
+		lng = +lng
+		if (this.out_of_china(lng, lat)) {
+			return [lng, lat]
+		} else {
+			let d = this.delta(lng, lat)
+			let mgLng = lng + d[0]
+			let mgLat = lat + d[1]
+			return [lng * 2 - mgLng, lat * 2 - mgLat]
+		}
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number[]}
+	 */
+	static delta(lng, lat) {
+		let dLng = this.transformLng(lng - 105, lat - 35)
+		let dLat = this.transformLat(lng - 105, lat - 35)
+		const radLat = (lat / 180) * PI
+		let magic = Math.sin(radLat)
+		magic = 1 - EE * magic * magic
+		const sqrtMagic = Math.sqrt(magic)
+		dLng = (dLng * 180) / ((RADIUS / sqrtMagic) * Math.cos(radLat) * PI)
+		dLat = (dLat * 180) / (((RADIUS * (1 - EE)) / (magic * sqrtMagic)) * PI)
+		return [dLng, dLat]
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number}
+	 */
+	static transformLng(lng, lat) {
+		lat = +lat
+		lng = +lng
+		let ret =
+			300.0 +
+			lng +
+			2.0 * lat +
+			0.1 * lng * lng +
+			0.1 * lng * lat +
+			0.1 * Math.sqrt(Math.abs(lng))
+		ret +=
+			((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
+				2.0) /
+			3.0
+		ret +=
+			((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) /
+			3.0
+		ret +=
+			((150.0 * Math.sin((lng / 12.0) * PI) +
+					300.0 * Math.sin((lng / 30.0) * PI)) *
+				2.0) /
+			3.0
+		return ret
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {number}
+	 */
+	static transformLat(lng, lat) {
+		lat = +lat
+		lng = +lng
+		let ret = -100.0 +
+			2.0 * lng +
+			3.0 * lat +
+			0.2 * lat * lat +
+			0.1 * lng * lat +
+			0.2 * Math.sqrt(Math.abs(lng))
+		ret +=
+			((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
+				2.0) /
+			3.0
+		ret +=
+			((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) /
+			3.0
+		ret +=
+			((160.0 * Math.sin((lat / 12.0) * PI) +
+					320 * Math.sin((lat * PI) / 30.0)) *
+				2.0) /
+			3.0
+		return ret
+	}
+
+	/**
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param lng
+	 * @param lat
+	 * @returns {boolean}
+	 */
+	static out_of_china(lng, lat) {
+		lat = +lat
+		lng = +lng
+		return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55)
+	}
+
+	/**
+	 * 获取Catesian3坐标
+	 */
+	static getCatesian3FromPX(viewer, px) {
+		let picks = viewer.scene.drillPick(px);
+		let cartesian = null;
+		let isOn3dtiles = false,
+			isOnTerrain = false;
+		// drillPick
+		for (let i in picks) {
+			let pick = picks[i];
+			if (
+				(pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
+				(pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
+				(pick && pick.primitive instanceof Cesium.Model)
+			) {
+				//模型上拾取
+				isOn3dtiles = true;
+			}
+			// 3dtilset
+			if (isOn3dtiles) {
+				viewer.scene.pick(px); // pick
+				cartesian = viewer.scene.pickPosition(px);
+				if (cartesian) {
+					let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
+					if (cartographic.height < 0) cartographic.height = 0;
+					let lon = Cesium.Math.toDegrees(cartographic.longitude),
+						lat = Cesium.Math.toDegrees(cartographic.latitude),
+						height = cartographic.height;
+					cartesian = this.transformWGS84ToCartesian({
+						lng: lon,
+						lat: lat,
+						alt: height,
+					});
+				}
+			}
+		}
+		// 地形
+		let boolTerrain = viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
+		// Terrain
+		if (!isOn3dtiles && !boolTerrain) {
+			let ray = viewer.scene.camera.getPickRay(px);
+			if (!ray) return null;
+			cartesian = viewer.scene.globe.pick(ray, viewer.scene);
+			isOnTerrain = true;
+		}
+		// 地球
+		if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
+			cartesian = viewer.scene.camera.pickEllipsoid(
+				px,
+				viewer.scene.globe.ellipsoid
+			);
+		}
+		if (cartesian) {
+			let position = this.transformCartesianToWGS84(cartesian);
+			if (position.alt < 0) {
+				cartesian = this.transformWGS84ToCartesian(position, 0.1);
+			}
+			return cartesian;
+		}
+		return false;
+	}
+
+	/**
+	 * 坐标转换 84转笛卡尔
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {object} position - {lng,lat,alt} 地理坐标
+	 * @param {number} alt - 高度
+	 * @returns {object} Cartesian3 笛卡尔坐标
+	 */
+	static transformWGS84ToCartesian(position, alt) {
+		return position ?
+			Cesium.Cartesian3.fromDegrees(
+				position.lng || position.lon,
+				position.lat,
+				(position.alt = alt || position.alt),
+				Cesium.Ellipsoid.WGS84
+			) :
+			Cesium.Cartesian3.ZERO
+	}
+
+	/**
+	 * 坐标转换 笛卡尔转84
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {object} cartesian - 笛卡尔坐标
+	 * @returns {object} - {lng,lat,alt} 地理坐标
+	 */
+	static transformCartesianToWGS84(cartesian) {
+		let ellipsoid = Cesium.Ellipsoid.WGS84
+		let cartographic = ellipsoid.cartesianToCartographic(cartesian)
+		return {
+			lng: Cesium.Math.toDegrees(cartographic.longitude),
+			lat: Cesium.Math.toDegrees(cartographic.latitude),
+			alt: cartographic.height
+		}
+	}
+
+	/**
+	 * 笛卡尔坐标数组转WGS84
+	 * @param {Array} cartesianList 笛卡尔坐标数组
+	 * @returns {Array} WGS84经纬度坐标数组
+	 */
+	static Cartesian3ListToWGS84(cartesianList) {
+		let ellipsoid = Cesium.Ellipsoid.WGS84;
+		let result = [];
+		for (let index = 0; index < cartesianList.length; index++) {
+			const cartesian = cartesianList[index];
+			let cartographic = ellipsoid.cartesianToCartographic(cartesian);
+			result.push({
+				lng: Cesium.Math.toDegrees(cartographic.longitude),
+				lat: Cesium.Math.toDegrees(cartographic.latitude),
+				alt: cartographic.height,
+			});
+		}
+		return result;
+	}
+
+	/**
+	 * 度(十进制)转度分秒
+	 * @param {Number} value 十进制度
+	 */
+	static Degrees2DMS(value) {
+		let degrees = Math.floor(value); //根据“floor”的字面意思“地板”去理解;舍小数位
+		let rem = (value - degrees) * 60;
+		let minutes = Math.floor(rem);
+		let _second = (rem - minutes) * 60;
+		// let seconds = Math.ceil(_second); //根据“ceil”的字面意思“天花板”去理解;进小数位
+		let seconds = Math.round(_second); //(小数点后第一位)大于五全部加,等于五正数加,小于五全不加。
+
+		var _radians = Cesium.Math.toRadians(value); //经纬度转弧度 
+		var _degrees = Cesium.Math.toDegrees(value); //弧度转经纬度
+		console.log(_radians)
+		console.log(_degrees)
+
+		let DMS = {
+			degrees: degrees,
+			minutes: minutes,
+			seconds: seconds
+		};
+		return DMS;
+	}
+
+	/**
+	 * 度分秒转度(十进制)
+	 * @param {Object} DMS 度分秒对象
+	 * @param {Object} DMS.degrees 度
+	 * @param {Object} DMS.minutes 分
+	 * @param {Object} DMS.seconds 秒
+	 */
+	static DMS2Degrees(DMS) {
+		let _double = parseFloat(DMS.degrees) + parseFloat(DMS.minutes) / 60 + parseFloat(DMS.seconds) / 3600;
+		return parseFloat(_double).toFixed(6);
+	}
+	
+	/**
+	 * 世界坐标转换为经纬度坐标
+	 * @ignore 生成方法时不对外公开
+	 * @param {Cesium.Cartesian3} position 点
+	 */
+	static _cartesian3ToGeo(position) {
+		let g = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
+		return {
+			longitude: Cesium.Math.toDegrees(g.longitude),
+			latitude: Cesium.Math.toDegrees(g.latitude),
+			height: g.height,
+		}
+	}
+	
+	/**
+	 * 弧度转度
+	 * @ignore
+	 * @param {Number} arc 弧度
+	 * @return {Number} 角度
+	 */
+	static _arcToDegree(arc) {
+		return arc / Math.PI * 180;
+	}
+	
+	/**
+	 * 根据地形或实景或模型检测当前屏幕位置的经纬度及高度
+	 * @ignore
+	 * @param {JSON} screenPoint 屏幕坐标
+	 * @param {Number} screenPoint.x 屏幕坐标x
+	 * @param {Number} screenPoint.y 屏幕坐标y
+	 * @return {JSON} 位置信息{lng,lat,height}
+	 */
+	static _getScreenClickPositionAndHeight(viewer,screenPoint) {
+		this._viewer=viewer;
+		
+		var lng = undefined,
+			lat = undefined,
+			height = undefined;
+	
+		/* 从相机位置到 windowPosition 处的像素创建射线在世界坐标系中 */
+		var ray = this._viewer.scene.camera.getPickRay(screenPoint);
+		/* 找到射线与渲染的地球表面之间的交点 */
+		var position = this._viewer.scene.globe.pick(ray, this._viewer.scene);
+		/* 获取地理位置的制图表达 */
+		var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
+	
+		/* 查询屏幕位置的要素 */
+		var feature = this._viewer.scene.pick(screenPoint);
+		if (feature == undefined) {
+			lng = this._arcToDegree(cartographic.longitude);
+			lat = this._arcToDegree(cartographic.latitude);
+			height = cartographic.height;
+		} else {
+			var cartesian = this._viewer.scene.pickPosition(screenPoint);
+			if (Cesium.defined(cartesian)) {
+				var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
+				lng = this._arcToDegree(cartographic.longitude);
+				lat = this._arcToDegree(cartographic.latitude);
+				height = cartographic.height;
+			}
+		}
+		/* 返回结果 */
+		return {
+			lng: lng,
+			lat: lat,
+			height: height,
+		}
+	}
+	
+	/**
+	 * 屏幕位置转换为经纬度位置及空间位置
+	 * @ignore
+	 * @param {Object} viewer 三维场景
+	 * @param {Cesium.Cartesian2} screenPosition 屏幕位置
+	 * @return {JSON} 经纬度位置及空间位置
+	 */
+	static _transfromFromScreenPoint(viewer,screenPosition) {
+		/* 根据屏幕位置获取经度、纬度和高度信息 */
+		let location = this._getScreenClickPositionAndHeight(viewer,screenPosition);
+		/* 经纬度位置转换为三维坐标 */
+		var cartesian = Cesium.Cartesian3.fromDegrees(location.lng, location.lat, location.height);
+		/* 返回 */
+		return {
+			gLocation: location,
+			sLocation: cartesian,
+		}
+	}
+}
+
+export default CoordTransform;

+ 66 - 0
packages/Widgets/common/ReminderTip.js

@@ -0,0 +1,66 @@
+/**
+ * 标绘提示弹窗tip
+ */
+const CreateRemindertip = function(arr, position, show) {
+	let tooltip = document.getElementById("toolTip");
+	let style, _x, _y, _color;
+	if (arr && typeof arr === "object") {
+		style = arr;
+	}
+	if (style && style.origin) {
+		style.origin === "center" && ((_x = 15), (_y = -12));
+		style.origin === "top" && ((_x = 15), (_y = -44));
+		style.origin === "bottom" && ((_x = 15), (_y = 20));
+	} else {
+		(_x = 15), (_y = 20);
+	}
+	if (style && style.color) {
+		style.color === "white" && (_color = "background: rgba(255, 255, 255, 0.8);color: black;");
+		style.color === "black" && (_color = "background: rgba(0, 0, 0, 0.65);color: white;");
+		style.color === "yellow" && (_color = "color: black;background-color: #ffcc33;border: 1px solid white;");
+	} else {
+		_color = "background: rgba(0, 0, 0, 0.65);color: white;";
+	}
+	if (!tooltip) {
+		const viewerDom = document.getElementsByClassName("cesium-viewer")[0];
+		let elementbottom = document.createElement("div");
+		viewerDom.append(elementbottom);
+		let html =
+			'<div id="toolTip" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' + _color + '"></div>';
+		viewerDom.insertAdjacentHTML("beforeend", html);
+		tooltip = document.getElementById("toolTip");
+	}
+	if (show) {
+		tooltip.innerHTML = arr;
+		tooltip.style.left = position.x + _x + "px";
+		tooltip.style.top = position.y + _y + "px";
+		tooltip.style.display = "block";
+	} else {
+		tooltip.style.display = "none";
+	}
+	return {
+		tooltip: tooltip,
+		style: style,
+		showAt: function(position, text) {
+			this.tooltip.innerHTML = text;
+			if (this.style && this.style.origin) {
+				this.style.origin === "center" && ((_x = 15), (_y = -this.tooltip.offsetHeight / 2));
+				this.style.origin === "top" && ((_x = 15), (_y = -this.tooltip.offsetHeight - 20));
+				this.style.origin === "bottom" && ((_x = 15), (_y = 20));
+			} else {
+				(_x = 15), (_y = -this.tooltip.offsetHeight / 2);
+			}
+			this.tooltip.style.left = position.x + _x + "px";
+			this.tooltip.style.top = position.y + _y + "px";
+			this.tooltip.style.display = "block";
+		},
+		show: function(show) {
+			if (show) {
+				this.tooltip.style.display = "block";
+			} else {
+				this.tooltip.style.display = "none";
+			}
+		},
+	};
+};
+export default CreateRemindertip;

+ 140 - 0
packages/Widgets/common/RuntimeEnvironment.js

@@ -0,0 +1,140 @@
+/**
+ * 检测程序运行环境
+ * @return
+ */
+const _checkAppOrWeb = function() {
+	if (window.navigator.userAgent.match(
+			/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+		)) {
+		return "App";
+	} else {
+		return "Web";
+	}
+}
+
+/**
+ * 是否是运行于App
+ * @ignore
+ */
+export const isRuntimeApp = function() {
+	if (_checkAppOrWeb() === "App") {
+		return true;
+	}
+	return false;
+}
+
+/**
+ * 是否是运行于App
+ * @ignore
+ */
+export const isRuntimeWeb = function() {
+	if (_checkAppOrWeb() === "Web") {
+		return true;
+	}
+	return false;
+}
+
+/**
+ * @ignore
+ * 创建操作的主容器
+ */
+export function createOperationMainDom() {
+	//创建画布
+	let buttonDiv = document.createElement('div');
+	buttonDiv.id = "drawButtonDiv";
+	buttonDiv.style.width = '80px';
+	buttonDiv.style.backgroundColor = 'rgba(5, 45, 155, 0.7)';
+	buttonDiv.style.borderRadius = '5px';
+	buttonDiv.style.display = 'flex';
+	buttonDiv.style.flexDirection = 'column';
+	buttonDiv.style.padding = '8px';
+	buttonDiv.style.justifyContent = 'center';
+	buttonDiv.style.position = 'absolute';
+	buttonDiv.style.bottom = '150px';
+	buttonDiv.style.right = '10px';
+
+	let btnUndo = document.createElement('button');
+	btnUndo.id = "btnDrawBackout";
+	btnUndo.style.height = '30px';
+	btnUndo.style.marginBottom = '8px';
+	btnUndo.style.backgroundColor = 'rgba(52, 137, 255, 1.0)';
+	btnUndo.style.color = 'rgb(255, 255, 255)';
+	btnUndo.style.border = '0px solid red';
+	btnUndo.style.borderRadius = '5px';
+	btnUndo.innerHTML = '回退';
+	btnUndo.style.fontSize = '13px';
+	btnUndo.style.cursor = 'pointer';
+	buttonDiv.appendChild(btnUndo);
+
+	let btnCompletion = document.createElement('button');
+	btnCompletion.id = "btnDrawComplete";
+	btnCompletion.style.height = '30px';
+	btnCompletion.style.backgroundColor = 'rgba(88, 185, 45, 1.0)';
+	btnCompletion.style.color = 'rgb(255, 255, 255)';
+	btnCompletion.style.border = '0px solid red';
+	btnCompletion.style.borderRadius = '5px';
+	btnCompletion.innerHTML = '完成';
+	btnCompletion.style.fontSize = '13px';
+	btnCompletion.style.cursor = 'pointer';
+	buttonDiv.appendChild(btnCompletion);
+
+	/* 加入到页面 */
+	document.body.appendChild(buttonDiv);
+}
+
+/**
+ * 创建顶部弹出提示消息 1秒后自动消失
+ * @ignore
+ * @param {String} message 消息内容
+ */
+export function showTooltipMessage(message) {
+	let msgMainDom = document.getElementById('messageMainDom');
+	if (msgMainDom !== null && msgMainDom !== undefined) {
+		document.body.removeChild(msgMainDom);
+	}
+	msgMainDom = document.createElement('div');
+	msgMainDom.style.width = '30%';
+	msgMainDom.style.backgroundColor = 'rgba(237, 248, 230, 1.0)';
+	msgMainDom.style.height = '45px';
+	msgMainDom.style.border = 'solid 2px rgb(219, 241, 208)';
+	msgMainDom.style.borderRadius = '8px';
+	msgMainDom.style.display = 'flex';
+	msgMainDom.style.alignItems = 'center';
+	msgMainDom.style.paddingLeft = '10px';
+	msgMainDom.style.color = 'rgb(91, 188, 48)';
+	msgMainDom.style.fontSize = '14px';
+	msgMainDom.style.fontWeight = '600';
+	msgMainDom.style.position = 'absolute';
+	msgMainDom.style.left = '35%';
+	msgMainDom.style.transition = 'transform 1s';
+	msgMainDom.style.transform = 'translateY(-90px)';
+	msgMainDom.style.top = '0px';
+	msgMainDom.style.zIndex = 1000;
+	document.body.appendChild(msgMainDom);
+
+	let strHtml = '';
+	strHtml += "<div style='"
+	strHtml += "background-color: rgb(88, 185, 45);";
+	strHtml += "color: rgb(255, 255, 255);";
+	strHtml += "height: 24px;";
+	strHtml += "width: 24px;";
+	strHtml += "border-radius: 20px;";
+	strHtml += "display: flex;";
+	strHtml += "justify-content: center;";
+	strHtml += "align-items: center;";
+	strHtml += "font-size: 14px;";
+	strHtml += "margin-right: 18px;";
+	strHtml += "'>&#10003</div>";
+	strHtml += "<div>" + message + "</div>";
+
+	msgMainDom.innerHTML = strHtml;
+	msgMainDom.addEventListener('transitionend', function() {
+		setTimeout(function() {
+			document.body.removeChild(msgMainDom);
+		}, 1000);
+	}, false);
+
+	setTimeout(function() {
+		msgMainDom.style.transform = 'translateY(50px)';
+	}, 100)
+}

+ 123 - 0
packages/Widgets/common/Util.js

@@ -0,0 +1,123 @@
+const CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
+
+/**
+ *  工具类
+ *  代码使用的leaflet开源工具
+ * https://github.com/Leaflet/Leaflet/tree/master/src/core
+ * @ignore
+ */
+class Util {
+	/**
+	 * generate uuid
+	 * @ignore
+	 * @param {*} prefix
+	 *
+	 */
+	static uuid(prefix = 'D') {
+		let uuid = []
+		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
+		uuid[14] = '4'
+		let r
+		for (let i = 0; i < 36; i++) {
+			if (!uuid[i]) {
+				r = 0 | (Math.random() * 16)
+				uuid[i] = CHARS[i == 19 ? (r & 0x3) | 0x8 : r]
+			}
+		}
+		return prefix + '-' + uuid.join('')
+	}
+
+	/**
+	 *
+	 * Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter.
+	 * @ignore
+	 * @param {*} dest
+	 * @param {*} sources
+	 *
+	 */
+	static merge(dest, ...sources) {
+		let i, j, len, src
+		for (j = 0, len = sources.length; j < len; j++) {
+			src = sources[j]
+			for (i in src) {
+				dest[i] = src[i]
+			}
+		}
+		return dest
+	}
+
+	/**
+	 *
+	 * Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
+	 * @ignore
+	 * @param {*} str
+	 *
+	 */
+	static trim(str) {
+		return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '')
+	}
+
+	/**
+	 * Trims and splits the string on whitespace and returns the array of parts.
+	 * @ignore
+	 * @param {*} str
+	 *
+	 */
+	static splitWords(str) {
+		return this.trim(str).split(/\s+/)
+	}
+
+	/**
+	 *
+	 * Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`.
+	 * @ignore
+	 * @param {*} obj
+	 * @param {*} options
+	 *
+	 */
+	static setOptions(obj, options) {
+		if (!obj.hasOwnProperty('options')) {
+			obj.options = obj.options ? create(obj.options) : {}
+		}
+		for (var i in options) {
+			obj.options[i] = options[i]
+		}
+		return obj.options
+	}
+
+	/**
+	 * Check position for validity
+	 * @ignore
+	 * @param {*} position
+	 */
+	static checkPosition(position) {
+		return (
+			position &&
+			position.hasOwnProperty('_lng') &&
+			position.hasOwnProperty('_lat') &&
+			position.hasOwnProperty('_alt')
+		)
+	}
+
+	/**
+	 * Check positions for validity
+	 * @ignore
+	 * @param {*} position
+	 */
+	static checkPositions(positions) {
+		return (
+			positions && (typeof positions === 'string' || Array.isArray(positions))
+		)
+	}
+
+	/**
+	 * Check viewer for validity
+	 * @ignore
+	 * @param {*} position
+	 */
+	static checkViewer(viewer) {
+		return viewer && viewer.delegate && viewer.canvas
+	}
+}
+
+export default Util

+ 219 - 0
packages/Widgets/common/common.js

@@ -0,0 +1,219 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * 创建随机数
+ * @return {String} 唯一标识符
+ */
+export function setSessionid(num) {
+	let len = num || 32;
+	let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
+	let maxPos = chars.length;
+	let pwd = "";
+	for (let i = 0; i < len; i++) {
+		pwd += chars.charAt(Math.floor(Math.random() * maxPos));
+	}
+	return pwd;
+}
+
+/**
+ * 创建GUID
+ * @return {String} 唯一标识符
+ */
+export function guid() {
+	function S4() {
+		return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+	}
+	return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+}
+
+/**
+ * 创建GUID
+ * @return {String} 唯一标识符
+ */
+export function getGuid(removeMinus) {
+	let d = new Date().getTime();
+	let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+		const r = (d + Math.random() * 16) % 16 | 0;
+		d = Math.floor(d / 16);
+		return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
+	});
+	if (removeMinus) {
+		uuid = uuid.replace(/-/g, "");
+	}
+	return uuid;
+}
+
+/**
+ * 获取非精确的地形的高度(一个点)
+ * sampleTerrain :   获取非精确的地形的高度
+ * @param {Object} viewer 三维场景
+ * @param {Object} options 
+ * @param {Number} options.longitude 经度,以度为单位
+ * @param {Number} options.latitude 纬度,以度为单位
+ * @param {Number} options.level 指定地形级别
+ */
+export function getHeigthByLngLat(viewer, options) {
+
+	if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+	if (!Cesium.defined(options.longitude) && !Cesium.defined(options.latitude)) {
+		throw new Cesium.DeveloperError("longitude and  latitude are required.");
+	}
+
+	options.level = Cesium.defaultValue(options.level, 11);
+
+	let positions = Cesium.Cartographic.fromDegrees(options.longitude, options.latitude); //经纬度转为世界坐标
+	let terrainProvider = viewer.terrainProvider;
+
+	//异步函数
+	return new Promise((resolve, reject) => {
+		//获取指定地形级别的高程
+		new Cesium.sampleTerrain(terrainProvider, options.level, [positions]).then(function(updatedPositions) {
+			if (updatedPositions) {
+				resolve(updatedPositions[0].height)
+			}
+		})
+	})
+}
+
+/**
+ * 获取非精确的地形的高度(多点)
+ * sampleTerrain :   获取非精确的地形的高度
+ * @param {Object} viewer 三维场景
+ * @param {Object} options
+ * @param {Number} options.points  [[lng,lat],[lng,lat],......]  
+ * @param {Number} options.level 指定地形级别
+ */
+export function getHeigthByPoints(viewer, options) {
+
+	if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+	if (!Cesium.defined(options)) {
+		throw new Cesium.DeveloperError("options is required.");
+	}
+
+	options.level = Cesium.defaultValue(options.level, 11);
+
+	let positions = [];
+	let points = options.points;
+	for (let i = 0; i < points.length; i++) {
+		let pointX = points[i][0];
+		let pointY = points[i][1];
+		positions.push(
+			Cesium.Cartographic.fromDegrees(pointX, pointY) //经纬度转为世界坐标
+		);
+	}
+
+	let terrainProvider = viewer.terrainProvider;
+
+	//异步函数
+	return new Promise((resolve, reject) => {
+		//获取指定地形级别的高程
+		new Cesium.sampleTerrain(terrainProvider, options.level, positions).then(function(updatedPositions) {
+			if (updatedPositions) {
+				resolve(updatedPositions);
+			}
+		});
+	});
+}
+
+/**
+ * 获取尽量精确的地形的高度(多点)
+ * sampleTerrainMostDetailed: 获取尽量精确的地形的高度
+ * @param {Object} viewer 三维场景
+ * @param {Number} points  [[lng,lat],[lng,lat],......]  
+ */
+export function getHeigthByPointsMostDetailed(viewer, points) {
+
+	if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+	if (!Cesium.defined(points)) {
+		throw new Cesium.DeveloperError("points is required.");
+	}
+
+	let positions = [];
+	for (let i = 0; i < points.length; i++) {
+		let pointX = points[i][0];
+		let pointY = points[i][1];
+		positions.push(Cesium.Cartographic.fromDegrees(pointX, pointY)); //经纬度转为世界坐标;
+	}
+
+	let terrainProvider = viewer.terrainProvider;
+
+	//异步函数
+	return new Promise((resolve, reject) => {
+		let promise = new Cesium.sampleTerrainMostDetailed(terrainProvider, positions);
+		promise.then(function(updatedPositions) {
+			// positions[0].height and positions[1].height have been updated.
+			// updatedPositions is just a reference to positions.
+			resolve(updatedPositions);
+		});
+	})
+}
+
+/**
+ * 获取尽量精确的地形的高度(单点)
+ * sampleTerrainMostDetailed: 获取尽量精确的地形的高度
+ * @param {Object} viewer 三维场景
+ * @param {Number} points  [lng,lat]
+ */
+export function getHeigthByPointMostDetailed(viewer, points) {
+
+	if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+
+	if (!Cesium.defined(points)) {
+		throw new Cesium.DeveloperError("points is required.");
+	}
+
+	let positions = Cesium.Cartographic.fromDegrees(points[0], points[1]); //经纬度转为世界坐标;
+
+	let terrainProvider = viewer.terrainProvider;
+
+	//异步函数
+	return new Promise((resolve, reject) => {
+		let promise = new Cesium.sampleTerrainMostDetailed(terrainProvider, positions);
+		promise.then(function(updatedPositions) {
+			resolve(updatedPositions);
+		});
+	})
+}
+
+import '../../Assets/styles/tooltip.css';
+export function createTooltip(frameDiv) {
+
+	var tooltip = function(frameDiv) {
+
+		var div = document.createElement('DIV');
+		div.className = "twipsy right";
+
+		var arrow = document.createElement('DIV');
+		arrow.className = "twipsy-arrow";
+		div.appendChild(arrow);
+
+		var title = document.createElement('DIV');
+		title.className = "twipsy-inner";
+		div.appendChild(title);
+
+		this._div = div;
+		this._title = title;
+
+		// add to frame div and display coordinates
+		frameDiv.appendChild(div);
+	}
+
+	tooltip.prototype.setVisible = function(visible) {
+		this._div.style.display = visible ? 'block' : 'none';
+	}
+
+	tooltip.prototype.showAt = function(position, message) {
+		if (position && message) {
+			this.setVisible(true);
+			this._title.innerHTML = message;
+			this._div.style.left = position.x + 10 + "px";
+			this._div.style.top = (position.y - this._div.clientHeight / 2) + "px";
+		}
+	}
+
+	return new tooltip(frameDiv);
+}

+ 183 - 0
packages/Widgets/common/doms.js

@@ -0,0 +1,183 @@
+import Util from './Util.js'
+
+/**
+ * Dom工具类
+ * 代码使用的leaflet开源工具
+ * https://github.com/Leaflet/Leaflet/tree/master/src/core
+ * @ignore
+ */
+class DomUtil {
+	/**
+	 * Returns an element given its DOM id, or returns the element itself
+	 *  if it was passed directly.
+	 * @ignore
+	 * @param {*} id
+	 */
+	static get(id) {
+		return typeof id === 'string' ? document.getElementById(id) : id
+	}
+
+	/**
+	 * Returns the value for a certain style attribute on an element,
+	 * including computed values or values set through CSS.
+	 * @ignore
+	 * @param {*} el
+	 * @param {*} style
+	 */
+	static getStyle(el, style) {
+		var value = el.style[style] || (el.currentStyle && el.currentStyle[style])
+
+		if ((!value || value === 'auto') && document.defaultView) {
+			var css = document.defaultView.getComputedStyle(el, null)
+			value = css ? css[style] : null
+		}
+		return value === 'auto' ? null : value
+	}
+
+	/**
+	 * Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
+	 * @ignore
+	 * @param {*} tagName
+	 * @param {*} className
+	 * @param {*} container
+	 */
+	static create(tagName, className, container) {
+		var el = document.createElement(tagName)
+		el.className = className || ''
+		if (container) {
+			container.appendChild(el)
+		}
+		return el
+	}
+
+	/**
+	 * Removes `el` from its parent element
+	 * @ignore
+	 * @param {*} el
+	 */
+	static remove(el) {
+		var parent = el.parentNode
+		if (parent) {
+			parent.removeChild(el)
+		}
+	}
+
+	/**
+	 * Removes all of `el`'s children elements from `el`
+	 * @ignore
+	 * @param {*} el
+	 */
+	static empty(el) {
+		while (el.firstChild) {
+			el.removeChild(el.firstChild)
+		}
+	}
+
+	/**
+	 * Returns `true` if the element's class attribute contains `name`.
+	 * @ignore
+	 * @param {*} el
+	 * @param {*} name
+	 */
+	hasClass(el, name) {
+		if (el.classList !== undefined) {
+			return el.classList.contains(name)
+		}
+		var className = getClass(el)
+		return (
+			className.length > 0 &&
+			new RegExp('(^|\\s)' + name + '(\\s|$)').test(className)
+		)
+	}
+
+	/**
+	 * Adds `name` to the element's class attribute.
+	 * @ignore
+	 * @param {*} el
+	 * @param {*} name
+	 */
+	static addClass(el, name) {
+		if (el.classList !== undefined) {
+			let classes = Util.splitWords(name)
+			for (let i = 0, len = classes.length; i < len; i++) {
+				el.classList.add(classes[i])
+			}
+		} else if (!this.hasClass(el, name)) {
+			let className = this.getClass(el)
+			this.setClass(el, (className ? className + ' ' : '') + name)
+		}
+	}
+
+	/**
+	 * Removes `name` from the element's class attribute.
+	 * @ignore
+	 * @param {*} el
+	 * @param {*} name
+	 */
+	static removeClass(el, name) {
+		if (el.classList !== undefined) {
+			el.classList.remove(name)
+		} else {
+			this.setClass(
+				el,
+				Util.trim(
+					(' ' + this.getClass(el) + ' ').replace(' ' + name + ' ', ' ')
+				)
+			)
+		}
+	}
+
+	/**
+	 *  Sets the element's class.
+	 * @ignore
+	 * @param {*} el
+	 * @param {*} name
+	 */
+	static setClass(el, name) {
+		if (el.className.baseVal === undefined) {
+			el.className = name
+		} else {
+			// in case of SVG element
+			el.className.baseVal = name
+		}
+	}
+
+	/**
+	 * Returns the element's class.
+	 * @ignore
+	 * @param {*} el
+	 */
+	static getClass(el) {
+		// Check if the element is an SVGElementInstance and use the correspondingElement instead
+		// (Required for linked SVG elements in IE11.)
+		if (el.correspondingElement) {
+			el = el.correspondingElement
+		}
+		return el.className.baseVal === undefined ?
+			el.className :
+			el.className.baseVal
+	}
+
+	/**
+	 * @ignore
+	 * @param {*} path
+	 * @param {*} width
+	 * @param {*} height
+	 */
+	static createSvg(width, height, path, container) {
+		let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg:svg')
+		svg.setAttribute('class', 'svg-path')
+		svg.setAttribute('width', width)
+		svg.setAttribute('height', height)
+		svg.setAttribute('viewBox', `0 0 ${width} ${height}`)
+		let pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path')
+		pathEl.setAttribute('d', path)
+		svg.appendChild(pathEl)
+		if (container) {
+			container.appendChild(svg)
+		}
+		return svg
+	}
+}
+
+export default DomUtil

+ 1783 - 0
packages/Widgets/layer.js

@@ -0,0 +1,1783 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+import CoordTransform from "./common/CoordTransform";
+
+/**
+ *流动纹理线
+ */
+import PolylineDirectionMaterialProperty from "./PolylineObject/PolylineDirectionMaterialProperty.js";
+import WallMaterialProperty from "./WallObject/WallMaterialProperty.js";
+
+/**
+ * 加载各类地图服务
+ */
+class LoadMapData {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 * 
+	 * @example
+	 * 
+	 * 例1:
+	 * const layer = new LoadMapData(viewer);
+	 *
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+	}
+
+	/**
+	 * 添加ImageryProvider到地图中
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} provider 图层构建器
+	 * @return {String} 服务Id
+	 */
+	_addImageryProvider(id, provider) {
+		/* 加入到整体图层中 以便可以删除对应的图层 */
+		window[id] = this._viewer.imageryLayers.addImageryProvider(provider);
+	}
+
+	/**
+	 * 在地图中移除ImageryProvider
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {String} serviceId 服务Id
+	 */
+	_removeImageryProvider(serviceId) {
+		this._viewer.imageryLayers.remove(window[serviceId]); //移除图层
+		window[serviceId] = null;
+	}
+
+	/**
+	 *Cesium中的地形类是直接通过不同的terrainProvider控制的,然后把某一个实例化的terrainProvider赋值给Viewer.terrainProvider来控制地形数据的显隐。所以Cesium中的地形图层只能有一个。
+	 * 添加terrainProvider到地图中(地形)
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} provider 图层构建器
+	 */
+	_addTerrainProvider(provider) {
+		this._viewer.terrainProvider = provider;
+	}
+
+	/**
+	 * 移除地形
+	 * @ignore 忽略注释,注释不生成Doc
+	 */
+	_setEllipsoidTerrain() {
+		this._viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider({});
+	}
+
+	/**
+	 * 添加scene.primitives到地图中(三维实景/白膜)
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} scenePrimitives
+	 */
+	_addScenePrimitives(scenePrimitives) {
+		/* 加入到整体图层中 以便可以删除对应的图层 */
+		this._viewer.scene.primitives.add(scenePrimitives);;
+	}
+
+	/**
+	 * 在地图中移除scene.primitives
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {String} serviceId 服务Id
+	 */
+	_removeScenePrimitives(serviceId) {
+		this._viewer.scene.primitives.remove(window[serviceId]); //移除图层
+		window[serviceId] = null;
+	}
+
+	/**
+	 * 创建GUID
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @return {String} 唯一标识符
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 地图纠偏
+	 * @ignore 忽略注释,注释不生成Doc
+	 * @param {Object} provider
+	 */
+	_transformProjection(provider) {
+		let webMercatorTilingScheme = provider.tilingScheme;
+		let projection = webMercatorTilingScheme._projection;
+		projection.x_project = projection.project;
+		projection.project = function(cartographic) {
+			let point;
+			return (
+				(point = CoordTransform.WGS84ToGCJ02(
+					Cesium.Math.toDegrees(cartographic.longitude),
+					Cesium.Math.toDegrees(cartographic.latitude)
+				)),
+				projection.x_project(
+					new Cesium.Cartographic(
+						Cesium.Math.toRadians(point[0]),
+						Cesium.Math.toRadians(point[1])
+					)
+				)
+			);
+		};
+		projection.x_unproject = projection.unproject;
+		projection.unproject = function(cartesian) {
+			let point,
+				cartographic = projection.x_unproject(cartesian);
+			return (
+				(point = CoordTransform.GCJ02ToWGS84(
+					Cesium.Math.toDegrees(cartographic.longitude),
+					Cesium.Math.toDegrees(cartographic.latitude)
+				)),
+				new Cesium.Cartographic(
+					Cesium.Math.toRadians(point[0]),
+					Cesium.Math.toRadians(point[1])
+				)
+			);
+		};
+		return provider;
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(LoadMapData.prototype, /** @lends LoadMapData.prototype */ {
+	/**
+	 * 添加地形
+	 * @function
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.url 地形服务url
+	 * @param {Number} [options.terrainExaggeration=1] 地形夸张系数
+	 * @param {Number} [options.requestVertexNormals=false] 请求地形照明数据
+	 * @param {Number} [options.requestWaterMask=false] 请求水体效果所需要的海岸线数据
+	 * 
+	 * @example
+	 * layer.addTerrain({
+	 *	 url: "http://data.marsgis.cn/terrain"
+	 * });
+	 *
+	 */
+	addTerrain(options) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		let _ConstructorOptions = {
+			url: options.url
+		};
+
+		// 请求地形照明数据
+		if (options.requestVertexNormals) {
+			_ConstructorOptions.requestVertexNormals = options.requestVertexNormals;
+		} else {
+			_ConstructorOptions.requestVertexNormals = false;
+		}
+
+		// 请求水体效果所需要的海岸线数据
+		if (options.requestWaterMask) {
+			_ConstructorOptions.requestWaterMask = options.requestWaterMask;
+		} else {
+			_ConstructorOptions.requestWaterMask = false;
+		}
+
+		var terrainProvider = new Cesium.CesiumTerrainProvider(_ConstructorOptions);
+
+		this._addTerrainProvider(terrainProvider);
+
+		// 地形夸张
+		this.setTerrainExaggeration(options)
+	},
+
+	/**
+	 * 添加Mapbox图层
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {String} [options.url='https://api.mapbox.com/styles/v1/'] Mapbox服务器url.
+	 * @param {String} [options.username='mapbox'] 映射帐户的用户名.
+	 * @param {String}  options.styleId Mapbox样式ID.
+	 * @param {String}  options.accessToken 图像的公共访问令牌.
+	 * @param {Boolean} [options.scaleFactor] 定瓷砖是否以@2倍的比例因子呈现
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addMapboxLayer({
+	 *   styleId: 'streets-v11',
+	 *   accessToken: 'thisIsMyAccessToken'
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addMapboxLayer(options, callSuccess) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.styleId)) {
+			throw new Cesium.DeveloperError("options.styleId is required.");
+		}
+		if (!Cesium.defined(options.accessToken)) {
+			throw new Cesium.DeveloperError("options.accessToken is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		var imageryProvider = new Cesium.MapboxStyleImageryProvider({
+			url: options.url,
+			username: options.username,
+			styleId: options.styleId,
+			accessToken: options.accessToken,
+			scaleFactor: options.scaleFactor
+		});
+
+		/* 加入图层 */
+		this._addImageryProvider(options.id, imageryProvider);
+
+		//设置透明度
+		this.setLayersStyle({
+			serviceId: options.id,
+			alpha: options.alpha
+		});
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 加载URL模板服务
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {string} options.url 服务地址
+	 * @param {string} [options.CRS] 坐标系,纠偏-“WGS84”
+	 * @param {Number} [options.minimumLevel=0] 最小层级
+	 * @param {Number} [options.maximumLevel=18] 最大层级
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addUrlTemplateImagery({
+	 *   url: 'https://yoururl/{Time}/{z}/{y}/{x}.png'
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addUrlTemplateImagery: function(options, callSuccess) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+		options.CRS = options.CRS || "";
+
+		let _ConstructorOptions = {
+			url: options.url
+		};
+
+		if (options.minimumLevel) {
+			_ConstructorOptions.minimumLevel = options.minimumLevel;
+		}
+
+		if (options.maximumLevel) {
+			_ConstructorOptions.maximumLevel = options.maximumLevel;
+		} else {
+			_ConstructorOptions.maximumLevel = 18;
+		}
+
+		var imageryProvider = new Cesium.UrlTemplateImageryProvider(_ConstructorOptions);
+
+		if (options.CRS.toUpperCase() === "WGS84") {
+			imageryProvider.readyPromise.then(() => {
+				this._transformProjection(imageryProvider);
+			});
+		}
+
+		/* 加入图层 */
+		this._addImageryProvider(options.id, imageryProvider);
+
+		//设置透明度
+		this.setLayersStyle({
+			serviceId: options.id,
+			alpha: options.alpha
+		});
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * @description:加载-TMS-地图服务
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {string} options.url 服务地址
+	 * @param {Number} [options.minimumLevel=0] 最小层级
+	 * @param {Number} [options.maximumLevel] 最大层级
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addTileMapServiceImagery({
+	 *   url: ''
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addTileMapServiceImagery: function(options, callSuccess) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let _ConstructorOptions = {
+			url: options.url
+		};
+
+		if (options.minimumLevel) {
+			_ConstructorOptions.minimumLevel = options.minimumLevel;
+		}
+
+		if (options.maximumLevel) {
+			_ConstructorOptions.maximumLevel = options.maximumLevel;
+		} else {
+			_ConstructorOptions.maximumLevel = 18;
+		}
+
+		var imageryProvider = new Cesium.TileMapServiceImageryProvider(_ConstructorOptions);
+
+		/* 加入图层 */
+		this._addImageryProvider(options.id, imageryProvider);
+
+		//设置透明度
+		this.setLayersStyle({
+			serviceId: options.id,
+			alpha: options.alpha
+		});
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 加载-WMTS-地图服务
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {string} options.url 服务地址
+	 * @param {string} options.layers 图层集合,WMTS请求的层名
+	 * @param {string} options.style 图层样式,WMTS请求的样式名
+	 * @param {string} options.tileMatrixSetID 用于WMTS请求的TileMatrixSet的标识符。
+	 * @param {Array} [options.tileMatrixLabels] TileMatrix中用于WMTS请求的标识符列表,每个TileMatrix级别一个标识符。
+	 * @param {string} [options.format='image/png'] 从服务器检索图像的MIME类型
+	 * @param {Number} [options.minimumLevel=0] 最小层级
+	 * @param {Number} [options.maximumLevel] 最大层级
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addWebMapTileService({
+	 *   url: 'http://t0.tianditu.gov.cn/cia_w/wmts?tk=10f42f91b6e50d2a8eec980577e6a2e6', //加载全国中文注记(经纬度)
+	 *   layers: 'cia',
+	 *   style: 'default',
+	 *   tileMatrixSetID: 'w',
+	 *   format: 'tiles',
+	 *   maximumLevel: 18
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addWebMapTileService: function(options, callSuccess) {
+
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+		if (!Cesium.defined(options.layers)) {
+			throw new Cesium.DeveloperError("options.layers is required.");
+		}
+		if (!Cesium.defined(options.style)) {
+			throw new Cesium.DeveloperError("options.style is required.");
+		}
+		if (!Cesium.defined(options.tileMatrixSetID)) {
+			throw new Cesium.DeveloperError("options.tileMatrixSetID is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let _ConstructorOptions = {
+			url: options.url,
+			layer: options.layers,
+			style: options.style,
+			tileMatrixSetID: options.tileMatrixSetID,
+			format: Cesium.defaultValue(options.format, 'image/png'),
+		};
+
+		if (options.tileMatrixLabels) {
+			_ConstructorOptions.tileMatrixLabels = options.tileMatrixLabels;
+		}
+
+		if (options.minimumLevel) {
+			_ConstructorOptions.minimumLevel = options.minimumLevel;
+		}
+
+		if (options.maximumLevel) {
+			_ConstructorOptions.maximumLevel = options.maximumLevel;
+		} else {
+			_ConstructorOptions.maximumLevel = 18;
+		}
+
+		let imageryProvider = new Cesium.WebMapTileServiceImageryProvider(_ConstructorOptions);
+
+		/* 加入图层 */
+		this._addImageryProvider(options.id, imageryProvider);
+
+		//设置透明度
+		this.setLayersStyle({
+			serviceId: options.id,
+			alpha: options.alpha
+		});
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 提供由Web地图服务(WMS)服务器托管的平铺图像。
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {string} options.url 服务地址
+	 * @param {string} options.layers 加载图层目录,要包含的层,用逗号分隔。
+	 * @param {Number} [options.parameters={
+			service:'WMS',
+			version:'1.1.1',
+			request:'GetMap',
+			styles:'',
+			format:'image/jpeg'
+	 }] 基础参数
+	 * @param {Number} [options.minimumLevel=0] 最小层级
+	 * @param {Number} [options.maximumLevel] 最大层级
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addWebMapService({
+	 * 	url : 'https://sampleserver1.arcgisonline.com/ArcGIS/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/WMSServer',
+	 * 	layers : '0',
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addWebMapService: function(options, callSuccess) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		if (!Cesium.defined(options.layers)) {
+			throw new Cesium.DeveloperError("options.layers is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let _ConstructorOptions = {
+			url: options.url,
+			layers: options.layers,
+		};
+
+		if (options.parameters) {
+			_ConstructorOptions.parameters = options.parameters;
+		} else {
+			_ConstructorOptions.parameters = {
+				service: 'WMS',
+				transparent: true, //是否透明
+				request: "GetMap", //添加上则显示,好像变成了必填
+				format: "image/png",
+			}
+		}
+
+		if (options.minimumLevel) {
+			_ConstructorOptions.minimumLevel = options.minimumLevel;
+		}
+
+		if (options.maximumLevel) {
+			_ConstructorOptions.maximumLevel = options.maximumLevel;
+		} else {
+			_ConstructorOptions.maximumLevel = 18;
+		}
+
+		let imageryProvider = new Cesium.WebMapServiceImageryProvider(_ConstructorOptions);
+
+		/* 加入图层 */
+		this._addImageryProvider(options.id, imageryProvider);
+
+		//设置透明度
+		this.setLayersStyle({
+			serviceId: options.id,
+			alpha: options.alpha
+		});
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 提供由 ArcGIS MapServer 托管的切片图像(ArcGIS Online和Server的相关服务)。默认情况下,使用服务器的预缓存切片(如果可用)。
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {string} options.url 服务地址
+	 * @param {string} [options.layers] 服务图层列表,以逗号分隔的要显示的层列表,如果要显示所有层,则未定义。
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addArcGisMapServer({
+	 * 	url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer',
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addArcGisMapServer: function(options, callSuccess) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let _ConstructorOptions = {
+			url: options.url
+		};
+		if (options.layers) {
+			_ConstructorOptions.layers = options.layers;
+		}
+
+		let imageryProvider = new Cesium.ArcGisMapServerImageryProvider(_ConstructorOptions);
+
+		/* 加入图层 */
+		this._addImageryProvider(options.id, imageryProvider);
+
+		//设置透明度
+		this.setLayersStyle({
+			serviceId: options.id,
+			alpha: options.alpha
+		});
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 加载Cesium3DTileset地图服务--实景
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {String} options.url 服务地址
+	 * @param {Number} [options.height=15] 实景抬高高度
+	 * @param {Number} [options.alpha=1] 实景透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addCesium3DTileset({
+	 * 	url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addCesium3DTileset: function(options, callSuccess) {
+		let _self = this;
+
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let _ConstructorOptions = {
+			url: options.url,
+			skipLevelOfDetail: true,
+		};
+
+		let tileSetModel = new Cesium.Cesium3DTileset(_ConstructorOptions);
+		tileSetModel.readyPromise.then(tileset => {
+			console.log("加载完成")
+
+			window[options.id] = tileset;
+			_self._addScenePrimitives(tileset);
+
+			//设置实景距离地面高度,抬高实景
+			_self.set3DTilePosition({
+				serviceId: options.id,
+				height: options.height,
+			});
+			//设置实景透明度
+			_self.set3DTileStyle({
+				serviceId: options.id,
+				alpha: options.alpha,
+			});
+
+			if (callSuccess) callSuccess(options.id);
+
+		}).catch(function(error) {
+			console.log(error);
+		});
+
+	},
+
+	/**
+	 * 加载Cesium3DTileset地图服务--白膜
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {String} options.url 服务地址
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addCesium3DTilesetBm({
+	 * 	url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addCesium3DTilesetBm: function(options, callSuccess) {
+		let _self = this;
+
+		if (!Cesium.defined(options) || !Cesium.defined(options.url)) {
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let _ConstructorOptions = {
+			url: options.url,
+			skipLevelOfDetail: true,
+		};
+
+		let tileSetModel = new Cesium.Cesium3DTileset(_ConstructorOptions);
+		tileSetModel.readyPromise.then(tileset => {
+			console.log("加载完成")
+
+			window[options.id] = tileset;
+			_self._addScenePrimitives(tileset);
+
+			//设置白膜样式
+			_self.set3DTileBMStyle({
+				serviceId: options.id,
+				color: options.color,
+			});
+
+			if (callSuccess) callSuccess(options.id);
+
+		}).catch(function(error) {
+			console.log(error);
+		});
+	},
+
+	/**
+	 * 图片服务
+	 * @param {Object} options 具有以下属性:
+	 * @param {Array/Cesium.Cartesian3} options.points 模型加载位置 Array[lng,lat,height]经度,以度为单位,纬度,以度为单位,高程
+	 * @param {String} options.url 服务地址
+	 * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
+	 * @param {Number} [options.alpha=1] 透明度
+	 * @return {String} 服务Id
+	 * 
+	 * @example
+	 * layer.addPolygonImageMaterial({
+	 *  id:"aa",
+	 * 	url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
+	 * },function (serviceId) {
+	 * 	
+	 * });
+	 *
+	 */
+	addPolygonImageMaterial: function(options, callSuccess) {
+		if (!Cesium.defined(options.points)) {
+			throw new Cesium.DeveloperError("options.points is required.");
+		}
+
+		if (options.points.length < 3) {
+			reject("面对象,点数至少3个");
+		}
+
+		/* 转换坐标 */
+		let positions = [];
+		if (options.points instanceof Cesium.Cartesian3) {
+			positions = options.points;
+		} else {
+			positions = options.points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+		}
+
+		options.id = options.id || this._guid();
+		options.alpha = options.alpha || 1;
+
+		this.classificationType = Cesium.ClassificationType.BOTH;
+		if (options.classificationType === "Terrain") {
+			this.classificationType = Cesium.ClassificationType.TERRAIN;
+		} else if (options.classificationType === "3DTiles") {
+			this.classificationType = Cesium.ClassificationType.CESIUM_3D_TILE;
+		}
+
+		/* 创建材质 */
+		if (options.url) {
+			if (!Cesium.Entity.supportsMaterialsforEntitiesOnTerrain(this._viewer.scene)) {
+				window.alert("Terrain Entity materials are not supported on this platform");
+			}
+			this.material = new Cesium.ImageMaterialProperty({
+				image: options.url,
+				repeat: Cesium.Cartesian2(1.0, 1.0), // 不重复
+				transparent: true, // 启用png透明
+				color: Cesium.Color.WHITE.withAlpha(options.alpha)
+			});
+		} else {
+			this.material = Cesium.Color.RED.withAlpha(options.alpha);
+		}
+
+		window[options.id] = this._viewer.entities.add({
+			id: options.id,
+			polygon: {
+				hierarchy: positions,
+				material: this.material,
+				classificationType: this.classificationType,
+			},
+		});
+
+		////设置透明度
+		// this.setPolygonImageMaterial({
+		// 	serviceId: options.id,
+		// 	alpha: options.alpha,
+		// });
+
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 加载GLTF/GLB模型数据
+	 * @param {Object} options 参数对象
+	 * @param {String} [options.id=guid] 模型实体加载ID,加入到整体图层中 以便可以删除对应的图层
+	 * @param {Array/Cesium.Cartesian3} options.points 模型加载位置 Array[lng,lat,height]经度,以度为单位,纬度,以度为单位,高程
+	 * @param {String} options.url 模型路径
+	 * @param {Number} [options.heading=0.0] 以弧度为单位的航向分量
+	 * @param {Number} [options.pitch=0.0] 以弧度为单位的螺距分量
+	 * @param {Number} [options.roll=0.0] 以弧度为单位的滚动分量
+	 * @param {Number} [options.minimumPixelSize] 模型最小刻度
+	 * @param {Number} [options.maximumScale] 模型的最大比例尺大小,设置模型最大放大大小
+	 * @param {Array<Number>} [options.silhouetteColor] 模型轮廓颜色[0~255,0~255,0~255,0~1]
+	 * @param {Number} [options.alpha] 模型透明度
+	 */
+	addEntitiesGltf: function(options, callSuccess) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(options.points)) {
+			resolve("options.points is required.");
+			throw new Cesium.DeveloperError("options.points is required.");
+		}
+		if (!Cesium.defined(options.url)) {
+			resolve("options.url is required.");
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		// 初始化参数默认值
+		options.id = options.id || this._guid();
+		options.heading = Cesium.defaultValue(options.heading, 0.0);
+		options.pitch = Cesium.defaultValue(options.pitch, 0.0);
+		options.roll = Cesium.defaultValue(options.roll, 0.0);
+		options.alpha = Cesium.defaultValue(options.alpha, 1);
+
+		//模型加载位置
+		let position = undefined;
+		if (options.points instanceof Cesium.Cartesian3) {
+			position = options.points;
+		} else {
+			position = Cesium.Cartesian3.fromDegrees(options.points[0], options.points[1], options.points[2] || 0);
+		}
+
+		//弧度的航向分量。
+		var heading = Cesium.Math.toRadians(options.heading);
+		//弧度的螺距分量。
+		var pitch = options.pitch;
+		//滚动分量(以弧度为单位)
+		var roll = options.roll;
+		//HeadingPitchRoll旋转表示为航向,俯仰和滚动。围绕Z轴。节距是绕负y轴的旋转。滚动是关于正x轴。
+		var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
+
+		var modelGltf = viewer.entities.add({
+			id: options.id, //模型id
+			position: position, // 模型位置
+			orientation: Cesium.Transforms.headingPitchRollQuaternion(position, hpr), // 模型方向
+			model: { // 模型资源
+				uri: options.url, // 模型路径
+				incrementallyLoadTextures: true, //加载模型后纹理是否能够继续流入
+				colorBlendMode: Cesium.ColorBlendMode['HIGHLIGHT'], //经常使用的有三个HIGHLIGHT,REPLACE,MIX
+				colorBlendAmount: 0.1, //这个属性必须是MIX混合属性才能生效,见colorBlendMode
+
+				color: Cesium.Color.WHITE.withAlpha(options.alpha), //模型颜色,这里可以设置颜色的变化,包含透明度的颜色
+
+				imageBasedLightingFactor: new Cesium.Cartesian2(12.0, 13.0),
+				runAnimations: true, //是否运行模型中的动画效果
+				show: true, // 模型是否可见
+
+				// 仅用于调试,显示魔仙绘制时的线框
+				debugWireframe: false,
+				// 仅用于调试。显示模型绘制时的边界球。
+				debugShowBoundingVolume: false,
+			},
+		});
+
+		// 模型最小刻度,不管缩放如何,模型的最小最小像素大小。
+		if (options.minimumPixelSize) {
+			modelGltf.model.minimumPixelSize = options.minimumPixelSize;
+		}
+		// 模型最大刻度,模型的最大比例尺大小。 minimumPixelSize的上限。
+		if (options.maximumScale) {
+			modelGltf.model.maximumScale = options.maximumScale;
+		}
+		// 模型轮廓颜色
+		if (options.silhouetteColor) {
+			modelGltf.model.silhouetteColor = new Cesium.Color(options.silhouetteColor[0] / 255, options.silhouetteColor[1] / 255, options.silhouetteColor[2] / 255, options.silhouetteColor[3]);
+		}
+
+		// //设置透明度
+		// this.setModelStyle({
+		// 	serviceId: options.id,
+		// 	alpha: options.alpha,
+		// });
+
+		window[options.id] = modelGltf;
+		if (callSuccess) callSuccess(options.id);
+
+	},
+
+	/**
+	 * 加载GLTF/GLB模型数据
+	 * @param {Object} options 参数对象
+	 * @param {Array/Cesium.Cartesian3} options.points 模型加载位置 Array[lng,lat,height]经度,以度为单位,纬度,以度为单位,高程
+	 * @param {String} options.url 模型路径
+	 * @param {String} [options.id=guid] 模型实体加载ID,加入到整体图层中 以便可以删除对应的图层
+	 * @param {Number} [options.scale] 放大倍数
+	 */
+	addScenePrimitivesGltf(options, callSuccess) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(options.points)) {
+			resolve("options.points is required.");
+			throw new Cesium.DeveloperError("options.points is required.");
+		}
+		if (!Cesium.defined(options.url)) {
+			resolve("options.url is required.");
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+		options.scale = Cesium.defaultValue(options.scale, 1);
+
+		//gltf数据加载位置
+		let position = undefined;
+		if (options.points instanceof Cesium.Cartesian3) {
+			position = options.points;
+		} else {
+			position = Cesium.Cartesian3.fromDegrees(options.points[0], options.points[1], options.points[2] || 0);
+		}
+
+		const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
+		let model = viewer.scene.primitives.add(
+			Cesium.Model.fromGltf({
+				show: true, //确定是否将显示模型基元
+				url: options.url, // 资源路径
+				modelMatrix: modelMatrix, // 模型矩阵
+				lightColor: new Cesium.Cartesian3(10.0, 10.0, 10.0),
+				scale: options.scale, // 放大倍数
+
+				// 仅用于调试,显示魔仙绘制时的线框
+				debugWireframe: false,
+				// 仅用于调试。显示模型绘制时的边界球。
+				debugShowBoundingVolume: false,
+			})
+		)
+
+		/** 模型旋转角度 */
+		model.readyPromise.then(function() {
+			//延z轴旋转-90度,其它轴同理
+			var rotationX = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(0)));
+			Cesium.Matrix4.multiply(model.modelMatrix, rotationX, model.modelMatrix);
+		})
+
+		window[options.id] = model;
+		if (callSuccess) callSuccess(options.id);
+	},
+
+	/**
+	 * 根据GeoJson绘制线
+	 * @param {Object} [options] 样式,具有以下属性:
+	 * @param {String} options.url geoJson文件路径
+	 * @param {Number} [options.id] 用于移除
+	 * @param {Number} [options.clampToGround=true] 是否贴地
+	 * @param {Number} [options.isImageAlpha=true] 是否采用图片颜色
+	 * @param {Number} [options.imgUrl] 精灵线图片
+	 * @param {String} [options.color="#FF0000"] 指定线的颜色
+	 * @param {Number} [options.width=3] 指定线的宽度,以像素为单位
+	 // * @param {Number} [options.minHeigh=0] 一个属性,指定该折线将显示在距离摄像机的距离。在该间隔内物体可见的最小距离。
+	 // * @param {Number} [options.maxHeigh=200000000] 一个属性,指定该折线将显示在距离摄像机的距离。在间隔内物体可见的最大距离。
+	 * @param {Number} [options.duration=3000] 持续时间 毫秒,越小越快
+	 * @param {Number} [options.count] 重复次数
+	 * @param {String} [options.direction='horizontal'] 方向 vertical纵,垂直方向,horizontal横,水平方向
+	 * @param {String} [options.order] 方向正负 
+	 *                                        vertical 纵:'-'(由下到上) , '+"(由上到下)
+	 *                                        horizontal 横:'-'(顺时针) , '+'(逆时针)
+	 */
+	addPolylineByGeoJson(options, callSuccess) {
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(options.url)) {
+			resolve("options.url is required.");
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+		options.clampToGround = Cesium.defaultValue(options.clampToGround, true);
+		options.width = Cesium.defaultValue(options.width, 3);
+		options.minHeigh = Cesium.defaultValue(options.minHeigh, 0);
+		options.maxHeigh = Cesium.defaultValue(options.maxHeigh, 200000000);
+
+		let promise = Cesium.GeoJsonDataSource.load(options.url, {
+			clampToGround: options.clampToGround
+		});
+		promise.then((dataSource) => {
+			_self._viewer.dataSources.add(dataSource); // 加载这个geojson资源
+			dataSource.name = options.id
+			let entities = dataSource.entities.values;
+			// let distanceDisplayCondition = new Cesium.DistanceDisplayCondition(options.minHeigh, options.maxHeigh);
+			let material = new PolylineDirectionMaterialProperty(options);
+			for (var i = 0; i < entities.length; i++) {
+				var entity = entities[i];
+				// entity.polyline.distanceDisplayCondition = distanceDisplayCondition;
+				entity.polyline.material = material;
+				entity.polyline.width = options.width;
+				if (options.clampToGround) {
+					entity.polyline.clampToGround = true;
+				}
+			}
+
+			if (callSuccess) callSuccess(options.id);
+		});
+	},
+
+	/**
+	 * 根据GeoJson添加广告牌
+	 * @param {Object} options
+	 * @param {String} options.url geoJson文件路径
+	 * @param {String} options.id 用于移除
+	 * @param {Object} [options.billboard] 广告牌的样式,具有以下属性:
+	 * @param {Number} [options.billboard.imgUrl] 广告牌图片
+	 * @param {Number} [options.billboard.scale=1] 尺寸
+	 * @param {Object} [options.billboard.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.billboard.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.billboard.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.billboard.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.billboard.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 * 
+	 * @param {Object} [options.lable] lable的样式,具有以下属性:
+	 * @param {Number} [options.lable.text=""] 文字
+	 * @param {Number} [options.lable.textField=""] 文字字段
+	 * @param {String} [options.lable.font="24px Helvetica"] 指定CSS字体的属性,字体大小及样式
+	 * @param {String} [options.lable.fillColor=[255,255,0,1]] 字体颜色
+	 * @param {String} [options.lable.outlineColor=[255,255,255,1]] 字体边框颜色
+	 * @param {Number} [options.lable.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.lable.showBackground=false] 是否显示背景颜色
+	 * @param {Number} [options.lable.backgroundColor=[255,255,255,1]] 背景颜色		
+	 * @param {Number} [options.lable.pixelOffset=0] 偏移量
+	 * @param {Number} [options.lable.scale=1] 尺寸
+	 * @param {Object} [options.lable.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.lable.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.lable.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.lable.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.lable.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	addBillboardByGeoJson(options, callSuccess) {
+
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(options.url)) {
+			resolve("options.url is required.");
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let billboard = options.billboard || {};
+		billboard.imgUrl = Cesium.defaultValue(billboard.imgUrl, 'jt3dSDK/imgs/point/point3.png');
+
+		billboard.scale = Cesium.defaultValue(billboard.scale, 1);
+		billboard.pixelOffset = Cesium.defaultValue(billboard.pixelOffset, 0);
+
+		const dataSource = new Cesium.GeoJsonDataSource(options.id); // 创建并取名
+		dataSource.load(options.url, {
+			clampToGround: true
+		}).then(function(data) {
+			viewer.dataSources.add(data); // 添加这个datasource
+			const entities = data.entities.values; // 拿到所有实体
+			entities.forEach(entity => {
+
+				entity.billboard = {
+					image: billboard.imgUrl,
+					horizontalOrigin: Cesium.HorizontalOrigin.CENTER, //水平
+					verticalOrigin: Cesium.VerticalOrigin.BOTTOM, //垂直位置
+					scale: billboard.scale, //尺寸
+					pixelOffset: new Cesium.Cartesian2(0, billboard.pixelOffset),
+					disableDepthTestDistance: Number.POSITIVE_INFINITY,
+				};
+
+				if (billboard.scaleByDistance) {
+					billboard.scaleByDistance.near = Cesium.defaultValue(billboard.scaleByDistance.near, 0);
+					billboard.scaleByDistance.nearValue = Cesium.defaultValue(billboard.scaleByDistance.nearValue, 0);
+					billboard.scaleByDistance.far = Cesium.defaultValue(billboard.scaleByDistance.far, 1);
+					billboard.scaleByDistance.farValue = Cesium.defaultValue(billboard.scaleByDistance.farValue, 0);
+
+					entity.billboard.scaleByDistance = new Cesium.NearFarScalar(billboard.scaleByDistance.near, billboard.scaleByDistance.nearValue, billboard.scaleByDistance.far, billboard.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+				}
+
+				if (options.label) {
+					let label = options.label || {};
+					label.text = Cesium.defaultValue(label.text, "");
+					label.textField = Cesium.defaultValue(label.textField, "");
+					label.font = Cesium.defaultValue(label.font, "24px Helvetica");
+					if (label.fillColor instanceof Array) {
+						label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+					} else if (typeof options.color === 'string') {
+						label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+					} else {
+						label.fillColor = new Cesium.Color.fromCssColorString("#ff0000");
+					}
+
+					if (label.outlineColor instanceof Array) {
+						label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+					} else if (label.outlineColor instanceof String) {
+						label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+					} else {
+						label.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+					}
+					label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+					//是否显示背景颜色
+					label.showBackground = Cesium.defaultValue(label.showBackground, false);
+					//背景颜色
+					if (label.backgroundColor instanceof Array) {
+						label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+					} else if (label.backgroundColor instanceof String) {
+						label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+					} else {
+						label.backgroundColor = new Cesium.Color.fromCssColorString("#FFFF00");
+					}
+
+					label.pixelOffset = Cesium.defaultValue(label.pixelOffset, 0);
+					label.scale = Cesium.defaultValue(label.scale, 1);
+
+					label.near = Cesium.defaultValue(label.near, 1.5e2);
+					label.nearValue = Cesium.defaultValue(label.nearValue, 1);
+					label.far = Cesium.defaultValue(label.far, 2400);
+					label.farValue = Cesium.defaultValue(label.farValue, 0);
+
+
+					let labelText = label.text;
+					if (entity.properties[label.textField]) {
+						labelText = entity.properties[label.textField]._value;
+					}
+					if (labelText === "") {
+						labelText = (i + 1).toString();
+					}
+
+					entity.label = {
+						text: labelText.toString(),
+						font: label.font,
+						fillColor: label.fillColor, //填充颜色
+						outlineColor: label.outlineColor, //边框颜色
+						outlineWidth: label.outlineWidth, //边框宽度	
+						style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+						showBackground: label.showBackground, //指定标签后面背景的可见性
+						backgroundColor: label.backgroundColor, // 背景颜色
+						backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+
+						pixelOffset: new Cesium.Cartesian2(0, label.pixelOffset), //偏移量
+						scale: label.scale, //尺寸
+					}
+
+					if (label.scaleByDistance) {
+						label.scaleByDistance.near = Cesium.defaultValue(label.scaleByDistance.near, 0);
+						label.scaleByDistance.nearValue = Cesium.defaultValue(label.scaleByDistance.nearValue, 0);
+						label.scaleByDistance.far = Cesium.defaultValue(label.scaleByDistance.far, 1);
+						label.scaleByDistance.farValue = Cesium.defaultValue(label.scaleByDistance.farValue, 0);
+
+						entity.label.scaleByDistance = new Cesium.NearFarScalar(label.scaleByDistance.near, label.scaleByDistance.nearValue, label.scaleByDistance.far, label.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+					}
+				}
+			})
+
+			if (callSuccess) callSuccess(options.id);
+		})
+	},
+
+	/**
+	 * 根据GeoJson添加广告牌
+	 * @param {Object} options
+	 * @param {String} options.url geoJson文件路径
+	 * @param {String} options.id 用于移除
+	 * @param {Object} [options.billboard] 广告牌的样式,具有以下属性:
+	 * @param {Number} [options.billboard.imgUrl] 广告牌图片
+	 * @param {Number} [options.billboard.scale=1] 尺寸
+	 * @param {Object} [options.billboard.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.billboard.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.billboard.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.billboard.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.billboard.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 * 
+	 * @param {Object} [options.lable] lable的样式,具有以下属性:
+	 * @param {Number} [options.lable.text=""] 文字
+	 * @param {Number} [options.lable.textField=""] 文字字段
+	 * @param {String} [options.lable.font="24px Helvetica"] 指定CSS字体的属性,字体大小及样式
+	 * @param {String} [options.lable.fillColor=[255,255,0,1]] 字体颜色
+	 * @param {String} [options.lable.outlineColor=[255,255,255,1]] 字体边框颜色
+	 * @param {Number} [options.lable.outlineWidth=1] 边框宽度	
+	 * @param {Number} [options.lable.showBackground=false] 是否显示背景颜色
+	 * @param {Number} [options.lable.backgroundColor=[255,255,255,1]] 背景颜色		
+	 * @param {Number} [options.lable.pixelOffset=0] 偏移量
+	 * @param {Number} [options.lable.scale=1] 尺寸
+	 * @param {Object} [options.lable.scaleByDistance] 距离相机的距离缩放点。
+	 * @param {Number} [options.lable.scaleByDistance.near=0] 相机范围的下界。
+	 * @param {String} [options.lable.scaleByDistance.nearValue=0] 相机范围下界的值。
+	 * @param {String} [options.lable.scaleByDistance.far=1] 相机范围的上限。
+	 * @param {Number} [options.lable.scaleByDistance.farValue=0] 该值位于摄像机范围的上界。
+	 */
+	addBillboardByJson(options, callSuccess) {
+
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(options.url)) {
+			resolve("options.url is required.");
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options.id = options.id || this._guid();
+
+		let billboard = options.billboard || {};
+		billboard.imgUrl = Cesium.defaultValue(billboard.imgUrl, 'jt3dSDK/imgs/point/point3.png');
+
+		billboard.scale = Cesium.defaultValue(billboard.scale, 1);
+		billboard.pixelOffset = Cesium.defaultValue(billboard.pixelOffset, 0);
+
+		fetch(options.url).then(res => {
+			return res.json();
+		}).then(res => {
+
+
+			for (var i = 0; i < res.features.length; i++) {
+				let coordinates = res.features[i].geometry.coordinates;
+				let position = Cesium.Cartesian3.fromDegrees(coordinates[0], coordinates[1], coordinates[2] || 0);
+
+				//先创建一个CustomDataSource源,然后把entity存入这里面
+				let Point = new Cesium.CustomDataSource(options.id);
+				viewer.dataSources.add(Point);
+
+				let entity = new Cesium.Entity({
+					// id: options.id,
+					name: "add billboard",
+					//位置
+					position: position,
+					//图片标签
+					billboard: {
+						image: billboard.imgUrl,
+						horizontalOrigin: Cesium.HorizontalOrigin.CENTER, //水平
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM, //垂直位置
+						scale: billboard.scale, //尺寸
+						pixelOffset: new Cesium.Cartesian2(0, billboard.pixelOffset),
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+					}
+				});
+
+				if (billboard.scaleByDistance) {
+					billboard.scaleByDistance.near = Cesium.defaultValue(billboard.scaleByDistance.near, 0);
+					billboard.scaleByDistance.nearValue = Cesium.defaultValue(billboard.scaleByDistance.nearValue, 0);
+					billboard.scaleByDistance.far = Cesium.defaultValue(billboard.scaleByDistance.far, 1);
+					billboard.scaleByDistance.farValue = Cesium.defaultValue(billboard.scaleByDistance.farValue, 0);
+
+					entity.billboard.scaleByDistance = new Cesium.NearFarScalar(billboard.scaleByDistance.near, billboard.scaleByDistance.nearValue, billboard.scaleByDistance.far, billboard.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+				}
+
+				if (options.label) {
+					let label = options.label || {};
+					label.text = Cesium.defaultValue(label.text, "");
+					label.textField = Cesium.defaultValue(label.textField, "");
+					label.font = Cesium.defaultValue(label.font, "24px Helvetica");
+					if (label.fillColor instanceof Array) {
+						label.fillColor = new Cesium.Color(label.fillColor[0] / 255, label.fillColor[1] / 255, label.fillColor[2] / 255, label.fillColor[3]);
+					} else if (typeof options.color === 'string') {
+						label.fillColor = new Cesium.Color.fromCssColorString(label.fillColor);
+					} else {
+						label.fillColor = new Cesium.Color.fromCssColorString("#ff0000");
+					}
+
+					if (label.outlineColor instanceof Array) {
+						label.outlineColor = new Cesium.Color(label.outlineColor[0] / 255, label.outlineColor[1] / 255, label.outlineColor[2] / 255, label.outlineColor[3]);
+					} else if (label.outlineColor instanceof String) {
+						label.outlineColor = new Cesium.Color.fromCssColorString(label.outlineColor);
+					} else {
+						label.outlineColor = new Cesium.Color.fromCssColorString("#FFFF00");
+					}
+					label.outlineWidth = Cesium.defaultValue(label.outlineWidth, 1);
+
+					//是否显示背景颜色
+					label.showBackground = Cesium.defaultValue(label.showBackground, false);
+					//背景颜色
+					if (label.backgroundColor instanceof Array) {
+						label.backgroundColor = new Cesium.Color(label.backgroundColor[0] / 255, label.backgroundColor[1] / 255, label.backgroundColor[2] / 255, label.backgroundColor[3]);
+					} else if (label.backgroundColor instanceof String) {
+						label.backgroundColor = new Cesium.Color.fromCssColorString(label.backgroundColor);
+					} else {
+						label.backgroundColor = new Cesium.Color.fromCssColorString("#FFFF00");
+					}
+
+					label.pixelOffset = Cesium.defaultValue(label.pixelOffset, 0);
+					label.scale = Cesium.defaultValue(label.scale, 1);
+
+					label.near = Cesium.defaultValue(label.near, 1.5e2);
+					label.nearValue = Cesium.defaultValue(label.nearValue, 1);
+					label.far = Cesium.defaultValue(label.far, 2400);
+					label.farValue = Cesium.defaultValue(label.farValue, 0);
+
+					let labelText = label.text;
+					if (res.features[i].properties[label.textField]) {
+						labelText = res.features[i].properties[label.textField];
+					}
+					if (labelText === "") {
+						labelText = (i + 1).toString();
+					}
+
+					entity.label = {
+						text: labelText.toString(),
+						font: label.font,
+						fillColor: label.fillColor, //填充颜色
+						outlineColor: label.outlineColor, //边框颜色
+						outlineWidth: label.outlineWidth, //边框宽度	
+						style: Cesium.LabelStyle.FILL_AND_OUTLINE, //FILL不要轮廓 , OUTLINE只要轮廓,FILL_AND_OUTLINE轮廓加填充
+
+						verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+						showBackground: label.showBackground, //指定标签后面背景的可见性
+						backgroundColor: label.backgroundColor, // 背景颜色
+						backgroundPadding: new Cesium.Cartesian2(6, 6), //指定以像素为单位的水平和垂直背景填充padding
+						disableDepthTestDistance: Number.POSITIVE_INFINITY,
+
+						pixelOffset: new Cesium.Cartesian2(0, label.pixelOffset), //偏移量
+						scale: label.scale, //尺寸
+					}
+
+					if (label.scaleByDistance) {
+						label.scaleByDistance.near = Cesium.defaultValue(label.scaleByDistance.near, 0);
+						label.scaleByDistance.nearValue = Cesium.defaultValue(label.scaleByDistance.nearValue, 0);
+						label.scaleByDistance.far = Cesium.defaultValue(label.scaleByDistance.far, 1);
+						label.scaleByDistance.farValue = Cesium.defaultValue(label.scaleByDistance.farValue, 0);
+
+						entity.label.scaleByDistance = new Cesium.NearFarScalar(label.scaleByDistance.near, label.scaleByDistance.nearValue, label.scaleByDistance.far, label.scaleByDistance.farValue) //按距离缩放,即距离大于180米时,图标不显示  Cesium.NearFarScalar(near, nearValue, far, farValue)相机范围的下界。相机范围下界的值。相机范围的上限。该值位于摄像机范围的上界。
+					}
+				}
+				// viewer.entities.add(entity);
+				Point.entities.add(entity)
+			}
+
+			if (callSuccess) callSuccess(options.id);
+		});
+	},
+
+	/**
+	 * 根据GeoJson添加动态墙
+	 * @param {Object} options
+	 * @param {String} options.url geoJson文件路径
+	 * @param {String} options.id 用于移除
+	 * @param {Number} [options.clampToGround=true] 是否贴地
+	 * @param {Number} [options.minimunHeights=0] 最低高度
+	 * @param {Number} [options.maximumHeights=100] 最高高度
+	 * @param {Number} [options.imgUrl] 动态墙图片
+	 * @param {String} [options.color="#FF0000"] 指定墙的颜色
+	 * @param {Number} [options.duration=3000] 持续时间 毫秒,越小越快
+	 * @param {Number} [options.count] 重复次数
+	 * @param {String} [options.direction='horizontal'] 方向 vertical纵,垂直方向,horizontal横,水平方向
+	 * @param {String} [options.order] 方向正负 
+	 *                                        vertical 纵:'-'(由下到上) , '+"(由上到下)
+	 *                                        horizontal 横:'-'(顺时针) , '+'(逆时针)
+	 */
+	addWallByJson(options, callSuccess) {
+
+		let _self = this;
+		let viewer = this._viewer;
+
+		if (!Cesium.defined(options.url)) {
+			resolve("options.url is required.");
+			throw new Cesium.DeveloperError("options.url is required.");
+		}
+
+		options = options || {};
+		options.id = options.id || setSessionid();
+		options.clampToGround = Cesium.defaultValue(options.clampToGround, true);
+
+		options.minimunHeights = options.minimunHeights !== undefined && typeof options.minimunHeights === 'number' ? options.minimunHeights : 0;
+		options.maximumHeights = options.maximumHeights !== undefined && typeof options.maximumHeights === 'number' ? options.maximumHeights : 1000;
+
+		if (options.color) {
+			if (options.color instanceof Array) {
+				options.color = new Cesium.Color(options.color[0] / 255, options.color[1] / 255, options.color[2] / 255, options.color[3]);
+			} else if (typeof(options.color) === 'string') {
+				options.color = new Cesium.Color.fromCssColorString(options.color);
+			} else {
+				options.color = new Cesium.Color.fromCssColorString("#FFFF00");
+			}
+		}
+
+		options.trailImage = Cesium.defaultValue(options.trailImage, 'jt3dSDK/imgs/wallmaterial/wl.png');
+		options.duration = Cesium.defaultValue(options.duration, 3000);
+		options.count = Cesium.defaultValue(options.count, 1);
+		options.direction = Cesium.defaultValue(options.direction, 'vertical');
+		options.order = Cesium.defaultValue(options.order, '-');
+
+		fetch(options.url).then(res => {
+			return res.json();
+		}).then(res => {
+			for (var i = 0; i < res.features.length; i++) {
+				let coordinates = res.features[i].geometry.coordinates;
+				let positions = coordinates.map(point => {
+					return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+				});
+
+				//先创建一个CustomDataSource源,然后把entity存入这里面
+				let wall = new Cesium.CustomDataSource(options.id);
+				viewer.dataSources.add(wall);
+
+				let entity = new Cesium.Entity({
+					name: "立体墙效果",
+					wall: {
+						positions: positions,
+						// 设置高度
+						maximumHeights: new Array(positions.length).fill(options.maximumHeights),
+						minimunHeights: new Array(positions.length).fill(options.minimunHeights),
+						// 扩散墙材质
+						// material: new Cesium.WallDiffuseMaterialProperty({
+						//     color: new Cesium.Color(1.0, 1.0, 0.0, 1.0)
+						// }),
+						material: new WallMaterialProperty(viewer, {
+							trailImage: options.trailImage,
+							color: options.color,
+							duration: options.duration,
+							param: {
+								count: options.count,
+								direction: options.direction,
+								order: options.order,
+							},
+						}),
+
+						// material: new Cesium.DynamicWallMaterialProperty({
+						// 	trailImage: 'jt3dSDK/imgs/wallmaterial/wl.png',
+						// 	color: Cesium.Color.CYAN,
+						// 	duration: 1500
+						// })
+					}
+				});
+
+				// 绘制墙体
+				wall.entities.add(entity)
+			}
+
+			if (callSuccess) callSuccess(options.id);
+		});
+	},
+
+});
+
+/**
+ * 通用对外公开函数 - 设置样式及透明度
+ */
+Object.assign(LoadMapData.prototype, /** @lends LoadMapData.prototype */ {
+
+	/**
+	 * 设置3DTile透明度
+	 * @param {Object} options
+	 * @param {String} options.serviceId 服务Id
+	 * @param {Number} [options.alpha=1] 透明度,0-1,0.0 表示完全透明,1.0 表示完全不透明	
+	 */
+	set3DTileStyle(options) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+			throw new Cesium.DeveloperError("options.serviceId is required.");
+		}
+
+		//透明度,0.0 表示完全透明,1.0 表示完全不透明
+		if (Cesium.defined(options.alpha)) {
+			Cesium.Check.typeOf.number("alpha", options.alpha);
+		}
+		options.alpha = Cesium.defaultValue(options.alpha, 1);
+
+		let tileset = window[options.serviceId];
+		//设置实景透明度
+		tileset.style = new Cesium.Cesium3DTileStyle({
+			color: "color('rgba(255,255,255," + options.alpha + ")')",
+		});
+	},
+
+	/**
+	 * 设置Cesium3DTileStyle白膜样式
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.serviceId 服务Id
+	 * @param {Array<Number>} [options.color=[245,82,0,1]] 设置白膜颜色样式[0~255,0~255,0~255,0~1]
+	 * @example
+	 * layer.set3DTileBMStyle({
+	 * 	serviceId : 'serviceId',
+	 * 	color : [0, 148, 220, 0.8],
+	 * });
+	 *
+	 */
+	set3DTileBMStyle: function(options) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+			throw new Cesium.DeveloperError("options.serviceId is required.");
+		}
+
+		// vec4(245 / 255, 82 / 255, 0 / 255, 1.0)
+		// vec4(0.0, 0.58, 0.86, 1.0)
+		// 设置白膜颜色样式,例vec4(0.0, 0.58, 0.86, 1.0)  前三个浮点数 (范围是 0.0 到 1.0) 代表红,绿,蓝,第四个值代表 alpha 通道,控制透明度 (0.0 完全透明,1.0 是完全不透明).
+		options.color = options.color ? "vec4(" + options.color[0] + "/255, " + options.color[1] + "/255, " + options.color[2] + "/255, " + options.color[3] + ")" : "vec4(0.0, 0.58, 0.86, 1.0)";
+
+		let tileset = window[options.serviceId];
+		tileset.readyPromise.then((tileset) => {
+			let r = tileset.boundingSphere.radius;
+			if (tileset.boundingSphere.radius > 10000) {
+				r = tileset.boundingSphere.radius / 10
+			}
+			tileset.style = new Cesium.Cesium3DTileStyle({
+				color: options.color,
+				// color: 'vec4(0, 0.2, 1.0,1.0)',
+			});
+			tileset.tileVisible.addEventListener((tile) => {
+				//console.log("tile:",tile);
+				let content = tile.content
+				let featuresLength = content.featuresLength
+				for (let i = 0; i < featuresLength; i += 2) {
+					const feature = content.getFeature(i)
+					const model = feature.content._model
+					if (model && model._sourcePrograms && model._rendererResources) {
+						Object.keys(model._sourcePrograms).forEach((key) => {
+							const program = model._sourcePrograms[key]
+							const fragmentShader = model._rendererResources.sourceShaders[program.fragmentShader]
+							let vPosition = ''
+							if (fragmentShader.indexOf(' v_positionEC;') !== -1) {
+								vPosition = 'v_positionEC'
+							} else if (fragmentShader.indexOf(' v_pos;') !== -1) {
+								vPosition = 'v_pos'
+							}
+							const color = `vec4(${feature.color.toString()})`
+							model._rendererResources.sourceShaders[program.fragmentShader] = `
+												  varying vec3 ${vPosition};
+												  void main(void){
+													vec4 v_helsing_position = czm_inverseModelView * vec4(${vPosition},1);  
+													
+													float _baseHeight = -30.0;
+													float vtxf_height = v_helsing_position.z - _baseHeight;
+													float stc_pl = fract(czm_frameNumber / 120.0) * 3.14159265 * 2.0;
+													float stc_sd = vtxf_height / 30.0 + sin(stc_pl) * 0.1;
+													gl_FragColor = ${color};
+													gl_FragColor *= vec4(stc_sd, stc_sd, stc_sd, 1.0);
+													/* 扫描线 */
+													float glowRange = 80.0;
+													float stc_a13 = fract(czm_frameNumber / 460.0);
+													float stc_h = clamp(v_helsing_position.z / glowRange, 0.0, 1.0);
+													stc_a13 = abs(stc_a13 - 0.5) * 1.0;
+													float stc_diff = step(0.003, abs(stc_h - stc_a13));
+													gl_FragColor.rgb += gl_FragColor.rgb * (1.0 - stc_diff);
+												  }
+												`
+						})
+						model._shouldRegenerateShaders = true;
+					}
+				}
+			})
+		})
+
+		//刷新地图	
+		this._viewer.scene.requestRender();
+	},
+
+	/**
+	 * 设置Cesium3DTileset(实景)三维高度
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.serviceId 服务Id
+	 * @param {Number} options.height=0 设置模型距离地形高度
+	 * 
+	 * @example
+	 * layer.set3DTilePosition({
+	 * 	serviceId : 'serviceId',
+	 * 	height : 0,
+	 * });
+	 *
+	 */
+	set3DTilePosition: function(options) {
+		if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+			throw new Cesium.DeveloperError("options.serviceId is required.");
+		}
+
+		options.height = Cesium.defaultValue(options.height, 0);
+
+		let boundingSphere = window[options.serviceId].boundingSphere;
+		let cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
+
+		// longitude number 经度,单位为弧度
+		// latitude  number 纬度,单位为弧度
+		// height    number 椭球的高度,以米为单位
+		let left = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, options.height);
+		let right = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
+
+		//left   左笛卡尔第一个笛卡尔。
+		//right 左笛卡尔第二个笛卡尔。
+		//result cartesian3存储结果的对象。
+		let translation = Cesium.Cartesian3.subtract(left, right, new Cesium.Cartesian3());
+		window[options.serviceId].modelMatrix = Cesium.Matrix4.fromTranslation(translation);
+
+		this._viewer.scene.requestRender(); //刷新地图	
+	},
+
+	/**
+	 * 设置图层的透明度、亮度、对比度、伽马、色调、饱和度等
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} [options.alpha] 透明度,0-1,0.0 表示完全透明,1.0 表示完全不透明	
+	 * @param {Number} [options.brightness] 亮度,>1.0 增加亮度.  < 1.0 减少亮度.
+	 * @param {Number} [options.contrast] 对比度,>1.0 增加对比度.  < 1.0 减少对比度.
+	 * @param {Number} [options.gamma] 伽马,>1.0 增加伽马.  < 1.0 减少伽马.
+	 * @param {Number} [options.hue] 色调,>0 增加色调
+	 * @param {Number} [options.saturation] 饱和度,>1.0 增加亮度.  < 1.0 减少亮度.
+	 * 
+	 * @example
+	 * layer.setLayersStyle({
+	 *	serviceId : 'serviceId',
+	 * 	alpha : 0.5,
+	 * 	brightness : 1,
+	 * });
+	 *
+	 */
+	setLayersStyle(options) {
+
+		if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+			throw new Cesium.DeveloperError("options.serviceId is required.");
+		}
+
+		let layer = window[options.serviceId];
+
+		//透明度,0.0 表示完全透明,1.0 表示完全不透明	
+		if (Cesium.defined(options.alpha)) {
+			Cesium.Check.typeOf.number("alpha", options.alpha);
+		}
+		options.alpha = Cesium.defaultValue(options.alpha, 1);
+		layer.alpha = options.alpha;
+
+		//亮度,>1.0 增加亮度.  < 1.0 减少亮度.
+		if (Cesium.defined(options.brightness)) {
+			Cesium.Check.typeOf.number("brightness", options.brightness);
+		}
+		options.brightness = Cesium.defaultValue(options.brightness, 1);
+		layer.brightness = options.brightness;
+
+		//对比度,>1.0 增加对比度.  < 1.0 减少对比度
+		if (Cesium.defined(options.contrast)) {
+			Cesium.Check.typeOf.number("contrast", options.contrast);
+		}
+		options.contrast = Cesium.defaultValue(options.contrast, 1);
+		layer.contrast = options.contrast;
+
+		//伽马,>1.0 增加亮度.  < 1.0 减少亮度.
+		if (Cesium.defined(options.gamma)) {
+			Cesium.Check.typeOf.number("gamma", options.gamma);
+		}
+		options.gamma = Cesium.defaultValue(options.gamma, 1);
+		layer.gamma = options.gamma;
+
+		//色调,>0 增加色调
+		if (Cesium.defined(options.hue)) {
+			Cesium.Check.typeOf.number("hue", options.hue);
+		}
+		options.hue = Cesium.defaultValue(options.hue, 0);
+		layer.hue = options.hue;
+
+		//饱和度,>1.0 增加饱和度.  < 1.0 减少饱和度.
+		if (Cesium.defined(options.saturation)) {
+			Cesium.Check.typeOf.number("saturation", options.saturation);
+		}
+		options.saturation = Cesium.defaultValue(options.saturation, 1);
+		layer.saturation = options.saturation;
+	},
+
+	/**
+	 * 设置图片服务透明度
+	 * @param {Object} options
+	 * @param {String} options.serviceId 服务Id
+	 * @param {Number} options.alpha 透明度,0-1,0.0 表示完全透明,1.0 表示完全不透明	
+	 */
+	setPolygonImageMaterial(options) {
+		//透明度,0.0 表示完全透明,1.0 表示完全不透明
+		if (Cesium.defined(options.alpha)) {
+			Cesium.Check.typeOf.number("alpha", options.alpha);
+		}
+		options.alpha = Cesium.defaultValue(options.alpha, 1);
+
+		let entity = window[options.serviceId];
+
+		// let color = entity.polygon.material.color.getValue().clone();
+		// entity.material.color.setValue(color.withAlpha(options.alpha));
+		entity.polygon.material.color._value.alpha = options.alpha;
+	},
+
+	/**
+	 * 设置图片服务透明度
+	 * @param {Object} options
+	 * @param {String} options.serviceId 服务Id
+	 * @param {Number} options.alpha 透明度,0-1,0.0 表示完全透明,1.0 表示完全不透明	
+	 */
+	setModelStyle(options) {
+		//透明度,0.0 表示完全透明,1.0 表示完全不透明
+		if (Cesium.defined(options.alpha)) {
+			Cesium.Check.typeOf.number("alpha", options.alpha);
+		}
+		options.alpha = Cesium.defaultValue(options.alpha, 1);
+
+		let entity = window[options.serviceId];
+		if (entity.model) {
+			entity.model.color._value.alpha = options.alpha;
+		} else {
+			entity.color._value.alpha = options.alpha;
+		}
+	},
+
+	/**
+	 * 动态设置地形夸张系数
+	 * @param {Object} options
+	 * @param {Number} options.terrainExaggeration=1 地形夸张系数
+	 */
+	setTerrainExaggeration(options) {
+		//透明度,0.0 表示完全透明,1.0 表示完全不透明	
+		if (Cesium.defined(options.terrainExaggeration)) {
+			Cesium.Check.typeOf.number("terrainExaggeration", options.terrainExaggeration);
+		}
+		options.terrainExaggeration = Cesium.defaultValue(options.terrainExaggeration, 1);
+
+		// 地形夸张
+		this._viewer.scene.globe.terrainExaggeration = options.terrainExaggeration;
+	}
+})
+
+/**
+ * 通用对外公开函数 - 移除图层
+ */
+Object.assign(LoadMapData.prototype, /** @lends LoadMapData.prototype */ {
+
+	/**
+	 * 将图层在地图中移除(ArcGIS Online和Server的相关服务、WMS、WMTS、URL模板服务)
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.serviceId 服务Id
+	 * @example
+	 * layer.removeImageryProvider({
+	 * 	serviceId : 'serviceId',
+	 * });
+	 *
+	 */
+	removeImageryProvider(options) {
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+				throw new Cesium.DeveloperError("options.serviceId is required.");
+			}
+
+			this._removeImageryProvider(options.serviceId);
+			resolve(true);
+		});
+	},
+
+	/**
+	 * 将图层在地图中移除(地形)
+	 *
+	 */
+	removeTerrain() {
+		return new Promise((resolve, reject) => {
+			this._setEllipsoidTerrain();
+			resolve(true);
+		});
+	},
+
+	/**
+	 * 将图层在地图中移除(实景/白膜)
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.serviceId 服务Id
+	 * 
+	 * @example
+	 * layer.removeScenePrimitives({
+	 * 	serviceId : 'serviceId',
+	 * });
+	 *
+	 */
+	removeScenePrimitives(options) {
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+				throw new Cesium.DeveloperError("options.serviceId is required.");
+			}
+			this._removeScenePrimitives(options.serviceId);
+			resolve(true);
+		});
+	},
+
+	/**
+	 * 将图层在地图中移除entity
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.serviceId 服务Id
+	 * 
+	 * @example
+	 * layer.removeEntity({
+	 * 	serviceId : 'serviceId',
+	 * });
+	 *
+	 */
+	removeEntity(options) {
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+				throw new Cesium.DeveloperError("options.serviceId is required.");
+			}
+			this._viewer.entities.remove(window[options.serviceId]);
+			window[options.serviceId] = null;
+			resolve(true);
+		});
+	},
+
+	/**
+	 * 将图层在地图中移除entity
+	 * @param {Object} options 具有以下属性:
+	 * @param {String} options.serviceId 服务Id
+	 * 
+	 * @example
+	 * layer.removeDataSources({
+	 * 	serviceId : 'serviceId',
+	 * });
+	 *
+	 */
+	removeDataSources(options) {
+
+		let _self = this;
+		let viewer = this._viewer;
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(options) || !Cesium.defined(options.serviceId)) {
+				throw new Cesium.DeveloperError("options.serviceId is required.");
+			}
+
+			//清除高亮显示
+			let list = viewer.dataSources.getByName(options.serviceId)
+			list.forEach((res, index) => {
+				viewer.dataSources.remove(res)
+				if (index === (list.length - 1)) {
+					resolve(true);
+				}
+			})
+		});
+	},
+})
+
+export default LoadMapData;

+ 303 - 0
packages/Widgets/locateUtil.js

@@ -0,0 +1,303 @@
+/* 引入Cesium */
+// import * as Cesium from 'Cesium';
+
+/**
+ * Cesium 的各种定位方法汇总,只列出项目中经常使用的,如果不够灵活,可直接调用Cesium官方API,也很方便。
+ * Cesium的定位从效果上包含两种:直接定位、飞行定位。在方法封装上,姑且将直接定位分类为zoomTo系列,飞行定位分类flyTo。
+ * 定位的对象上包括:坐标点、矩形范围、entities、3dtiles、gltf、kml、geojson、影像、地形、geometry 
+ * Cesium的定位主要是使用Camera对象和Viewer对象,Viewer的定位zoomTo,flyTo等方法是较高级别的函数,可以定位到Entity、3dtiles、DataSource等添加到三维球上显示的实体,
+ * Viewer的定位方法内部都是调用Camera的相关定位方法,针对不同的定位对象,通过一些列计算得出传入实体的合适定位范围和摄像机视角,然后定位,使用起来很方便。
+ * Camera的flyTo、flyToBoundingSphere、lookat、setView等方法是较低级别函数,通过定位坐标和角度参数的传入,精细化控制定位视角,灵活。
+ */
+class LocateUtil {
+	/**
+	 * 默认初始化
+	 * @param {Object} viewer 三维场景
+	 */
+	constructor(viewer) {
+		if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
+		this._viewer = viewer;
+		this._locationEntity = null;
+	}
+}
+
+/**
+ * 通用对外公开函数(坐标定位)
+ */
+Object.assign(LocateUtil.prototype, /** @lends LocateUtil.prototype */ {
+
+	/**
+	 * 飞行定位到一个笛卡尔空间直角坐标点位置
+	 * @param {Object} options 具有以下属性:
+	 * @param {Number} options.longitude 经度,以度为单位
+	 * @param {Number} options.latitude 纬度,以度为单位
+	 * @param {Number} [options.height=0.0] 椭球的高度,以米为单位
+	 * @param {Number} [options.heading=0.0] 指向,默认值0.0(北)
+	 * @param {Number} [options.pitch=-90] 俯仰角, 垂直向下。默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.range=0.0] 距目标点距离
+	 * @param {Number} [options.duration=3] 持续时间
+	 */
+	flyToPoint: function(options) {
+		return new Promise((resolve, reject) => {
+			if (!Cesium.defined(options) || !Cesium.defined(options.longitude) || !Cesium.defined(options.latitude)) {
+				throw new Cesium.DeveloperError("options.longitude and options.latitude  are required.");
+			}
+
+			// 初始化参数默认值
+			options.height = Cesium.defaultValue(options.height, 0);
+			options.heading = Cesium.defaultValue(options.heading, 0);
+			options.pitch = Cesium.defaultValue(options.pitch, -90);
+			options.range = Cesium.defaultValue(options.range, 0.0);
+			options.duration = Cesium.defaultValue(options.duration, 3);
+
+			var boundingSphere = new Cesium.BoundingSphere(Cesium.Cartesian3.fromDegrees(options.longitude, options.latitude, options.height), 0.0);
+			this._viewer.camera.flyToBoundingSphere(boundingSphere, {
+				duration: options.duration,
+				complete: function() {
+					resolve(true);
+				},
+				offset: {
+					heading: Cesium.Math.toRadians(options.heading),
+					pitch: Cesium.Math.toRadians(options.pitch),
+					range: options.range
+				},
+			});
+		});
+	},
+
+	/**
+	 * @description 根据坐标飞行定位,支持点、线、面等
+	 * @param {Array}  points 坐标集合 [[lng,lat],[lng,lat],......]  
+	 * @param {String} type 定位类型 point multiplePoint polyline polygon
+	 * @param {Object} [options] 飞行的样式,具有以下属性:
+	 * @param {Number} [options.heading=0.0] 指向,默认值0.0(北)
+	 * @param {Number} [options.pitch=-90] 俯仰角, 垂直向下。默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.range=0.0] 距目标点距离
+	 * @param {Number} [options.duration=3] 持续时间
+	 */
+	flyToEntityByPoints: function(points, type, options) {
+
+		return new Promise((resolve, reject) => {
+			let _self = this;
+
+			options = options || {};
+
+			if (points === undefined || points.length === undefined) {
+				reject("输入的坐标集合异常!");
+				return;
+			}
+
+			/* 转换坐标 */
+			let pointsArray = points.map(point => {
+				return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
+			});
+
+			if (_self._locationEntity) {
+				_self._viewer.entities.remove(_self._locationEntity);
+			}
+
+			/* 分别判断 */
+			switch (type) {
+				case "point":
+
+					_self._locationEntity = _self._viewer.entities.add({
+						position: pointsArray[0],
+						point: {
+							pixelSize: 1,
+						},
+					});
+
+					break;
+				case "polyline":
+
+					if (pointsArray.length < 2) {
+						reject("线对象定位,点数至少2个");
+					} else {
+						_self._locationEntity = _self._viewer.entities.add({
+							polyline: {
+								positions: pointsArray,
+								clampToGround: true, //指定折线是否应该固定在地面上
+								// material: new Cesium.Color.fromCssColorString("#ffffff00"),
+								material: new Cesium.Color(255, 0, 0, 0.5),
+								width: 1,
+							}
+						});
+					}
+
+					break;
+				case "polygon":
+
+					if (pointsArray.length < 3) {
+						reject("面对象定位,点数至少3个");
+					} else {
+						_self._locationEntity = _self._viewer.entities.add({
+							polygon: {
+								hierarchy: {
+									positions: pointsArray
+								},
+								// material: new Cesium.Color.fromCssColorString("#ffffff00"),
+								material: new Cesium.Color(255, 0, 0, 0.5),
+								outline: true,
+							}
+						});
+					}
+					break;
+				default:
+					reject("坐标异常!");
+					break;
+			}
+
+			// 初始化参数默认值
+			options.duration = Cesium.defaultValue(options.duration, 3);
+			options.heading = Cesium.defaultValue(options.heading, 0);
+			options.pitch = Cesium.defaultValue(options.pitch, -90);
+			options.range = Cesium.defaultValue(options.range, 0.0);
+
+			let flyPromise = _self._viewer.flyTo(_self._locationEntity, {
+				duration: options.duration,
+				offset: {
+					heading: Cesium.Math.toRadians(options.heading),
+					pitch: Cesium.Math.toRadians(options.pitch),
+					range: options.range
+				}
+			});
+			flyPromise.then(function(flag) {
+				if (flag) {
+					// _self._viewer.entities.remove(_self._locationEntity);
+					resolve(_self._locationEntity);
+				}
+			});
+		});
+
+	},
+
+	/**
+	 * @description 飞行定位到一个实体
+	 * @param {Object} entity
+	 * @param {Number} [options.heading=0.0] 指向,默认值0.0(北)
+	 * @param {Number} [options.pitch=-90] 俯仰角, 垂直向下。默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.range=0.0] 距目标点距离
+	 * @param {Number} [options.duration=3] 持续时间
+	 */
+	flyToEntity: function(entity, options) {
+
+		return new Promise((resolve, reject) => {
+			let _self = this;
+
+			options = options || {};
+
+			if (_self._locationEntity) {
+				_self._viewer.entities.remove(_self._locationEntity);
+			}
+
+			_self._locationEntity = entity;
+
+			// 初始化参数默认值
+			options.duration = Cesium.defaultValue(options.duration, 3);
+			options.heading = Cesium.defaultValue(options.heading, 0);
+			options.pitch = Cesium.defaultValue(options.pitch, -90);
+			options.range = Cesium.defaultValue(options.range, 0.0);
+
+			let flyPromise = _self._viewer.flyTo(_self._locationEntity, {
+				duration: options.duration,
+				offset: {
+					heading: Cesium.Math.toRadians(options.heading),
+					pitch: Cesium.Math.toRadians(options.pitch),
+					range: options.range
+				}
+			});
+			flyPromise.then(function(flag) {
+				if (flag) {
+					// _self._viewer.entities.remove(_self._locationEntity);
+					resolve(_self._locationEntity);
+				}
+			});
+		});
+	},
+
+	/**
+	 * 定位实景三维
+	 * @param {Object} tileset
+	 * @param {Object} [options] 飞行的样式,具有以下属性:
+	 * @param {Number} [options.heading=120] 指向,默认值0.0(北)
+	 * @param {Number} [options.pitch=-10] 俯仰角, 垂直向下。默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.range=450.0] 距目标点距离
+	 * @param {Number} [options.duration=3] 持续时间
+	 */
+	zoomToTilesets(tileset, options) {
+		return new Promise((resolve, reject) => {
+			let _self = this;
+
+			if (!Cesium.defined(tileset)) {
+				throw new Cesium.DeveloperError("tileset is required.");
+			}
+
+			// 初始化参数默认值
+			options = options || {};
+			options.heading = Cesium.defaultValue(options.heading, 120);
+			options.pitch = Cesium.defaultValue(options.pitch, -10);
+			options.range = Cesium.defaultValue(options.range, 450.0);
+			options.duration = Cesium.defaultValue(options.duration, 3);
+
+			// var boundingSphere = new Cesium.BoundingSphere(Cesium.Cartesian3.fromDegrees(options.longitude, options.latitude, options.height), 0.0);
+			let boundingSphere = tileset.boundingSphere;
+			_self._viewer.camera.flyToBoundingSphere(boundingSphere, {
+				duration: options.duration,
+				complete: function() {
+					resolve(true);
+				},
+				offset: {
+					heading: Cesium.Math.toRadians(options.heading),
+					pitch: Cesium.Math.toRadians(options.pitch),
+					range: options.range
+				},
+			});
+		});
+	},
+
+	/**
+	 * 飞行定位实景三维
+	 * @param {Object} tileset
+	 * @param {Object} [options] 飞行的样式,具有以下属性:
+	 * @param {Number} [options.heading=120] 指向,默认值0.0(北)
+	 * @param {Number} [options.pitch=-10] 俯仰角, 垂直向下。默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
+	 * @param {Number} [options.range=450.0] 距目标点距离
+	 * @param {Number} [options.duration=3] 持续时间
+	 */
+	flyToTileset(tileset, options) {
+		return new Promise((resolve, reject) => {
+			let _self = this;
+
+			if (!Cesium.defined(tileset)) {
+				throw new Cesium.DeveloperError("tileset is required.");
+			}
+
+			// 初始化参数默认值
+			options = options || {};
+			options.heading = Cesium.defaultValue(options.heading, 120);
+			options.pitch = Cesium.defaultValue(options.pitch, -10);
+			options.range = Cesium.defaultValue(options.range, 450.0);
+			options.duration = Cesium.defaultValue(options.duration, 3);
+
+			/*viewer.flyTo() 方法,返回一个 promise (承诺)。
+			 * 如果飞行成功,该承诺将解析为 true; 
+			 * 如果视图中目标不可见或飞行被取消,该承诺将解析为 false。
+			 * 用途:在飞到某实体后,移除该实体。*/
+			let flyPromise = _self._viewer.flyTo(tileset, {
+				duration: options.duration,
+				offset: {
+					heading: Cesium.Math.toRadians(options.heading),
+					pitch: Cesium.Math.toRadians(options.pitch),
+					range: options.range
+				}
+			});
+			flyPromise.then(function(flag) {
+				if (flag) {
+					resolve(true);
+				}
+			});
+		});
+	}
+});
+
+export default LocateUtil;

+ 15 - 0
packages/Widgets/terrainAnalysis.js

@@ -0,0 +1,15 @@
+//地形开挖
+import TerrainExcavation from "./TerrainAnalysis/TerrainExcavation.js";
+//坡度坡向分析
+import SlopeAspect from "./TerrainAnalysis/SlopeAspect.js";
+
+/**
+ * 地形分析
+ * @ignore
+ */
+let TerrainAnalysis = {
+	TerrainExcavation: TerrainExcavation,
+	SlopeAspect: SlopeAspect,
+}
+export default TerrainAnalysis;
+

+ 159 - 0
packages/index.js

@@ -0,0 +1,159 @@
+//大球初始化
+import jtMap3d from './Widgets/base.js';
+import StatusBar from './Widgets/StatusBar.js';
+//加载各类图层服务
+import layer from "./Widgets/layer.js";
+//加载浮动图层
+import CrImageServerLayer from "./Widgets/CrImageServerLayer.js";
+//定位
+import LocateUtil from "./Widgets/LocateUtil.js";
+
+//空间分析
+import SpatialAnalysis from "./Widgets/SpatialAnalysis.js";
+//地形分析
+import TerrainAnalysis from "./Widgets/TerrainAnalysis.js";
+
+//场景特效
+import SceneEffects from "./Widgets/SceneEffects.js";
+//场景控件
+import SceneControl from "./Widgets/SceneControl.js";
+//跟踪漫游
+import TrackRoam from "./Widgets/Roaming/TrackRoam.js";
+import Roaming from "./Widgets/Roaming/Roaming.js";
+
+//点对象
+import PointObject from "./Widgets/PointObject.js";
+//线对象
+import PolylineObject from "./Widgets/PolylineObject.js";
+//面对象
+import PolygonObject from "./Widgets/PolygonObject.js";
+//墙体对象
+import WallObject from "./Widgets/WallObject.js";
+//墙体对象
+import CircleObject from "./Widgets/CircleObject.js";
+
+//绘图工具
+import CommonTools from "./Widgets/DrawTools/CommonTools.js";
+import {
+	SketchViewModel
+} from './Widgets/DrawTools/SketchViewModel.js';
+
+//绘图工具
+import {
+	DrawTools
+} from './Widgets/DrawTools/DrawTools.js';
+import DrawMilitaryPlot from './Widgets/DrawTools/DrawMilitaryPlot.js';
+import DrawPoint from './Widgets/DrawTools/DrawPoint.js';
+
+//自定义窗口
+import PopupWindow from './Widgets/PopupWindow.js';
+
+//公共类方法
+import * as common from "./Widgets/common/common.js";
+//公共类方法-坐标转换
+import CoordTransform from "./Widgets/common/CoordTransform.js";
+//公共类方法-提示tip
+import ReminderTip from "./Widgets/common/ReminderTip.js";
+
+//相机绕点旋转
+import AroundPoint from './Widgets/AroundPoint.js';
+//相机绕地旋转
+import AroundView from './Widgets/AroundView.js';
+
+// var jt3dSDK = {
+//     version: "2.0.2",
+//     createTime: "2023.05.16",
+//     author: "joy",
+// }
+
+// function expose() {
+
+//     var old = window.jt3dSDK;
+
+//     jt3dSDK.noConflict = function () {
+//         window.jt3dSDK = old;
+//         return this;
+//     };
+
+//     window.jt3dSDK = jt3dSDK;
+// }
+
+// // define P for Node module pattern loaders, including Browserify
+// if (typeof module === 'object' && typeof module.exports === 'object') {
+//     module.exports = jt3dSDK;
+
+// // define P as an AMD module
+// } else if (typeof define === 'function' && define.amd) {
+//     define(jt3dSDK);
+// }
+
+// // define gispace as a global P variable, saving the original P to restore later if needed
+// if (typeof window !== 'undefined') {
+//     expose();
+// }
+
+// jt3dSDK.jtMap3d=jtMap3d
+
+// export default jt3dSDK
+
+(function(global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+		typeof define === 'function' && define.amd ? define(['exports'], factory) :
+		(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jt3dSDK = {}));
+})(this, (function(exports) {
+	'use strict';
+
+	exports.jtMap3d = jtMap3d;
+	exports.StatusBar = StatusBar;
+	exports.layer = layer;
+	exports.CrImageServerLayer = CrImageServerLayer;
+	exports.LocateUtil = LocateUtil;
+	exports.SpatialAnalysis = SpatialAnalysis;
+	exports.TerrainAnalysis = TerrainAnalysis;
+
+	exports.SceneEffects = SceneEffects;
+	exports.SceneControl = SceneControl;
+	exports.TrackRoam = TrackRoam;
+	exports.Roaming = Roaming;
+
+	exports.PointObject = PointObject;
+	exports.PolylineObject = PolylineObject;
+	exports.PolygonObject = PolygonObject;
+	exports.WallObject = WallObject;
+	exports.CircleObject = CircleObject;
+
+	exports.CommonTools = CommonTools;
+	exports.SketchViewModel = SketchViewModel;
+
+	exports.DrawTools = DrawTools;
+	exports.DrawMilitaryPlot = DrawMilitaryPlot;
+	exports.DrawPoint = DrawPoint;
+
+	exports.PopupWindow = PopupWindow;
+
+	exports.common = common;
+	exports.CoordTransform = CoordTransform;
+	exports.ReminderTip = ReminderTip;
+
+	exports.AroundPoint = AroundPoint;
+	exports.AroundView = AroundView;
+	
+	Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
+
+// (function(global, factory) {
+// 	if (typeof exports === 'object' && typeof module !== 'undefined' && !window.Cesium) {
+// 		require('../public/ThirdParty/Cesium-1.93/Widgets/widgets.css')
+// 	};
+// 	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, (window.Cesium || require('../public/ThirdParty/Cesium-1.93/Cesium.js')), (window.turf || require('@turf/turf'))) :
+// 		typeof define === 'function' && define.amd ? define(['exports', 'Cesium', '@turf/turf'], factory) :
+// 		(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jt3dSDK = {}, global.Cesium, global.turf));
+// })(this, (function(exports, Cesium, turf) {
+// 	'use strict';
+
+// 	exports.jtMap3d = jtMap3d
+
+// }));
+
+export default jt3dSDK

+ 39 - 0
packages/package.json

@@ -0,0 +1,39 @@
+{
+	"name": "@jintian/jt-map3d-sdk",
+	"version": "0.0.2",
+	"private": false,
+	"keywords": [
+	  "jt",
+	  "map",
+	  "3d",
+	  "ui",
+	  "jt-map3d-sdk",
+	  "cesium"
+	],
+	"scripts": {
+		"dev": "vite",
+		"build": "vite build",
+		"serve": "vite preview",
+		"jsDoc": "jsdoc -c jsdoc.json",
+		"doc": "jsdoc --configure Tools/jsdoc/conf.json"
+	},
+	"files": [
+	  "lib"
+	],
+	"main": "lib/jt-map3d-sdk.umd.js",
+	"module": "lib/jt-map3d-sdk.es.js",
+	"exports": {
+	  "./lib/style.css": "./lib/style.css",
+	  ".": {
+	    "import": "./lib/jt-map3d-sdk.es.js",
+	    "require": "./lib/jt-map3d-sdk.umd.js"
+	  }
+	},
+	"dependencies": {
+		"vue": "^3.2.25"
+	},
+	"devDependencies": {
+		"@vitejs/plugin-vue": "^1.6.0",
+		"vite": "^2.5.2"
+	}
+}

+ 2 - 1
src/jtMap3d/Widgets/DrawTools/DrawMilitaryPlot.js

@@ -4,7 +4,8 @@ import MilitaryPlot from './/MilitaryPlot/drawingMethod/index.js'
 import EntityEdit from './MilitaryPlot/EntityEdit.js';
 
 /* 引入属性编辑框 */
-import DialogEditProperty from './CrEditProperty_MilitaryPlot.ce.vue'
+// import DialogEditProperty from './CrEditProperty_MilitaryPlot.ce.vue'
+import DialogEditProperty from './components/MilitaryPlot.ce.vue'
 /* 引入组件注册 */
 import {
 	defineCustomElement

+ 266 - 0
src/jtMap3d/Widgets/DrawTools/components/MilitaryPlot.ce.vue

@@ -0,0 +1,266 @@
+<script setup>
+
+</script>
+
+<template>
+	<div class="jt-drawing-dialog" ref="popup">
+		<div class="borderstyle">
+			<div class="angle-border left-bottom-border"></div>
+			<div class="angle-border right-bottom-border"></div>
+			<div class="header">
+				<div style="width: 20rem;"></div>
+				<span>底图</span>
+				<i :class="store.userport == 'PC'?'iconfont icon-youjiantou':'iconfont icon-youjiantou'" @click="closeBasicLayer" style="font-size: 16rem;" />
+			</div>
+			<div class="middle">
+				<div class="onceLayer" v-for="(item,index) in layerList" :key="index" @click="changeBasicLayer(item)">
+					<img v-if="item.imageurl" :src="item.imageurl" :class="item.layerorder==selectImg?'selectImg':''" />
+					<!-- <span>{{item.title}}</span> -->
+				</div>
+			</div>
+			<div class="footer">
+				
+				<button type="primary"  @click="submit()">修改</button>
+				<button type="primary" style="background-color: rgb(222, 146, 47);"  @click="remove()">删除</button>
+				<button type="primary" style="background-color: rgb(126, 128, 135);"  @click="close()">关闭</button>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+
+			}
+		},
+		methods: {
+			//关闭模块事件
+			closeBasicLayer() {
+				let style = document.styleSheets[0];
+				style.insertRule(
+					"@keyframes move-right {0% {opacity: 1;transform: translateX(-100%)}100% {opacity: 1;transform: translateX(0%)}}",
+					10);
+				style.insertRule(
+					"@keyframes slide-right {0% {opacity: 1;transform: translateX(100%)}100% {opacity: 1;transform: translateX(0%)}}",
+					11);
+				let popup = this.$refs.popup
+				popup.style.right = '-400rem'
+				popup.style.animation = 'move-right .4s linear';
+				// popup.style.animation-duration = '.8s';transform: translate(-50%,-50%);
+				setTimeout(res => {
+					this.$parent.showbasicLayer = false
+					popup.style.animation = 'slide-right .4s linear'
+					popup.style.right = '26rem'
+				}, 400)
+				if (this.isEmit) {
+					this.$emit('closeJTPopup');
+				}
+			},
+
+		},
+		mounted() {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@charset "UTF-8";
+
+	@font-face {
+		font-family: "TTTGB-Medium";
+		src: url("@/assets/fonts/fonts/TTTGB-Medium.ttf") format("truetype"),
+			url("@/assets/fonts/fonts/TTTGB-Medium.eot") format("embedded-opentype"),
+			url("@/assets/fonts/fonts/TTTGB-Medium.svg") format("svg");
+		font-weight: normal;
+		font-style: normal;
+	}
+
+	::v-deep .is-checked .el-switch__core .el-switch__action {
+		margin-left: calc(-1rem - 14rem);
+	}
+
+	::v-deep .el-switch__core .el-switch__action {
+		top: 1rem;
+	}
+
+	::v-deep .el-switch__core .el-switch__action {
+		width: 14rem;
+		height: 14rem;
+	}
+
+	::v-deep .el-switch__core {
+		width: 40rem !important;
+		height: 20rem !important;
+	}
+
+	.basicLayer {
+		position: absolute;
+		right: 26rem;
+		top: 125rem;
+		width: 350rem;
+		height: calc(100vh - 200rem);
+		// padding: 10rem;
+		z-index: 1000;
+		font-size: 16rem;
+		color: white;
+		user-select: none;
+		animation-name: slide-right;
+		animation-duration: .8s;
+
+		//头部背景图
+		.header {
+			height: 51rem;
+			width: calc(100% + 20rem);
+			background: url('@/assets/images/PopupHeader.png') no-repeat;
+			background-size: 100% 100%;
+			margin: -10rem;
+			margin-bottom: 0rem;
+			line-height: 51rem;
+			display: flex;
+			text-align: left;
+
+
+			span {
+				font-family: 'TTTGB-Medium', sans-serif !important;
+				flex: 15;
+				font-size: 20rem;
+			}
+
+			i:hover {
+				cursor: pointer;
+			}
+
+			i {
+				z-index: 101;
+				flex: 1;
+				margin: 0rem 8rem;
+				font-size: 20rem;
+			}
+		}
+
+		.middle:hover {
+			// overflow: auto;
+		}
+
+		.middle {
+			height: calc(100% - 125rem);
+			padding: 10rem 5rem;
+			// display: flex;
+			flex-wrap: wrap;
+			justify-content: space-around;
+			// flex: 3;
+			overflow-y: scroll; // 设置y轴方向的滚动条
+			overflow: hidden; // 超出部分隐藏
+
+
+			.onceLayer {
+				// flex: 1;
+				display: inline-block;
+				padding: 5rem;
+				width: 100rem;
+				height: 120rem;
+
+				img {
+					height: 100%;
+					width: 100%;
+					border-radius: 5rem;
+					// border: 2rem solid #008aff70 !important;
+				}
+
+				img:hover {
+					// border: 2rem dashed rgb(0, 255, 238);
+					cursor: pointer;
+					height: calc(100% - 0rem);
+					width: calc(100% - 0rem);
+					border: 0rem solid rgba(255, 255, 255, .8);
+					box-shadow: 0 0 2rem 2rem rgba(255, 255, 255, .5);
+					transition: all .2s;
+				}
+
+				//选中图片样式
+				.selectImg {
+					border: 0rem solid rgba(255, 255, 255, .8);
+					box-shadow: 0 0 3rem 3rem rgba(255, 255, 255, .5);
+					// height: calc(100% - 4rem);
+					// width: calc(100% - 4rem);
+				}
+
+				span {
+					font-size: 14rem;
+					display: inline-block;
+				}
+			}
+		}
+
+		.footer {
+			height: 44rem;
+			width: 100%;
+			line-height: 44rem;
+			text-align: left;
+			padding-left: 10rem;
+
+			el-switch {
+				margin: 3rem 0rem;
+				width: 36rem !important;
+			}
+
+			span {
+				margin: 4rem 4rem;
+			}
+		}
+
+		/* 四个边角样式 */
+		.borderstyle {
+			position: relative;
+			width: 350rem;
+			height: calc(100vh - 200rem);
+			padding: 10rem;
+			border: 1rem solid #008aff70 !important;
+			background-color: rgba(5, 45, 115, 0.7) !important;
+			box-shadow: 0 4rem 15rem 1rem #02213bb3;
+
+			.angle-border {
+				position: absolute;
+				width: 12rem;
+				height: 12rem;
+			}
+
+			.angle-border-blue {
+				position: absolute;
+				width: 70rem;
+				height: 30rem;
+			}
+
+
+
+			.left-bottom-border {
+				bottom: -2rem;
+				left: -2rem;
+				border-bottom: 2rem solid #FFFFFF;
+				border-left: 2rem solid #FFFFFF;
+			}
+
+			.right-bottom-border {
+				bottom: -2rem;
+				right: -2rem;
+				border-right: 2rem solid #FFFFFF;
+				border-bottom: 2rem solid #FFFFFF;
+			}
+		}
+	}
+
+	@keyframes slide-right {
+		0% {
+			opacity: 0;
+			transform: translateX(100%)
+		}
+
+		100% {
+			opacity: 1;
+			transform: translateX(0)
+		}
+	}
+</style>

+ 0 - 2
src/jtMap3d/Widgets/SpatialAnalysis/HeightLimit.js

@@ -1,8 +1,6 @@
 /* 引入Cesium */
 // import * as Cesium from 'Cesium';
 
-/* 引入克里金插值 */
-import kriging from '@sakitam-gis/kriging';
 /* 引入算法 */
 import * as turf from "@turf/turf";
 

+ 406 - 0
src/jtMap3d/Widgets/SpatialAnalysis/ViewShedStage.js

@@ -0,0 +1,406 @@
+// ViewShed.js
+
+/**
+ * 可视域分析。
+ *
+ * @author Helsing
+ * @date 2020/08/28
+ * @alias ViewShedStage
+ * @class
+ * @param {Cesium.Viewer} viewer Cesium三维视窗。
+ * @param {Object} options 选项。
+ * @param {Cesium.Cartesian3} options.viewPosition 观测点位置。
+ * @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。
+ * @param {Number} options.viewDistance 观测距离(单位`米`,默认值100)。
+ * @param {Number} options.viewHeading 航向角(单位`度`,默认值0)。
+ * @param {Number} options.viewPitch 俯仰角(单位`度`,默认值0)。
+ * @param {Number} options.horizontalViewAngle 可视域水平夹角(单位`度`,默认值90)。
+ * @param {Number} options.verticalViewAngle 可视域垂直夹角(单位`度`,默认值60)。
+ * @param {Cesium.Color} options.visibleAreaColor 可视区域颜色(默认值`绿色`)。
+ * @param {Cesium.Color} options.invisibleAreaColor 不可视区域颜色(默认值`红色`)。
+ * @param {Boolean} options.enabled 阴影贴图是否可用。
+ * @param {Boolean} options.softShadows 是否启用柔和阴影。
+ * @param {Boolean} options.size 每个阴影贴图的大小。
+ */
+class ViewShedStage {
+
+	constructor(viewer, options) {
+		this.viewer = viewer;
+		this.viewPosition = options.viewPosition;
+		this.viewPositionEnd = options.viewPositionEnd;
+		this.viewDistance = this.viewPositionEnd ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) : (options.viewDistance || 100.0);
+		this.viewHeading = this.viewPositionEnd ? getHeading(this.viewPosition, this.viewPositionEnd) : (options.viewHeading || 0.0);
+		this.viewPitch = this.viewPositionEnd ? getPitch(this.viewPosition, this.viewPositionEnd) : (options.viewPitch || 0.0);
+		this.horizontalViewAngle = options.horizontalViewAngle || 90.0;
+		this.verticalViewAngle = options.verticalViewAngle || 60.0;
+		this.visibleAreaColor = options.visibleAreaColor || Cesium.Color.GREEN;
+		this.invisibleAreaColor = options.invisibleAreaColor || Cesium.Color.RED;
+		this.enabled = (typeof options.enabled === "boolean") ? options.enabled : true;
+		this.softShadows = (typeof options.softShadows === "boolean") ? options.softShadows : true;
+		this.size = options.size || 2048;
+
+		this.update();
+	}
+
+	add() {
+		this.createLightCamera();
+		this.createShadowMap();
+		this.createPostStage();
+		this.drawFrustumOutine();
+		this.drawSketch();
+	}
+
+	update() {
+		this.clear();
+		this.add();
+	}
+
+	clear() {
+		if (this.sketch) {
+			this.viewer.entities.removeById(this.sketch.id);
+			this.sketch = null;
+		}
+		if (this.frustumOutline) {
+			this.frustumOutline.destroy();
+			this.frustumOutline = null;
+		}
+		if (this.postStage) {
+			this.viewer.scene.postProcessStages.remove(this.postStage);
+			this.postStage = null;
+		}
+	}
+}
+
+/**
+ * 通用对外公开函数 
+ */
+Object.assign(ViewShedStage.prototype, /** @lends ViewShedStage.prototype */ {
+	/**
+	 * 创建相机
+	 */
+	createLightCamera() {
+	    this.lightCamera = new Cesium.Camera(this.viewer.scene);
+	    this.lightCamera.position = this.viewPosition;
+	    // if (this.viewPositionEnd) {
+	    //     let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
+	    //     this.lightCamera.direction = direction; // direction是相机面向的方向
+	    // }
+	    this.lightCamera.frustum.near = this.viewDistance * 0.001;
+	    this.lightCamera.frustum.far = this.viewDistance;
+	    const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
+	    const vr = Cesium.Math.toRadians(this.verticalViewAngle);
+	    const aspectRatio =
+	        (this.viewDistance * Math.tan(hr / 2) * 2) /
+	        (this.viewDistance * Math.tan(vr / 2) * 2);
+	    this.lightCamera.frustum.aspectRatio = aspectRatio;
+	    if (hr > vr) {
+	        this.lightCamera.frustum.fov = hr;
+	    } else {
+	        this.lightCamera.frustum.fov = vr;
+	    }
+	    this.lightCamera.setView({
+	        destination: this.viewPosition,
+	        orientation: {
+	            heading: Cesium.Math.toRadians(this.viewHeading || 0),
+	            pitch: Cesium.Math.toRadians(this.viewPitch || 0),
+	            roll: 0
+	        }
+	    });
+	},
+	
+	/**
+	 * 创建阴影贴图
+	 */
+	createShadowMap() {
+	    this.shadowMap = new Cesium.ShadowMap({
+	        context: (this.viewer.scene).context,
+	        lightCamera: this.lightCamera,
+	        enabled: this.enabled,
+	        isPointLight: true,
+	        pointLightRadius: this.viewDistance,
+	        cascadesEnabled: false,
+	        size: this.size,
+	        softShadows: this.softShadows,
+	        normalOffset: false,
+	        fromLightSource: false
+	    });
+	    this.viewer.scene.shadowMap = this.shadowMap;
+	},
+	
+	/**
+	 * 创建PostStage
+	 */
+	createPostStage() {
+	    const fs = glsl
+	    const postStage = new Cesium.PostProcessStage({
+	        fragmentShader: fs,
+	        uniforms: {
+	            shadowMap_textureCube: () => {
+	                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+	                return Reflect.get(this.shadowMap, "_shadowMapTexture");
+	            },
+	            shadowMap_matrix: () => {
+	                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+	                return Reflect.get(this.shadowMap, "_shadowMapMatrix");
+	            },
+	            shadowMap_lightPositionEC: () => {
+	                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+	                return Reflect.get(this.shadowMap, "_lightPositionEC");
+	            },
+	            shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
+	                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+	                const bias = this.shadowMap._pointBias;
+	                return Cesium.Cartesian4.fromElements(
+	                    bias.normalOffsetScale,
+	                    this.shadowMap._distance,
+	                    this.shadowMap.maximumDistance,
+	                    0.0,
+	                    new Cesium.Cartesian4()
+	                );
+	            },
+	            shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
+	                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+	                const bias = this.shadowMap._pointBias;
+	                const scratchTexelStepSize = new Cesium.Cartesian2();
+	                const texelStepSize = scratchTexelStepSize;
+	                texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
+	                texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;
+	 
+	                return Cesium.Cartesian4.fromElements(
+	                    texelStepSize.x,
+	                    texelStepSize.y,
+	                    bias.depthBias,
+	                    bias.normalShadingSmooth,
+	                    new Cesium.Cartesian4()
+	                );
+	            },
+	            camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
+	            camera_view_matrix: this.lightCamera.viewMatrix,
+	            helsing_viewDistance: () => {
+	                return this.viewDistance;
+	            },
+	            helsing_visibleAreaColor: this.visibleAreaColor,
+	            helsing_invisibleAreaColor: this.invisibleAreaColor,
+	        }
+	    });
+	    this.postStage = this.viewer.scene.postProcessStages.add(postStage);
+	},
+	
+	/**
+	 * 创建视锥线
+	 */
+	drawFrustumOutline() {
+	    const scratchRight = new Cesium.Cartesian3();
+	    const scratchRotation = new Cesium.Matrix3();
+	    const scratchOrientation = new Cesium.Quaternion();
+	    const position = this.lightCamera.positionWC;
+	    const direction = this.lightCamera.directionWC;
+	    const up = this.lightCamera.upWC;
+	    let right = this.lightCamera.rightWC;
+	    right = Cesium.Cartesian3.negate(right, scratchRight);
+	    let rotation = scratchRotation;
+	    Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
+	    Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
+	    Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
+	    let orientation = Cesium.Quaternion.fromRotationMatrix(rotation, scratchOrientation);
+	 
+	    let instance = new Cesium.GeometryInstance({
+	        geometry: new Cesium.FrustumOutlineGeometry({
+	            frustum: this.lightCamera.frustum,
+	            origin: this.viewPosition,
+	            orientation: orientation
+	        }),
+	        id: Math.random().toString(36).substr(2),
+	        attributes: {
+	            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+	                Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
+	            ),
+	            show: new Cesium.ShowGeometryInstanceAttribute(true)
+	        }
+	    });
+	 
+	    this.frustumOutline = this.viewer.scene.primitives.add(
+	        new Cesium.Primitive({
+	            geometryInstances: [instance],
+	            appearance: new Cesium.PerInstanceColorAppearance({
+	                flat: true,
+	                translucent: false
+	            })
+	        })
+	    );
+	},
+	
+	/**
+	 * 创建视网
+	 */
+	drawSketch() {
+	    this.sketch = this.viewer.entities.add({
+	        name: 'sketch',
+	        position: this.viewPosition,
+	        orientation: Cesium.Transforms.headingPitchRollQuaternion(
+	            this.viewPosition,
+	            Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - this.horizontalViewAngle, this.viewPitch, 0.0)
+	        ),
+	        ellipsoid: {
+	            radii: new Cesium.Cartesian3(
+	                this.viewDistance,
+	                this.viewDistance,
+	                this.viewDistance
+	            ),
+	            // innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
+	            minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
+	            maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
+	            minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
+	            maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
+	            fill: false,
+	            outline: true,
+	            subdivisions: 256,
+	            stackPartitions: 64,
+	            slicePartitions: 64,
+	            outlineColor: Cesium.Color.YELLOWGREEN
+	        }
+	    });
+	}
+})
+
+export default ViewShedStage;
+
+function getHeading(fromPosition, toPosition) {
+    let finalPosition = new Cesium.Cartesian3();
+    let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
+    Cesium.Matrix4.inverse(matrix4, matrix4);
+    Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
+    Cesium.Cartesian3.normalize(finalPosition, finalPosition);
+    return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y));
+}
+ 
+function getPitch(fromPosition, toPosition) {
+    let finalPosition = new Cesium.Cartesian3();
+    let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
+    Cesium.Matrix4.inverse(matrix4, matrix4);
+    Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
+    Cesium.Cartesian3.normalize(finalPosition, finalPosition);
+    return Cesium.Math.toDegrees(Math.asin(finalPosition.z));
+}
+
+export default `
+ #define USE_CUBE_MAP_SHADOW true
+ uniform sampler2D colorTexture;
+ uniform sampler2D depthTexture;
+ varying vec2 v_textureCoordinates;
+ uniform mat4 camera_projection_matrix;
+ uniform mat4 camera_view_matrix;
+ uniform samplerCube shadowMap_textureCube;
+ uniform mat4 shadowMap_matrix;
+ uniform vec4 shadowMap_lightPositionEC;
+ uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
+ uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
+ uniform float helsing_viewDistance; 
+ uniform vec4 helsing_visibleAreaColor;
+ uniform vec4 helsing_invisibleAreaColor;
+ struct zx_shadowParameters
+ {
+     vec3 texCoords;
+     float depthBias;
+     float depth;
+     float nDotL;
+     vec2 texelStepSize;
+     float normalShadingSmooth;
+     float darkness;
+ };
+ float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
+ {
+     float depthBias = shadowParameters.depthBias;
+     float depth = shadowParameters.depth;
+     float nDotL = shadowParameters.nDotL;
+     float normalShadingSmooth = shadowParameters.normalShadingSmooth;
+     float darkness = shadowParameters.darkness;
+     vec3 uvw = shadowParameters.texCoords;
+     depth -= depthBias;
+     float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
+     return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
+ }
+ vec4 getPositionEC(){
+     return czm_windowToEyeCoordinates(gl_FragCoord);
+ }
+ vec3 getNormalEC(){
+     return vec3(1.);
+ }
+ vec4 toEye(in vec2 uv,in float depth){
+     vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
+     vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
+     posInCamera=posInCamera/posInCamera.w;
+     return posInCamera;
+ }
+ vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
+     vec3 v01=point-planeOrigin;
+     float d=dot(planeNormal,v01);
+     return(point-planeNormal*d);
+ }
+ float getDepth(in vec4 depth){
+     float z_window=czm_unpackDepth(depth);
+     z_window=czm_reverseLogDepth(z_window);
+     float n_range=czm_depthRange.near;
+     float f_range=czm_depthRange.far;
+     return(2.*z_window-n_range-f_range)/(f_range-n_range);
+ }
+ float shadow(in vec4 positionEC){
+     vec3 normalEC=getNormalEC();
+     zx_shadowParameters shadowParameters;
+     shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
+     shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
+     shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
+     shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
+     vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
+     float distance=length(directionEC);
+     directionEC=normalize(directionEC);
+     float radius=shadowMap_lightPositionEC.w;
+     if(distance>radius)
+     {
+         return 2.0;
+     }
+     vec3 directionWC=czm_inverseViewRotation*directionEC;
+     shadowParameters.depth=distance/radius-0.0003;
+     shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
+     shadowParameters.texCoords=directionWC;
+     float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
+     return visibility;
+ }
+ bool visible(in vec4 result)
+ {
+     result.x/=result.w;
+     result.y/=result.w;
+     result.z/=result.w;
+     return result.x>=-1.&&result.x<=1.
+     &&result.y>=-1.&&result.y<=1.
+     &&result.z>=-1.&&result.z<=1.;
+ }
+ void main(){
+     // 釉色 = 结构二维(颜色纹理, 纹理坐标)
+     gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
+     // 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
+     float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
+     // 视角 = (纹理坐标, 深度)
+     vec4 viewPos = toEye(v_textureCoordinates, depth);
+     // 世界坐标
+     vec4 wordPos = czm_inverseView * viewPos;
+     // 虚拟相机中坐标
+     vec4 vcPos = camera_view_matrix * wordPos;
+     float near = .001 * helsing_viewDistance;
+     float dis = length(vcPos.xyz);
+     if(dis > near && dis < helsing_viewDistance){
+         // 透视投影
+         vec4 posInEye = camera_projection_matrix * vcPos;
+         // 可视区颜色
+         // vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
+         // vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
+         if(visible(posInEye)){
+             float vis = shadow(viewPos);
+             if(vis > 0.3){
+                 gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
+             } else{
+                 gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
+             }
+         }
+     }
+ }`;

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно