qwc2
Version:
QGIS Web Client
23 lines • 16.1 kB
JavaScript
function _typeof(o){"@babel/helpers - typeof";return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o},_typeof(o)}function _construct(t,e,r){if(_isNativeReflectConstruct())return Reflect.construct.apply(null,arguments);var o=[null];o.push.apply(o,e);var p=new(t.bind.apply(t,o));return r&&_setPrototypeOf(p,r.prototype),p}function _toConsumableArray(r){return _arrayWithoutHoles(r)||_iterableToArray(r)||_unsupportedIterableToArray(r)||_nonIterableSpread()}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _iterableToArray(r){if("undefined"!=typeof Symbol&&null!=r[Symbol.iterator]||null!=r["@@iterator"])return Array.from(r)}function _arrayWithoutHoles(r){if(Array.isArray(r))return _arrayLikeToArray(r)}function _slicedToArray(r,e){return _arrayWithHoles(r)||_iterableToArrayLimit(r,e)||_unsupportedIterableToArray(r,e)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(r,a){if(r){if("string"==typeof r)return _arrayLikeToArray(r,a);var t={}.toString.call(r).slice(8,-1);return"Object"===t&&r.constructor&&(t=r.constructor.name),"Map"===t||"Set"===t?Array.from(r):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?_arrayLikeToArray(r,a):void 0}}function _arrayLikeToArray(r,a){(null==a||a>r.length)&&(a=r.length);for(var e=0,n=Array(a);e<a;e++)n[e]=r[e];return n}function _iterableToArrayLimit(r,l){var t=null==r?null:"undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(null!=t){var e,n,i,u,a=[],f=!0,o=!1;try{if(i=(t=t.call(r)).next,0===l){if(Object(t)!==t)return;f=!1}else for(;!(f=(e=i.call(t)).done)&&(a.push(e.value),a.length!==l);f=!0);}catch(r){o=!0,n=r}finally{try{if(!f&&null!=t["return"]&&(u=t["return"](),Object(u)!==u))return}finally{if(o)throw n}}return a}}function _arrayWithHoles(r){if(Array.isArray(r))return r}function _classCallCheck(a,n){if(!(a instanceof n))throw new TypeError("Cannot call a class as a function")}function _defineProperties(e,r){for(var t=0;t<r.length;t++){var o=r[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,_toPropertyKey(o.key),o)}}function _createClass(e,r,t){return r&&_defineProperties(e.prototype,r),t&&_defineProperties(e,t),Object.defineProperty(e,"prototype",{writable:!1}),e}function _callSuper(t,o,e){return o=_getPrototypeOf(o),_possibleConstructorReturn(t,_isNativeReflectConstruct()?Reflect.construct(o,e||[],_getPrototypeOf(t).constructor):o.apply(t,e))}function _possibleConstructorReturn(t,e){if(e&&("object"==_typeof(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return _assertThisInitialized(t)}function _assertThisInitialized(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function _isNativeReflectConstruct(){try{var t=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(t){}return(_isNativeReflectConstruct=function _isNativeReflectConstruct(){return!!t})()}function _getPrototypeOf(t){return _getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},_getPrototypeOf(t)}function _inherits(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&_setPrototypeOf(t,e)}function _setPrototypeOf(t,e){return _setPrototypeOf=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},_setPrototypeOf(t,e)}function _defineProperty(e,r,t){return(r=_toPropertyKey(r))in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function _toPropertyKey(t){var i=_toPrimitive(t,"string");return"symbol"==_typeof(i)?i:i+""}function _toPrimitive(t,r){if("object"!=_typeof(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var i=e.call(t,r||"default");if("object"!=_typeof(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===r?String:Number)(t)}/**
* Copyright 2025 Sourcepole AG
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/import React from"react";import{connect}from"react-redux";import ColorLayer from"@giro3d/giro3d/core/layer/ColorLayer";import DrawTool,{conditions}from"@giro3d/giro3d/interactions/DrawTool";import VectorSource from"@giro3d/giro3d/sources/VectorSource";import FileSaver from"file-saver";import ol from"openlayers";import pointInPolygon from"point-in-polygon";import PropTypes from"prop-types";import{Box3,BufferGeometry,Float32BufferAttribute,Group,Matrix4,Mesh,MeshStandardMaterial,Quaternion,Scene,Vector3}from"three";import{GLTFExporter}from"three/addons/exporters/GLTFExporter.js";import{setCurrentTask}from"../../actions/task";import LocaleUtils from"../../utils/LocaleUtils";import VectorLayerUtils from"../../utils/VectorLayerUtils";import SideBar from"../SideBar";import Spinner from"../widgets/Spinner";var ExportObjects3D=/*#__PURE__*/function(_React$Component){function ExportObjects3D(props){var _this;_classCallCheck(this,ExportObjects3D);_this=_callSuper(this,ExportObjects3D,[props]);_defineProperty(_this,"state",{selectedFormat:"model/gltf+json",exporting:false,exportPolygon:null});_defineProperty(_this,"onShow",function(){_this.abortController=new AbortController;_this.measureTool=new DrawTool({instance:_this.props.sceneContext.scene});_this.drawLayer=new ColorLayer({source:new VectorSource({data:[],format:new ol.format.GeoJSON,style:_this.featureStyleFunction})});_this.props.sceneContext.map.addLayer(_this.drawLayer);_this.restart()});_defineProperty(_this,"onHide",function(){_this.abortController.abort();_this.abortController=null;_this.measureTool.dispose();_this.measureTool=null;_this.props.sceneContext.map.removeLayer(_this.drawLayer,{dispose:true});_this.drawLayer=null;_this.setState({exporting:false,exportPolygon:null})});_defineProperty(_this,"formatChanged",function(ev){_this.setState({selectedFormat:ev.target.value})});_defineProperty(_this,"renderBody",function(){var exportDisabled=_this.state.exporting||_this.state.exportPolygon===null;var formatMap={"model/gltf+json":"GLTF"};return/*#__PURE__*/React.createElement("div",{className:"mapexport-body"},/*#__PURE__*/React.createElement("form",{onSubmit:_this.exportArea},/*#__PURE__*/React.createElement("table",{className:"options-table"},/*#__PURE__*/React.createElement("tbody",null,/*#__PURE__*/React.createElement("tr",null,/*#__PURE__*/React.createElement("td",null,LocaleUtils.tr("mapexport.format")),/*#__PURE__*/React.createElement("td",null,/*#__PURE__*/React.createElement("select",{name:"FORMAT",onChange:_this.formatChanged,value:_this.state.selectedFormat},Object.entries(formatMap).map(function(_ref){var _ref2=_slicedToArray(_ref,2),format=_ref2[0],label=_ref2[1];return/*#__PURE__*/React.createElement("option",{key:format,value:format},label)})))))),/*#__PURE__*/React.createElement("div",{className:"button-bar"},/*#__PURE__*/React.createElement("button",{className:"button",disabled:exportDisabled,type:"submit"},_this.state.exporting?/*#__PURE__*/React.createElement("span",{className:"mapexport-wait"},/*#__PURE__*/React.createElement(Spinner,null)," ",LocaleUtils.tr("mapexport.wait")):LocaleUtils.tr("mapexport.submit")))))});_defineProperty(_this,"restart",function(){if(_this.abortController){_this.abortController.abort()}_this.abortController=new AbortController;var pick=function pick(e){return _this.props.sceneContext.scene.pickObjectsAt(e,{sortByDistance:true,where:[_this.props.sceneContext.getMap()]})};var options={signal:_this.abortController.signal,endCondition:conditions.doubleClick,pick:pick};_this.measureTool.createPolygon(options).then(_this.selectArea)["catch"](function(){})});_defineProperty(_this,"selectArea",function(polygon){if(polygon===null){_this.restart();return}_this.drawLayer.source.clear();var polyGeoJson=polygon.toGeoJSON();var feature=new ol.format.GeoJSON().readFeature(polyGeoJson,{dataProjection:"EPSG:4326",featureProjection:_this.props.sceneContext.mapCrs});_this.drawLayer.source.addFeature(feature);_this.props.sceneContext.scene.remove(polygon);_this.setState({exportPolygon:feature.getGeometry().getCoordinates()});// Setup for next selection
_this.restart()});_defineProperty(_this,"featureStyleFunction",function(){return[new ol.style.Style({fill:new ol.style.Fill({color:[41,120,180,0.5]})}),new ol.style.Style({stroke:new ol.style.Stroke({color:[255,255,255],width:4})}),new ol.style.Style({stroke:new ol.style.Stroke({color:[41,120,180],width:1.5})})]});_defineProperty(_this,"exportArea",function(ev){ev.preventDefault();_this.setState({exporting:true});if(_this.state.selectedFormat==="model/gltf+json"){// Delay one loop to ensure exporting: true is set
setTimeout(_this.exportToGltf,0)}});_defineProperty(_this,"exportToGltf",function(){var bbox=VectorLayerUtils.computeFeatureBBox({type:"Polygon",coordinates:_this.state.exportPolygon});// Create a bounding box in world space
var selectionBox=new Box3().setFromPoints([new Vector3(bbox[0],bbox[1],0),new Vector3(bbox[2],bbox[3],8000)]);var exportGroup=new Group;exportGroup.rotation.set(-Math.PI/2,0,0);// GLTF is Y-UP
Object.entries(_this.props.sceneContext.sceneObjects).forEach(function(_ref3){var _ref4=_slicedToArray(_ref3,2),objectId=_ref4[0],options=_ref4[1];if(!options.layertree||!options.visibility){return}var object=_this.props.sceneContext.getSceneObject(objectId);if(object.tiles){_this.addTileToExportGroup(object.tiles,exportGroup,selectionBox)}else{_this.addObjectToExportGroup(object,exportGroup,selectionBox)}});var exportScene=new Scene;exportScene.add(exportGroup);var exporter=new GLTFExporter;exporter.parse(exportScene,function(gltf){var blob=new Blob([JSON.stringify(gltf)],{type:"application/json"});FileSaver.saveAs(blob,"scene.gltf");_this.setState({exporting:false})})});_defineProperty(_this,"addTileToExportGroup",function(tiles,exportGroup,selectionBox){tiles.group.traverse(function(c){if(c.geometry){var bbox=c.geometry.boundingBox.clone().applyMatrix4(c.matrixWorld);if(!selectionBox.intersectsBox(bbox)){return}var batchidAttr=c.geometry.getAttribute("_batchid");if(!batchidAttr){// Not a tile
return}var posAttr=c.geometry.getAttribute("position");var norAttr=c.geometry.getAttribute("normal");var colAttr=c.geometry.getAttribute("color");var colStride=c.material.transparent?4:3;var batches={};batchidAttr.array.forEach(function(batchId,idx){var _batches$batchId$posi,_batches$batchId$norm;if(!batches[batchId]){batches[batchId]={position:[],normal:[],color:colAttr?[]:null,colorStride:colStride,bbox:new Box3}}var pos=posAttr.array.slice(3*idx,3*idx+3);(_batches$batchId$posi=batches[batchId].position).push.apply(_batches$batchId$posi,_toConsumableArray(pos));var nor=norAttr.array.slice(3*idx,3*idx+3);(_batches$batchId$norm=batches[batchId].normal).push.apply(_batches$batchId$norm,_toConsumableArray(nor));if(colAttr){var _batches$batchId$colo;var col=colAttr.array.slice(colStride*idx,colStride*idx+colStride);(_batches$batchId$colo=batches[batchId].color).push.apply(_batches$batchId$colo,_toConsumableArray(col))}batches[batchId].bbox.expandByPoint(_construct(Vector3,_toConsumableArray(pos)).applyMatrix4(c.matrixWorld))});Object.entries(batches).forEach(function(_ref5){var _ref6=_slicedToArray(_ref5,2),batchId=_ref6[0],batch=_ref6[1];if(selectionBox.intersectsBox(batch.bbox)&&_this.bboxInExportPolygon(batch.bbox)){var _batchTableObject$use;// Get batch table object
var batchTableObject=c;while(!batchTableObject.batchTable){batchTableObject=batchTableObject.parent}// Express coordinates wrt center of batch object bbox
var prevPosition=new Vector3;c.matrixWorld.decompose(prevPosition,new Quaternion,new Vector3);var newPosition=new Vector3;batch.bbox.getCenter(newPosition);var offset=new Vector3().subVectors(newPosition,prevPosition);for(var i=0;i<batch.position.length/3;++i){batch.position[3*i+0]-=offset.x;batch.position[3*i+1]-=offset.y;batch.position[3*i+2]-=offset.z}// Construct mesh
var material=new MeshStandardMaterial({color:16777215});var geometry=new BufferGeometry;geometry.setAttribute("position",new Float32BufferAttribute(batch.position,3));geometry.setAttribute("normal",new Float32BufferAttribute(batch.normal,3));if(batch.color){var _material$color;// geometry.setAttribute('color', new Float32BufferAttribute(batch.color, batch.colorStride));
// material.vertexColors = batch.color !== null;
// material.transparent = batch.colorStride === 4;
(_material$color=material.color).set.apply(_material$color,_toConsumableArray(batch.color.slice(0,3)))}var mesh=new Mesh(geometry,material);mesh.applyMatrix4(c.matrixWorld.clone().multiply(new Matrix4().makeTranslation(offset)));// Include attribute from batch table
var batchAttrs=batchTableObject.batchTable.getDataFromId(batchId);Object.assign(mesh.userData,batchAttrs);// Add label
var labelEntry=(_batchTableObject$use=batchTableObject.userData.tileLabels)===null||_batchTableObject$use===void 0?void 0:_batchTableObject$use[batchId];if(labelEntry){mesh.userData.label=labelEntry.label;mesh.userData.labelOffset=labelEntry.labelOffset}exportGroup.add(mesh)}})}})});_defineProperty(_this,"addObjectToExportGroup",function(object,exportGroup,selectionBox){object.children.forEach(function(child){var objBox=new Box3().setFromObject(child);if(selectionBox.intersectsBox(objBox)&&_this.bboxInExportPolygon(objBox)){exportGroup.add(child.clone())}})});_defineProperty(_this,"bboxInExportPolygon",function(box3){var polygon=_this.state.exportPolygon[0];var _ref7=[box3.min.x,box3.min.y,box3.max.x,box3.max.y],xmin=_ref7[0],ymin=_ref7[1],xmax=_ref7[2],ymax=_ref7[3];function doLinesIntersect(p1,p2,p3,p4){// Helper function to check if two line segments (p1-p2 and p3-p4) intersect
function ccw(A,B,C){return(C[1]-A[1])*(B[0]-A[0])>(B[1]-A[1])*(C[0]-A[0])}return ccw(p1,p3,p4)!==ccw(p2,p3,p4)&&ccw(p1,p2,p3)!==ccw(p1,p2,p4)}// Check if any bbox vertex is inside the polygon
if(pointInPolygon([xmin,ymin],polygon)||pointInPolygon([xmax,ymin],polygon)||pointInPolygon([xmax,ymax],polygon)||pointInPolygon([xmax,ymin],polygon)){return true}// Check if any edge of the polygon intersects the bbox
for(var i=0;i<polygon.length-1;i++){var _polygon$i=_slicedToArray(polygon[i],2),x1=_polygon$i[0],y1=_polygon$i[1];var _polygon=_slicedToArray(polygon[i+1],2),x2=_polygon[0],y2=_polygon[1];if(doLinesIntersect([x1,y1],[x2,y2],[xmin,ymin],[xmin,ymax])||doLinesIntersect([x1,y1],[x2,y2],[xmin,ymax],[xmax,ymax])||doLinesIntersect([x1,y1],[x2,y2],[xmax,ymax],[xmax,ymin])||doLinesIntersect([x1,y1],[x2,y2],[xmax,ymin],[xmin,ymin])){return true}}return false});_this.measureTool=null;_this.drawLayer=null;return _this}_inherits(ExportObjects3D,_React$Component);return _createClass(ExportObjects3D,[{key:"render",value:function render(){var _this2=this;return/*#__PURE__*/React.createElement(SideBar,{extraClasses:"MapExport",icon:"export",id:"ExportObjects3D",onHide:this.onHide,onShow:this.onShow,title:LocaleUtils.tr("appmenu.items.ExportObjects3D"),width:"20em"},function(){return{body:_this2.renderBody()}})}}])}(React.Component);_defineProperty(ExportObjects3D,"propTypes",{sceneContext:PropTypes.object,setCurrentTask:PropTypes.func});export default connect(function(state){return{theme:state.theme.current}},{setCurrentTask:setCurrentTask})(ExportObjects3D);