Skip to content

Commit

Permalink
Add initial Compare3D component
Browse files Browse the repository at this point in the history
  • Loading branch information
manisandro committed Jan 6, 2025
1 parent 8166126 commit d083713
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 0 deletions.
193 changes: 193 additions & 0 deletions components/map3d/Compare3D.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/**
* Copyright 2024 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 PropTypes from 'prop-types';
import {Plane, Vector3} from 'three';

import LocaleUtils from '../../utils/LocaleUtils';
import Icon from '../Icon';
import SideBar from '../SideBar';
import NumberInput from '../widgets/NumberInput';

import './style/Compare3D.css';


export default class Compare3D extends React.Component {
static propTypes = {
sceneContext: PropTypes.object
};
state = {
enabled: false,
clippedObjects: {},
planeX: 0,
planeY: 0,
planeA: 0
};
componentWillUnmount() {
this.clearClippingPlane();
}
componentDidUpdate(prevProps, prevState) {
if (this.state.enabled && this.state !== prevState) {
// Recompute clipping plane
this.updateClippingPlane();
} else if (!this.state.enabled && prevState.enabled) {
this.clearClippingPlane();
}
}
updateClippingPlane = () => {
const point = new Vector3(this.state.planeX, this.state.planeY, 0);
const alpha = this.state.planeA / 180 * Math.PI;
const normal = new Vector3(Math.sin(alpha), Math.cos(alpha), 0);
const leftPlane = new Plane();
const rightPlane = new Plane();
leftPlane.setFromNormalAndCoplanarPoint(normal, point);
rightPlane.setFromNormalAndCoplanarPoint(-normal, point);
Object.entries(this.state.clippedObjects).forEach(([objectId, config]) => {
const planes = [];
if (config.left) {
planes.push(leftPlane);
}
if (config.right) {
planes.push(rightPlane);
}
if (objectId === "__terrain") {
this.props.sceneContext.map.clippingPlanes = planes;
} else {
this.props.sceneContext.getSceneObject(objectId).clippingPlanes = planes;
}
});
this.props.sceneContext.scene.notifyChange();
};
clearClippingPlane = () => {
Object.keys(this.state.clippedObjects).forEach(objectId => {
if (objectId === "__terrain") {
this.props.sceneContext.map.clippingPlanes = [];
} else {
this.props.sceneContext.getSceneObject(objectId).clippingPlanes = [];
}
});
this.props.sceneContext.scene.notifyChange();
};
render() {
return (
<div>
<SideBar icon="layers" id="Compare3D"
title={LocaleUtils.tr("appmenu.items.Compare3D")}
width="20em"
>
{() => ({
body: this.renderBody()
})}
</SideBar>
</div>
);
}
renderBody = () => {
const sceneContext = this.props.sceneContext;
const objects = {__terrain: {layertree: true, title: LocaleUtils.tr("map3d.terrain")}, ...sceneContext.sceneObjects};
const objectIds = Object.keys(objects).filter(objectId => objects[objectId].layertree);
return (
<div className="compare3d-body" role="body">
<div className="compare3d-title" onClick={this.toggleCompare}>
<Icon icon={this.state.enabled ? "checked" : "unchecked"} />
<span>{LocaleUtils.tr("compare3d.compare_objects")}</span>
</div>
<div className="compare3d-objects">
{["left", "right"].map(section => {
const clipState = this.state.clippedObjects;
let toggleAllIcon = "checked";
let toggleAllValue = true;
const toggleAllState = objectIds.reduce((res, id) => res + clipState[id]?.[section], 0);
if (toggleAllState === objectIds.length) {
toggleAllIcon = "unchecked";
toggleAllValue = false;
} else if (toggleAllState > 0) {
toggleAllIcon = "tristate";
}
return (
<div className="compare3d-section" key={"compare-" + section}>
<div
className="compare3d-item compare3d-item-toggleall"
onClick={() => this.toggleAllObjects(section, objectIds, toggleAllValue)}
title={LocaleUtils.tr("compare3d.toggleall")}
>
<Icon className="compare3d-item-checkbox" disabled={!this.state.enabled} icon={toggleAllIcon} />
<span>{LocaleUtils.tr("compare3d.toggleall")}</span>
</div>
{objectIds.map(objectId => (
<div
className="compare3d-item"
key={objectId}
onClick={() => this.toggleObject(section, objectId)}
title={objects[objectId].title ?? objectId}
>
<Icon className="compare3d-item-checkbox" disabled={!this.state.enabled} icon={clipState[objectId]?.[section] ? "unchecked" : "checked"} />
<span>{objects[objectId].title ?? objectId}</span>
</div>
))}
</div>
);
})}
</div>
<div className="compare3d-title">{LocaleUtils.tr("compare3d.clipplane")}</div>
<table className="compare3d-planeconfig">
<tbody>
<tr>
<td>x</td>
<td><NumberInput disabled={!this.state.enabled} onChange={x => this.setState({planeX: x})} value={this.state.planeX}/></td>
</tr>
<tr>
<td>y</td>
<td><NumberInput disabled={!this.state.enabled} onChange={y => this.setState({planeY: y})} value={this.state.planeY}/></td>
</tr>
<tr>
<td>&#945;</td>
<td><NumberInput disabled={!this.state.enabled} onChange={a => this.setState({planeA: a})} suffix="°" value={this.state.planeA} /></td>
</tr>
</tbody>
</table>
</div>
);
};
toggleCompare = () => {
this.setState(state => {
const newState = {enabled: !state.enabled};
if (newState.enabled) {
// Position plane in current view
newState.planeX = this.props.sceneContext.scene.view.controls.target.x;
newState.planeY = this.props.sceneContext.scene.view.controls.target.y;
newState.planeA = -this.props.sceneContext.scene.view.controls.getAzimuthalAngle() / Math.PI * 180 + 90;
}
return newState;
});
};
toggleObject = (section, objectId) => {
this.setState(state => ({
clippedObjects: {
...state.clippedObjects,
[objectId]: {
...state.clippedObjects[objectId],
[section]: !state.clippedObjects[objectId]?.[section]
}
}
}));
};
toggleAllObjects = (section, objectIds, value) => {
this.setState(state => ({
clippedObjects: objectIds.reduce((res, objectId) => ({
...res,
[objectId]: {
...state.clippedObjects[objectId],
[section]: value
}
}), {})
}));
};
}
2 changes: 2 additions & 0 deletions components/map3d/Map3D.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import CoordinatesUtils from '../../utils/CoordinatesUtils';
import MiscUtils from '../../utils/MiscUtils';
import Icon from '../Icon';
import BottomBar3D from './BottomBar3D';
import Compare3D from './Compare3D';
import LayerTree3D from './LayerTree3D';
import Map3DLight from './Map3DLight';
import Measure3D from './Measure3D';
Expand Down Expand Up @@ -339,6 +340,7 @@ class Map3D extends React.Component {
<OverviewMap3D baseLayer={baseLayer} sceneContext={this.state.sceneContext} />
<Map3DLight sceneContext={this.state.sceneContext} />
<Measure3D sceneContext={this.state.sceneContext} />
<Compare3D sceneContext={this.state.sceneContext} />
</div>
) : null}
</div>
Expand Down
1 change: 1 addition & 0 deletions components/map3d/TopBar3D.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TopBar3D extends React.Component {
const menuItems = [
{key: "LayerTree3D", icon: "layers"},
{key: "Measure3D", icon: "measure"},
{key: "Compare3D", icon: "compare"},
{key: "DateTime3D", icon: "clock"}
];
return (
Expand Down
57 changes: 57 additions & 0 deletions components/map3d/style/Compare3D.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#Compare3D div.compare3d-title {
display: flex;
align-items: center;
padding: 0 0.125em;
}

#Compare3D div.compare3d-title > span.icon {
margin-right: 0.5em;
}

#Compare3D div.compare3d-objects {
display: flex;
background-color: var(--list-bg-color);
margin: 0.25em;
}

#Compare3D div.compare3d-section {
flex: 1 1 auto;
border: 1px solid var(--border-color);
}

#Compare3D div.compare3d-section:first-child {
border-right: 1px solid var(--border-color);
}

#Compare3D div.compare3d-section:last-child {
border-left: 1px solid var(--border-color);
}

#Compare3D div.compare3d-item {
display: flex;
align-items: center;
padding: 0.25em;
}

#Compare3D div.compare3d-item-toggleall {
border-bottom: 1px solid var(--border-color);
}

#Compare3D span.compare3d-item-checkbox {
margin-right: 0.5em;
flex: 0 0 auto;
}

#Compare3D div.compare3d-title {
font-weight: bold;
margin: 0.25em;
}

#Compare3D table.compare3d-planeconfig {
width: 100%;
margin-bottom: 0.25em;
}

#Compare3D table.compare3d-planeconfig td {
padding: 0 0.25em 0 0.5em;
}
72 changes: 72 additions & 0 deletions icons/compare.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions translations/ca-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"filter": "Menú de filtres...",
"items": {
"Bookmark": "Marcador",
"Compare3D": "",
"DateTime3D": "",
"Editing": "Edició",
"Help": "Ajuda",
Expand Down Expand Up @@ -95,6 +96,11 @@
"terms_label": "Condicions del servei",
"viewertitle_label": ""
},
"compare3d": {
"clipplane": "",
"compare_objects": "",
"toggleall": ""
},
"cookiepopup": {
"accept": "",
"message": ""
Expand Down Expand Up @@ -277,6 +283,7 @@
},
"map3d": {
"syncview": "",
"terrain": "",
"title": ""
},
"mapexport": {
Expand Down
Loading

0 comments on commit d083713

Please sign in to comment.