// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2007 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "SoFCBoundingBox.h" using namespace Gui; SO_NODE_SOURCE(SoFCBoundingBox) // vertices used to create a box static const int32_t bBoxVerts[8][3] = {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}}; // indexes used to create the edges static const int32_t bBoxEdges[36] = {0, 1, -1, 1, 2, -1, 2, 3, -1, 3, 0, -1, 4, 5, -1, 5, 6, -1, 6, 7, -1, 7, 4, -1, 0, 4, -1, 1, 5, -1, 2, 6, -1, 3, 7, -1}; void SoFCBoundingBox::initClass() { SO_NODE_INIT_CLASS(SoFCBoundingBox, SoShape, "Shape"); } SoFCBoundingBox::SoFCBoundingBox() { SO_NODE_CONSTRUCTOR(SoFCBoundingBox); SO_NODE_ADD_FIELD(minBounds, (-1.0, -1.0, -1.0)); SO_NODE_ADD_FIELD(maxBounds, (1.0, 1.0, 1.0)); SO_NODE_ADD_FIELD(coordsOn, (true)); SO_NODE_ADD_FIELD(dimensionsOn, (true)); root = new SoSeparator(); auto bboxSep = new SoSeparator(); bboxCoords = new SoCoordinate3(); bboxCoords->point.setNum(8); bboxSep->addChild(bboxCoords); root->addChild(bboxSep); // the lines of the box bboxLines = new SoIndexedLineSet(); bboxLines->coordIndex.setNum(36); bboxLines->coordIndex.setValues(0, 36, bBoxEdges); bboxSep->addChild(bboxLines); // create the text nodes, including a transform for each vertice offset textSep = new SoSeparator(); for (int i = 0; i < 8; i++) { auto temp = new SoSeparator(); auto trans = new SoTransform(); temp->addChild(trans); auto text = new SoText2(); text->justification.setValue(SoText2::CENTER); temp->addChild(text); textSep->addChild(temp); } // create the text nodes, including a transform for each dimension dimSep = new SoSeparator(); for (int i = 0; i < 3; i++) { auto temp = new SoSeparator(); auto trans = new SoTransform(); temp->addChild(trans); auto text = new SoText2(); text->justification.setValue(SoText2::CENTER); temp->addChild(text); dimSep->addChild(temp); } root->addChild(textSep); root->addChild(dimSep); root->ref(); } SoFCBoundingBox::~SoFCBoundingBox() { root->unref(); } void SoFCBoundingBox::GLRender(SoGLRenderAction* action) { SbVec3f corner[2], ctr, *vptr; SbBool coord, dimension; // grab the current state // SoState *state = action->getState(); if (!shouldGLRender(action)) { return; } // get the latest values from the fields corner[0] = minBounds.getValue(); corner[1] = maxBounds.getValue(); coord = coordsOn.getValue(); dimension = dimensionsOn.getValue(); // set the coordinates for the LineSet to point to vptr = bboxCoords->point.startEditing(); for (int i = 0; i < 8; i++) { for (int j = 0; j < 3; j++) { vptr[i][j] = corner[bBoxVerts[i][j]][j]; } } // if coord is true then set the text nodes if (coord) { ctr = (corner[1] - corner[0]) / 2.0f; for (int i = 0; i < 8; i++) { // create the string for the text std::stringstream str; str.precision(2); str.setf(std::ios::fixed | std::ios::showpoint); str << "(" << vptr[i][0] << "," << vptr[i][1] << "," << vptr[i][2] << ")"; SoSeparator* sep = static_cast(textSep->getChild(i)); SoTransform* trans = static_cast(sep->getChild(0)); trans->translation.setValue(vptr[i].getValue()); SoText2* t = static_cast(sep->getChild(1)); t->string.setValue(str.str().c_str()); } textSep->ref(); if (root->findChild(textSep) < 0) { root->addChild(textSep); } } else { if (root->findChild(textSep) >= 0) { root->removeChild(textSep); } } // if dimension is true then set the text nodes if (dimension) { ctr = (corner[1] - corner[0]) / 2.0f; for (int i = 0; i < 3; i++) { // create the string for the text std::stringstream str; str.precision(2); str.setf(std::ios::fixed | std::ios::showpoint); str << (2.0f * ctr[i]); SoSeparator* sep = static_cast(dimSep->getChild(i)); SoTransform* trans = static_cast(sep->getChild(0)); SbVec3f point = corner[0]; point[i] += ctr[i]; trans->translation.setValue(point.getValue()); SoText2* t = static_cast(sep->getChild(1)); t->string.setValue(str.str().c_str()); } dimSep->ref(); if (root->findChild(dimSep) < 0) { root->addChild(dimSep); } } else { if (root->findChild(dimSep) >= 0) { root->removeChild(dimSep); } } bboxCoords->point.finishEditing(); // Avoid shading SoState* state = action->getState(); state->push(); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); root->GLRender(action); state->pop(); } void SoFCBoundingBox::generatePrimitives(SoAction* /*action*/) {} void SoFCBoundingBox::computeBBox(SoAction* /*action*/, SbBox3f& box, SbVec3f& center) { center = (minBounds.getValue() + maxBounds.getValue()) / 2.0f; box.setBounds(minBounds.getValue(), maxBounds.getValue()); } void SoFCBoundingBox::finish() { atexit_cleanup(); } // --------------------------------------------------------------- SO_NODE_SOURCE(SoSkipBoundingGroup) /*! Constructor. */ SoSkipBoundingGroup::SoSkipBoundingGroup() { SO_NODE_CONSTRUCTOR(SoSkipBoundingGroup); SO_NODE_ADD_FIELD(mode, (INCLUDE_BBOX)); SO_NODE_DEFINE_ENUM_VALUE(Modes, INCLUDE_BBOX); SO_NODE_DEFINE_ENUM_VALUE(Modes, EXCLUDE_BBOX); SO_NODE_SET_SF_ENUM_TYPE(mode, Modes); } /*! Destructor. */ SoSkipBoundingGroup::~SoSkipBoundingGroup() = default; void SoSkipBoundingGroup::initClass() { SO_NODE_INIT_CLASS(SoSkipBoundingGroup, SoGroup, "Group"); } void SoSkipBoundingGroup::finish() { atexit_cleanup(); } void SoSkipBoundingGroup::getBoundingBox(SoGetBoundingBoxAction* action) { if (mode.getValue() == INCLUDE_BBOX) { inherited::getBoundingBox(action); } }