Skip to content

Commit

Permalink
Merge pull request #5249 from 3drepo/ISSUE_5243
Browse files Browse the repository at this point in the history
Issue 5243 - Slope measurements
  • Loading branch information
sanmont3drepo authored Jan 10, 2025
2 parents 7fbe3d1 + 3daaac2 commit fd61405
Show file tree
Hide file tree
Showing 35 changed files with 304 additions and 57 deletions.
2 changes: 1 addition & 1 deletion backend/src/v4/models/shapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const shapeSchema = yup.object().shape({
"normals": yup.array().of(coordinatesSchema),
"value": yup.number().min(0),
"color": colorSchema.required(),
"type": yup.mixed().oneOf([0, 1, 2]).required(),
"type": yup.mixed().oneOf([0, 1, 2, 3]).required(),
"name": yup.string()
}).noUnknown();

Expand Down
28 changes: 28 additions & 0 deletions frontend/assets/icons/measurements/slope.svg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (C) 2024 3D Repo Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

type IProps = {
className?: string,
};

export default ({ className }: IProps) => (
<svg width="18" height="15" viewBox="0 0 18 15" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path fillRule="evenodd" clipRule="evenodd" d="M5.73602 3.90927V2.77097C5.73423 2.2591 5.64653 1.83403 5.47293 1.49576C5.30111 1.15749 5.06486 0.904239 4.76418 0.736001C4.46529 0.567762 4.12344 0.483643 3.73864 0.483643C3.34668 0.483643 3.00036 0.568657 2.69967 0.738685C2.39899 0.906924 2.16364 1.16107 1.99361 1.50113C1.82358 1.8394 1.73946 2.26268 1.74125 2.77097L1.74125 3.90927C1.73946 4.42472 1.82358 4.84979 1.99361 5.18448C2.16364 5.51917 2.39989 5.76795 2.70236 5.93082C3.00483 6.09368 3.35384 6.17512 3.74938 6.17512C4.13776 6.17512 4.4805 6.09368 4.7776 5.93082C5.07649 5.76795 5.31006 5.51917 5.4783 5.18448C5.64832 4.84979 5.73423 4.42472 5.73602 3.90927ZM4.31852 3.8341H3.16949V4.07035C3.1677 4.44083 3.20976 4.6914 3.29567 4.82205C3.38158 4.95092 3.53281 5.01535 3.74938 5.01535C3.86571 5.01535 3.96594 4.99387 4.05006 4.95092C4.13418 4.90796 4.1995 4.81937 4.24604 4.68513C4.29257 4.5509 4.31673 4.34597 4.31852 4.07035V3.8341ZM4.31852 2.79245V2.57768C4.31673 2.31995 4.29257 2.12307 4.24604 1.98705C4.1995 1.85103 4.13328 1.75796 4.04737 1.70785C3.96146 1.65773 3.85855 1.63268 3.73864 1.63268C3.52744 1.63268 3.37889 1.70337 3.29298 1.84476C3.20886 1.98437 3.1677 2.22867 3.16949 2.57768V2.79245H4.31852Z" fill="currentColor"/>
<path fillRule="evenodd" clipRule="evenodd" d="M8.26295 3.3186C8.0088 3.3186 7.77792 3.25686 7.57031 3.13336C7.36269 3.00987 7.19714 2.84431 7.07365 2.6367C6.95015 2.4273 6.88841 2.19641 6.88841 1.94406C6.88841 1.68991 6.95015 1.45903 7.07365 1.25141C7.19714 1.0438 7.36269 0.878248 7.57031 0.754753C7.77792 0.631259 8.0088 0.569512 8.26295 0.569512C8.5171 0.569512 8.74798 0.631259 8.95559 0.754753C9.16321 0.878248 9.32876 1.0438 9.45225 1.25141C9.57575 1.45903 9.6375 1.68991 9.6375 1.94406C9.6375 2.19641 9.57575 2.4273 9.45225 2.6367C9.32876 2.84431 9.16321 3.00987 8.95559 3.13336C8.74798 3.25686 8.5171 3.3186 8.26295 3.3186ZM8.26295 2.40582C8.34886 2.40582 8.42671 2.38524 8.49652 2.34407C8.56632 2.30291 8.6218 2.24742 8.66296 2.17762C8.70413 2.10603 8.72471 2.02818 8.72471 1.94406C8.72471 1.85815 8.70413 1.78029 8.66296 1.71049C8.6218 1.64069 8.56632 1.58521 8.49652 1.54404C8.42671 1.50288 8.34886 1.4823 8.26295 1.4823C8.17883 1.4823 8.10098 1.50288 8.02938 1.54404C7.95958 1.58521 7.9041 1.64069 7.86294 1.71049C7.82177 1.78029 7.80119 1.85815 7.80119 1.94406C7.80119 2.02818 7.82177 2.10603 7.86294 2.17762C7.9041 2.24742 7.95958 2.30291 8.02938 2.34407C8.10098 2.38524 8.17883 2.40582 8.26295 2.40582Z" fill="currentColor"/>
<path fillRule="evenodd" clipRule="evenodd" d="M17.6751 2.47605C17.8756 2.58701 18.0001 2.79811 18.0001 3.02729V13.5214C18.0001 13.8694 17.718 14.1514 17.3701 14.1514L0.630053 14.1514C0.349162 14.1514 0.102204 13.9655 0.0245841 13.6955C-0.0530358 13.4256 0.0574359 13.1368 0.295428 12.9876L17.0354 2.4935C17.2296 2.37177 17.4746 2.36509 17.6751 2.47605ZM2.82112 12.8914L16.7401 12.8914V4.16578L2.82112 12.8914Z" fill="currentColor"/>
</svg>
);
27 changes: 27 additions & 0 deletions frontend/assets/icons/measurements/slope_units.svg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (C) 2024 3D Repo Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

type IProps = {
className?: any;
};

export default ({ className }: IProps) => (
<svg width="24" height="21" viewBox="0 0 24 21" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path d="M22.1742 5.89912C22.6536 5.59582 23.2791 5.94029 23.2791 6.50757L23.2791 19.3601C23.2791 19.7577 22.9568 20.0801 22.5591 20.0801L2.24387 20.0801C1.52256 20.0801 1.24936 19.1373 1.85893 18.7516L22.1742 5.89912Z" fill="currentColor"/>
<path d="M5.7071 13.3626C5.80776 12.9097 5.52224 12.461 5.06938 12.3603L3.57101 12.0273L16.8096 3.62172L16.4751 5.12629C16.3745 5.57916 16.66 6.02788 17.1129 6.12855C17.5657 6.22921 18.0145 5.94369 18.1151 5.49083L18.8888 2.01012C18.9371 1.79265 18.8971 1.56488 18.7775 1.37692C18.6579 1.18896 18.4686 1.05621 18.2511 1.00787L14.7704 0.234182C14.3175 0.133519 13.8688 0.419037 13.7681 0.871904C13.6675 1.32477 13.953 1.77349 14.4058 1.87416L15.9034 2.20704L2.66582 10.612L3.00009 9.10821C3.10075 8.65534 2.81523 8.20662 2.36236 8.10596C1.9095 8.00529 1.46077 8.29081 1.36011 8.74368L0.586422 12.2244C0.538082 12.4419 0.578114 12.6696 0.69771 12.8576C0.817305 13.0455 1.00667 13.1783 1.22414 13.2266L4.70485 14.0003C5.15771 14.101 5.60644 13.8155 5.7071 13.3626Z" fill="currentColor"/>
</svg>
);
31 changes: 30 additions & 1 deletion frontend/src/globals/unity-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ export class UnityUtil {
* Set the measure tool mode.
* @category Measuring tool
* @param mode - The measuring mode, accepted values are "Point", "Raycast", "MinimumDistance",
* "SurfaceArea", "PolygonArea", "PolyLine" or "Angle".
* "SurfaceArea", "PolygonArea", "PolyLine", "Angle" or "Slope".
*/
public static setMeasureToolMode(mode) {
UnityUtil.toUnity('SetMeasureToolMode', undefined, mode);
Expand All @@ -1158,6 +1158,15 @@ export class UnityUtil {
UnityUtil.toUnity('SetMeasureToolUnits', undefined, units);
}

/**
* Set the measure tool units for the slope measurements.
* @category Measuring tool
* @param units - The measuring units accepted values are "Degrees", "Percentage"
*/
public static setMeasureToolSlopeUnits(units) {
UnityUtil.toUnity('SetMeasureToolSlopeUnits', undefined, units);
}

/**
* Enable snapping to snap the cursor to the closest edge
* @category Configurations
Expand All @@ -1174,6 +1183,26 @@ export class UnityUtil {
UnityUtil.toUnity('DisableSnapping', undefined, undefined);
}

/**
* Enable Cursor
* Note: Changing the snap mode can affect the cursor.
* Call this after setting snapping.
* @category Configurations
*/
public static enableCursor() {
UnityUtil.toUnity('EnableCursor', undefined, undefined);
}

/**
* Disable Cursor
* Note: Changing the snap mode can affect the cursor.
* Call this after setting snapping.
* @category Configurations
*/
public static disableCursor() {
UnityUtil.toUnity('DisableCursor', undefined, undefined);
}

/**
* Clear all measurements
* @category Measuring tool
Expand Down
17 changes: 16 additions & 1 deletion frontend/src/v4/constants/measure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,22 @@ import DeleteIcon from '@mui/icons-material/Delete';
import EdgeSnappingIcon from '@mui/icons-material/PermDataSetting';
import ResetIcon from '@mui/icons-material/RotateLeft';
import UnitsIcon from '@assets/icons/outlined/measure-outlined.svg';
import SlopeUnitsIcon from '@assets/icons/measurements/slope_units.svg';
import ShowXYZIcon from '@mui/icons-material/Toc';

export const MAX_SLOPE_IN_PERCENTAGE = 89.99 * Math.PI / 180;
export const DEGREES_SYMBOL = '°';
export const SLOPE_UNITS = {
DEGREES: 'Degrees',
PERCENTAGE: 'Percentage'
} as const;
export const slopeUnitsToSymbol = (slopeUnits) => slopeUnits === SLOPE_UNITS.DEGREES ? DEGREES_SYMBOL : '%';

export const MEASURE_ACTIONS_ITEMS = {
EDGE_SNAPPING: 'edgeSnapping',
SHOW_XYZ: 'showXYZ',
UNITS_DISPLAYED_IN: 'unitsDisplayedIn',
SLOPE_UNITS_DISPLAYED_IN: 'slopeUnitsDisplayedIn',
RESET_COLOURS: 'resetColours',
DELETE_ALL: 'deleteAll'
};
Expand All @@ -42,9 +52,14 @@ export const MEASURE_ACTIONS_MENU = [
},
{
name: MEASURE_ACTIONS_ITEMS.UNITS_DISPLAYED_IN,
label: 'Units displayed in',
label: 'Length units displayed in',
Icon: UnitsIcon
},
{
name: MEASURE_ACTIONS_ITEMS.SLOPE_UNITS_DISPLAYED_IN,
label: 'Slope units displayed in',
Icon: SlopeUnitsIcon
},
{
name: MEASURE_ACTIONS_ITEMS.RESET_COLOURS,
label: 'Reset Colours',
Expand Down
1 change: 1 addition & 0 deletions frontend/src/v4/constants/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,5 +170,6 @@ export const VIEWER_MEASURING_MODE = {
SAM: 'SurfaceArea',
CSAM: 'PolygonArea',
ANGLE: 'Angle',
SLOPE: 'Slope',
POINT_TO_POINT: 'Point',
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ export const MEASURE_TYPE = {
LENGTH: 0,
AREA: 1,
ANGLE: 2,
SLOPE: 3,
};

export const MEASURE_TYPE_NAME = {
[MEASURE_TYPE.POINT]: 'Point',
[MEASURE_TYPE.LENGTH]: 'Length',
[MEASURE_TYPE.AREA]: 'Area',
[MEASURE_TYPE.ANGLE]: 'Angle',
[MEASURE_TYPE.SLOPE]: 'Slope',
};

export const MEASURE_TYPE_STATE_MAP = {
[MEASURE_TYPE.POINT]: 'pointMeasurements',
[MEASURE_TYPE.LENGTH]: 'lengthMeasurements',
[MEASURE_TYPE.AREA]: 'areaMeasurements',
[MEASURE_TYPE.ANGLE]: 'angleMeasurements',
[MEASURE_TYPE.SLOPE]: 'slopeMeasurements',
};

export const MEASURING_TYPE = {
Expand All @@ -44,5 +47,6 @@ export const MEASURING_TYPE = {
POINT_TO_POINT: 'Point to Point',
RAY_CAST: 'Ray Cast',
ANGLE: 'Angle',
SLOPE: 'Slope',
POLYLINE: 'Polyline',
};
19 changes: 19 additions & 0 deletions frontend/src/v4/modules/measurements/measurements.redux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
*/

import { createActions, createReducer } from 'reduxsauce';
import { SLOPE_UNITS } from '@/v4/constants/measure';
import { MEASURE_TYPE_STATE_MAP } from './measurements.constants';

export const { Types: MeasurementsTypes, Creators: MeasurementsActions } = createActions({
setMeasureMode: ['mode'],
setMeasureModeSuccess: ['mode'],
setMeasureUnits: ['units'],
setMeasureUnitsSuccess: ['units'],
setMeasureSlopeUnits: ['slopeUnits'],
setMeasureSlopeUnitsSuccess: ['slopeUnits'],
addMeasurement: ['measurement'],
addMeasurementSuccess: ['measurement'],
clearMeasurements: [],
Expand All @@ -47,10 +50,12 @@ export interface IMeasurementState {
isDisabled: boolean;
mode: string;
units: string;
slopeUnits: 'Degrees' | 'Percentage';
areaMeasurements: any[];
lengthMeasurements: any[];
pointMeasurements: any[];
angleMeasurements: any[];
slopeMeasurements: any[];
edgeSnapping: boolean;
xyzDisplay: boolean;
}
Expand All @@ -59,10 +64,12 @@ export const INITIAL_STATE: IMeasurementState = {
isDisabled: false,
mode: '',
units: 'm',
slopeUnits: SLOPE_UNITS.PERCENTAGE,
areaMeasurements: [],
lengthMeasurements: [],
pointMeasurements: [],
angleMeasurements: [],
slopeMeasurements: [],
edgeSnapping: true,
xyzDisplay: false,
};
Expand All @@ -71,6 +78,8 @@ export const setMeasureModeSuccess = (state = INITIAL_STATE, { mode }) => ({ ...

export const setMeasureUnitsSuccess = (state = INITIAL_STATE, { units }) => ({ ...state, units });

export const setMeasureSlopeUnitsSuccess = (state = INITIAL_STATE, { slopeUnits }) => ({ ...state, slopeUnits });

export const setMeasureEdgeSnappingSuccess = (state = INITIAL_STATE, { edgeSnapping }) => ({ ...state, edgeSnapping });

export const setMeasureXyzDisplaySuccess = (state = INITIAL_STATE, { xyzDisplay }) => ({ ...state, xyzDisplay });
Expand All @@ -83,6 +92,7 @@ export const clearMeasurementsSuccess = (state = INITIAL_STATE) => ({
lengthMeasurements: INITIAL_STATE.lengthMeasurements,
pointMeasurements: INITIAL_STATE.pointMeasurements,
angleMeasurements: INITIAL_STATE.angleMeasurements,
slopeMeasurements: INITIAL_STATE.slopeMeasurements,
});

export const removeMeasurementSuccess = (state = INITIAL_STATE, { uuid }) => ({
Expand All @@ -91,6 +101,7 @@ export const removeMeasurementSuccess = (state = INITIAL_STATE, { uuid }) => ({
lengthMeasurements: state.lengthMeasurements.filter((measurement) => measurement.uuid !== uuid),
pointMeasurements: state.pointMeasurements.filter((measurement) => measurement.uuid !== uuid),
angleMeasurements: state.angleMeasurements.filter((measurement) => measurement.uuid !== uuid),
slopeMeasurements: state.slopeMeasurements.filter((measurement) => measurement.uuid !== uuid),
});

export const addMeasurementSuccess = (state = INITIAL_STATE, { measurement }) => {
Expand Down Expand Up @@ -120,6 +131,8 @@ export const setMeasurementColorSuccess = (state = INITIAL_STATE, { uuid, color
const lengthMeasurement = state.lengthMeasurements.find((measure) => measure.uuid === uuid);
const pointMeasurement = state.pointMeasurements.find((measure) => measure.uuid === uuid);
const angleMeasurement = state.angleMeasurements.find((measure) => measure.uuid === uuid);
const slopeMeasurement = state.slopeMeasurements.find((measure) => measure.uuid === uuid);


if (areaMeasurement) {
areaMeasurement.customColor = color;
Expand All @@ -133,6 +146,9 @@ export const setMeasurementColorSuccess = (state = INITIAL_STATE, { uuid, color
} else if (angleMeasurement) {
angleMeasurement.customColor = color;
return ({ ...state, angleMeasurements: [...state.angleMeasurements]});
} else if (slopeMeasurement) {
slopeMeasurement.customColor = color;
return ({ ...state, slopeMeasurements: [...state.slopeMeasurements]});
}

return ({ ...state });
Expand All @@ -144,19 +160,22 @@ export const resetMeasurementColorsSuccess = (state = INITIAL_STATE, {}) => {
const lengthMeasurements = state.lengthMeasurements.map(removeCustomColor);
const pointMeasurements = state.pointMeasurements.map(removeCustomColor);
const angleMeasurements = state.angleMeasurements.map(removeCustomColor);
const slopeMeasurements = state.slopeMeasurements.map(removeCustomColor);

return ({
...state,
areaMeasurements,
lengthMeasurements,
pointMeasurements,
angleMeasurements,
slopeMeasurements,
});
};

export const reducer = createReducer(INITIAL_STATE, {
[MeasurementsTypes.SET_MEASURE_MODE_SUCCESS]: setMeasureModeSuccess,
[MeasurementsTypes.SET_MEASURE_UNITS_SUCCESS]: setMeasureUnitsSuccess,
[MeasurementsTypes.SET_MEASURE_SLOPE_UNITS_SUCCESS]: setMeasureSlopeUnitsSuccess,
[MeasurementsTypes.ADD_MEASUREMENT_SUCCESS]: addMeasurementSuccess,
[MeasurementsTypes.CLEAR_MEASUREMENTS_SUCCESS]: clearMeasurementsSuccess,
[MeasurementsTypes.REMOVE_MEASUREMENT_SUCCESS]: removeMeasurementSuccess,
Expand Down
21 changes: 20 additions & 1 deletion frontend/src/v4/modules/measurements/measurements.sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { dispatch } from '@/v5/helpers/redux.helpers';
MeasurementsTypes,
selectXyzDisplay,
selectAngleMeasurements,
selectSlopeMeasurements,
} from './';

const onMeasurementCreated = (measure) => {
Expand Down Expand Up @@ -95,6 +96,17 @@ export function* setMeasureUnits({ units }) {
}
}

export function* setMeasureSlopeUnits({ slopeUnits }) {
try {
yield all([
Viewer.setMeasuringSlopeUnits(slopeUnits),
put(MeasurementsActions.setMeasureSlopeUnitsSuccess(slopeUnits))
]);
} catch (error) {
DialogActions.showErrorDialog('set', `measure slope slopeUnits to ${slopeUnits}`, error);
}
}

export function* addMeasurement({ measurement }) {
try {
const measurementStateName = MEASURE_TYPE_STATE_MAP[measurement.type];
Expand Down Expand Up @@ -146,6 +158,7 @@ export function* resetMeasurementColors() {
const lengthMeasurements = yield select(selectLengthMeasurements);
const pointMeasurements = yield select(selectPointMeasurements);
const angleMeasurements = yield select(selectAngleMeasurements);
const slopeMeasurements = yield select(selectSlopeMeasurements);

const setDefaultColor = async ({ uuid, color }) => {
await Viewer.setMeasurementColor(uuid, color);
Expand All @@ -167,6 +180,10 @@ export function* resetMeasurementColors() {
angleMeasurements.forEach(setDefaultColor);
}

if (slopeMeasurements.length) {
slopeMeasurements.forEach(setDefaultColor);
}

yield put(MeasurementsActions.resetMeasurementColorsSuccess());
} catch (error) {
DialogActions.showErrorDialog('set color', 'measure', error);
Expand Down Expand Up @@ -206,8 +223,9 @@ export function* clearMeasurements() {
const areaMeasurements = yield select(selectAreaMeasurements);
const lengthMeasurements = yield select(selectLengthMeasurements);
const angleMeasurements = yield select(selectAngleMeasurements);
const slopeMeasurements = yield select(selectSlopeMeasurements);

[...areaMeasurements, ...lengthMeasurements, ...angleMeasurements].forEach(({uuid}) => Viewer.removeMeasurement(uuid));
[...areaMeasurements, ...lengthMeasurements, ...angleMeasurements, ...slopeMeasurements].forEach(({uuid}) => Viewer.removeMeasurement(uuid));
yield put(MeasurementsActions.clearMeasurementsSuccess());
} catch (error) {
DialogActions.showErrorDialog('clear', 'measurements', error);
Expand All @@ -227,6 +245,7 @@ export function* resetMeasurementTool() {
export default function* MeasurementsSaga() {
yield takeLatest(MeasurementsTypes.SET_MEASURE_MODE, setMeasureMode);
yield takeLatest(MeasurementsTypes.SET_MEASURE_UNITS, setMeasureUnits);
yield takeLatest(MeasurementsTypes.SET_MEASURE_SLOPE_UNITS, setMeasureSlopeUnits);
yield takeLatest(MeasurementsTypes.ADD_MEASUREMENT, addMeasurement);
yield takeLatest(MeasurementsTypes.REMOVE_MEASUREMENT, removeMeasurement);
yield takeLatest(MeasurementsTypes.CLEAR_MEASUREMENTS, clearMeasurements);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export const selectMeasureUnits = createSelector(
selectMeasurementsDomain, (state) => state.units
);

export const selectMeasureSlopeUnits = createSelector(
selectMeasurementsDomain, (state) => state.slopeUnits
);

export const selectEdgeSnapping = createSelector(
selectMeasurementsDomain, (state) => state.edgeSnapping
);
Expand All @@ -51,6 +55,10 @@ export const selectAngleMeasurements = createSelector(
selectMeasurementsDomain, (state) => state.angleMeasurements
);

export const selectSlopeMeasurements = createSelector(
selectMeasurementsDomain, (state) => state.slopeMeasurements
);

export const selectPins = createSelector(
selectPointMeasurements, (state) =>
state.map(({ customColor, ...measure }) => {
Expand Down
Loading

0 comments on commit fd61405

Please sign in to comment.