Move measure button to the toolbar.

This commit is contained in:
kovacsv 2022-02-20 14:35:24 +01:00
parent b4febdcfc2
commit f18748f5e6
8 changed files with 125 additions and 217 deletions

View File

@ -65,7 +65,6 @@ import { HasHighpDriverIssue, GetShadingType, ConvertThreeColorToColor, ConvertC
import { Camera, CameraIsEqual3D } from './viewer/camera.js';
import { GetIntegerFromStyle, GetDomElementExternalWidth, GetDomElementExternalHeight, GetDomElementInnerDimensions, GetDomElementClientCoordinates, CreateDomElement, AddDomElement, AddDiv, ClearDomElement, InsertDomElementBefore, InsertDomElementAfter, ShowDomElement, IsDomElementVisible, SetDomElementWidth, SetDomElementHeight, GetDomElementOuterWidth, GetDomElementOuterHeight, SetDomElementOuterWidth, SetDomElementOuterHeight, AddCheckbox, AddRangeSlider, AddSelect, AddToggle, CreateDiv } from './viewer/domutils.js';
import { EmbeddedViewer, Init3DViewerElement, Init3DViewerElements } from './viewer/embeddedviewer.js';
import { MeasureTool } from './viewer/measuretool.js';
import { MouseInteraction, TouchInteraction, ClickDetector, Navigation, NavigationType } from './viewer/navigation.js';
import { UpVector, ShadingModel, Viewer, GetDefaultCamera, TraverseThreeObject, GetShadingTypeOfObject } from './viewer/viewer.js';
import { ViewerGeometry, ViewerExtraGeometry, SetThreeMeshPolygonOffset } from './viewer/viewergeometry.js';
@ -301,7 +300,6 @@ export {
EmbeddedViewer,
Init3DViewerElement,
Init3DViewerElements,
MeasureTool,
MouseInteraction,
TouchInteraction,
ClickDetector,

View File

@ -1,20 +1,21 @@
import { BigEps, IsEqualEps } from '../geometry/geometry.js';
import { BigEps, IsEqualEps } from '../engine/geometry/geometry.js';
import { AddDiv } from '../engine/viewer/domutils.js';
export class MeasureTool
{
constructor ()
{
this.viewer = null;
this.highlightColor = null;
this.isActive = false;
this.markers = [];
}
Init (viewer, highlightColor)
constructor (viewer)
{
this.viewer = viewer;
this.highlightColor = highlightColor;
this.isActive = false;
this.markers = [];
this.panel = null;
this.button = null;
}
SetButton (button)
{
this.button = button;
}
IsActive ()
@ -24,9 +25,18 @@ export class MeasureTool
SetActive (isActive)
{
if (this.isActive === isActive) {
return;
}
this.isActive = isActive;
if (!this.isActive) {
this.Clear ();
this.button.SetSelected (isActive);
if (this.isActive) {
this.panel = AddDiv (document.body, 'ov_measure_panel', 'hejj');
this.UpdatePanel ();
this.Resize ();
} else {
this.ClearMarkers ();
this.panel.remove ();
}
}
@ -34,20 +44,17 @@ export class MeasureTool
{
let intersection = this.viewer.GetMeshIntersectionUnderMouse (mouseCoordinates);
if (intersection === null) {
this.Clear ();
this.ClearMarkers ();
this.UpdatePanel ();
return;
}
if (this.markers.length === 2) {
this.Clear ();
this.ClearMarkers ();
}
this.AddMarker (intersection);
}
GetMarkerCount ()
{
return this.markers.length;
this.UpdatePanel ();
}
AddMarker (intersection)
@ -56,6 +63,53 @@ export class MeasureTool
this.GenerateMarker (intersection);
}
GenerateMarker (intersection)
{
let boundingSphere = this.viewer.GetBoundingSphere ((meshUserData) => {
return true;
});
let coneHeight = boundingSphere.radius / 5.0;
let coneRadius = coneHeight / 2.0;
let coneGeometry = new THREE.ConeGeometry (coneRadius, coneHeight, 32);
coneGeometry.translate (0.0, -coneHeight / 2.0, 0.0);
coneGeometry.rotateX (-Math.PI / 2);
let coneMaterial = this.viewer.CreateHighlightMaterial (0xcc0000);
coneMaterial.opacity = 0.6;
coneMaterial.transparent = true;
let cone = new THREE.Mesh (coneGeometry, coneMaterial);
let faceNormal = this.GetFaceWorldNormal (intersection);
cone.lookAt (faceNormal);
cone.position.set (intersection.point.x, intersection.point.y, intersection.point.z);
this.viewer.AddExtraObject (cone);
}
GetFaceWorldNormal (intersection)
{
let normalMatrix = new THREE.Matrix4 ();
intersection.object.updateWorldMatrix (true, false);
normalMatrix.extractRotation (intersection.object.matrixWorld);
let faceNormal = intersection.face.normal.clone ();
faceNormal.applyMatrix4 (normalMatrix);
return faceNormal;
}
UpdatePanel ()
{
if (this.markers.length === 0) {
this.panel.innerHTML = 'Select a point to start measuring.';
} else if (this.markers.length === 1) {
this.panel.innerHTML = 'Select another point to start measuring.';
} else {
let calcResult = this.Calculate ();
this.panel.innerHTML = JSON.stringify (calcResult);
}
}
Calculate ()
{
if (this.markers.length !== 2) {
@ -81,44 +135,20 @@ export class MeasureTool
return result;
}
Clear ()
Resize ()
{
if (!this.isActive) {
return;
}
let canvas = this.viewer.GetCanvas ();
let rect = canvas.getBoundingClientRect ();
this.panel.style.left = rect.left + 'px';
this.panel.style.top = rect.top + 'px';
}
ClearMarkers ()
{
this.viewer.ClearExtra ();
this.markers = [];
}
GenerateMarker (intersection)
{
let boundingSphere = this.viewer.GetBoundingSphere ((meshUserData) => {
return true;
});
let coneHeight = boundingSphere.radius / 5.0;
let coneRadius = coneHeight / 2.0;
let coneGeometry = new THREE.ConeGeometry (coneRadius, coneHeight, 32);
coneGeometry.translate (0.0, -coneHeight / 2.0, 0.0);
coneGeometry.rotateX (-Math.PI / 2);
let coneMaterial = this.viewer.CreateHighlightMaterial (this.highlightColor);
coneMaterial.opacity = 0.6;
coneMaterial.transparent = true;
let cone = new THREE.Mesh (coneGeometry, coneMaterial);
let faceNormal = this.GetFaceWorldNormal (intersection);
cone.lookAt (faceNormal);
cone.position.set (intersection.point.x, intersection.point.y, intersection.point.z);
this.viewer.AddExtraObject (cone);
}
GetFaceWorldNormal (intersection)
{
let normalMatrix = new THREE.Matrix4 ();
intersection.object.updateWorldMatrix (true, false);
normalMatrix.extractRotation (intersection.object.matrixWorld);
let faceNormal = intersection.face.normal.clone ();
faceNormal.applyMatrix4 (normalMatrix);
return faceNormal;
}
}

View File

@ -1,14 +1,12 @@
import { ShowDomElement, SetDomElementWidth, SetDomElementHeight, GetDomElementOuterWidth, SetDomElementOuterHeight } from '../engine/viewer/domutils.js';
import { FeatureSet } from './featureset.js';
import { PanelSet } from './panelset.js';
import { SidebarDetailsPanel } from './sidebardetailspanel.js';
import { SidebarMeasurePanel } from './sidebarmeasurepanel.js';
import { SidebarSettingsPanel } from './sidebarsettingspanel.js';
import { InstallVerticalSplitter } from './utils.js';
export class Sidebar
{
constructor (mainDiv, splitterDiv, settings, measureTool)
constructor (mainDiv, splitterDiv, settings)
{
this.mainDiv = mainDiv;
this.splitterDiv = splitterDiv;
@ -16,13 +14,9 @@ export class Sidebar
this.detailsPanel = new SidebarDetailsPanel (this.panelSet.GetContentDiv ());
this.settingsPanel = new SidebarSettingsPanel (this.panelSet.GetContentDiv (), settings);
this.measurePanel = new SidebarMeasurePanel (this.panelSet.GetContentDiv (), measureTool);
this.panelSet.AddPanel (this.detailsPanel);
this.panelSet.AddPanel (this.settingsPanel);
if (FeatureSet.MeasureTool) {
this.panelSet.AddPanel (this.measurePanel);
}
this.panelSet.ShowPanel (this.detailsPanel);
}
@ -71,12 +65,6 @@ export class Sidebar
}
});
this.measurePanel.Init ({
onActivatedChange : (isActivated) => {
this.callbacks.onMeasureToolActivedChange (isActivated);
}
});
InstallVerticalSplitter (this.splitterDiv, this.mainDiv, true, () => {
this.callbacks.onResize ();
});
@ -87,11 +75,6 @@ export class Sidebar
this.settingsPanel.UpdateSettings (isPhysicallyBased, hasDefaultMaterial);
}
UpdateMeasureTool ()
{
this.measurePanel.UpdateMeasureTool ();
}
Resize (height)
{
SetDomElementOuterHeight (this.mainDiv, height);

View File

@ -1,114 +0,0 @@
import { RadDeg } from '../engine/geometry/geometry.js';
import { AddDiv, ShowDomElement, ClearDomElement } from '../engine/viewer/domutils.js';
import { SidebarPanel } from './sidebarpanel.js';
export class SidebarMeasurePanel extends SidebarPanel
{
constructor (parentDiv, measureTool)
{
super (parentDiv);
this.measureTool = measureTool;
this.helpSection = null;
this.resultSection = null;
}
GetName ()
{
return 'Measure';
}
GetIcon ()
{
return 'measure';
}
Init (callbacks)
{
super.Init (callbacks);
let isActive = false;
let activateButton = AddDiv (this.contentDiv, 'ov_button ov_panel_button', 'Activate');
activateButton.addEventListener ('click', () => {
isActive = !isActive;
if (isActive) {
activateButton.classList.add ('outline');
activateButton.innerHTML = 'Deactivate';
} else {
activateButton.classList.remove ('outline');
activateButton.innerHTML = 'Activate';
}
this.callbacks.onActivatedChange (isActive);
});
this.helpSection = AddDiv (this.contentDiv, 'ov_sidebar_section');
this.resultSection = AddDiv (this.contentDiv, 'ov_sidebar_section');
this.helpSection.innerHTML = this.GetDefaultHelpText ();
}
UpdateMeasureTool ()
{
ClearDomElement (this.helpSection);
ClearDomElement (this.resultSection);
ShowDomElement (this.helpSection, true);
ShowDomElement (this.resultSection, false);
if (this.measureTool.IsActive ()) {
let markerCount = this.measureTool.GetMarkerCount ();
if (markerCount === 0) {
this.helpSection.innerHTML = 'Click on a model point to start measure.';
} else if (markerCount === 1) {
this.helpSection.innerHTML = 'Click on another model point to see the results.';
} else if (markerCount === 2) {
ShowDomElement (this.helpSection, false);
ShowDomElement (this.resultSection, true);
let calculatedValues = this.measureTool.Calculate ();
AddDiv (this.resultSection, 'ov_sidebar_measure_name', 'Distance of points');
let pointsDistanceStr = calculatedValues.pointsDistance.toLocaleString (undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 4
});
AddDiv (this.resultSection, 'ov_sidebar_measure_value', pointsDistanceStr);
AddDiv (this.resultSection, 'ov_sidebar_measure_name', 'Distance of parallel faces');
if (calculatedValues.parallelFacesDistance !== null) {
let facesDistanceStr = calculatedValues.parallelFacesDistance.toLocaleString (undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 4
});
AddDiv (this.resultSection, 'ov_sidebar_measure_value', facesDistanceStr);
} else {
AddDiv (this.resultSection, 'ov_sidebar_measure_value', 'Faces are not parallel');
}
AddDiv (this.resultSection, 'ov_sidebar_measure_name', 'Angle of faces');
let facesAngleDegree = calculatedValues.facesAngle * RadDeg;
let facesAngleStr = facesAngleDegree.toLocaleString (undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 4
});
AddDiv (this.resultSection, 'ov_sidebar_measure_value', facesAngleStr + '°');
}
} else {
this.helpSection.innerHTML = this.GetDefaultHelpText ();
}
}
GetDefaultHelpText ()
{
return `<ol>
<li>Activate measure mode with the button above.</li>
<li>Click two points in the model to see the results.</li>
</ol>`;
}
Clear ()
{
}
}

View File

@ -78,7 +78,7 @@ export class Toolbar
{
let button = new ToolbarButton (image, imageTitle, () => {
button.SetSelected (!button.IsSelected ());
onClick ();
onClick (button.IsSelected ());
});
button.AddDomElements (this.mainDiv);
button.SetSelected (isSelected);

View File

@ -1,7 +1,6 @@
import { FileSource, GetFileExtension, TransformFileHostUrls } from '../engine/io/fileutils.js';
import { ImportErrorCode, ImportSettings } from '../engine/import/importer.js';
import { Viewer } from '../engine/viewer/viewer.js';
import { MeasureTool } from '../engine/viewer/measuretool.js';
import { AddDiv, AddDomElement, ShowDomElement, SetDomElementOuterHeight } from '../engine/viewer/domutils.js';
import { CalculatePopupPositionToScreen, ShowListPopup } from './dialogs.js';
import { HandleEvent } from './eventhandler.js';
@ -20,6 +19,8 @@ import { HasDefaultMaterial, ReplaceDefaultMaterialColor } from '../engine/model
import { Direction } from '../engine/geometry/geometry.js';
import { CookieGetBoolVal, CookieSetBoolVal } from './cookiehandler.js';
import { ShadingType } from '../engine/threejs/threeutils.js';
import { FeatureSet } from './featureset.js';
import { MeasureTool } from './measuretool.js';
export const WebsiteUIState =
{
@ -36,11 +37,11 @@ export class Website
this.parameters = parameters;
this.settings = new Settings ();
this.viewer = new Viewer ();
this.measureTool = new MeasureTool ();
this.measureTool = new MeasureTool (this.viewer);
this.hashHandler = new HashHandler ();
this.toolbar = new Toolbar (this.parameters.toolbarDiv);
this.navigator = new Navigator (this.parameters.navigatorDiv, this.parameters.navigatorSplitterDiv);
this.sidebar = new Sidebar (this.parameters.sidebarDiv, this.parameters.sidebarSplitterDiv, this.settings, this.measureTool);
this.sidebar = new Sidebar (this.parameters.sidebarDiv, this.parameters.sidebarSplitterDiv, this.settings);
this.modelLoaderUI = new ThreeModelLoaderUI ();
this.themeHandler = new ThemeHandler ();
this.highlightColor = new THREE.Color (0x8ec9f0);
@ -56,7 +57,6 @@ export class Website
HandleEvent ('theme_on_load', this.settings.themeId === Theme.Light ? 'light' : 'dark');
this.InitViewer ();
this.InitMeasureTool ();
this.InitToolbar ();
this.InitDragAndDrop ();
this.InitSidebar ();
@ -109,6 +109,7 @@ export class Website
this.navigator.Resize (contentHeight);
this.sidebar.Resize (contentHeight);
this.viewer.Resize (contentWidth - safetyMargin, contentHeight);
this.measureTool.Resize ();
}
OnSmallWidthChanged ()
@ -166,8 +167,7 @@ export class Website
this.navigator.Clear ();
this.sidebar.Clear ();
this.measureTool.Clear ();
this.sidebar.UpdateMeasureTool ();
this.measureTool.SetActive (false);
}
OnModelLoaded (importResult, threeObject)
@ -189,7 +189,6 @@ export class Website
if (this.measureTool.IsActive ()) {
this.measureTool.Click (mouseCoordinates);
this.sidebar.UpdateMeasureTool ();
return;
}
@ -484,11 +483,6 @@ export class Website
this.UpdateEnvironmentMap ();
}
InitMeasureTool ()
{
this.measureTool.Init (this.viewer, this.highlightColor);
}
InitToolbar ()
{
function AddButton (toolbar, imageName, imageTitle, classNames, onClick)
@ -502,6 +496,17 @@ export class Website
return button;
}
function AddPushButton (toolbar, imageName, imageTitle, classNames, onClick)
{
let button = toolbar.AddImagePushButton (imageName, imageTitle, false, (isSelected) => {
onClick (isSelected);
});
for (let className of classNames) {
button.AddClass (className);
}
return button;
}
function AddRadioButton (toolbar, imageNames, imageTitles, selectedIndex, classNames, onClick)
{
let imageData = [];
@ -566,6 +571,15 @@ export class Website
this.viewer.SetFixUpVector (false);
}
});
if (FeatureSet.MeasureTool) {
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
let measureToolButton = AddPushButton (this.toolbar, 'measure', 'Measure', ['only_full_width', 'only_on_model'], (isSelected) => {
HandleEvent ('measure_tool_activated', isSelected ? 'on' : 'off');
this.navigator.SetSelection (null);
this.measureTool.SetActive (isSelected);
});
this.measureTool.SetButton (measureToolButton);
}
AddSeparator (this.toolbar, ['only_full_width', 'only_on_model']);
AddButton (this.toolbar, 'export', 'Export model', ['only_full_width', 'only_on_model'], () => {
let exportDialog = new ExportDialog ({
@ -645,7 +659,7 @@ export class Website
HandleEvent ('theme_changed', this.settings.themeId === Theme.Light ? 'light' : 'dark');
this.SwitchTheme (this.settings.themeId, true);
},
onMeasureToolActivedChange : (isActivated) => {
/* onMeasureToolActivedChange : (isActivated) => {
if (isActivated) {
this.navigator.SetSelection (null);
this.measureTool.SetActive (true);
@ -653,7 +667,7 @@ export class Website
this.measureTool.SetActive (false);
}
this.sidebar.UpdateMeasureTool ();
},
},*/
onResize : () => {
this.Resize ();
},

View File

@ -83,17 +83,6 @@ div.ov_sidebar_content div.ov_sidebar_settings_padded
overflow: hidden;
}
div.ov_sidebar_content div.ov_sidebar_measure_name
{
font-weight: bold;
margin-bottom: 5px;
}
div.ov_sidebar_content div.ov_sidebar_measure_value
{
margin-bottom: 10px;
}
div.ov_sidebar_content button.pcr-button
{
width: 30px;

View File

@ -271,6 +271,14 @@ div.ov_bottom_floating_panel div.ov_floating_panel_button
float: right;
}
div.ov_measure_panel
{
background: red;
position: absolute;
left : 0px;
top : 0px;
}
@media (hover)
{