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

StaticGroundPolylinePerMaterialBatch.js 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. import AssociativeArray from "../Core/AssociativeArray.js";
  2. import Color from "../Core/Color.js";
  3. import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
  4. import defined from "../Core/defined.js";
  5. import DistanceDisplayCondition from "../Core/DistanceDisplayCondition.js";
  6. import DistanceDisplayConditionGeometryInstanceAttribute from "../Core/DistanceDisplayConditionGeometryInstanceAttribute.js";
  7. import ShowGeometryInstanceAttribute from "../Core/ShowGeometryInstanceAttribute.js";
  8. import GroundPolylinePrimitive from "../Scene/GroundPolylinePrimitive.js";
  9. import PolylineColorAppearance from "../Scene/PolylineColorAppearance.js";
  10. import PolylineMaterialAppearance from "../Scene/PolylineMaterialAppearance.js";
  11. import BoundingSphereState from "./BoundingSphereState.js";
  12. import ColorMaterialProperty from "./ColorMaterialProperty.js";
  13. import MaterialProperty from "./MaterialProperty.js";
  14. import Property from "./Property.js";
  15. const scratchColor = new Color();
  16. const distanceDisplayConditionScratch = new DistanceDisplayCondition();
  17. const defaultDistanceDisplayCondition = new DistanceDisplayCondition();
  18. // Encapsulates a Primitive and all the entities that it represents.
  19. function Batch(
  20. orderedGroundPrimitives,
  21. classificationType,
  22. materialProperty,
  23. zIndex,
  24. asynchronous,
  25. ) {
  26. let appearanceType;
  27. if (materialProperty instanceof ColorMaterialProperty) {
  28. appearanceType = PolylineColorAppearance;
  29. } else {
  30. appearanceType = PolylineMaterialAppearance;
  31. }
  32. this.orderedGroundPrimitives = orderedGroundPrimitives; // scene level primitive collection
  33. this.classificationType = classificationType;
  34. this.appearanceType = appearanceType;
  35. this.materialProperty = materialProperty;
  36. this.updaters = new AssociativeArray();
  37. this.createPrimitive = true;
  38. this.primitive = undefined; // a GroundPolylinePrimitive encapsulating all the entities
  39. this.oldPrimitive = undefined;
  40. this.geometry = new AssociativeArray();
  41. this.material = undefined;
  42. this.updatersWithAttributes = new AssociativeArray();
  43. this.attributes = new AssociativeArray();
  44. this.invalidated = false;
  45. this.removeMaterialSubscription =
  46. materialProperty.definitionChanged.addEventListener(
  47. Batch.prototype.onMaterialChanged,
  48. this,
  49. );
  50. this.subscriptions = new AssociativeArray();
  51. this.showsUpdated = new AssociativeArray();
  52. this.zIndex = zIndex;
  53. this._asynchronous = asynchronous;
  54. }
  55. Batch.prototype.onMaterialChanged = function () {
  56. this.invalidated = true;
  57. };
  58. // Check if the given updater's material is compatible with this batch
  59. Batch.prototype.isMaterial = function (updater) {
  60. const material = this.materialProperty;
  61. const updaterMaterial = updater.fillMaterialProperty;
  62. if (
  63. updaterMaterial === material ||
  64. (updaterMaterial instanceof ColorMaterialProperty &&
  65. material instanceof ColorMaterialProperty)
  66. ) {
  67. return true;
  68. }
  69. return defined(material) && material.equals(updaterMaterial);
  70. };
  71. Batch.prototype.add = function (time, updater, geometryInstance) {
  72. const id = updater.id;
  73. this.updaters.set(id, updater);
  74. this.geometry.set(id, geometryInstance);
  75. // Updaters with dynamic attributes must be tracked separately, may exit the batch
  76. if (
  77. !updater.hasConstantFill ||
  78. !updater.fillMaterialProperty.isConstant ||
  79. !Property.isConstant(updater.distanceDisplayConditionProperty)
  80. ) {
  81. this.updatersWithAttributes.set(id, updater);
  82. } else {
  83. const that = this;
  84. // Listen for show changes. These will be synchronized in updateShows.
  85. this.subscriptions.set(
  86. id,
  87. updater.entity.definitionChanged.addEventListener(
  88. function (entity, propertyName, newValue, oldValue) {
  89. if (propertyName === "isShowing") {
  90. that.showsUpdated.set(updater.id, updater);
  91. }
  92. },
  93. ),
  94. );
  95. }
  96. this.createPrimitive = true;
  97. };
  98. Batch.prototype.remove = function (updater) {
  99. const id = updater.id;
  100. this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
  101. if (this.updaters.remove(id)) {
  102. this.updatersWithAttributes.remove(id);
  103. const unsubscribe = this.subscriptions.get(id);
  104. if (defined(unsubscribe)) {
  105. unsubscribe();
  106. this.subscriptions.remove(id);
  107. this.showsUpdated.remove(id);
  108. }
  109. return true;
  110. }
  111. return false;
  112. };
  113. Batch.prototype.update = function (time) {
  114. let isUpdated = true;
  115. let primitive = this.primitive;
  116. const orderedGroundPrimitives = this.orderedGroundPrimitives;
  117. const geometries = this.geometry.values;
  118. let i;
  119. if (this.createPrimitive) {
  120. const geometriesLength = geometries.length;
  121. if (geometriesLength > 0) {
  122. if (defined(primitive)) {
  123. // Keep a handle to the old primitive so it can be removed when the updated version is ready.
  124. if (!defined(this.oldPrimitive)) {
  125. this.oldPrimitive = primitive;
  126. } else {
  127. // For if the new primitive changes again before it is ready.
  128. orderedGroundPrimitives.remove(primitive);
  129. }
  130. }
  131. const AppearanceType = this.appearanceType;
  132. primitive = new GroundPolylinePrimitive({
  133. show: false,
  134. asynchronous: this._asynchronous,
  135. geometryInstances: geometries.slice(),
  136. appearance: new AppearanceType(),
  137. classificationType: this.classificationType,
  138. });
  139. if (this.appearanceType === PolylineMaterialAppearance) {
  140. this.material = MaterialProperty.getValue(
  141. time,
  142. this.materialProperty,
  143. this.material,
  144. );
  145. primitive.appearance.material = this.material;
  146. }
  147. orderedGroundPrimitives.add(primitive, this.zIndex);
  148. isUpdated = false;
  149. } else {
  150. if (defined(primitive)) {
  151. orderedGroundPrimitives.remove(primitive);
  152. primitive = undefined;
  153. }
  154. const oldPrimitive = this.oldPrimitive;
  155. if (defined(oldPrimitive)) {
  156. orderedGroundPrimitives.remove(oldPrimitive);
  157. this.oldPrimitive = undefined;
  158. }
  159. }
  160. this.attributes.removeAll();
  161. this.primitive = primitive;
  162. this.createPrimitive = false;
  163. } else if (defined(primitive) && primitive.ready) {
  164. primitive.show = true;
  165. if (defined(this.oldPrimitive)) {
  166. orderedGroundPrimitives.remove(this.oldPrimitive);
  167. this.oldPrimitive = undefined;
  168. }
  169. if (this.appearanceType === PolylineMaterialAppearance) {
  170. this.material = MaterialProperty.getValue(
  171. time,
  172. this.materialProperty,
  173. this.material,
  174. );
  175. this.primitive.appearance.material = this.material;
  176. }
  177. const updatersWithAttributes = this.updatersWithAttributes.values;
  178. const length = updatersWithAttributes.length;
  179. for (i = 0; i < length; i++) {
  180. const updater = updatersWithAttributes[i];
  181. const entity = updater.entity;
  182. const instance = this.geometry.get(updater.id);
  183. let attributes = this.attributes.get(instance.id.id);
  184. if (!defined(attributes)) {
  185. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  186. this.attributes.set(instance.id.id, attributes);
  187. }
  188. if (!updater.fillMaterialProperty.isConstant) {
  189. const colorProperty = updater.fillMaterialProperty.color;
  190. const resultColor = Property.getValueOrDefault(
  191. colorProperty,
  192. time,
  193. Color.WHITE,
  194. scratchColor,
  195. );
  196. if (!Color.equals(attributes._lastColor, resultColor)) {
  197. attributes._lastColor = Color.clone(
  198. resultColor,
  199. attributes._lastColor,
  200. );
  201. attributes.color = ColorGeometryInstanceAttribute.toValue(
  202. resultColor,
  203. attributes.color,
  204. );
  205. }
  206. }
  207. const show =
  208. entity.isShowing && (updater.hasConstantFill || updater.isFilled(time));
  209. const currentShow = attributes.show[0] === 1;
  210. if (show !== currentShow) {
  211. attributes.show = ShowGeometryInstanceAttribute.toValue(
  212. show,
  213. attributes.show,
  214. );
  215. }
  216. const distanceDisplayConditionProperty =
  217. updater.distanceDisplayConditionProperty;
  218. if (!Property.isConstant(distanceDisplayConditionProperty)) {
  219. const distanceDisplayCondition = Property.getValueOrDefault(
  220. distanceDisplayConditionProperty,
  221. time,
  222. defaultDistanceDisplayCondition,
  223. distanceDisplayConditionScratch,
  224. );
  225. if (
  226. !DistanceDisplayCondition.equals(
  227. distanceDisplayCondition,
  228. attributes._lastDistanceDisplayCondition,
  229. )
  230. ) {
  231. attributes._lastDistanceDisplayCondition =
  232. DistanceDisplayCondition.clone(
  233. distanceDisplayCondition,
  234. attributes._lastDistanceDisplayCondition,
  235. );
  236. attributes.distanceDisplayCondition =
  237. DistanceDisplayConditionGeometryInstanceAttribute.toValue(
  238. distanceDisplayCondition,
  239. attributes.distanceDisplayCondition,
  240. );
  241. }
  242. }
  243. }
  244. this.updateShows(primitive);
  245. } else if (defined(primitive) && !primitive.ready) {
  246. isUpdated = false;
  247. }
  248. return isUpdated;
  249. };
  250. Batch.prototype.updateShows = function (primitive) {
  251. const showsUpdated = this.showsUpdated.values;
  252. const length = showsUpdated.length;
  253. for (let i = 0; i < length; i++) {
  254. const updater = showsUpdated[i];
  255. const entity = updater.entity;
  256. const instance = this.geometry.get(updater.id);
  257. let attributes = this.attributes.get(instance.id.id);
  258. if (!defined(attributes)) {
  259. attributes = primitive.getGeometryInstanceAttributes(instance.id);
  260. this.attributes.set(instance.id.id, attributes);
  261. }
  262. const show = entity.isShowing;
  263. const currentShow = attributes.show[0] === 1;
  264. if (show !== currentShow) {
  265. attributes.show = ShowGeometryInstanceAttribute.toValue(
  266. show,
  267. attributes.show,
  268. );
  269. instance.attributes.show.value[0] = attributes.show[0];
  270. }
  271. }
  272. this.showsUpdated.removeAll();
  273. };
  274. Batch.prototype.contains = function (updater) {
  275. return this.updaters.contains(updater.id);
  276. };
  277. Batch.prototype.getBoundingSphere = function (updater, result) {
  278. const primitive = this.primitive;
  279. if (!primitive.ready) {
  280. return BoundingSphereState.PENDING;
  281. }
  282. const attributes = primitive.getGeometryInstanceAttributes(updater.entity);
  283. if (
  284. !defined(attributes) ||
  285. !defined(attributes.boundingSphere) ||
  286. (defined(attributes.show) && attributes.show[0] === 0)
  287. ) {
  288. return BoundingSphereState.FAILED;
  289. }
  290. attributes.boundingSphere.clone(result);
  291. return BoundingSphereState.DONE;
  292. };
  293. Batch.prototype.destroy = function () {
  294. const primitive = this.primitive;
  295. const orderedGroundPrimitives = this.orderedGroundPrimitives;
  296. if (defined(primitive)) {
  297. orderedGroundPrimitives.remove(primitive);
  298. }
  299. const oldPrimitive = this.oldPrimitive;
  300. if (defined(oldPrimitive)) {
  301. orderedGroundPrimitives.remove(oldPrimitive);
  302. }
  303. this.removeMaterialSubscription();
  304. };
  305. /**
  306. * @private
  307. */
  308. function StaticGroundPolylinePerMaterialBatch(
  309. orderedGroundPrimitives,
  310. classificationType,
  311. asynchronous,
  312. ) {
  313. this._items = [];
  314. this._orderedGroundPrimitives = orderedGroundPrimitives;
  315. this._classificationType = classificationType;
  316. this._asynchronous = asynchronous ?? true;
  317. }
  318. StaticGroundPolylinePerMaterialBatch.prototype.add = function (time, updater) {
  319. const items = this._items;
  320. const length = items.length;
  321. const geometryInstance = updater.createFillGeometryInstance(time);
  322. const zIndex = Property.getValueOrDefault(updater.zIndex, 0);
  323. // Check if the Entity represented by the updater has the same material or a material representable with per-instance color.
  324. for (let i = 0; i < length; ++i) {
  325. const item = items[i];
  326. if (item.isMaterial(updater) && item.zIndex === zIndex) {
  327. item.add(time, updater, geometryInstance);
  328. return;
  329. }
  330. }
  331. // If a compatible batch wasn't found, create a new batch.
  332. const batch = new Batch(
  333. this._orderedGroundPrimitives,
  334. this._classificationType,
  335. updater.fillMaterialProperty,
  336. zIndex,
  337. this._asynchronous,
  338. );
  339. batch.add(time, updater, geometryInstance);
  340. items.push(batch);
  341. };
  342. StaticGroundPolylinePerMaterialBatch.prototype.remove = function (updater) {
  343. const items = this._items;
  344. const length = items.length;
  345. for (let i = length - 1; i >= 0; i--) {
  346. const item = items[i];
  347. if (item.remove(updater)) {
  348. if (item.updaters.length === 0) {
  349. items.splice(i, 1);
  350. item.destroy();
  351. }
  352. break;
  353. }
  354. }
  355. };
  356. StaticGroundPolylinePerMaterialBatch.prototype.update = function (time) {
  357. let i;
  358. const items = this._items;
  359. const length = items.length;
  360. for (i = length - 1; i >= 0; i--) {
  361. const item = items[i];
  362. if (item.invalidated) {
  363. items.splice(i, 1);
  364. const updaters = item.updaters.values;
  365. const updatersLength = updaters.length;
  366. for (let h = 0; h < updatersLength; h++) {
  367. this.add(time, updaters[h]);
  368. }
  369. item.destroy();
  370. }
  371. }
  372. let isUpdated = true;
  373. for (i = 0; i < items.length; i++) {
  374. isUpdated = items[i].update(time) && isUpdated;
  375. }
  376. return isUpdated;
  377. };
  378. StaticGroundPolylinePerMaterialBatch.prototype.getBoundingSphere = function (
  379. updater,
  380. result,
  381. ) {
  382. const items = this._items;
  383. const length = items.length;
  384. for (let i = 0; i < length; i++) {
  385. const item = items[i];
  386. if (item.contains(updater)) {
  387. return item.getBoundingSphere(updater, result);
  388. }
  389. }
  390. return BoundingSphereState.FAILED;
  391. };
  392. StaticGroundPolylinePerMaterialBatch.prototype.removeAllPrimitives =
  393. function () {
  394. const items = this._items;
  395. const length = items.length;
  396. for (let i = 0; i < length; i++) {
  397. items[i].destroy();
  398. }
  399. this._items.length = 0;
  400. };
  401. export default StaticGroundPolylinePerMaterialBatch;