An error occurred while loading the file. Please try again.
index.js 17.38 KiB
import { ToolboxType, WindowSlot, NotificationType } from '@vcmap/ui';
import { Cesium3DTileStyle, Math as CMath, Ellipsoid, Cartesian3, ConstantProperty, Transforms, HeadingPitchRoll, Cesium3DTileset, Matrix4 } from '@vcmap-cesium/engine';
import { AbstractInteraction, EventType } from '@vcmap/core';
import { name, version, mapVersion } from '../package.json';
import BIMOptions, { bimOptionsId } from './upload.vue';
import objectList, { objectListId } from './objectList.vue';
import scaleControl, { scaleControlId } from './scaleControl.vue';
let model;
let conditions = [[true, true]];
let activeMouseEvent;
let currentMousePosition;
let heightDif = 0;
const hpRollMap = new Map();
let placedModels = [];
let hpRoll;
let app;
let currentlyScaledModel;
const hidingFeatures = [];
const hidingListener = function(tile) {
  let allHidden = true;
  for (const featureToHide of hidingFeatures) {
    if (featureToHide.loops < 10) {
      allHidden = false;
      const feature = tile.content.getFeature(featureToHide.id);
      if (feature !== undefined) {
        app.maps.activeMap.layerCollection.globalHider.addFeature("manual", feature);
        app.maps.activeMap.layerCollection.globalHider.hideObjects(["manual"]);
        featureToHide.loops++;
  if (allHidden) {
    const primitives = app.maps.activeMap.getScene().primitives;
    for (let i = 0; i < primitives.length; i++) {
      const tileSet = primitives.get(i);
      if (!(tileSet instanceof Cesium3DTileset)) {
        continue;
      tileSet.tileVisible.removeEventListener(hidingListener);
function updateHideCondition(gmlId) {
  conditions.unshift(['${gml_id} === "' + gmlId + '"', false]);
function setScale(scaleValue) {
  const vcMap = app.maps.activeMap;
  const name = currentlyScaledModel.name;
  const position = currentlyScaledModel.position.getValue();
  const orientation = currentlyScaledModel.orientation;
  const uri = currentlyScaledModel.model.uri;
  vcMap.getEntities().remove(currentlyScaledModel);
  removePlacedModel(currentlyScaledModel);
  // Add the new model to the viewer
  const newModel = vcMap.getEntities().add({
    name: name,
    position: position,
    orientation: orientation,
    model: {
      uri: uri,
      scale: scaleValue,
      show: true,
  });
placedModels.push({ model: newModel, name: name, }); const oldHpRoll = hpRollMap.get(currentlyScaledModel); if (oldHpRoll !== undefined) { hpRollMap.set(newModel, oldHpRoll); } currentlyScaledModel = newModel; } function saveObjects() { const outputObject = {}; const outputArray = []; for (const m of placedModels) { const tempRoll = hpRollMap.get(m.model); let heading = 0; if (tempRoll !== undefined) { heading = tempRoll.heading; } const ellipPos = Ellipsoid.WGS84.cartesianToCartographic(m.model.position.getValue()); const wgs84X = CMath.toDegrees(ellipPos.longitude); const wgs84Y = CMath.toDegrees(ellipPos.latitude); const height = ellipPos.height; outputArray.push({ name: m.name, position: [wgs84X, wgs84Y, height], heading: heading, scale: m.model.model.scale.getValue(), }); } outputObject.placedObjects = outputArray; const hiddenObjects = []; for (const o of hidingFeatures) { hiddenObjects.push(o.id); } outputObject.hiddenObjects = hiddenObjects; let textData = JSON.stringify(outputObject); let blobData = new Blob([textData], {type: "application/json"}); saveFile('ObjektPositionierung.json', window.URL.createObjectURL(blobData)); } function saveFile(fileName, urlFile){ let a = document.createElement("a"); a.style = "display: none"; document.body.appendChild(a); a.href = urlFile; a.download = fileName; a.click(); window.URL.revokeObjectURL(urlFile); a.remove(); } function setupModel(vcsApp, windowPos, url, name) { const vcMap = vcsApp.maps.activeMap; const scene = vcMap.getScene(); const ray = scene.camera.getPickRay(windowPos); const center = scene.globe.pick(ray, scene); // Add the model to the viewer model = vcMap.getEntities().add({ name: name, position: center, model: { uri: url, show: true, scale: 1, },
}); placedModels.push({ model: model, name: name, }); vcMap.requestRender(); const interaction = new MoveInteraction(); interaction.setActive(EventType.CLICKMOVE); activeMouseEvent = vcsApp.maps.eventHandler.addExclusiveInteraction(interaction, () => {}); } function removePlacedModel(modelToBeRemoved) { placedModels = placedModels.filter(function(m) { return m.model !== modelToBeRemoved; }); } class MoveInteraction extends AbstractInteraction { async pipe(event) { if (event.pointerEvent === 2) { if (activeMouseEvent !== undefined) { activeMouseEvent(); } } else if (event.pointerEvent === 3 && model !== undefined) { const cesiumMap = event.map; const scene = cesiumMap.getScene(); const pickResult = scene.globe.pick( event.ray, scene ); pickResult.z = pickResult.z + heightDif; model.position.setValue(pickResult); } return event; } } class HeightInteraction extends AbstractInteraction { async pipe(event) { // prevent the event from beeing passed to the next interaction within the chain event.stopPropagation = false; if (model === undefined) { if (activeMouseEvent !== undefined) { activeMouseEvent(); } return event; } if (event.pointerEvent === 2) { if (activeMouseEvent !== undefined) { currentMousePosition = undefined; activeMouseEvent(); return event; } } else if (event.pointerEvent === 3) { if (currentMousePosition === undefined) { currentMousePosition = [event.windowPosition.x, event.windowPosition.y]; return event; } const dif = event.windowPosition.y - currentMousePosition[1]; if (dif === 0) { return event; } heightDif = heightDif - (dif / 50); let pos = model.position.getValue(); currentMousePosition = [event.windowPosition.x, event.windowPosition.y]; pos.z = pos.z - (dif / 50); model.position.setValue(pos); }
return event; } } class RotateAction extends AbstractInteraction { async pipe(event) { // prevent the event from beeing passed to the next interaction within the chain event.stopPropagation = false; if (model === undefined) { if (activeMouseEvent !== undefined) { activeMouseEvent(); } return event; } if (event.pointerEvent === 2) { if (activeMouseEvent !== undefined) { currentMousePosition = undefined; activeMouseEvent(); return event; } } else if (event.pointerEvent === 3) { if (currentMousePosition === undefined) { currentMousePosition = [event.windowPosition.x, event.windowPosition.y]; return event; } const dif = event.windowPosition.x - currentMousePosition[0]; if (dif === 0) { return event; } currentMousePosition = [event.windowPosition.x, event.windowPosition.y]; const modelPos = model.position.getValue(); const deltaRadians = CMath.toRadians(dif / 3); hpRoll.heading += deltaRadians; if (hpRoll.heading > CMath.TWO_PI) { hpRoll.heading -= CMath.TWO_PI; } if (hpRoll.heading < 0.0) { hpRoll.heading += CMath.TWO_PI; } const orientation = new ConstantProperty(Transforms.headingPitchRollQuaternion(modelPos, hpRoll)); model.orientation = orientation; } return event; } } /** * @param {PluginConfig} config - the configuration of this plugin instance, passed in from the app. * @param {string} baseUrl - the absolute URL from which the plugin was loaded (without filename, ending on /) * @returns {import("@vcmap/ui/src/vcsUiApp").VcsPlugin<PluginConfig, PluginState>} */ export default function smartVillagesPlugin(config, baseUrl) { const pluginState = { files: [], objects: [], }; return { get name() { return name; }, get version() { return version; }, get mapVersion() { return mapVersion; }, pluginState,
setupModel, setScale, saveObjects, loadObjects(app) { // Create an input element const inputElement = document.createElement("input"); // Set its type to file inputElement.type = "file"; // Set accept to the file types you want the user to select. // Include both the file extension and the mime type inputElement.accept = ".json, .txt"; // set onchange event to call callback when user has selected file inputElement.addEventListener("change", e => { const fileInput = e.target; const file = fileInput.files[0]; const reader = new FileReader(); reader.onload = async readerEvent => { const content = readerEvent.target.result; const objects = JSON.parse(content); const vcMap = app.maps.activeMap; for (const loadingObject of objects.placedObjects) { let objectUrl = undefined; for (const loadedObject of pluginState.objects) { if (loadedObject.name === loadingObject.name) { objectUrl = loadedObject.url; break; } } if (objectUrl === undefined) { app.notifier.add({ type: NotificationType.ERROR, message: "Objekt mit dem namen: " + loadingObject.name + " konnte nicht in den geladenen Objekten gefunden werden. Konfiguration konnte nicht vollständig geladen werden.", }); // abort return; } const cartPos = Cartesian3.fromDegrees(loadingObject.position[0], loadingObject.position[1], loadingObject.position[2]); // Add the model to the viewer model = vcMap.getEntities().add({ name: loadingObject.name, position: cartPos, model: { uri: objectUrl, scale: loadingObject.scale, show: true, }, }); const roll = new HeadingPitchRoll(); hpRollMap.set(model, roll); roll.heading = loadingObject.heading; const orientation = new ConstantProperty(Transforms.headingPitchRollQuaternion(model.position.getValue(), roll)); model.orientation = orientation; placedModels.push({ model: model, name: loadingObject.name, }); } for (const objectToHide of objects.hiddenObjects) { hidingFeatures.push({ id: objectToHide, loops: 0, }); } if (objects.hiddenObjects.length > 0) {
const primitives = vcMap.getScene().primitives; for (let i = 0; i < primitives.length; i++) { const tileSet = primitives.get(i); if (!(tileSet instanceof Cesium3DTileset)) { continue; } tileSet.tileVisible.addEventListener(hidingListener); } } } reader.readAsText(file); }); // dispatch a click event to open the file dialog inputElement.dispatchEvent(new MouseEvent("click")); }, get config() { return config; }, initialize(vcsApp) { app = vcsApp; vcsApp.contextMenuManager.addEventHandler(async (event) => { const actions = []; const pick = vcsApp.maps.activeMap.getScene().pick(event.windowPosition); if (pick !== undefined && pick.primitive !== undefined && pick.primitive.id !== undefined) { model = pick.primitive.id actions.push({ id: 'move', name: 'Objekt verschieben', callback() { const interaction = new MoveInteraction(); interaction.setActive(EventType.CLICKMOVE); activeMouseEvent = vcsApp.maps.eventHandler.addExclusiveInteraction(interaction, () => { console.log("removed") }); }, }); actions.push({ id: 'move', name: 'Objekthöhe verändern', callback() { const interaction = new HeightInteraction(); interaction.setActive(EventType.CLICKMOVE); activeMouseEvent = vcsApp.maps.eventHandler.addExclusiveInteraction(interaction, () => { console.log("removed") }); }, }); actions.push({ id: 'rotate', name: 'Objekt drehen', callback() { hpRoll = hpRollMap.get(model); if (hpRoll === undefined) { hpRoll = new HeadingPitchRoll(); hpRollMap.set(model, hpRoll); } const interaction = new RotateAction(); interaction.setActive(EventType.CLICKMOVE); activeMouseEvent = vcsApp.maps.eventHandler.addExclusiveInteraction(interaction, () => { console.log("removed") }); }, }); actions.push({ id: 'scale', name: 'Objekt skalieren', callback() { currentlyScaledModel = model; vcsApp.windowManager.add( { id: scaleControlId,
component: scaleControl, slot: WindowSlot.DYNAMIC_LEFT, state: { headerTitle: "Skalierung", }, }, name, ); } }); actions.push({ id: 'delete', name: 'Objekt entfernen', callback() { vcsApp.maps.activeMap.getEntities().remove(model); removePlacedModel(model); }, }); } else if (event.feature) { actions.push({ id: 'delete', name: 'Objekt verstecken', callback() { const gmlId = event.feature.getProperty("gml_id"); if (gmlId !== undefined) { updateHideCondition(); event.feature.tileset.style = new Cesium3DTileStyle({ show: { conditions: conditions, }, }); activeMap.layerCollection.requestRender(); } else { const { activeMap } = vcsApp.maps; activeMap.layerCollection.globalHider.addFeature("manual", event.feature); hidingFeatures.push({ id: event.feature.featureId, loops: 3, }); activeMap.layerCollection.globalHider.hideObjects(["manual"]); } }, }); } return actions; }, name); this._app = vcsApp; }, /** * @param {import("@vcmap/ui").VcsUiApp} vcsUiApp * @returns {Promise<void>} */ async onVcsAppMounted(vcsApp) { const bimGroup = { id: 'bim-functions', type: ToolboxType.GROUP, icon: "ifc", disabled: false, title: 'BIM Funktionen', }; vcsApp.toolboxManager.add( bimGroup, name, ); /** * @type {Array<import("@vcmap/ui").ButtonComponentOptions>} */
const buttonComponents = [ { id: 'ifcUpload', action: { name: 'ifcUpload', title: 'IFC nach gltf Konvertierung', icon: 'mdi-upload-outline', active: false, callback() { vcsApp.windowManager.add( { id: bimOptionsId, component: BIMOptions, slot: WindowSlot.DETACHED, position: { width: 400, }, state: { headerTitle: "IFC nach gltf Konvertierung", }, }, name, ); }, }, }, { id: 'objectManager', action: { name: 'objectManager', title: 'Objektverwaltung', icon: 'mdi-bookmark-outline', active: false, callback() { vcsApp.windowManager.add( { id: objectListId, component: objectList, slot: WindowSlot.DYNAMIC_LEFT, state: { headerTitle: "Objektverwaltung", }, }, name, ); }, }, }, { id: 'help', action: { name: 'help', title: 'Anleitung', icon: 'mdi-help', active: false, callback() { window.open(config.instructions); }, }, }, ]; const groupButtonManager = vcsApp.toolboxManager.get( 'bim-functions', ).buttonManager; buttonComponents.forEach((b) => groupButtonManager.add(b, name), ); },
/** * @param {boolean} forUrl * @returns {PluginState} */ getState(forUrl) { return undefined; }, /** * @returns {PluginConfig} */ toJSON() { const options = {}; return options; }, i18n: { }, destroy() { // empty }, }; }