481 lines
17 KiB
C++
481 lines
17 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2004 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 "PreCompiled.h"
|
|
|
|
#ifndef _PreComp_
|
|
# ifdef FC_OS_WIN32
|
|
# include <windows.h>
|
|
# endif
|
|
# include <Inventor/nodes/SoCamera.h>
|
|
# include <Inventor/nodes/SoCoordinate3.h>
|
|
# include <Inventor/nodes/SoDrawStyle.h>
|
|
# include <Inventor/nodes/SoPointSet.h>
|
|
# include <Inventor/nodes/SoMaterial.h>
|
|
# include <Inventor/nodes/SoMaterialBinding.h>
|
|
# include <Inventor/nodes/SoNormal.h>
|
|
# include <Inventor/errors/SoDebugError.h>
|
|
# include <Inventor/events/SoMouseButtonEvent.h>
|
|
#endif
|
|
|
|
/// Here the FreeCAD includes sorted by Base,App,Gui,...
|
|
#include <Base/Console.h>
|
|
#include <Base/Parameter.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/Sequencer.h>
|
|
#include <Base/Tools2D.h>
|
|
#include <Base/Vector3D.h>
|
|
#include <App/Application.h>
|
|
#include <App/Document.h>
|
|
#include <Gui/Application.h>
|
|
#include <Gui/Document.h>
|
|
#include <Gui/SoFCSelection.h>
|
|
|
|
#include <Gui/View3DInventorViewer.h>
|
|
#include <Mod/Points/App/PointsFeature.h>
|
|
|
|
#include "ViewProvider.h"
|
|
#include "../App/Properties.h"
|
|
|
|
|
|
using namespace PointsGui;
|
|
using namespace Points;
|
|
|
|
|
|
PROPERTY_SOURCE(PointsGui::ViewProviderPoints, Gui::ViewProviderGeometryObject)
|
|
|
|
|
|
App::PropertyFloatConstraint::Constraints ViewProviderPoints::floatRange = {1.0,64.0,1.0};
|
|
|
|
ViewProviderPoints::ViewProviderPoints()
|
|
{
|
|
ADD_PROPERTY(PointSize,(2.0f));
|
|
PointSize.setConstraints(&floatRange);
|
|
|
|
pcPointsCoord = new SoCoordinate3();
|
|
pcPointsCoord->ref();
|
|
pcPoints = new SoPointSet();
|
|
pcPoints->ref();
|
|
pcPointsNormal = new SoNormal();
|
|
pcPointsNormal->ref();
|
|
pcColorMat = new SoMaterial;
|
|
pcColorMat->ref();
|
|
|
|
pcPointStyle = new SoDrawStyle();
|
|
pcPointStyle->ref();
|
|
pcPointStyle->style = SoDrawStyle::POINTS;
|
|
pcPointStyle->pointSize = PointSize.getValue();
|
|
}
|
|
|
|
ViewProviderPoints::~ViewProviderPoints()
|
|
{
|
|
pcPointsCoord->unref();
|
|
pcPoints->unref();
|
|
pcPointsNormal->unref();
|
|
pcColorMat->unref();
|
|
pcPointStyle->unref();
|
|
}
|
|
|
|
void ViewProviderPoints::onChanged(const App::Property* prop)
|
|
{
|
|
if ( prop == &PointSize ) {
|
|
pcPointStyle->pointSize = PointSize.getValue();
|
|
}
|
|
else {
|
|
ViewProviderGeometryObject::onChanged(prop);
|
|
}
|
|
}
|
|
|
|
void ViewProviderPoints::setVertexColorMode(App::PropertyColorList* pcProperty)
|
|
{
|
|
const std::vector<App::Color>& val = pcProperty->getValues();
|
|
unsigned long i=0;
|
|
|
|
pcColorMat->enableNotify(false);
|
|
pcColorMat->diffuseColor.deleteValues(0);
|
|
pcColorMat->diffuseColor.setNum(val.size());
|
|
|
|
for ( std::vector<App::Color>::const_iterator it = val.begin(); it != val.end(); ++it ) {
|
|
pcColorMat->diffuseColor.set1Value(i++, SbColor(it->r, it->g, it->b));
|
|
}
|
|
|
|
pcColorMat->enableNotify(true);
|
|
pcColorMat->touch();
|
|
}
|
|
|
|
void ViewProviderPoints::setVertexGreyvalueMode(Points::PropertyGreyValueList* pcProperty)
|
|
{
|
|
const std::vector<float>& val = pcProperty->getValues();
|
|
unsigned long i=0;
|
|
|
|
pcColorMat->enableNotify(false);
|
|
pcColorMat->diffuseColor.deleteValues(0);
|
|
pcColorMat->diffuseColor.setNum(val.size());
|
|
|
|
for ( std::vector<float>::const_iterator it = val.begin(); it != val.end(); ++it ) {
|
|
pcColorMat->diffuseColor.set1Value(i++, SbColor(*it, *it, *it));
|
|
}
|
|
|
|
pcColorMat->enableNotify(true);
|
|
pcColorMat->touch();
|
|
}
|
|
|
|
void ViewProviderPoints::setVertexNormalMode(Points::PropertyNormalList* pcProperty)
|
|
{
|
|
const std::vector<Base::Vector3f>& val = pcProperty->getValues();
|
|
unsigned long i=0;
|
|
|
|
pcPointsNormal->enableNotify(false);
|
|
pcPointsNormal->vector.deleteValues(0);
|
|
pcPointsNormal->vector.setNum(val.size());
|
|
|
|
for ( std::vector<Base::Vector3f>::const_iterator it = val.begin(); it != val.end(); ++it ) {
|
|
pcPointsNormal->vector.set1Value(i++, it->x, it->y, it->z);
|
|
}
|
|
|
|
pcPointsNormal->enableNotify(true);
|
|
pcPointsNormal->touch();
|
|
}
|
|
|
|
void ViewProviderPoints::attach(App::DocumentObject* pcObj)
|
|
{
|
|
// call parent's attach to define display modes
|
|
ViewProviderGeometryObject::attach(pcObj);
|
|
|
|
SoGroup* pcPointRoot = new SoGroup();
|
|
SoGroup* pcPointShadedRoot = new SoGroup();
|
|
SoGroup* pcColorShadedRoot = new SoGroup();
|
|
|
|
// Hilight for selection
|
|
pcHighlight->addChild(pcPointsCoord);
|
|
pcHighlight->addChild(pcPoints);
|
|
|
|
// points part ---------------------------------------------
|
|
pcPointRoot->addChild(pcPointStyle);
|
|
pcPointRoot->addChild(pcShapeMaterial);
|
|
pcPointRoot->addChild(pcHighlight);
|
|
|
|
// points shaded ---------------------------------------------
|
|
pcPointShadedRoot->addChild(pcPointStyle);
|
|
pcPointShadedRoot->addChild(pcShapeMaterial);
|
|
pcPointShadedRoot->addChild(pcPointsNormal);
|
|
pcPointShadedRoot->addChild(pcHighlight);
|
|
|
|
// color shaded ------------------------------------------
|
|
pcColorShadedRoot->addChild(pcPointStyle);
|
|
SoMaterialBinding* pcMatBinding = new SoMaterialBinding;
|
|
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
|
|
pcColorShadedRoot->addChild(pcColorMat);
|
|
pcColorShadedRoot->addChild(pcMatBinding);
|
|
pcColorShadedRoot->addChild(pcHighlight);
|
|
|
|
// putting all together with a switch
|
|
addDisplayMaskMode(pcPointRoot, "Point");
|
|
addDisplayMaskMode(pcColorShadedRoot, "Color");
|
|
addDisplayMaskMode(pcPointShadedRoot, "Shaded");
|
|
}
|
|
|
|
void ViewProviderPoints::setDisplayMode(const char* ModeName)
|
|
{
|
|
int numPoints = pcPointsCoord->point.getNum();
|
|
|
|
if ( strcmp("Color",ModeName)==0 )
|
|
{
|
|
std::map<std::string,App::Property*> Map;
|
|
pcObject->getPropertyMap(Map);
|
|
for( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it )
|
|
{
|
|
Base::Type t = it->second->getTypeId();
|
|
if ( t==App::PropertyColorList::getClassTypeId() )
|
|
{
|
|
App::PropertyColorList* colors = (App::PropertyColorList*)it->second;
|
|
if ( numPoints != colors->getSize() ) {
|
|
#ifdef FC_DEBUG
|
|
SoDebugError::postWarning("ViewProviderPoints::setDisplayMode",
|
|
"The number of points (%d) doesn't match with the number of colors (%d).", numPoints, colors->getSize());
|
|
#endif
|
|
// fallback
|
|
setDisplayMaskMode("Point");
|
|
} else {
|
|
setVertexColorMode(colors);
|
|
setDisplayMaskMode("Color");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( strcmp("Intensity",ModeName)==0 )
|
|
{
|
|
std::map<std::string,App::Property*> Map;
|
|
pcObject->getPropertyMap(Map);
|
|
for( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it )
|
|
{
|
|
Base::Type t = it->second->getTypeId();
|
|
if ( t==Points::PropertyGreyValueList::getClassTypeId() )
|
|
{
|
|
Points::PropertyGreyValueList* greyValues = (Points::PropertyGreyValueList*)it->second;
|
|
if ( numPoints != greyValues->getSize() ) {
|
|
#ifdef FC_DEBUG
|
|
SoDebugError::postWarning("ViewProviderPoints::setDisplayMode",
|
|
"The number of points (%d) doesn't match with the number of grey values (%d).", numPoints, greyValues->getSize());
|
|
#endif
|
|
// Intensity mode is not possible then set the default () mode instead.
|
|
setDisplayMaskMode("Point");
|
|
} else {
|
|
setVertexGreyvalueMode((Points::PropertyGreyValueList*)it->second);
|
|
setDisplayMaskMode("Color");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( strcmp("Shaded",ModeName)==0 )
|
|
{
|
|
std::map<std::string,App::Property*> Map;
|
|
pcObject->getPropertyMap(Map);
|
|
for( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it )
|
|
{
|
|
Base::Type t = it->second->getTypeId();
|
|
if ( t==Points::PropertyNormalList::getClassTypeId() )
|
|
{
|
|
Points::PropertyNormalList* normals = (Points::PropertyNormalList*)it->second;
|
|
if ( numPoints != normals->getSize() ) {
|
|
#ifdef FC_DEBUG
|
|
SoDebugError::postWarning("ViewProviderPoints::setDisplayMode",
|
|
"The number of points (%d) doesn't match with the number of normals (%d).", numPoints, normals->getSize());
|
|
#endif
|
|
// fallback
|
|
setDisplayMaskMode("Point");
|
|
} else {
|
|
setVertexNormalMode(normals);
|
|
setDisplayMaskMode("Shaded");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( strcmp("Points",ModeName)==0 )
|
|
{
|
|
setDisplayMaskMode("Point");
|
|
}
|
|
|
|
ViewProviderGeometryObject::setDisplayMode(ModeName);
|
|
}
|
|
|
|
std::vector<std::string> ViewProviderPoints::getDisplayModes(void) const
|
|
{
|
|
std::vector<std::string> StrList;
|
|
StrList.push_back("Points");
|
|
|
|
if ( pcObject )
|
|
{
|
|
std::map<std::string,App::Property*> Map;
|
|
pcObject->getPropertyMap(Map);
|
|
|
|
for( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it )
|
|
{
|
|
Base::Type t = it->second->getTypeId();
|
|
if ( t==Points::PropertyNormalList::getClassTypeId() )
|
|
StrList.push_back("Shaded");
|
|
else if ( t==Points::PropertyGreyValueList::getClassTypeId() )
|
|
StrList.push_back("Intensity");
|
|
else if ( t==App::PropertyColorList::getClassTypeId() )
|
|
StrList.push_back("Color");
|
|
}
|
|
}
|
|
|
|
return StrList;
|
|
}
|
|
|
|
void ViewProviderPoints::updateData(const App::Property* prop)
|
|
{
|
|
Gui::ViewProviderGeometryObject::updateData(prop);
|
|
if (prop->getTypeId() == Points::PropertyPointKernel::getClassTypeId()) {
|
|
ViewProviderPointsBuilder builder;
|
|
builder.createPoints(prop, pcPointsCoord, pcPoints);
|
|
|
|
// The number of points might have changed, so force also a resize of the Inventor internals
|
|
setActiveMode();
|
|
}
|
|
}
|
|
|
|
QIcon ViewProviderPoints::getIcon() const
|
|
{
|
|
static const char * const Points_Feature_xpm[] = {
|
|
"16 16 4 1",
|
|
". c none",
|
|
"s c #000000",
|
|
"b c #FFFF00",
|
|
"r c #FF0000",
|
|
"ss.....ss.....bb",
|
|
"ss..ss.ss.....bb",
|
|
"....ss..........",
|
|
"...........bb...",
|
|
".ss..ss....bb...",
|
|
".ss..ss.........",
|
|
"........bb....bb",
|
|
"ss......bb....bb",
|
|
"ss..rr......bb..",
|
|
"....rr......bb..",
|
|
"........bb......",
|
|
"..rr....bb..bb..",
|
|
"..rr........bb..",
|
|
".....rr.........",
|
|
"rr...rr..rr..rr.",
|
|
"rr.......rr..rr."};
|
|
QPixmap px(Points_Feature_xpm);
|
|
return px;
|
|
}
|
|
|
|
bool ViewProviderPoints::setEdit(int)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ViewProviderPoints::unsetEdit(int)
|
|
{
|
|
}
|
|
|
|
void ViewProviderPoints::clipPointsCallback(void * ud, SoEventCallback * n)
|
|
{
|
|
// When this callback function is invoked we must in either case leave the edit mode
|
|
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
|
|
view->setEditing(false);
|
|
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), clipPointsCallback);
|
|
n->setHandled();
|
|
|
|
std::vector<SbVec2f> clPoly = view->getGLPolygon();
|
|
if (clPoly.size() < 3)
|
|
return;
|
|
if (clPoly.front() != clPoly.back())
|
|
clPoly.push_back(clPoly.front());
|
|
|
|
std::vector<Gui::ViewProvider*> views = view->getViewProvidersOfType(ViewProviderPoints::getClassTypeId());
|
|
for (std::vector<Gui::ViewProvider*>::iterator it = views.begin(); it != views.end(); ++it) {
|
|
ViewProviderPoints* that = static_cast<ViewProviderPoints*>(*it);
|
|
if (that->getEditingMode() > -1) {
|
|
that->finishEditing();
|
|
that->cut(clPoly, *view);
|
|
}
|
|
}
|
|
|
|
view->render();
|
|
}
|
|
|
|
void ViewProviderPoints::cut(const std::vector<SbVec2f>& picked, Gui::View3DInventorViewer &Viewer)
|
|
{
|
|
// create the polygon from the picked points
|
|
Base::Polygon2D cPoly;
|
|
for (std::vector<SbVec2f>::const_iterator it = picked.begin(); it != picked.end(); ++it) {
|
|
cPoly.Add(Base::Vector2D((*it)[0],(*it)[1]));
|
|
}
|
|
|
|
// get a reference to the point feature
|
|
Points::Feature* fea = (Points::Feature*)pcObject;
|
|
const Points::PointKernel& points = fea->Points.getValue();
|
|
|
|
SoCamera* pCam = Viewer.getCamera();
|
|
SbViewVolume vol = pCam->getViewVolume();
|
|
|
|
// search for all points inside/outside the polygon
|
|
Points::PointKernel newKernel;
|
|
for ( Points::PointKernel::const_iterator jt = points.begin(); jt != points.end(); ++jt ) {
|
|
SbVec3f pt(jt->x,jt->y,jt->z);
|
|
|
|
// project from 3d to 2d
|
|
vol.projectToScreen(pt, pt);
|
|
if (!cPoly.Contains(Base::Vector2D(pt[0],pt[1])))
|
|
newKernel.push_back(*jt);
|
|
}
|
|
|
|
if (newKernel.size() == points.size())
|
|
return; // nothing needs to be done
|
|
|
|
//Remove the points from the cloud and open a transaction object for the undo/redo stuff
|
|
Gui::Application::Instance->activeDocument()->openCommand("Cut points");
|
|
|
|
// sets the points outside the polygon to update the Inventor node
|
|
fea->Points.setValue(newKernel);
|
|
|
|
// unset the modified flag because we don't need the features' execute() to be called
|
|
Gui::Application::Instance->activeDocument()->commitCommand();
|
|
fea->purgeTouched();
|
|
}
|
|
|
|
// -------------------------------------------------
|
|
|
|
namespace Gui {
|
|
/// @cond DOXERR
|
|
PROPERTY_SOURCE_TEMPLATE(PointsGui::ViewProviderPython, PointsGui::ViewProviderPoints)
|
|
/// @endcond
|
|
|
|
// explicit template instantiation
|
|
template class PointsGuiExport ViewProviderPythonFeatureT<PointsGui::ViewProviderPoints>;
|
|
}
|
|
|
|
// -------------------------------------------------
|
|
|
|
void ViewProviderPointsBuilder::buildNodes(const App::Property* prop, std::vector<SoNode*>& nodes) const
|
|
{
|
|
SoCoordinate3 *pcPointsCoord=0;
|
|
SoPointSet *pcPoints=0;
|
|
|
|
if (nodes.empty()) {
|
|
pcPointsCoord = new SoCoordinate3();
|
|
nodes.push_back(pcPointsCoord);
|
|
pcPoints = new SoPointSet();
|
|
nodes.push_back(pcPoints);
|
|
}
|
|
else if (nodes.size() == 2) {
|
|
if (nodes[0]->getTypeId() == SoCoordinate3::getClassTypeId())
|
|
pcPointsCoord = static_cast<SoCoordinate3*>(nodes[0]);
|
|
if (nodes[1]->getTypeId() == SoPointSet::getClassTypeId())
|
|
pcPoints = static_cast<SoPointSet*>(nodes[1]);
|
|
}
|
|
|
|
if (pcPointsCoord && pcPoints)
|
|
createPoints(prop, pcPointsCoord, pcPoints);
|
|
}
|
|
|
|
void ViewProviderPointsBuilder::createPoints(const App::Property* prop, SoCoordinate3* coords, SoPointSet* points) const
|
|
{
|
|
const Points::PropertyPointKernel* prop_points = static_cast<const Points::PropertyPointKernel*>(prop);
|
|
const Points::PointKernel& cPts = prop_points->getValue();
|
|
|
|
// disable the notification, otherwise whenever a point is inserted SoPointSet gets notified
|
|
coords->enableNotify(false);
|
|
coords->point.deleteValues(0);
|
|
coords->point.setNum(cPts.size());
|
|
|
|
// get all points
|
|
int idx=0;
|
|
const std::vector<Points::PointKernel::value_type>& kernel = cPts.getBasicPoints();
|
|
for (std::vector<Points::PointKernel::value_type>::const_iterator it = kernel.begin(); it != kernel.end(); ++it, idx++) {
|
|
coords->point.set1Value(idx, (float)it->x, (float)it->y, (float)it->z);
|
|
}
|
|
|
|
points->numPoints = cPts.size();
|
|
coords->enableNotify(true);
|
|
coords->touch();
|
|
}
|