#ifndef __MeasurementsApplication_HeaderFile
#define __MeasurementsApplication_HeaderFile
#include "../baseviewer/BaseViewerApplication.hxx"
#include <cadex/Base_AngleUnit.hxx>
#include <cadex/Base_LengthUnit.hxx>
#include <cadex/ModelData_Shape.hxx>
#include <cadex/ModelPrs_Measurement.hxx>
#include <cadex/ModelPrs_MeasurementType.hxx>
#include <cadex/ModelPrs_SelectionChangesObserver.hxx>
class ModelPrs_Selection;
class ModelPrs_SceneNode;
}
class MeasurementsApplication;
{
public:
SelectionChangesObserver (MeasurementsApplication& theApplication);
void Clear();
private:
MeasurementsApplication& myApplication;
std::vector<cadex::ModelData_Shape> myShapes;
};
class MeasurementInfo : public QObject
{
Q_OBJECT
Q_PROPERTY (int numberOfSelectedShapes MEMBER myNumberOfSelectedShapes WRITE setNumberOfSelectedShapes NOTIFY numberOfSelectedShapesChanged)
Q_PROPERTY (QString measurementsResults MEMBER myMeasurementsResults WRITE setMeasurementsResults NOTIFY measurementsResultsChanged)
public:
MeasurementInfo (MeasurementsApplication* theParent);
void setNumberOfSelectedShapes (int theValue);
void setMeasurementsResults (const QString& theValue);
signals:
void numberOfSelectedShapesChanged();
void measurementsResultsChanged();
private:
int myNumberOfSelectedShapes = 0;
QString myMeasurementsResults;
};
class MeasurementsApplication : public BaseViewerApplication
{
Q_OBJECT
public:
MeasurementsApplication();
void OnSelectionChanged (const std::vector<cadex::ModelData_Shape>& theShapes);
public slots:
void onInitialized();
void onMeasurementModeChanged (const QVariant& theMode);
void onMeasurementAngleUnitsChanged (const QVariant& theIndex);
void onMeasurementLengthUnitsChanged (const QVariant& theIndex);
protected:
void Clear() override;
void UpdateResult();
protected:
SelectionChangesObserver mySelectionObserver;
double myMeasurementSize;
cadex::Base_AngleUnit myAngleUnit;
std::vector<cadex::ModelPrs_Measurement> myMeasurements;
MeasurementInfo* myMeasurementInfo;
};
#endif
Represents a node in the visual scene graph.
Definition: ModelPrs_SceneNode.hxx:44
Defines an observer on selection events.
Definition: ModelPrs_SelectionChangesObserver.hxx:30
virtual void SelectionChangedByManager(const ModelPrs_Selection &theCurrent, const ModelPrs_Selection &theSelected, const ModelPrs_Selection &theDeselected)=0
The method is invoked when the source of the selection event is the manager's method call.
virtual void SelectionChangedByScene(const ModelPrs_Selection &theCurrent, const ModelPrs_Selection &theSelected, const ModelPrs_Selection &theDeselected)=0
The method is invoked when the source of the selection event is mouse click on the scene.
Encapsulates a container of selected scene nodes.
Definition: ModelPrs_Selection.hxx:41
Defines classes, types, and global functions related to CAD Exchanger.
Definition: A3DSTestLib.hxx:22
Base_LengthUnit
Length units used in exporters.
Definition: Base_LengthUnit.hxx:26
ModelPrs_MeasurementType
Defines a type of created measurement.
Definition: ModelPrs_MeasurementType.hxx:25
#include "MeasurementsApplication.hxx"
#include <cadex/ModelAlgo_BoundingBox.hxx>
#include <cadex/ModelAlgo_TransformationApplier.hxx>
#include <cadex/ModelData_Appearance.hxx>
#include <cadex/ModelData_Box.hxx>
#include <cadex/ModelData_Color.hxx>
#include <cadex/ModelData_Face.hxx>
#include <cadex/ModelData_Transformation.hxx>
#include <cadex/ModelData_Vertex.hxx>
#include <cadex/ModelPrsQtQuick_ViewPort.hxx>
#include <cadex/ModelPrs_Geometry.hxx>
#include <cadex/ModelPrs_Measurement.hxx>
#include <cadex/ModelPrs_MeasurementFactory.hxx>
#include <cadex/ModelPrs_SceneNode.hxx>
#include <cadex/ModelPrs_SceneNodeFactory.hxx>
#include <cadex/ModelPrs_Selection.hxx>
#include <cadex/ModelPrs_SelectionManager.hxx>
#include <cadex/ModelPrs_SelectionVisitor.hxx>
#include <QtCore/QDebug>
#include <QtQuick/QQuickWindow>
#include <deque>
#include <memory>
namespace {
{
public:
{
}
{
auto aParent = theNode.
Parent();
while (aParent) {
aParent = aParent.Parent();
}
myShape = theShapes.
First();
myShape = ModelAlgo_TransformationApplier::Transform (myShape, aTrsf);
}
};
{
switch (theType) {
case ModelPrs_MT_Radius:
case ModelPrs_MT_Diameter:
return 1;
case ModelPrs_MT_Distance:
case ModelPrs_MT_AngleBetweenPlanes:
return 2;
case ModelPrs_MT_AngleBetweenVertexes:
return 3;
default:
return 0;
}
}
{
switch (theType) {
case ModelPrs_MT_Radius:
case ModelPrs_MT_Diameter:
return ModelPrs_SM_Face | ModelPrs_SM_Edge;
case ModelPrs_MT_Distance:
return ModelPrs_SM_Vertex | ModelPrs_SM_Edge | ModelPrs_SM_Face;
case ModelPrs_MT_AngleBetweenPlanes:
return ModelPrs_SM_Face;
case ModelPrs_MT_AngleBetweenVertexes:
return ModelPrs_SM_Vertex;
default:
return ModelPrs_SM_None;
}
}
{
switch (theType) {
case ModelPrs_MT_Radius:
case ModelPrs_MT_Diameter:
return ModelPrs_SFT_CircleEdgeFilter | ModelPrs_SFT_RevolFaceFilter;
case ModelPrs_MT_AngleBetweenPlanes:
return ModelPrs_SFT_PlanarFaceFilter;
case ModelPrs_MT_Distance:
case ModelPrs_MT_AngleBetweenVertexes:
default:
return ModelPrs_SFT_None;
}
}
std::vector<ModelPrs_Measurement> CreateMeasurements (const std::vector<cadex::ModelData_Shape>& theShapes,
{
std::vector<ModelPrs_Measurement> aMeasurements;
switch (theType) {
case ModelPrs_MT_Radius: {
if (aMinorRadius) {
aMeasurements.push_back (aMinorRadius);
}
if (aMajorRadius && aMinorRadius != aMajorRadius) {
aMeasurements.push_back (aMajorRadius);
}
break;
}
case ModelPrs_MT_Diameter: {
if (aMinorDiameter) {
aMeasurements.push_back (aMinorDiameter);
}
if (aMajorDiameter && aMinorDiameter != aMajorDiameter) {
aMeasurements.push_back (aMajorDiameter);
}
break;
}
case ModelPrs_MT_Distance: {
auto aDistance = aFactory.
CreateDistance (theShapes[0], theShapes[1]);
if (aDistance) {
aMeasurements.push_back (aDistance);
}
break;
}
case ModelPrs_MT_AngleBetweenPlanes: {
Q_ASSERT (theShapes[0].Type() == ModelData_ST_Face && theShapes[1].Type() == ModelData_ST_Face);
const auto& aFirstFace = ModelData_Face::Cast (theShapes[0]);
const auto& aSecondFace = ModelData_Face::Cast (theShapes[1]);
auto anAngle = aFactory.
CreateAngle (aFirstFace, aSecondFace);
if (anAngle) {
aMeasurements.push_back (anAngle);
}
break;
}
case ModelPrs_MT_AngleBetweenVertexes: {
Q_ASSERT (theShapes[0].Type() == ModelData_ST_Vertex
&& theShapes[1].Type() == ModelData_ST_Vertex
&& theShapes[2].Type() == ModelData_ST_Vertex);
const auto& aFirstVertex = ModelData_Vertex::Cast (theShapes[0]);
const auto& aSecondVertex = ModelData_Vertex::Cast (theShapes[1]);
const auto& aThirdVertex = ModelData_Vertex::Cast (theShapes[2]);
auto anAngle = aFactory.
CreateAngle (aFirstVertex, aSecondVertex, aThirdVertex);
if (anAngle) {
aMeasurements.push_back (anAngle);
}
break;
}
default:
Q_ASSERT(false);
}
return aMeasurements;
}
}
SelectionChangesObserver::SelectionChangesObserver (MeasurementsApplication& theApplication)
: myApplication (theApplication)
{
}
{
Clear();
} else {
SelectionVisitor aVisitor;
myShapes.push_back (aVisitor.myShape);
}
myApplication.OnSelectionChanged (myShapes);
}
void SelectionChangesObserver::Clear()
{
myShapes.clear();
}
MeasurementInfo::MeasurementInfo (MeasurementsApplication* theParent)
: QObject (theParent)
{
}
void MeasurementInfo::setNumberOfSelectedShapes (int theValue)
{
if (myNumberOfSelectedShapes != theValue) {
myNumberOfSelectedShapes = theValue;
emit numberOfSelectedShapesChanged();
}
}
void MeasurementInfo::setMeasurementsResults (const QString& theValue)
{
if (myMeasurementsResults != theValue) {
myMeasurementsResults = theValue;
emit measurementsResultsChanged();
}
}
MeasurementsApplication::MeasurementsApplication()
: mySelectionObserver (*this),
myMeasurementSize (-1.),
myAngleUnit (Base_AU_Degree),
myLengthUnit (Base_LU_Millimeters)
{
myMeasurementInfo = new MeasurementInfo (this);
myScene.SelectionManager().Register (mySelectionObserver);
connect (this, &BaseViewerApplication::initialized, this, &MeasurementsApplication::onInitialized);
}
void MeasurementsApplication::onMeasurementModeChanged (const QVariant& theMode)
{
auto aSelectionMode = GetSelectionModeForMeasurement (myMeasurementMode);
auto aSelectionFilter = GetSelectionFilterForMeasurement (myMeasurementMode);
mySelectionObserver.Clear();
myRoot.RemoveChildNode (myRootMeasurementsNode);
myScene.Update();
}
void MeasurementsApplication::onMeasurementAngleUnitsChanged (const QVariant& theIndex)
{
myAngleUnit = static_cast<Base_AngleUnit> (theIndex.toInt());
UpdateResult();
myRootMeasurementsNode.Invalidate();
myScene.Update();
}
void MeasurementsApplication::onMeasurementLengthUnitsChanged (const QVariant& theIndex)
{
UpdateResult();
myRootMeasurementsNode.Invalidate();
myScene.Update();
}
namespace {
{
ModelAlgo_BoundingBox::Compute (theModel, aModelBoundingBox);
auto r = std::max ({ aModelBoundingBox.
XRange(),
aModelBoundingBox.
ZRange() });
return r / 16.;
} else {
return 10.;
}
}
}
void MeasurementsApplication::UpdateResult()
{
QStringList aResult;
for (auto& aMeasurement : myMeasurements) {
aMeasurement.SetAngleUnit (myAngleUnit);
aMeasurement.SetLengthUnit (myLengthUnit);
aResult.push_back (QString::number (aMeasurement.Value(), 'g', 3));
}
myMeasurementInfo->setMeasurementsResults (aResult.join ("; "));
}
void MeasurementsApplication::OnSelectionChanged (const std::vector<cadex::ModelData_Shape>& theShapes)
{
myMeasurementInfo->setNumberOfSelectedShapes (static_cast<int> (theShapes.size()));
if (theShapes.empty() || theShapes.size() < NumberOfRequiredShapes (myMeasurementMode)) {
return;
}
myMeasurements = CreateMeasurements (theShapes, myMeasurementMode);
UpdateResult();
if (myMeasurements.empty()) {
myMeasurementInfo->setNumberOfSelectedShapes (0);
mySelectionObserver.Clear();
return;
}
if (myMeasurementSize < 0) {
myMeasurementSize = ComputeMeasurementSize (myModel);
}
for (auto& aMeasurement : myMeasurements) {
aMeasurement.SetSize (myMeasurementSize);
auto aSceneNode = aFactory.
CreateNode (aMeasurement);
}
myScene.RemoveRoot (myRootMeasurementsNode);
myScene.AddRoot (aTempRootMeasureNode);
myScene.Update();
myRootMeasurementsNode = aTempRootMeasureNode;
mySelectionObserver.Clear();
}
void MeasurementsApplication::onInitialized()
{
connect (myMainWindow, SIGNAL (measurementModeChanged (const QVariant&)),
this, SLOT (onMeasurementModeChanged (const QVariant&)));
connect (myMainWindow, SIGNAL (measurementAngleUnitsChanged (const QVariant&)),
this, SLOT (onMeasurementAngleUnitsChanged (const QVariant&)));
connect (myMainWindow, SIGNAL (measurementLengthUnitsChanged (const QVariant&)),
this, SLOT (onMeasurementLengthUnitsChanged (const QVariant&)));
myMainWindow->setProperty ("model", QVariant::fromValue (myMeasurementInfo));
}
void MeasurementsApplication::Clear()
{
myMeasurementSize = -1.;
myMeasurementInfo->setNumberOfSelectedShapes (0);
myMeasurementInfo->setMeasurementsResults("");
myScene.RemoveRoot (myRootMeasurementsNode);
BaseViewerApplication::Clear();
}
bool IsNull() const
Returns true if the object is nullified.
Definition: Base_PublicObject.cxx:46
Defines a 3D axis-aligned bounding box.
Definition: ModelData_Box.hxx:31
double ZRange() const
Returns the length of range along Z axis.
Definition: ModelData_Box.hxx:91
bool IsInfinite() const
Returns true if at least one coordinate is infinite.
Definition: ModelData_Box.cxx:301
double YRange() const
Returns the length of range along Y axis.
Definition: ModelData_Box.hxx:89
double XRange() const
Returns the length of range along X axis.
Definition: ModelData_Box.hxx:87
Defines an RGBA color (with alpha channel).
Definition: ModelData_Color.hxx:34
Provides CAD Exchanger data model.
Definition: ModelData_Model.hxx:43
Base class of topological shapes.
Definition: ModelData_Shape.hxx:37
Defines a list of shapes.
Definition: ModelData_ShapeList.hxx:32
Creates measurement objects that store the sources and result of a measurement.
Definition: ModelPrs_MeasurementFactory.hxx:39
ModelPrs_Measurement CreateDistance(const ModelData_Shape &theFirstShape, const ModelData_Shape &theSecondShape)
Creates minimum distance measurement between any two shapes.
Definition: ModelPrs_MeasurementFactory.cxx:132
ModelPrs_Measurement CreateMajorDiameter(const ModelData_Shape &theShape)
Creates a diameter measurement of an edge or a face that might have such.
Definition: ModelPrs_MeasurementFactory.cxx:204
ModelPrs_Measurement CreateAngle(const ModelData_Face &theFirstFace, const ModelData_Face &theSecondFace)
Creates an angle measurement between two planar faces.
Definition: ModelPrs_MeasurementFactory.cxx:228
ModelPrs_Measurement CreateMajorRadius(const ModelData_Shape &theShape)
Creates a radius measurement of an edge or a face that might have such.
Definition: ModelPrs_MeasurementFactory.cxx:167
ModelPrs_Measurement CreateMinorDiameter(const ModelData_Shape &theShape)
Creates a diameter measurement of an edge or a face that might have such.
Definition: ModelPrs_MeasurementFactory.cxx:218
ModelPrs_Measurement CreateMinorRadius(const ModelData_Shape &theShape)
Creates a radius measurement of an edge or a face that might have such.
Definition: ModelPrs_MeasurementFactory.cxx:181
Creates a scene nodes and its children from input data model objects.
Definition: ModelPrs_SceneNodeFactory.hxx:53
ModelPrs_SceneNode CreateNode(const ModelData_DrawingElement &theDrawingElement)
Creates scene node using ModelData_DrawingElement.
Definition: ModelPrs_SceneNodeFactory.cxx:789
ModelData_Transformation Transformation() const
Returns transformation.
Definition: ModelPrs_SceneNode.cxx:900
bool AddChildNode(ModelPrs_SceneNode &theNode)
Adds theNode to children. Returns false if the node already has a parent, otherwise returns true.
Definition: ModelPrs_SceneNode.cxx:787
void SetAppearance(const ModelData_Appearance &theAppearance)
Definition: ModelPrs_SceneNode.cxx:894
ModelPrs_SceneNode Parent() const
Returns a parent of this.
Definition: ModelPrs_SceneNode.cxx:739
void Accept(ModelPrs_SelectionVisitor &theVisitor) const
Accepts a visitor.
Definition: ModelPrs_Selection.cxx:235
Defines a visitor of the selection object.
Definition: ModelPrs_SelectionVisitor.hxx:34
ModelPrs_SelectionFilterType
Defines filters for selection based on the entities' underlying geometry.
Definition: ModelPrs_SelectionFilterType.hxx:25
ModelPrs_SelectionMode
Defines a selection mode of the ModelPrs_SceneNode.
Definition: ModelPrs_SelectionMode.hxx:29
import QtQuick 2.12
import QtQuick.Controls 2.3
import CadEx 1.2
BaseViewerWindow {
signal measurementModeChanged (var index)
signal measurementAngleUnitsChanged (var index)
signal measurementLengthUnitsChanged (var index)
property var model: null
property int currentMeasurementMode: -1
property int numberOfRequiredShapes: 0
enum MeasurementType {
Distance,
Radius,
Diameter,
AngleBetweenPlanes,
AngleBetweenVertexes
}
function isAngleMeasure()
{
switch (currentMeasurementMode) {
case MeasurementsWindow.MeasurementType.Distance:
case MeasurementsWindow.MeasurementType.Radius:
case MeasurementsWindow.MeasurementType.Diameter:
return false;
case MeasurementsWindow.MeasurementType.AngleBetweenPlanes:
case MeasurementsWindow.MeasurementType.AngleBetweenVertexes:
return true;
}
}
function getShapesTypesString()
{
switch (currentMeasurementMode) {
case MeasurementsWindow.MeasurementType.Distance:
return "vertex, edge or face";
case MeasurementsWindow.MeasurementType.Radius:
case MeasurementsWindow.MeasurementType.Diameter:
return "edge or face";
case MeasurementsWindow.MeasurementType.AngleBetweenPlanes:
return "face";
case MeasurementsWindow.MeasurementType.AngleBetweenVertexes:
return "vertex";
}
}
function getNumberOfRequiredShapes()
{
switch (currentMeasurementMode) {
case MeasurementsWindow.MeasurementType.Distance:
return 2;
case MeasurementsWindow.MeasurementType.Radius:
case MeasurementsWindow.MeasurementType.Diameter:
return 1;
case MeasurementsWindow.MeasurementType.AngleBetweenPlanes:
return 2;
case MeasurementsWindow.MeasurementType.AngleBetweenVertexes:
return 3;
}
}
Menu {
id: measurementsTypeMenu
title: qsTr ("&Measurements")
property string currentMenuItemName: ""
width: angleBetweenVertexesMenuItem.width
ButtonGroup {
id: buttonGroup
buttons: measurementsTypeMenu.contentChildren
onCheckedButtonChanged: {
measurementsTypeMenu.currentMenuItemName = checkedButton.text;
currentMeasurementMode = checkedButton.mode;
}
}
MenuItem {
id: distanceMenuItem
text: qsTr ("Distance")
checkable: true
property var mode: MeasurementsWindow.MeasurementType.Distance
}
MenuItem {
id: radiusMenuItem
text: qsTr ("Radius")
checkable: true
property var mode: MeasurementsWindow.MeasurementType.Radius
}
MenuItem {
id: diameterMenuItem
text: qsTr ("Diameter")
checkable: true
property var mode: MeasurementsWindow.MeasurementType.Diameter;
}
MenuItem {
id: angleBetweenPlanesMenuItem
text: qsTr ("Angle between planes")
checkable: true
property var mode: MeasurementsWindow.MeasurementType.AngleBetweenPlanes
}
MenuItem {
id: angleBetweenVertexesMenuItem
text: qsTr ("Angle between vertexes")
checkable: true
property var mode: MeasurementsWindow.MeasurementType.AngleBetweenVertexes
}
}
onMenuCompleted: {
menuBarItem.addMenu (measurementsTypeMenu);
}
onCurrentMeasurementModeChanged: {
numberOfRequiredShapes = getNumberOfRequiredShapes();
model.numberOfSelectedShapes = 0;
measurementModeChanged (currentMeasurementMode);
}
Rectangle {
id: measurementBar
visible: currentMeasurementMode != -1
radius: 3
width: 300
height: column.implicitHeight
anchors.margins: 10
anchors.top: parent.top
anchors.right: parent.right
color: "#CCFFFFFF"
border.color: "#55000000"
readonly property string textColor: "#BB000000"
Column {
id: column
padding: 20
spacing: 20
width: parent.width
Text {
width: parent.width - 40
horizontalAlignment: Text.AlignHCenter
font.pointSize: 14
font.bold: true
color: measurementBar.textColor
text: measurementsTypeMenu.currentMenuItemName
}
Text {
visible: numberOfRequiredShapes != 0 && model.numberOfSelectedShapes !== numberOfRequiredShapes
text: !model ? " " : !model.numberOfSelectedShapes ? qsTr ("Select ") + getShapesTypesString()
: qsTr ("Selected ") + model.numberOfSelectedShapes +
qsTr (" of ") + numberOfRequiredShapes
font.pointSize: 13
font.italic: true
color: measurementBar.textColor
}
Text {
id: resultText
visible: !model ? "" : !model.numberOfSelectedShapes !== 0
&& model.numberOfSelectedShapes === numberOfRequiredShapes
&& model.measurementsResults !== ""
property string units: isAngleMeasure() ? "" : lengthUnitComboBox.currentText
text: !model ? "" : qsTr ("Result: ") + model.measurementsResults + units
font.pointSize: 13
color: measurementBar.textColor
}
Row {
visible: resultText.visible
Text {
text: qsTr ("Units: ")
font.pointSize: 13
color: measurementBar.textColor
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
id: lengthUnitComboBox
visible: resultText.visible && !isAngleMeasure()
model: ["mm", "cm", "m", "in", "ft", "yd"]
onCurrentIndexChanged: measurementLengthUnitsChanged (currentIndex);
}
ComboBox {
currentIndex: 1
visible: resultText.visible && isAngleMeasure()
model: ["rad", "deg"]
onCurrentIndexChanged: measurementAngleUnitsChanged (currentIndex);
}
}
}
}
}