206 lines
6.8 KiB
C++
206 lines
6.8 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
/***************************************************************************
|
|
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* 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 <FCConfig.h>
|
|
|
|
#ifdef FC_OS_WIN32
|
|
# include <windows.h>
|
|
#endif
|
|
#ifdef FC_OS_MACOSX
|
|
# include <OpenGL/gl.h>
|
|
#else
|
|
# include <GL/gl.h>
|
|
#endif
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include <Inventor/actions/SoGLRenderAction.h>
|
|
#include <Inventor/bundles/SoMaterialBundle.h>
|
|
#include <Inventor/bundles/SoTextureCoordinateBundle.h>
|
|
#include <Inventor/elements/SoCoordinateElement.h>
|
|
#include <Inventor/elements/SoLazyElement.h>
|
|
#include <Inventor/errors/SoReadError.h>
|
|
#include <Inventor/misc/SoState.h>
|
|
|
|
#include "SoFCShapeObject.h"
|
|
|
|
|
|
using namespace PartGui;
|
|
|
|
SO_NODE_SOURCE(SoFCShape);
|
|
|
|
SoFCShape::SoFCShape()
|
|
: coords(new SoCoordinate3)
|
|
, norm(new SoNormal)
|
|
, faceset(new SoBrepFaceSet)
|
|
, lineset(new SoBrepEdgeSet)
|
|
, nodeset(new SoBrepPointSet)
|
|
{
|
|
SO_NODE_CONSTRUCTOR(SoFCShape);
|
|
}
|
|
|
|
void SoFCShape::initClass()
|
|
{
|
|
SO_NODE_INIT_CLASS(SoFCShape, SoSeparator, "Separator");
|
|
}
|
|
|
|
SO_NODE_SOURCE(SoFCControlPoints)
|
|
|
|
void SoFCControlPoints::initClass()
|
|
{
|
|
SO_NODE_INIT_CLASS(SoFCControlPoints, SoShape, "Shape");
|
|
}
|
|
|
|
SoFCControlPoints::SoFCControlPoints()
|
|
{
|
|
SO_NODE_CONSTRUCTOR(SoFCControlPoints);
|
|
|
|
SbVec3f c(1.0f, 0.447059f, 0.337255f);
|
|
SO_NODE_ADD_FIELD(numPolesU, (0));
|
|
SO_NODE_ADD_FIELD(numPolesV, (0));
|
|
SO_NODE_ADD_FIELD(numKnotsU, (0));
|
|
SO_NODE_ADD_FIELD(numKnotsV, (0));
|
|
SO_NODE_ADD_FIELD(lineColor, (c));
|
|
}
|
|
|
|
/**
|
|
* Renders the control points.
|
|
*/
|
|
void SoFCControlPoints::GLRender(SoGLRenderAction* action)
|
|
{
|
|
if (shouldGLRender(action)) {
|
|
SoState* state = action->getState();
|
|
const SoCoordinateElement* coords = SoCoordinateElement::getInstance(state);
|
|
if (!coords) {
|
|
return;
|
|
}
|
|
const SbVec3f* points = coords->getArrayPtr3();
|
|
if (!points) {
|
|
return;
|
|
}
|
|
|
|
SoMaterialBundle mb(action);
|
|
SoTextureCoordinateBundle tb(action, true, false);
|
|
SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
|
|
mb.sendFirst(); // make sure we have the correct material
|
|
|
|
int32_t len = coords->getNum();
|
|
drawControlPoints(points, len);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Renders the control points and knots.
|
|
*/
|
|
void SoFCControlPoints::drawControlPoints(const SbVec3f* points, int32_t len) const
|
|
{
|
|
glLineWidth(1.0f);
|
|
glColor3fv(lineColor.getValue().getValue());
|
|
|
|
uint32_t nCtU = numPolesU.getValue();
|
|
uint32_t nCtV = numPolesV.getValue();
|
|
uint32_t poles = nCtU * nCtV;
|
|
if (poles > (uint32_t)len) {
|
|
return; // wrong setup, too few points
|
|
}
|
|
// draw control mesh
|
|
glBegin(GL_LINES);
|
|
for (uint32_t u = 0; u < nCtU - 1; ++u) {
|
|
for (uint32_t v = 0; v < nCtV - 1; ++v) {
|
|
glVertex3fv(points[u * nCtV + v].getValue());
|
|
glVertex3fv(points[u * nCtV + v + 1].getValue());
|
|
glVertex3fv(points[u * nCtV + v].getValue());
|
|
glVertex3fv(points[(u + 1) * nCtV + v].getValue());
|
|
}
|
|
glVertex3fv(points[(u + 1) * nCtV - 1].getValue());
|
|
glVertex3fv(points[(u + 2) * nCtV - 1].getValue());
|
|
}
|
|
for (uint32_t v = 0; v < nCtV - 1; ++v) {
|
|
glVertex3fv(points[(nCtU - 1) * nCtV + v].getValue());
|
|
glVertex3fv(points[(nCtU - 1) * nCtV + v + 1].getValue());
|
|
}
|
|
glEnd();
|
|
|
|
// draw poles
|
|
glPointSize(5.0f);
|
|
glBegin(GL_POINTS);
|
|
for (uint32_t p = 0; p < poles; p++) {
|
|
glVertex3fv(points[p].getValue());
|
|
}
|
|
glEnd();
|
|
|
|
// draw knots if available
|
|
uint32_t knots = numKnotsU.getValue() * numKnotsV.getValue();
|
|
uint32_t index = poles + knots;
|
|
if (index > (uint32_t)len) {
|
|
return; // wrong setup, too few points
|
|
}
|
|
glColor3f(1.0f, 1.0f, 0.0f);
|
|
glPointSize(6.0f);
|
|
glBegin(GL_POINTS);
|
|
for (uint32_t p = poles; p < index; p++) {
|
|
glVertex3fv(points[p].getValue());
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
void SoFCControlPoints::generatePrimitives(SoAction* /*action*/)
|
|
{}
|
|
|
|
/**
|
|
* Sets the bounding box of the mesh to \a box and its center to \a center.
|
|
*/
|
|
void SoFCControlPoints::computeBBox(SoAction* action, SbBox3f& box, SbVec3f& center)
|
|
{
|
|
SoState* state = action->getState();
|
|
const SoCoordinateElement* coords = SoCoordinateElement::getInstance(state);
|
|
if (!coords) {
|
|
return;
|
|
}
|
|
const SbVec3f* points = coords->getArrayPtr3();
|
|
if (!points) {
|
|
return;
|
|
}
|
|
constexpr float floatMax = std::numeric_limits<float>::max();
|
|
float maxX = -floatMax, minX = floatMax, maxY = -floatMax, minY = floatMax, maxZ = -floatMax,
|
|
minZ = floatMax;
|
|
int32_t len = coords->getNum();
|
|
if (len > 0) {
|
|
for (int32_t i = 0; i < len; i++) {
|
|
maxX = std::max<float>(maxX, points[i][0]);
|
|
minX = std::min<float>(minX, points[i][0]);
|
|
maxY = std::max<float>(maxY, points[i][1]);
|
|
minY = std::min<float>(minY, points[i][1]);
|
|
maxZ = std::max<float>(maxZ, points[i][2]);
|
|
minZ = std::min<float>(minZ, points[i][2]);
|
|
}
|
|
|
|
box.setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
|
center.setValue(0.5f * (minX + maxX), 0.5f * (minY + maxY), 0.5f * (minZ + maxZ));
|
|
}
|
|
else {
|
|
box.setBounds(SbVec3f(0, 0, 0), SbVec3f(0, 0, 0));
|
|
center.setValue(0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|