FreeCAD
803 строки · 28.7 Кб
1/***************************************************************************
2* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
3* *
4* This file is part of the FreeCAD CAx development system. *
5* *
6* This library is free software; you can redistribute it and/or *
7* modify it under the terms of the GNU Library General Public *
8* License as published by the Free Software Foundation; either *
9* version 2 of the License, or (at your option) any later version. *
10* *
11* This library is distributed in the hope that it will be useful, *
12* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14* GNU Library General Public License for more details. *
15* *
16* You should have received a copy of the GNU Library General Public *
17* License along with this library; see the file COPYING.LIB. If not, *
18* write to the Free Software Foundation, Inc., 59 Temple Place, *
19* Suite 330, Boston, MA 02111-1307, USA *
20* *
21***************************************************************************/
22
23#include "PreCompiled.h"24
25#ifndef _PreComp_26#include <QApplication>27#include <QMenu>28#include <QMessageBox>29
30#include <Inventor/SoPickedPoint.h>31#include <Inventor/actions/SoRayPickAction.h>32#include <Inventor/actions/SoSearchAction.h>33#include <Inventor/details/SoFaceDetail.h>34#include <Inventor/errors/SoDebugError.h>35#include <Inventor/events/SoButtonEvent.h>36#include <Inventor/events/SoKeyboardEvent.h>37#include <Inventor/events/SoMouseButtonEvent.h>38#include <Inventor/nodes/SoCoordinate3.h>39#include <Inventor/nodes/SoDrawStyle.h>40#include <Inventor/nodes/SoIndexedFaceSet.h>41#include <Inventor/nodes/SoIndexedLineSet.h>42#include <Inventor/nodes/SoMaterial.h>43#include <Inventor/nodes/SoMaterialBinding.h>44#include <Inventor/nodes/SoNormal.h>45#include <Inventor/nodes/SoPointSet.h>46#include <Inventor/nodes/SoShapeHints.h>47#endif48
49#include <App/GeoFeature.h>50#include <Gui/Application.h>51#include <Gui/Document.h>52#include <Gui/Flag.h>53#include <Gui/MainWindow.h>54#include <Gui/SoFCColorBar.h>55#include <Gui/View3DInventorViewer.h>56#include <Gui/Widgets.h>57#include <Mod/Inspection/App/InspectionFeature.h>58#include <Mod/Points/App/Properties.h>59
60#include "ViewProviderInspection.h"61
62
63using namespace InspectionGui;64
65
66bool ViewProviderInspection::addflag = false;67App::PropertyFloatConstraint::Constraints ViewProviderInspection::floatRange = {1.0, 64.0, 1.0};68
69PROPERTY_SOURCE(InspectionGui::ViewProviderInspection, Gui::ViewProviderDocumentObject)70
71ViewProviderInspection::ViewProviderInspection()72{
73ADD_PROPERTY_TYPE(OutsideGrayed,74(false),75"",76(App::PropertyType)(App::Prop_Output | App::Prop_Hidden),77"");78ADD_PROPERTY_TYPE(PointSize,79(1.0),80"Display",81(App::PropertyType)(App::Prop_None /*App::Prop_Hidden*/),82"");83PointSize.setConstraints(&floatRange);84
85pcColorRoot = new SoSeparator();86pcColorRoot->ref();87pcMatBinding = new SoMaterialBinding;88pcMatBinding->ref();89pcColorMat = new SoMaterial;90pcColorMat->ref();91pcColorStyle = new SoDrawStyle();92pcColorRoot->addChild(pcColorStyle);93pcCoords = new SoCoordinate3;94pcCoords->ref();95// simple color bar96pcColorBar = new Gui::SoFCColorBar;97pcColorBar->Attach(this);98pcColorBar->ref();99pcColorBar->setRange(-0.1f, 0.1f, 3);100pcLinkRoot = new SoGroup;101pcLinkRoot->ref();102
103pcPointStyle = new SoDrawStyle();104pcPointStyle->ref();105pcPointStyle->style = SoDrawStyle::POINTS;106pcPointStyle->pointSize = PointSize.getValue();107SelectionStyle.setValue(1); // BBOX108}
109
110ViewProviderInspection::~ViewProviderInspection()111{
112pcColorRoot->unref();113pcCoords->unref();114pcMatBinding->unref();115pcColorMat->unref();116pcColorBar->Detach(this);117pcColorBar->unref();118pcLinkRoot->unref();119pcPointStyle->unref();120}
121
122void ViewProviderInspection::onChanged(const App::Property* prop)123{
124if (prop == &OutsideGrayed) {125if (pcColorBar) {126pcColorBar->setOutsideGrayed(OutsideGrayed.getValue());127pcColorBar->Notify(0);128}129}130else if (prop == &PointSize) {131pcPointStyle->pointSize = PointSize.getValue();132}133else {134inherited::onChanged(prop);135}136}
137
138void ViewProviderInspection::hide()139{
140inherited::hide();141pcColorStyle->style = SoDrawStyle::INVISIBLE;142}
143
144void ViewProviderInspection::show()145{
146inherited::show();147pcColorStyle->style = SoDrawStyle::FILLED;148}
149
150void ViewProviderInspection::attach(App::DocumentObject* pcFeat)151{
152// creates the standard viewing modes153inherited::attach(pcFeat);154
155SoShapeHints* flathints = new SoShapeHints;156flathints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;157flathints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;158
159SoGroup* pcColorShadedRoot = new SoGroup();160pcColorShadedRoot->addChild(flathints);161
162// color shaded ------------------------------------------163SoDrawStyle* pcFlatStyle = new SoDrawStyle();164pcFlatStyle->style = SoDrawStyle::FILLED;165pcColorShadedRoot->addChild(pcFlatStyle);166
167pcColorShadedRoot->addChild(pcColorMat);168pcColorShadedRoot->addChild(pcMatBinding);169pcColorShadedRoot->addChild(pcLinkRoot);170
171addDisplayMaskMode(pcColorShadedRoot, "ColorShaded");172
173// Check for an already existing color bar174Gui::SoFCColorBar* pcBar =175((Gui::SoFCColorBar*)findFrontRootOfType(Gui::SoFCColorBar::getClassTypeId()));176if (pcBar) {177float fMin = pcColorBar->getMinValue();178float fMax = pcColorBar->getMaxValue();179
180// Attach to the foreign color bar and delete our own bar181pcBar->Attach(this);182pcBar->ref();183pcBar->setRange(fMin, fMax, 3);184pcBar->Notify(0);185pcColorBar->Detach(this);186pcColorBar->unref();187pcColorBar = pcBar;188}189
190pcColorRoot->addChild(pcColorBar);191}
192
193bool ViewProviderInspection::setupFaces(const Data::ComplexGeoData* data)194{
195std::vector<Base::Vector3d> points;196std::vector<Data::ComplexGeoData::Facet> faces;197
198// set the Distance property to the correct size to sync size of material node with number199// of vertices/points of the referenced geometry200double accuracy = data->getAccuracy();201data->getFaces(points, faces, accuracy);202if (faces.empty()) {203return false;204}205
206setupCoords(points);207setupFaceIndexes(faces);208return true;209}
210
211bool ViewProviderInspection::setupLines(const Data::ComplexGeoData* data)212{
213std::vector<Base::Vector3d> points;214std::vector<Data::ComplexGeoData::Line> lines;215
216double accuracy = data->getAccuracy();217data->getLines(points, lines, accuracy);218if (lines.empty()) {219return false;220}221
222setupCoords(points);223setupLineIndexes(lines);224return true;225}
226
227bool ViewProviderInspection::setupPoints(const Data::ComplexGeoData* data,228App::PropertyContainer* container)229{
230std::vector<Base::Vector3d> points;231std::vector<Base::Vector3f> normals;232std::vector<Base::Vector3d> normals_d;233double accuracy = data->getAccuracy();234data->getPoints(points, normals_d, accuracy);235if (points.empty()) {236return false;237}238
239normals.reserve(normals_d.size());240std::transform(normals_d.cbegin(),241normals_d.cend(),242std::back_inserter(normals),243[](const Base::Vector3d& p) {244return Base::toVector<float>(p);245});246
247// If getPoints() doesn't deliver normals check a second property248if (normals.empty() && container) {249App::Property* propN = container->getPropertyByName("Normal");250if (propN && propN->isDerivedFrom<Points::PropertyNormalList>()) {251normals = static_cast<Points::PropertyNormalList*>(propN)->getValues();252}253}254
255setupCoords(points);256if (!normals.empty() && normals.size() == points.size()) {257setupNormals(normals);258}259
260this->pcLinkRoot->addChild(this->pcPointStyle);261this->pcLinkRoot->addChild(new SoPointSet());262
263return true;264}
265
266void ViewProviderInspection::setupCoords(const std::vector<Base::Vector3d>& points)267{
268this->pcLinkRoot->addChild(this->pcCoords);269this->pcCoords->point.setNum(points.size());270SbVec3f* pts = this->pcCoords->point.startEditing();271for (size_t i = 0; i < points.size(); i++) {272const Base::Vector3d& p = points[i];273pts[i].setValue((float)p.x, (float)p.y, (float)p.z);274}275this->pcCoords->point.finishEditing();276}
277
278void ViewProviderInspection::setupNormals(const std::vector<Base::Vector3f>& normals)279{
280SoNormal* normalNode = new SoNormal();281normalNode->vector.setNum(normals.size());282SbVec3f* norm = normalNode->vector.startEditing();283
284std::size_t i = 0;285for (const auto& it : normals) {286norm[i++].setValue(it.x, it.y, it.z);287}288
289normalNode->vector.finishEditing();290this->pcLinkRoot->addChild(normalNode);291}
292
293void ViewProviderInspection::setupLineIndexes(const std::vector<Data::ComplexGeoData::Line>& lines)294{
295SoIndexedLineSet* line = new SoIndexedLineSet();296this->pcLinkRoot->addChild(line);297line->coordIndex.setNum(3 * lines.size());298int32_t* indices = line->coordIndex.startEditing();299unsigned long j = 0;300for (const auto& it : lines) {301indices[3 * j + 0] = it.I1;302indices[3 * j + 1] = it.I2;303indices[3 * j + 2] = SO_END_LINE_INDEX;304j++;305}306line->coordIndex.finishEditing();307}
308
309void ViewProviderInspection::setupFaceIndexes(const std::vector<Data::ComplexGeoData::Facet>& faces)310{
311SoIndexedFaceSet* face = new SoIndexedFaceSet();312this->pcLinkRoot->addChild(face);313face->coordIndex.setNum(4 * faces.size());314int32_t* indices = face->coordIndex.startEditing();315unsigned long j = 0;316for (const auto& it : faces) {317indices[4 * j + 0] = it.I1;318indices[4 * j + 1] = it.I2;319indices[4 * j + 2] = it.I3;320indices[4 * j + 3] = SO_END_FACE_INDEX;321j++;322}323face->coordIndex.finishEditing();324}
325
326void ViewProviderInspection::updateData(const App::Property* prop)327{
328// set to the expected size329if (prop->isDerivedFrom<App::PropertyLink>()) {330App::GeoFeature* object =331static_cast<const App::PropertyLink*>(prop)->getValue<App::GeoFeature*>();332const App::PropertyComplexGeoData* propData =333object ? object->getPropertyOfGeometry() : nullptr;334if (propData) {335Gui::coinRemoveAllChildren(this->pcLinkRoot);336
337const Data::ComplexGeoData* data = propData->getComplexData();338if (!setupFaces(data)) {339if (!setupLines(data)) {340setupPoints(data, object);341}342}343}344}345else if (prop->is<Inspection::PropertyDistanceList>()) {346// force an update of the Inventor data nodes347if (this->pcObject) {348App::Property* link = this->pcObject->getPropertyByName("Actual");349if (link) {350updateData(link);351}352setDistances();353}354}355else if (prop->is<App::PropertyFloat>()) {356if (strcmp(prop->getName(), "SearchRadius") == 0) {357float fSearchRadius = ((App::PropertyFloat*)prop)->getValue();358this->search_radius = fSearchRadius;359pcColorBar->setRange(-fSearchRadius, fSearchRadius, 4);360pcColorBar->Notify(0);361}362}363}
364
365SoSeparator* ViewProviderInspection::getFrontRoot() const366{
367return pcColorRoot;368}
369
370void ViewProviderInspection::setDistances()371{
372if (!pcObject) {373return;374}375
376App::Property* pDistances = pcObject->getPropertyByName("Distances");377if (!pDistances) {378SoDebugError::post("ViewProviderInspection::setDistances", "Unknown property 'Distances'");379return;380}381if (pDistances->getTypeId() != Inspection::PropertyDistanceList::getClassTypeId()) {382SoDebugError::post(383"ViewProviderInspection::setDistances",384"Property 'Distances' has type %s (Inspection::PropertyDistanceList was expected)",385pDistances->getTypeId().getName());386return;387}388
389// distance values390const std::vector<float>& fValues =391static_cast<Inspection::PropertyDistanceList*>(pDistances)->getValues();392if ((int)fValues.size() != this->pcCoords->point.getNum()) {393pcMatBinding->value = SoMaterialBinding::OVERALL;394return;395}396
397if (pcColorMat->diffuseColor.getNum() != static_cast<int>(fValues.size())) {398pcColorMat->diffuseColor.setNum(static_cast<int>(fValues.size()));399}400if (pcColorMat->transparency.getNum() != static_cast<int>(fValues.size())) {401pcColorMat->transparency.setNum(static_cast<int>(fValues.size()));402}403
404SbColor* cols = pcColorMat->diffuseColor.startEditing();405float* tran = pcColorMat->transparency.startEditing();406
407unsigned long j = 0;408for (std::vector<float>::const_iterator jt = fValues.begin(); jt != fValues.end(); ++jt, j++) {409App::Color col = pcColorBar->getColor(*jt);410cols[j] = SbColor(col.r, col.g, col.b);411if (pcColorBar->isVisible(*jt)) {412tran[j] = 0.0f;413}414else {415tran[j] = 0.8f;416}417}418
419pcColorMat->diffuseColor.finishEditing();420pcColorMat->transparency.finishEditing();421pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;422}
423
424QIcon ViewProviderInspection::getIcon() const425{
426// Get the icon of the view provider to the associated feature427QIcon px = inherited::getIcon();428App::Property* pActual = pcObject->getPropertyByName("Actual");429if (pActual && pActual->isDerivedFrom<App::PropertyLink>()) {430App::DocumentObject* docobj = ((App::PropertyLink*)pActual)->getValue();431if (docobj) {432Gui::Document* doc = Gui::Application::Instance->getDocument(docobj->getDocument());433Gui::ViewProvider* view = doc->getViewProvider(docobj);434px = view->getIcon();435}436}437
438return px;439}
440
441void ViewProviderInspection::setDisplayMode(const char* ModeName)442{
443if (strcmp("Visual Inspection", ModeName) == 0) {444setDistances();445setDisplayMaskMode("ColorShaded");446}447
448inherited::setDisplayMode(ModeName);449}
450
451std::vector<std::string> ViewProviderInspection::getDisplayModes() const452{
453// add modes454std::vector<std::string> StrList;455StrList.emplace_back("Visual Inspection");456return StrList;457}
458
459void ViewProviderInspection::OnChange(Base::Subject<int>& /*rCaller*/, int /*rcReason*/)460{
461setActiveMode();462}
463
464namespace InspectionGui465{
466// Proxy class that receives an asynchronous custom event
467class ViewProviderProxyObject: public QObject468{
469public:470explicit ViewProviderProxyObject(QWidget* w)471: QObject(nullptr)472, widget(w)473{}474~ViewProviderProxyObject() override = default;475void customEvent(QEvent*) override476{477if (!widget.isNull()) {478QList<Gui::Flag*> flags = widget->findChildren<Gui::Flag*>();479if (!flags.isEmpty()) {480int ret =481QMessageBox::question(Gui::getMainWindow(),482QObject::tr("Remove annotations"),483QObject::tr("Do you want to remove all annotations?"),484QMessageBox::Yes,485QMessageBox::No);486if (ret == QMessageBox::Yes) {487for (auto it : flags) {488it->deleteLater();489}490}491}492}493
494this->deleteLater();495}496
497static void498addFlag(Gui::View3DInventorViewer* view, const QString& text, const SoPickedPoint* point)499{500Gui::Flag* flag = new Gui::Flag;501QPalette p;502p.setColor(QPalette::Window, QColor(85, 0, 127));503p.setColor(QPalette::Text, QColor(220, 220, 220));504flag->setPalette(p);505flag->setText(text);506flag->setOrigin(point->getPoint());507Gui::GLFlagWindow* flags = nullptr;508std::list<Gui::GLGraphicsItem*> glItems =509view->getGraphicsItemsOfType(Gui::GLFlagWindow::getClassTypeId());510if (glItems.empty()) {511flags = new Gui::GLFlagWindow(view);512view->addGraphicsItem(flags);513}514else {515flags = static_cast<Gui::GLFlagWindow*>(glItems.front());516}517flags->addFlag(flag, Gui::FlagLayout::BottomLeft);518}519
520private:521QPointer<QWidget> widget;522};523} // namespace InspectionGui524
525void ViewProviderInspection::inspectCallback(void* ud, SoEventCallback* n)526{
527Gui::View3DInventorViewer* view = static_cast<Gui::View3DInventorViewer*>(n->getUserData());528const SoEvent* ev = n->getEvent();529if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {530const SoMouseButtonEvent* mbe = static_cast<const SoMouseButtonEvent*>(ev);531
532// Mark all incoming mouse button events as handled, especially, to deactivate the selection533// node534n->getAction()->setHandled();535n->setHandled();536if (mbe->getButton() == SoMouseButtonEvent::BUTTON2537&& mbe->getState() == SoButtonEvent::UP) {538n->setHandled();539// context-menu540QMenu menu;541QAction* fl = menu.addAction(QObject::tr("Annotation"));542fl->setCheckable(true);543fl->setChecked(addflag);544QAction* cl = menu.addAction(QObject::tr("Leave info mode"));545QAction* id = menu.exec(QCursor::pos());546if (fl == id) {547addflag = fl->isChecked();548}549else if (cl == id) {550// post an event to a proxy object to make sure to avoid problems551// when opening a modal dialog552QApplication::postEvent(new ViewProviderProxyObject(view->getGLWidget()),553new QEvent(QEvent::User));554view->setEditing(false);555view->getWidget()->setCursor(QCursor(Qt::ArrowCursor));556view->setRedirectToSceneGraph(false);557view->setRedirectToSceneGraphEnabled(false);558view->setSelectionEnabled(true);559view->removeEventCallback(SoButtonEvent::getClassTypeId(), inspectCallback, ud);560}561}562else if (mbe->getButton() == SoMouseButtonEvent::BUTTON1563&& mbe->getState() == SoButtonEvent::UP) {564const SoPickedPoint* point = n->getPickedPoint();565if (!point) {566Base::Console().Message("No point picked.\n");567return;568}569
570n->setHandled();571
572// check if we have picked one a node of the view provider we are insterested in573Gui::ViewProvider* vp = view->getViewProviderByPathFromTail(point->getPath());574if (vp && vp->isDerivedFrom<ViewProviderInspection>()) {575ViewProviderInspection* that = static_cast<ViewProviderInspection*>(vp);576QString info = that->inspectDistance(point);577Gui::getMainWindow()->setPaneText(1, info);578if (addflag) {579ViewProviderProxyObject::addFlag(view, info, point);580}581else {582Gui::ToolTip::showText(QCursor::pos(), info);583}584}585else {586// the nearest picked point was not part of the view provider587SoRayPickAction action(view->getSoRenderManager()->getViewportRegion());588action.setPickAll(true);589action.setPoint(mbe->getPosition());590action.apply(view->getSoRenderManager()->getSceneGraph());591
592const SoPickedPointList& pps = action.getPickedPointList();593for (int i = 0; i < pps.getLength(); ++i) {594const SoPickedPoint* point = pps[i];595vp = view->getViewProviderByPathFromTail(point->getPath());596if (vp && vp->isDerivedFrom<ViewProviderInspection>()) {597ViewProviderInspection* self = static_cast<ViewProviderInspection*>(vp);598QString info = self->inspectDistance(point);599Gui::getMainWindow()->setPaneText(1, info);600if (addflag) {601ViewProviderProxyObject::addFlag(view, info, point);602}603else {604Gui::ToolTip::showText(QCursor::pos(), info);605}606break;607}608}609}610}611}612// toggle between inspection and navigation mode613else if (ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {614const SoKeyboardEvent* const ke = static_cast<const SoKeyboardEvent*>(ev);615if (ke->getState() == SoButtonEvent::DOWN && ke->getKey() == SoKeyboardEvent::ESCAPE) {616SbBool toggle = view->isRedirectedToSceneGraph();617view->setRedirectToSceneGraph(!toggle);618n->setHandled();619}620}621}
622
623namespace InspectionGui624{
625float calcArea(const SbVec3f& v1, const SbVec3f& v2, const SbVec3f& v3)626{
627SbVec3f a = v2 - v1;628SbVec3f b = v3 - v1;629return a.cross(b).length() / 2.0f;630}
631
632bool calcWeights(const SbVec3f& v1,633const SbVec3f& v2,634const SbVec3f& v3,635const SbVec3f& p,636float& w0,637float& w1,638float& w2)639{
640float fAreaABC = calcArea(v1, v2, v3);641float fAreaPBC = calcArea(p, v2, v3);642float fAreaPCA = calcArea(p, v3, v1);643float fAreaPAB = calcArea(p, v1, v2);644
645w0 = fAreaPBC / fAreaABC;646w1 = fAreaPCA / fAreaABC;647w2 = fAreaPAB / fAreaABC;648
649return fabs(w0 + w1 + w2 - 1.0f) < 0.001f;650}
651} // namespace InspectionGui652
653QString ViewProviderInspection::inspectDistance(const SoPickedPoint* pp) const654{
655QString info;656const SoDetail* detail = pp->getDetail(pp->getPath()->getTail());657if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {658// get the distances of the three points of the picked facet659const SoFaceDetail* facedetail = static_cast<const SoFaceDetail*>(detail);660App::Property* pDistance = this->pcObject->getPropertyByName("Distances");661if (pDistance && pDistance->is<Inspection::PropertyDistanceList>()) {662Inspection::PropertyDistanceList* dist =663static_cast<Inspection::PropertyDistanceList*>(pDistance);664int index1 = facedetail->getPoint(0)->getCoordinateIndex();665int index2 = facedetail->getPoint(1)->getCoordinateIndex();666int index3 = facedetail->getPoint(2)->getCoordinateIndex();667float fVal1 = (*dist)[index1];668float fVal2 = (*dist)[index2];669float fVal3 = (*dist)[index3];670
671App::Property* pActual = this->pcObject->getPropertyByName("Actual");672if (pActual && pActual->isDerivedFrom<App::PropertyLink>()) {673float fSearchRadius = this->search_radius;674if (fVal1 > fSearchRadius || fVal2 > fSearchRadius || fVal3 > fSearchRadius) {675info = QObject::tr("Distance: > %1").arg(fSearchRadius);676}677else if (fVal1 < -fSearchRadius || fVal2 < -fSearchRadius678|| fVal3 < -fSearchRadius) {679info = QObject::tr("Distance: < %1").arg(-fSearchRadius);680}681else {682SoSearchAction searchAction;683searchAction.setType(SoCoordinate3::getClassTypeId());684searchAction.setInterest(SoSearchAction::FIRST);685searchAction.apply(pp->getPath()->getNodeFromTail(1));686SoPath* selectionPath = searchAction.getPath();687
688if (selectionPath) {689SoCoordinate3* coords =690static_cast<SoCoordinate3*>(selectionPath->getTail());691const SbVec3f& v1 = coords->point[index1];692const SbVec3f& v2 = coords->point[index2];693const SbVec3f& v3 = coords->point[index3];694const SbVec3f& p = pp->getObjectPoint();695// get the weights696float w1, w2, w3;697calcWeights(v1, v2, v3, p, w1, w2, w3);698float fVal = w1 * fVal1 + w2 * fVal2 + w3 * fVal3;699info = QObject::tr("Distance: %1").arg(fVal);700}701}702}703}704}705else if (detail && detail->getTypeId() == SoPointDetail::getClassTypeId()) {706// safe downward cast, know the type707const SoPointDetail* pointdetail = static_cast<const SoPointDetail*>(detail);708
709// get the distance of the picked point710int index = pointdetail->getCoordinateIndex();711App::Property* prop = this->pcObject->getPropertyByName("Distances");712if (prop && prop->is<Inspection::PropertyDistanceList>()) {713Inspection::PropertyDistanceList* dist =714static_cast<Inspection::PropertyDistanceList*>(prop);715float fVal = (*dist)[index];716info = QObject::tr("Distance: %1").arg(fVal);717}718}719
720return info;721}
722
723// -----------------------------------------------
724
725PROPERTY_SOURCE(InspectionGui::ViewProviderInspectionGroup, Gui::ViewProviderDocumentObjectGroup)726
727
728/**
729* Creates the view provider for an object group.
730*/
731ViewProviderInspectionGroup::ViewProviderInspectionGroup() = default;732
733ViewProviderInspectionGroup::~ViewProviderInspectionGroup() = default;734
735/**
736* Returns the pixmap for the opened list item.
737*/
738QIcon ViewProviderInspectionGroup::getIcon() const739{
740// clang-format off741static const char * const ScanViewOpen[]={742"16 16 10 1",743"c c #000000",744". c None",745"h c #808000",746"# c #808080",747"a c #ffff00",748"r c #ff0000",749"o c #ffff00",750"g c #00ff00",751"t c #00ffff",752"b c #0000ff",753"................",754"...#####........",755"..#hhhhh#.......",756".#hhhhhhh######.",757".#hhhhhhhhhhhh#c",758".#hhhhhhhhhhhh#c",759".#hhhhhhhhhhhh#c",760"#############h#c",761"#aaaaaaaaaa##h#c",762"#aarroggtbbac##c",763".#arroggtbbaac#c",764".#aarroggtbbac#c",765"..#aaaaaaaaaa#cc",766"..#############c",767"...ccccccccccccc",768"................"};769
770static const char * const ScanViewClosed[] = {771"16 16 9 1",772"c c #000000",773". c None",774"# c #808080",775"a c #ffff00",776"r c #ff0000",777"o c #ffff00",778"g c #00ff00",779"t c #00ffff",780"b c #0000ff",781"................",782"...#####........",783"..#aaaaa#.......",784".#aaaaaaa######.",785".#aaaaaaaaaaaa#c",786".#aarroggtbbaa#c",787".#aarroggtbbaa#c",788".#aarroggtbbaa#c",789".#aarroggtbbaa#c",790".#aarroggtbbaa#c",791".#aarroggtbbaa#c",792".#aarroggtbbaa#c",793".#aaaaaaaaaaaa#c",794".##############c",795"..cccccccccccccc",796"................"};797// clang-format on798
799QIcon groupIcon;800groupIcon.addPixmap(QPixmap(ScanViewClosed), QIcon::Normal, QIcon::Off);801groupIcon.addPixmap(QPixmap(ScanViewOpen), QIcon::Normal, QIcon::On);802return groupIcon;803}
804