diff --git a/src/app/widget_gui_document.cpp b/src/app/widget_gui_document.cpp index 66bc1c5e..5dde3114 100644 --- a/src/app/widget_gui_document.cpp +++ b/src/app/widget_gui_document.cpp @@ -365,7 +365,8 @@ ButtonFlat* WidgetGuiDocument::createViewBtn(QWidget* parent, Theme::Icon icon, const QColor bkgndColor = m_qtOccView->supportsWidgetOpacity() ? Qt::transparent : - mayoTheme()->color(Theme::Color::ButtonView3d_Background); + mayoTheme()->color(Theme::Color::ButtonView3d_Background) + ; auto btn = new ButtonFlat(parent); btn->setBackgroundBrush(bkgndColor); @@ -476,8 +477,10 @@ void WidgetGuiDocument::layoutViewControls() case Aspect_TOTP_LEFT_LOWER: return { ctrlXOffset, this->height() - viewCubeBndSize - margin - ctrlHeight }; case Aspect_TOTP_RIGHT_LOWER: - return { this->width() - viewCubeBndSize + ctrlXOffset, - this->height() - viewCubeBndSize - margin - ctrlHeight }; + return { + this->width() - viewCubeBndSize + ctrlXOffset, + this->height() - viewCubeBndSize - margin - ctrlHeight + }; default: return { margin, margin }; } // endswitch diff --git a/src/app/widget_measure.cpp b/src/app/widget_measure.cpp index 9a681677..237bb184 100644 --- a/src/app/widget_measure.cpp +++ b/src/app/widget_measure.cpp @@ -91,6 +91,10 @@ WidgetMeasure::WidgetMeasure(GuiDocument* guiDoc, QWidget* parent) m_ui->combo_AreaUnit, qOverload(&QComboBox::currentIndexChanged), this, &WidgetMeasure::onMeasureUnitsChanged ); + QObject::connect( + m_ui->combo_VolumeUnit, qOverload(&QComboBox::currentIndexChanged), + this, &WidgetMeasure::onMeasureUnitsChanged + ); this->onMeasureTypeChanged(m_ui->combo_MeasureType->currentIndex()); this->updateMessagePanel(); @@ -137,6 +141,7 @@ MeasureType WidgetMeasure::toMeasureType(int comboBoxId) case 5: return MeasureType::Angle; case 6: return MeasureType::Length; case 7: return MeasureType::Area; + case 8: return MeasureType::BoundingBox; } return MeasureType::None; } @@ -176,6 +181,21 @@ AreaUnit WidgetMeasure::toMeasureAreaUnit(int comboBoxId) return {}; } +VolumeUnit WidgetMeasure::toMeasureVolumeUnit(int comboBoxId) +{ + switch (comboBoxId) { + case 0: return VolumeUnit::CubicMillimeter; + case 1: return VolumeUnit::CubicCentimeter; + case 2: return VolumeUnit::CubicMeter; + case 3: return VolumeUnit::CubicInch; + case 4: return VolumeUnit::CubicFoot; + case 5: return VolumeUnit::Liter; + case 6: return VolumeUnit::ImperialGallon; + case 7: return VolumeUnit::USGallon; + } + return {}; +} + void WidgetMeasure::onMeasureTypeChanged(int id) { // Update widgets visibility @@ -183,12 +203,15 @@ void WidgetMeasure::onMeasureTypeChanged(int id) const bool measureIsLengthBased = measureType != MeasureType::Angle; const bool measureIsAngle = measureType == MeasureType::Angle; const bool measureIsArea = measureType == MeasureType::Area; + const bool measureIsVolume = measureType == MeasureType::BoundingBox; m_ui->label_LengthUnit->setVisible(measureIsLengthBased && !measureIsArea); - m_ui->combo_LengthUnit->setVisible(measureIsLengthBased && !measureIsArea); + m_ui->combo_LengthUnit->setVisible(m_ui->label_LengthUnit->isVisible()); m_ui->label_AngleUnit->setVisible(measureIsAngle); - m_ui->combo_AngleUnit->setVisible(measureIsAngle); + m_ui->combo_AngleUnit->setVisible(m_ui->label_AngleUnit->isVisible()); m_ui->label_AreaUnit->setVisible(measureIsArea); - m_ui->combo_AreaUnit->setVisible(measureIsArea); + m_ui->combo_AreaUnit->setVisible(m_ui->label_AreaUnit->isVisible()); + m_ui->label_VolumeUnit->setVisible(measureIsVolume); + m_ui->combo_VolumeUnit->setVisible(m_ui->label_VolumeUnit->isVisible()); auto gfxScene = m_guiDoc->graphicsScene(); @@ -239,6 +262,7 @@ MeasureDisplayConfig WidgetMeasure::currentMeasureDisplayConfig() const cfg.lengthUnit = WidgetMeasure::toMeasureLengthUnit(m_ui->combo_LengthUnit->currentIndex()); cfg.angleUnit = WidgetMeasure::toMeasureAngleUnit(m_ui->combo_AngleUnit->currentIndex()); cfg.areaUnit = WidgetMeasure::toMeasureAreaUnit(m_ui->combo_AreaUnit->currentIndex()); + cfg.volumeUnit = WidgetMeasure::toMeasureVolumeUnit(m_ui->combo_VolumeUnit->currentIndex()); cfg.doubleToStringOptions.locale = AppModule::get()->stdLocale(); cfg.doubleToStringOptions.decimalCount = AppModule::get()->defaultTextOptions().unitDecimals; cfg.devicePixelRatio = this->devicePixelRatioF(); @@ -335,8 +359,7 @@ void WidgetMeasure::onGraphicsSelectionChanged() measure->update(measureDisplayConfig); measure->adaptGraphics(gfxScene->v3dViewer()->Driver()); foreachGraphicsObject(measure, [=](const GraphicsObjectPtr& gfxObject) { - gfxObject->SetZLayer(Graphic3d_ZLayerId_Topmost); - gfxScene->addObject(gfxObject); + gfxScene->addObject(gfxObject, GraphicsScene::AddObjectDisableSelectionMode); }); m_vecMeasureDisplay.push_back(std::move(measure)); diff --git a/src/app/widget_measure.h b/src/app/widget_measure.h index f451433d..d2171d2a 100644 --- a/src/app/widget_measure.h +++ b/src/app/widget_measure.h @@ -42,6 +42,7 @@ class WidgetMeasure : public QWidget { static LengthUnit toMeasureLengthUnit(int comboBoxId); static AngleUnit toMeasureAngleUnit(int comboBoxId); static AreaUnit toMeasureAreaUnit(int comboBoxId); + static VolumeUnit toMeasureVolumeUnit(int comboBoxId); MeasureType currentMeasureType() const; MeasureDisplayConfig currentMeasureDisplayConfig() const; diff --git a/src/app/widget_measure.ui b/src/app/widget_measure.ui index d5b2559f..0c60e0e2 100644 --- a/src/app/widget_measure.ui +++ b/src/app/widget_measure.ui @@ -6,8 +6,8 @@ 0 0 - 229 - 156 + 246 + 158 @@ -33,6 +33,40 @@ + + + + + Square Millimeter(mm²) + + + + + Square Centimeter(cm²) + + + + + Square Meter(m²) + + + + + Square Inch(in²) + + + + + Square Foot(ft²) + + + + + Square Yard(yd²) + + + + @@ -47,13 +81,6 @@ - - - - Angle Unit - - - @@ -102,6 +129,41 @@ + + + + Angle Unit + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + Volume Unit + + + @@ -144,61 +206,55 @@ Surface Area + + + Bounding Box + + - - + + - Square Millimeter(mm²) + Cubic Millimeter(mm³) - Square Centimeter(cm²) + Cubic Centimeter(cm³) - Square Meter(m²) + Cubic Meter(m³) - Square Inch(in²) + Cubic Inch(in³) - Square Foot(ft²) + Cubic Foot(ft³) - Square Yard(yd²) + Liter(L) - - - - - - - 0 - - - 0 - - - 0 + + + Imperial Gallon(GBgal) - - 0 + + + + US Gallon(USgal) - - - - + diff --git a/src/base/quantity.h b/src/base/quantity.h index 1a9d98cb..5ed8d4bf 100644 --- a/src/base/quantity.h +++ b/src/base/quantity.h @@ -108,6 +108,8 @@ constexpr QuantityVolume Quantity_CubicFoot(Quantity_Foot.value() * Quantity_Squ constexpr QuantityVelocity Quantity_MillimeterPerSecond(1.); constexpr QuantityVolume Quantity_Liter(1e6); +constexpr QuantityVolume Quantity_ImperialGallon(1e6 * 4.54609); +constexpr QuantityVolume Quantity_USGallon(1e6 * 3.785411784); constexpr QuantityMass Quantity_Microgram(1e-9); constexpr QuantityMass Quantity_Milligram(1e-6); diff --git a/src/base/unit.h b/src/base/unit.h index 16a0199f..748535fe 100644 --- a/src/base/unit.h +++ b/src/base/unit.h @@ -49,6 +49,15 @@ enum AreaUnit { SquareInch, SquareFoot, SquareYard, SquareMile }; +enum VolumeUnit { + // SI + CubicMillimeter, CubicCentimeter, CubicMeter, + // Imperial UK + CubicInch, CubicFoot, + // Others + Liter, ImperialGallon, USGallon +}; + #if 0 enum class BaseUnit { Length = 0, // Meter(m) diff --git a/src/base/unit_system.cpp b/src/base/unit_system.cpp index 6bff41f2..11697e21 100644 --- a/src/base/unit_system.cpp +++ b/src/base/unit_system.cpp @@ -341,6 +341,27 @@ UnitSystem::TranslateResult UnitSystem::translateArea(QuantityArea area, AreaUni return {}; } +UnitSystem::TranslateResult UnitSystem::translateVolume(QuantityVolume volume, VolumeUnit unit) +{ + auto fnTrResult = [=](QuantityVolume qtyFactor, const char* strUnit) { + return Internal::translateHelper(volume, qtyFactor, strUnit); + }; + switch (unit) { + // SI + case VolumeUnit::CubicMillimeter: return fnTrResult(Quantity_CubicMillimeter, "mm³"); + case VolumeUnit::CubicCentimeter: return fnTrResult(Quantity_CubicCentimeter, "cm³"); + case VolumeUnit::CubicMeter: return fnTrResult(Quantity_CubicMeter, "m³"); + // Imperial UK + case VolumeUnit::CubicInch: return fnTrResult(Quantity_CubicInch, "in³"); + case VolumeUnit::CubicFoot: return fnTrResult(Quantity_CubicFoot, "ft³"); + // Others + case VolumeUnit::Liter: return fnTrResult(Quantity_Liter, "L"); + case VolumeUnit::ImperialGallon: return fnTrResult(Quantity_ImperialGallon, "GBgal"); + case VolumeUnit::USGallon: return fnTrResult(Quantity_USGallon, "USgal"); + } + return {}; +} + UnitSystem::TranslateResult UnitSystem::translateAngle(QuantityAngle angle, AngleUnit unit) { switch (unit) { diff --git a/src/base/unit_system.h b/src/base/unit_system.h index e773e31a..54ab1577 100644 --- a/src/base/unit_system.h +++ b/src/base/unit_system.h @@ -32,6 +32,7 @@ class UnitSystem { static TranslateResult translateLength(QuantityLength length, LengthUnit unit); static TranslateResult translateArea(QuantityArea area, AreaUnit unit); + static TranslateResult translateVolume(QuantityVolume volume, VolumeUnit unit); static TranslateResult translateAngle(QuantityAngle angle, AngleUnit unit); static TranslateResult radians(QuantityAngle angle); diff --git a/src/graphics/graphics_scene.cpp b/src/graphics/graphics_scene.cpp index c3cc49db..a589f2dd 100644 --- a/src/graphics/graphics_scene.cpp +++ b/src/graphics/graphics_scene.cpp @@ -73,6 +73,15 @@ class InteractiveContext : public AIS_InteractiveContext { {} constexpr const GraphicsOwnerPtr& member_myLastPicked() const { return myLastPicked; } + + int defaultDisplayMode(const GraphicsObjectPtr& object) const + { + int displayMode; + int hilightMode; + int selMode; + this->GetDefModes(object, displayMode, hilightMode, selMode); + return displayMode; + } }; DEFINE_STANDARD_HANDLE(InteractiveContext, AIS_InteractiveContext) @@ -133,10 +142,20 @@ const opencascade::handle& GraphicsScene::drawerHighlight(Prs3d_Ty return d->m_aisContext->HighlightStyle(style); } -void GraphicsScene::addObject(const GraphicsObjectPtr& object) +void GraphicsScene::addObject(const GraphicsObjectPtr& object, AddObjectFlags flags) { - if (object) - d->m_aisContext->Display(object, false); + if (object) { + if ((flags & AddObjectDisableSelectionMode) != 0) { + const bool onEntry_AutoActivateSelection = d->m_aisContext->GetAutoActivateSelection(); + const int defaultDisplayMode = d->m_aisContext->defaultDisplayMode(object); + d->m_aisContext->SetAutoActivateSelection(false); + d->m_aisContext->Display(object, defaultDisplayMode, -1, false); + d->m_aisContext->SetAutoActivateSelection(onEntry_AutoActivateSelection); + } + else { + d->m_aisContext->Display(object, false); + } + } } void GraphicsScene::eraseObject(const GraphicsObjectPtr& object) diff --git a/src/graphics/graphics_scene.h b/src/graphics/graphics_scene.h index 1245e629..68ccc554 100644 --- a/src/graphics/graphics_scene.h +++ b/src/graphics/graphics_scene.h @@ -37,7 +37,13 @@ class GraphicsScene { const opencascade::handle& drawerDefault() const; const opencascade::handle& drawerHighlight(Prs3d_TypeOfHighlight style) const; - void addObject(const GraphicsObjectPtr& object); + enum AddObjectFlag { + AddObjectDefault = 0, + AddObjectDisableSelectionMode = 1 + }; + using AddObjectFlags = unsigned; + + void addObject(const GraphicsObjectPtr& object, AddObjectFlags flags = AddObjectDefault); void eraseObject(const GraphicsObjectPtr& object); void redraw(); diff --git a/src/measure/measure_display.cpp b/src/measure/measure_display.cpp index 62f24d63..c0c12e15 100644 --- a/src/measure/measure_display.cpp +++ b/src/measure/measure_display.cpp @@ -6,10 +6,14 @@ #include "measure_display.h" +#include "../base/occ_handle.h" #include "../base/text_id.h" #include "../base/unit_system.h" #include "measure_tool.h" +#include +#include +#include #include #include #include @@ -19,6 +23,7 @@ #include #include +#include namespace Mayo { @@ -44,6 +49,8 @@ std::unique_ptr BaseMeasureDisplay::createFrom(MeasureType type return std::make_unique(std::get(value)); case MeasureType::Area: return std::make_unique(std::get(value)); + case MeasureType::BoundingBox: + return std::make_unique(std::get(value)); default: return {}; } @@ -133,6 +140,7 @@ void BaseMeasureDisplay::applyGraphicsDefaults(IMeasureDisplay* measureDisplay) { for (int i = 0; i < measureDisplay->graphicsObjectsCount(); ++i) { auto gfxObject = measureDisplay->graphicsObjectAt(i); + gfxObject->SetZLayer(Graphic3d_ZLayerId_Topmost); auto gfxText = Handle(AIS_TextLabel)::DownCast(gfxObject); if (gfxText) { gfxText->SetDisplayType(Aspect_TODT_SUBTITLE); @@ -448,4 +456,81 @@ void MeasureDisplayArea::sumAdd(const IMeasureDisplay& other) BaseMeasureDisplay::sumAdd(other); } +// -- +// -- Bounding Box +// -- + +MeasureDisplayBoundingBox::MeasureDisplayBoundingBox(const MeasureBoundingBox& bnd) + : m_bnd(bnd), + m_gfxXLengthText(new AIS_TextLabel), + m_gfxYLengthText(new AIS_TextLabel), + m_gfxZLengthText(new AIS_TextLabel) +{ + m_gfxMinPoint = new AIS_Point(new Geom_CartesianPoint(bnd.cornerMin)); + m_gfxMaxPoint = new AIS_Point(new Geom_CartesianPoint(bnd.cornerMax)); + + const TopoDS_Shape shapeBox = BRepPrimAPI_MakeBox(bnd.cornerMin, bnd.cornerMax); + auto aisShapeBox = new AIS_Shape(shapeBox); + m_gfxBox = aisShapeBox; + m_gfxBox->SetDisplayMode(AIS_Shaded); + m_gfxBox->SetTransparency(0.85); + m_gfxBox->Attributes()->SetFaceBoundaryDraw(true); + m_gfxBox->Attributes()->SetFaceBoundaryAspect(new Prs3d_LineAspect({}, Aspect_TOL_DOT, 1.)); + + const double diffX = bnd.cornerMax.X() - bnd.cornerMin.X(); + const double diffY = bnd.cornerMax.Y() - bnd.cornerMin.Y(); + const double diffZ = bnd.cornerMax.Z() - bnd.cornerMin.Z(); + m_gfxXLengthText->SetPosition(bnd.cornerMin.Translated((diffX / 2.) * gp_Vec{1, 0, 0})); + m_gfxYLengthText->SetPosition(bnd.cornerMin.Translated((diffY / 2.) * gp_Vec{0, 1, 0})); + m_gfxZLengthText->SetPosition(bnd.cornerMin.Translated((diffZ / 2.) * gp_Vec{0, 0, 1})); + + BaseMeasureDisplay::applyGraphicsDefaults(this); + m_gfxBox->SetColor(Quantity_NOC_BEIGE); + m_gfxBox->SetZLayer(Graphic3d_ZLayerId_Default); +} + +void MeasureDisplayBoundingBox::update(const MeasureDisplayConfig& config) +{ + const auto trXLength = UnitSystem::translateLength(m_bnd.xLength, config.lengthUnit); + const auto trYLength = UnitSystem::translateLength(m_bnd.yLength, config.lengthUnit); + const auto trZLength = UnitSystem::translateLength(m_bnd.zLength, config.lengthUnit); + const auto trVolume = UnitSystem::translateVolume(m_bnd.volume, config.volumeUnit); + this->setText(fmt::format( + MeasureDisplayI18N::textIdTr( + "Min point: {0}
Max point: {1}
" + "Size: {2} x {3} x {4}{5}
" + "Volume: {6}{7}" + ), + BaseMeasureDisplay::text(m_bnd.cornerMin, config), + BaseMeasureDisplay::text(m_bnd.cornerMax, config), + BaseMeasureDisplay::text(trXLength, config), + BaseMeasureDisplay::text(trYLength, config), + BaseMeasureDisplay::text(trZLength, config), + trXLength.strUnit, + BaseMeasureDisplay::text(trVolume, config), + trVolume.strUnit + )); + + m_gfxXLengthText->SetText(to_OccExtString(BaseMeasureDisplay::text(trXLength, config))); + m_gfxYLengthText->SetText(to_OccExtString(BaseMeasureDisplay::text(trYLength, config))); + m_gfxZLengthText->SetText(to_OccExtString(BaseMeasureDisplay::text(trZLength, config))); + BaseMeasureDisplay::adaptScale(m_gfxXLengthText, config); + BaseMeasureDisplay::adaptScale(m_gfxYLengthText, config); + BaseMeasureDisplay::adaptScale(m_gfxZLengthText, config); +} + +GraphicsObjectPtr MeasureDisplayBoundingBox::graphicsObjectAt(int i) const +{ + switch (i) { + case 0: return m_gfxMinPoint; + case 1: return m_gfxMaxPoint; + case 2: return m_gfxBox; + case 3: return m_gfxXLengthText; + case 4: return m_gfxYLengthText; + case 5: return m_gfxZLengthText; + } + + return {}; +} + } // namespace Mayo diff --git a/src/measure/measure_display.h b/src/measure/measure_display.h index 23aa0be5..4cb70713 100644 --- a/src/measure/measure_display.h +++ b/src/measure/measure_display.h @@ -29,6 +29,7 @@ struct MeasureDisplayConfig { LengthUnit lengthUnit = LengthUnit::Millimeter; AngleUnit angleUnit = AngleUnit::Degree; AreaUnit areaUnit = AreaUnit::SquareMillimeter; + VolumeUnit volumeUnit = VolumeUnit::CubicMillimeter; DoubleToStringOptions doubleToStringOptions; double devicePixelRatio = 1.; }; @@ -228,4 +229,25 @@ class MeasureDisplayArea : public BaseMeasureDisplay { Handle_AIS_TextLabel m_gfxAreaText; }; +// -- +// -- Bounding Box +// -- + +class MeasureDisplayBoundingBox : public BaseMeasureDisplay { +public: + MeasureDisplayBoundingBox(const MeasureBoundingBox& bnd); + void update(const MeasureDisplayConfig& config) override; + int graphicsObjectsCount() const override { return 6; } + GraphicsObjectPtr graphicsObjectAt(int i) const override; + +private: + MeasureBoundingBox m_bnd; + Handle_AIS_Point m_gfxMinPoint; + Handle_AIS_Point m_gfxMaxPoint; + Handle_AIS_InteractiveObject m_gfxBox; + Handle_AIS_TextLabel m_gfxXLengthText; + Handle_AIS_TextLabel m_gfxYLengthText; + Handle_AIS_TextLabel m_gfxZLengthText; +}; + } // namespace Mayo diff --git a/src/measure/measure_tool.cpp b/src/measure/measure_tool.cpp index 2c688a72..a78a6e91 100644 --- a/src/measure/measure_tool.cpp +++ b/src/measure/measure_tool.cpp @@ -9,7 +9,8 @@ namespace Mayo { MeasureValue IMeasureTool_computeValue( - const IMeasureTool& tool, MeasureType type, const GraphicsOwnerPtr& owner) + const IMeasureTool& tool, MeasureType type, const GraphicsOwnerPtr& owner + ) { MeasureValue value; switch (type) { @@ -22,6 +23,8 @@ MeasureValue IMeasureTool_computeValue( return tool.length(owner); case MeasureType::Area: return tool.area(owner); + case MeasureType::BoundingBox: + return tool.boundingBox(owner); default: return value; } // endswitch @@ -31,7 +34,8 @@ MeasureValue IMeasureTool_computeValue( const IMeasureTool& tool, MeasureType type, const GraphicsOwnerPtr& owner1, - const GraphicsOwnerPtr& owner2) + const GraphicsOwnerPtr& owner2 + ) { MeasureValue value; switch (type) { diff --git a/src/measure/measure_tool.h b/src/measure/measure_tool.h index 2b56d6b5..261cc36a 100644 --- a/src/measure/measure_tool.h +++ b/src/measure/measure_tool.h @@ -80,7 +80,21 @@ struct MeasureArea { QuantityArea value; }; - +// Measure of the bounding box of an entity +struct MeasureBoundingBox { + // Lower corner of the bounding box + gp_Pnt cornerMin; + // Upper corner of the bounding box + gp_Pnt cornerMax; + // Length of the bounding box along the X-axis + QuantityLength xLength; + // Length of the bounding box along the Y-axis + QuantityLength yLength; + // Length of the bounding box along the Z-axis + QuantityLength zLength; + // Volume of the bounding box + QuantityVolume volume; +}; // Provides an interface to various measurement services // Input data of a measure service is one or many graphics entities pointed to by GraphicsOwner objects @@ -99,6 +113,7 @@ class IMeasureTool { virtual MeasureAngle angle(const GraphicsOwnerPtr& owner1, const GraphicsOwnerPtr& owner2) const = 0; virtual MeasureLength length(const GraphicsOwnerPtr& owner) const = 0; virtual MeasureArea area(const GraphicsOwnerPtr& owner) const = 0; + virtual MeasureBoundingBox boundingBox(const GraphicsOwnerPtr& owner) const = 0; }; // Base interface for errors reported by measurement services of IMeasureTool @@ -115,7 +130,8 @@ using MeasureValue = std::variant< MeasureDistance, MeasureAngle, MeasureLength, - MeasureArea + MeasureArea, + MeasureBoundingBox >; bool MeasureValue_isValid(const MeasureValue& res); diff --git a/src/measure/measure_tool_brep.cpp b/src/measure/measure_tool_brep.cpp index f4132fb7..755ba340 100644 --- a/src/measure/measure_tool_brep.cpp +++ b/src/measure/measure_tool_brep.cpp @@ -15,9 +15,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -57,7 +59,8 @@ enum class ErrorCode { NotAllEdges, NotLinearEdge, NotAllFaces, - ParallelEdges + ParallelEdges, + BoundingBoxIsVoid }; template @@ -89,6 +92,8 @@ class BRepMeasureError : public IMeasureError { return textIdTr("All entities must be faces"); case ErrorCode::ParallelEdges: return textIdTr("Entities must not be parallel"); + case ErrorCode::BoundingBoxIsVoid: + return textIdTr("Bounding box computed is void"); default: return textIdTr("Unknown error"); } @@ -181,6 +186,14 @@ Span MeasureToolBRep::selectionModes(MeasureT static const GraphicsObjectSelectionMode modes[] = { AIS_Shape::SelectionMode(TopAbs_FACE) }; return modes; } + case MeasureType::BoundingBox: { + static const GraphicsObjectSelectionMode modes[] = { + //AIS_Shape::SelectionMode(TopAbs_FACE), + //AIS_Shape::SelectionMode(TopAbs_SOLID) + AIS_Shape::SelectionMode(TopAbs_COMPOUND) + }; + return modes; + } default: { return {}; } @@ -233,6 +246,11 @@ MeasureArea MeasureToolBRep::area(const GraphicsOwnerPtr& owner) const return brepArea(getShape(owner)); } +MeasureBoundingBox MeasureToolBRep::boundingBox(const GraphicsOwnerPtr& owner) const +{ + return brepBoundingBox(getShape(owner)); +} + gp_Pnt MeasureToolBRep::brepVertexPosition(const TopoDS_Shape& shape) { throwErrorIf(shape.IsNull() || shape.ShapeType() != TopAbs_VERTEX); @@ -509,4 +527,31 @@ MeasureArea MeasureToolBRep::brepArea(const TopoDS_Shape& shape) return areaResult; } +MeasureBoundingBox MeasureToolBRep::brepBoundingBox(const TopoDS_Shape& shape) +{ + MeasureBoundingBox measure; +#if 0 + Bnd_OBB bnd; + BRepBndLib::AddOBB(shape, bnd); + //BRepBndLib::AddOBB(shape, bnd, false/*!useTriangulation*/, true/*optimal*/, false/*!useShapeTolerance*/); + + gp_Pnt points[8] = {}; + bnd.GetVertex(points); + measure.cornerMin = points[0]; + measure.cornerMax = points[7]; + //measure.isAxisAligned = bnd.IsAABox(); +#else + Bnd_Box bnd; + BRepBndLib::AddOptimal(shape, bnd); + throwErrorIf(bnd.IsVoid()); + measure.cornerMin = bnd.CornerMin(); + measure.cornerMax = bnd.CornerMax(); + measure.xLength = std::abs(measure.cornerMax.X() - measure.cornerMin.X()) * Quantity_Millimeter; + measure.yLength = std::abs(measure.cornerMax.Y() - measure.cornerMin.Y()) * Quantity_Millimeter; + measure.zLength = std::abs(measure.cornerMax.Z() - measure.cornerMin.Z()) * Quantity_Millimeter; + measure.volume = measure.xLength * measure.yLength * measure.zLength; +#endif + return measure; +} + } // namespace Mayo diff --git a/src/measure/measure_tool_brep.h b/src/measure/measure_tool_brep.h index 777fb76b..903af38c 100644 --- a/src/measure/measure_tool_brep.h +++ b/src/measure/measure_tool_brep.h @@ -27,6 +27,7 @@ class MeasureToolBRep : public IMeasureTool { MeasureAngle angle(const GraphicsOwnerPtr& owner1, const GraphicsOwnerPtr& owner2) const override; MeasureLength length(const GraphicsOwnerPtr& owner) const override; MeasureArea area(const GraphicsOwnerPtr& owner) const override; + MeasureBoundingBox boundingBox(const GraphicsOwnerPtr& owner) const override; static gp_Pnt brepVertexPosition(const TopoDS_Shape& shape); static MeasureCircle brepCircle(const TopoDS_Shape& shape); @@ -35,6 +36,7 @@ class MeasureToolBRep : public IMeasureTool { static MeasureAngle brepAngle(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); static MeasureLength brepLength(const TopoDS_Shape& shape); static MeasureArea brepArea(const TopoDS_Shape& shape); + static MeasureBoundingBox brepBoundingBox(const TopoDS_Shape& shape); private: static MeasureCircle brepCircleFromGeometricEdge(const TopoDS_Edge& edge); diff --git a/src/measure/measure_type.h b/src/measure/measure_type.h index b1bb640d..9c5b6442 100644 --- a/src/measure/measure_type.h +++ b/src/measure/measure_type.h @@ -9,7 +9,16 @@ namespace Mayo { enum class MeasureType { - None, VertexPosition, CircleCenter, CircleDiameter, MinDistance, CenterDistance, Angle, Length, Area + None, + VertexPosition, + CircleCenter, + CircleDiameter, + MinDistance, + CenterDistance, + Angle, + Length, + Area, + BoundingBox }; } // namespace Mayo diff --git a/tests/test_measure.cpp b/tests/test_measure.cpp index 5c2a6606..061f93e3 100644 --- a/tests/test_measure.cpp +++ b/tests/test_measure.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -174,7 +175,7 @@ void TestMeasure::BRepLength_PolygonEdge_test() QCOMPARE(UnitSystem::millimeters(len.value).value, 24.); } -void TestMeasure::BRepArea_TriangulationFace() +void TestMeasure::BRepArea_TriangulationFace_test() { auto progress = &TaskProgress::null(); IO::OccStlReader reader; @@ -189,4 +190,23 @@ void TestMeasure::BRepArea_TriangulationFace() QVERIFY(std::abs(double(UnitSystem::squareMillimeters(area.value)) - 597.6224) < 0.0001); } +void TestMeasure::BRepBoundingBox_Sphere_test() +{ + const double sphereRadius = 50.; + const TopoDS_Shape sphereShape = BRepPrimAPI_MakeSphere(50.); + const MeasureBoundingBox bndBox = MeasureToolBRep::brepBoundingBox(sphereShape); + QVERIFY(bndBox.cornerMin.IsEqual(gp_Pnt{-sphereRadius, -sphereRadius, -sphereRadius}, Precision::Confusion())); + QVERIFY(bndBox.cornerMax.IsEqual(gp_Pnt{sphereRadius, sphereRadius, sphereRadius}, Precision::Confusion())); + QCOMPARE(double(UnitSystem::millimeters(bndBox.xLength)), 2 * sphereRadius); + QCOMPARE(double(UnitSystem::millimeters(bndBox.yLength)), 2 * sphereRadius); + QCOMPARE(double(UnitSystem::millimeters(bndBox.zLength)), 2 * sphereRadius); + QCOMPARE(double(UnitSystem::cubicMillimeters(bndBox.volume)), 8 * sphereRadius * sphereRadius * sphereRadius); +} + +void TestMeasure::BRepBoundingBox_NullShape_test() +{ + const TopoDS_Shape nullShape; + QVERIFY_EXCEPTION_THROWN(MeasureToolBRep::brepBoundingBox(nullShape), IMeasureError); +} + } // namespace Mayo diff --git a/tests/test_measure.h b/tests/test_measure.h index c66d9756..21324679 100644 --- a/tests/test_measure.h +++ b/tests/test_measure.h @@ -32,7 +32,10 @@ private slots: void BRepLength_PolygonEdge_test(); - void BRepArea_TriangulationFace(); + void BRepArea_TriangulationFace_test(); + + void BRepBoundingBox_Sphere_test(); + void BRepBoundingBox_NullShape_test(); }; } // namespace Mayo