智慧水务管理系统 - 精河县供水工程综合管理平台

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. import AssociativeArray from "../Core/AssociativeArray.js";
  2. import BoundingSphere from "../Core/BoundingSphere.js";
  3. import Cartesian2 from "../Core/Cartesian2.js";
  4. import Cartesian3 from "../Core/Cartesian3.js";
  5. import Check from "../Core/Check.js";
  6. import Color from "../Core/Color.js";
  7. import defined from "../Core/defined.js";
  8. import destroyObject from "../Core/destroyObject.js";
  9. import DeveloperError from "../Core/DeveloperError.js";
  10. import Ellipsoid from "../Core/Ellipsoid.js";
  11. import Matrix4 from "../Core/Matrix4.js";
  12. import Resource from "../Core/Resource.js";
  13. import ColorBlendMode from "../Scene/ColorBlendMode.js";
  14. import HeightReference, {
  15. isHeightReferenceClamp,
  16. } from "../Scene/HeightReference.js";
  17. import Model from "../Scene/Model/Model.js";
  18. import ModelAnimationLoop from "../Scene/ModelAnimationLoop.js";
  19. import ShadowMode from "../Scene/ShadowMode.js";
  20. import BoundingSphereState from "./BoundingSphereState.js";
  21. import Property from "./Property.js";
  22. import Cartographic from "../Core/Cartographic.js";
  23. const defaultScale = 1.0;
  24. const defaultEnableVerticalExaggeration = true;
  25. const defaultMinimumPixelSize = 0.0;
  26. const defaultIncrementallyLoadTextures = true;
  27. const defaultClampAnimations = true;
  28. const defaultShadows = ShadowMode.ENABLED;
  29. const defaultHeightReference = HeightReference.NONE;
  30. const defaultSilhouetteColor = Color.RED;
  31. const defaultSilhouetteSize = 0.0;
  32. const defaultColor = Color.WHITE;
  33. const defaultColorBlendMode = ColorBlendMode.HIGHLIGHT;
  34. const defaultColorBlendAmount = 0.5;
  35. const defaultImageBasedLightingFactor = new Cartesian2(1.0, 1.0);
  36. const defaultEnvironmentMapOptions = {
  37. maximumPositionEpsilon: Number.POSITIVE_INFINITY,
  38. };
  39. const modelMatrixScratch = new Matrix4();
  40. const nodeMatrixScratch = new Matrix4();
  41. const scratchColor = new Color();
  42. const scratchArray = new Array(4);
  43. const scratchCartesian = new Cartesian3();
  44. /**
  45. * A {@link Visualizer} which maps {@link Entity#model} to a {@link Model}.
  46. * @alias ModelVisualizer
  47. * @constructor
  48. *
  49. * @param {Scene} scene The scene the primitives will be rendered in.
  50. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  51. */
  52. function ModelVisualizer(scene, entityCollection) {
  53. //>>includeStart('debug', pragmas.debug);
  54. Check.typeOf.object("scene", scene);
  55. Check.typeOf.object("entityCollection", entityCollection);
  56. //>>includeEnd('debug');
  57. entityCollection.collectionChanged.addEventListener(
  58. ModelVisualizer.prototype._onCollectionChanged,
  59. this,
  60. );
  61. this._scene = scene;
  62. this._primitives = scene.primitives;
  63. this._entityCollection = entityCollection;
  64. this._modelHash = {};
  65. this._entitiesToVisualize = new AssociativeArray();
  66. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  67. }
  68. async function createModelPrimitive(
  69. visualizer,
  70. entity,
  71. resource,
  72. incrementallyLoadTextures,
  73. environmentMapOptions,
  74. ) {
  75. const primitives = visualizer._primitives;
  76. const modelHash = visualizer._modelHash;
  77. try {
  78. const model = await Model.fromGltfAsync({
  79. url: resource,
  80. incrementallyLoadTextures: incrementallyLoadTextures,
  81. scene: visualizer._scene,
  82. environmentMapOptions: environmentMapOptions,
  83. });
  84. if (visualizer.isDestroyed() || !defined(modelHash[entity.id])) {
  85. return;
  86. }
  87. model.id = entity;
  88. primitives.add(model);
  89. modelHash[entity.id].modelPrimitive = model;
  90. model.errorEvent.addEventListener((error) => {
  91. if (!defined(modelHash[entity.id])) {
  92. return;
  93. }
  94. console.log(error);
  95. // Texture failures when incrementallyLoadTextures
  96. // will not affect the ability to compute the bounding sphere
  97. if (error.name !== "TextureError" && model.incrementallyLoadTextures) {
  98. modelHash[entity.id].loadFailed = true;
  99. }
  100. });
  101. } catch (error) {
  102. if (visualizer.isDestroyed() || !defined(modelHash[entity.id])) {
  103. return;
  104. }
  105. console.log(error);
  106. modelHash[entity.id].loadFailed = true;
  107. }
  108. }
  109. /**
  110. * Updates models created this visualizer to match their
  111. * Entity counterpart at the given time.
  112. *
  113. * @param {JulianDate} time The time to update to.
  114. * @returns {boolean} This function always returns true.
  115. */
  116. ModelVisualizer.prototype.update = function (time) {
  117. //>>includeStart('debug', pragmas.debug);
  118. if (!defined(time)) {
  119. throw new DeveloperError("time is required.");
  120. }
  121. //>>includeEnd('debug');
  122. const entities = this._entitiesToVisualize.values;
  123. const modelHash = this._modelHash;
  124. const primitives = this._primitives;
  125. for (let i = 0, len = entities.length; i < len; i++) {
  126. const entity = entities[i];
  127. const modelGraphics = entity._model;
  128. let resource;
  129. let modelData = modelHash[entity.id];
  130. let show =
  131. entity.isShowing &&
  132. entity.isAvailable(time) &&
  133. Property.getValueOrDefault(modelGraphics._show, time, true);
  134. let modelMatrix;
  135. if (show) {
  136. modelMatrix = entity.computeModelMatrix(time, modelMatrixScratch);
  137. resource = Resource.createIfNeeded(
  138. Property.getValueOrUndefined(modelGraphics._uri, time),
  139. );
  140. show = defined(modelMatrix) && defined(resource);
  141. }
  142. if (!show) {
  143. if (defined(modelData) && modelData.modelPrimitive) {
  144. modelData.modelPrimitive.show = false;
  145. }
  146. continue;
  147. }
  148. if (!defined(modelData) || resource.url !== modelData.url) {
  149. if (defined(modelData?.modelPrimitive)) {
  150. primitives.removeAndDestroy(modelData.modelPrimitive);
  151. delete modelHash[entity.id];
  152. }
  153. modelData = {
  154. modelPrimitive: undefined,
  155. url: resource.url,
  156. animationsRunning: false,
  157. nodeTransformationsScratch: {},
  158. articulationsScratch: {},
  159. loadFailed: false,
  160. modelUpdated: false,
  161. environmentMapOptionsScratch: {
  162. ...defaultEnvironmentMapOptions,
  163. },
  164. };
  165. modelHash[entity.id] = modelData;
  166. const incrementallyLoadTextures = Property.getValueOrDefault(
  167. modelGraphics._incrementallyLoadTextures,
  168. time,
  169. defaultIncrementallyLoadTextures,
  170. );
  171. const environmentMapOptions = Property.getValueOrDefault(
  172. modelGraphics._environmentMapOptions,
  173. time,
  174. defaultEnvironmentMapOptions,
  175. modelData.environmentMapOptionsScratch,
  176. );
  177. createModelPrimitive(
  178. this,
  179. entity,
  180. resource,
  181. incrementallyLoadTextures,
  182. environmentMapOptions,
  183. );
  184. }
  185. const model = modelData.modelPrimitive;
  186. if (!defined(model)) {
  187. continue;
  188. }
  189. model.show = true;
  190. model.scale = Property.getValueOrDefault(
  191. modelGraphics._scale,
  192. time,
  193. defaultScale,
  194. );
  195. model.enableVerticalExaggeration = Property.getValueOrDefault(
  196. modelGraphics._enableVerticalExaggeration,
  197. time,
  198. defaultEnableVerticalExaggeration,
  199. );
  200. model.minimumPixelSize = Property.getValueOrDefault(
  201. modelGraphics._minimumPixelSize,
  202. time,
  203. defaultMinimumPixelSize,
  204. );
  205. model.maximumScale = Property.getValueOrUndefined(
  206. modelGraphics._maximumScale,
  207. time,
  208. );
  209. model.modelMatrix = Matrix4.clone(modelMatrix, model.modelMatrix);
  210. model.shadows = Property.getValueOrDefault(
  211. modelGraphics._shadows,
  212. time,
  213. defaultShadows,
  214. );
  215. model.heightReference = Property.getValueOrDefault(
  216. modelGraphics._heightReference,
  217. time,
  218. defaultHeightReference,
  219. );
  220. model.distanceDisplayCondition = Property.getValueOrUndefined(
  221. modelGraphics._distanceDisplayCondition,
  222. time,
  223. );
  224. model.silhouetteColor = Property.getValueOrDefault(
  225. modelGraphics._silhouetteColor,
  226. time,
  227. defaultSilhouetteColor,
  228. scratchColor,
  229. );
  230. model.silhouetteSize = Property.getValueOrDefault(
  231. modelGraphics._silhouetteSize,
  232. time,
  233. defaultSilhouetteSize,
  234. );
  235. model.color = Property.getValueOrDefault(
  236. modelGraphics._color,
  237. time,
  238. defaultColor,
  239. scratchColor,
  240. );
  241. model.colorBlendMode = Property.getValueOrDefault(
  242. modelGraphics._colorBlendMode,
  243. time,
  244. defaultColorBlendMode,
  245. );
  246. model.colorBlendAmount = Property.getValueOrDefault(
  247. modelGraphics._colorBlendAmount,
  248. time,
  249. defaultColorBlendAmount,
  250. );
  251. model.clippingPlanes = Property.getValueOrUndefined(
  252. modelGraphics._clippingPlanes,
  253. time,
  254. );
  255. model.clampAnimations = Property.getValueOrDefault(
  256. modelGraphics._clampAnimations,
  257. time,
  258. defaultClampAnimations,
  259. );
  260. model.imageBasedLighting.imageBasedLightingFactor =
  261. Property.getValueOrDefault(
  262. modelGraphics._imageBasedLightingFactor,
  263. time,
  264. defaultImageBasedLightingFactor,
  265. );
  266. let lightColor = Property.getValueOrUndefined(
  267. modelGraphics._lightColor,
  268. time,
  269. );
  270. // Convert from Color to Cartesian3
  271. if (defined(lightColor)) {
  272. Color.pack(lightColor, scratchArray, 0);
  273. lightColor = Cartesian3.unpack(scratchArray, 0, scratchCartesian);
  274. }
  275. model.lightColor = lightColor;
  276. model.customShader = Property.getValueOrUndefined(
  277. modelGraphics._customShader,
  278. time,
  279. );
  280. // It's possible for getBoundingSphere to run before
  281. // model becomes ready and these properties are updated
  282. modelHash[entity.id].modelUpdated = true;
  283. if (model.ready) {
  284. const runAnimations = Property.getValueOrDefault(
  285. modelGraphics._runAnimations,
  286. time,
  287. true,
  288. );
  289. if (modelData.animationsRunning !== runAnimations) {
  290. if (runAnimations) {
  291. model.activeAnimations.addAll({
  292. loop: ModelAnimationLoop.REPEAT,
  293. });
  294. } else {
  295. model.activeAnimations.removeAll();
  296. }
  297. modelData.animationsRunning = runAnimations;
  298. }
  299. // Apply node transformations
  300. const nodeTransformations = Property.getValueOrUndefined(
  301. modelGraphics._nodeTransformations,
  302. time,
  303. modelData.nodeTransformationsScratch,
  304. );
  305. if (defined(nodeTransformations)) {
  306. const nodeNames = Object.keys(nodeTransformations);
  307. for (
  308. let nodeIndex = 0, nodeLength = nodeNames.length;
  309. nodeIndex < nodeLength;
  310. ++nodeIndex
  311. ) {
  312. const nodeName = nodeNames[nodeIndex];
  313. const nodeTransformation = nodeTransformations[nodeName];
  314. if (!defined(nodeTransformation)) {
  315. continue;
  316. }
  317. const modelNode = model.getNode(nodeName);
  318. if (!defined(modelNode)) {
  319. continue;
  320. }
  321. const transformationMatrix = Matrix4.fromTranslationRotationScale(
  322. nodeTransformation,
  323. nodeMatrixScratch,
  324. );
  325. modelNode.matrix = Matrix4.multiply(
  326. modelNode.originalMatrix,
  327. transformationMatrix,
  328. transformationMatrix,
  329. );
  330. }
  331. }
  332. // Apply articulations
  333. let anyArticulationUpdated = false;
  334. const articulations = Property.getValueOrUndefined(
  335. modelGraphics._articulations,
  336. time,
  337. modelData.articulationsScratch,
  338. );
  339. if (defined(articulations)) {
  340. const articulationStageKeys = Object.keys(articulations);
  341. for (
  342. let s = 0, numKeys = articulationStageKeys.length;
  343. s < numKeys;
  344. ++s
  345. ) {
  346. const key = articulationStageKeys[s];
  347. const articulationStageValue = articulations[key];
  348. if (!defined(articulationStageValue)) {
  349. continue;
  350. }
  351. anyArticulationUpdated = true;
  352. model.setArticulationStage(key, articulationStageValue);
  353. }
  354. }
  355. if (anyArticulationUpdated) {
  356. model.applyArticulations();
  357. }
  358. }
  359. }
  360. return true;
  361. };
  362. /**
  363. * Returns true if this object was destroyed; otherwise, false.
  364. *
  365. * @returns {boolean} True if this object was destroyed; otherwise, false.
  366. */
  367. ModelVisualizer.prototype.isDestroyed = function () {
  368. return false;
  369. };
  370. /**
  371. * Removes and destroys all primitives created by this instance.
  372. */
  373. ModelVisualizer.prototype.destroy = function () {
  374. this._entityCollection.collectionChanged.removeEventListener(
  375. ModelVisualizer.prototype._onCollectionChanged,
  376. this,
  377. );
  378. const entities = this._entitiesToVisualize.values;
  379. const modelHash = this._modelHash;
  380. const primitives = this._primitives;
  381. for (let i = entities.length - 1; i > -1; i--) {
  382. removeModel(this, entities[i], modelHash, primitives);
  383. }
  384. return destroyObject(this);
  385. };
  386. const scratchPosition = new Cartesian3();
  387. const scratchCartographic = new Cartographic();
  388. /**
  389. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  390. * The bounding sphere is in the fixed frame of the scene's globe.
  391. *
  392. * @param {Entity} entity The entity whose bounding sphere to compute.
  393. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  394. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  395. * BoundingSphereState.PENDING if the result is still being computed, or
  396. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  397. * @private
  398. */
  399. ModelVisualizer.prototype.getBoundingSphere = function (entity, result) {
  400. //>>includeStart('debug', pragmas.debug);
  401. if (!defined(entity)) {
  402. throw new DeveloperError("entity is required.");
  403. }
  404. if (!defined(result)) {
  405. throw new DeveloperError("result is required.");
  406. }
  407. //>>includeEnd('debug');
  408. const modelData = this._modelHash[entity.id];
  409. if (!defined(modelData)) {
  410. return BoundingSphereState.FAILED;
  411. }
  412. if (modelData.loadFailed) {
  413. return BoundingSphereState.FAILED;
  414. }
  415. const model = modelData.modelPrimitive;
  416. if (!defined(model) || !model.show) {
  417. return BoundingSphereState.PENDING;
  418. }
  419. if (!model.ready || !modelData.modelUpdated) {
  420. return BoundingSphereState.PENDING;
  421. }
  422. const scene = this._scene;
  423. const ellipsoid = scene.ellipsoid ?? Ellipsoid.default;
  424. const hasHeightReference = model.heightReference !== HeightReference.NONE;
  425. if (hasHeightReference) {
  426. const modelMatrix = model.modelMatrix;
  427. scratchPosition.x = modelMatrix[12];
  428. scratchPosition.y = modelMatrix[13];
  429. scratchPosition.z = modelMatrix[14];
  430. const cartoPosition = ellipsoid.cartesianToCartographic(
  431. scratchPosition,
  432. scratchCartographic,
  433. );
  434. const height = scene.getHeight(cartoPosition, model.heightReference);
  435. if (defined(height)) {
  436. if (isHeightReferenceClamp(model.heightReference)) {
  437. cartoPosition.height = height;
  438. } else {
  439. cartoPosition.height += height;
  440. }
  441. }
  442. BoundingSphere.clone(model.boundingSphere, result);
  443. result.center = ellipsoid.cartographicToCartesian(cartoPosition);
  444. return BoundingSphereState.DONE;
  445. }
  446. BoundingSphere.clone(model.boundingSphere, result);
  447. return BoundingSphereState.DONE;
  448. };
  449. /**
  450. * @private
  451. */
  452. ModelVisualizer.prototype._onCollectionChanged = function (
  453. entityCollection,
  454. added,
  455. removed,
  456. changed,
  457. ) {
  458. let i;
  459. let entity;
  460. const entities = this._entitiesToVisualize;
  461. const modelHash = this._modelHash;
  462. const primitives = this._primitives;
  463. for (i = added.length - 1; i > -1; i--) {
  464. entity = added[i];
  465. if (defined(entity._model) && defined(entity._position)) {
  466. entities.set(entity.id, entity);
  467. }
  468. }
  469. for (i = changed.length - 1; i > -1; i--) {
  470. entity = changed[i];
  471. if (defined(entity._model) && defined(entity._position)) {
  472. clearNodeTransformationsArticulationsScratch(entity, modelHash);
  473. entities.set(entity.id, entity);
  474. } else {
  475. removeModel(this, entity, modelHash, primitives);
  476. entities.remove(entity.id);
  477. }
  478. }
  479. for (i = removed.length - 1; i > -1; i--) {
  480. entity = removed[i];
  481. removeModel(this, entity, modelHash, primitives);
  482. entities.remove(entity.id);
  483. }
  484. };
  485. function removeModel(visualizer, entity, modelHash, primitives) {
  486. const modelData = modelHash[entity.id];
  487. if (defined(modelData)) {
  488. primitives.removeAndDestroy(modelData.modelPrimitive);
  489. delete modelHash[entity.id];
  490. }
  491. }
  492. function clearNodeTransformationsArticulationsScratch(entity, modelHash) {
  493. const modelData = modelHash[entity.id];
  494. if (defined(modelData)) {
  495. modelData.nodeTransformationsScratch = {};
  496. modelData.articulationsScratch = {};
  497. }
  498. }
  499. export default ModelVisualizer;