Commit 8d6d13f8 authored by Jan Möbius's avatar Jan Möbius
Browse files

Generate multiple polylines on plane cuts


git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@20814 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 8295d5d6
......@@ -226,7 +226,7 @@ slotMouseEvent( QMouseEvent* _event )
default:
break;
}
} else if (PluginFunctions::pickMode() == CREATE_CUT_POLYLINE) {
} else if ( (PluginFunctions::pickMode() == CREATE_CUT_POLYLINE) || (PluginFunctions::pickMode() == CREATE_CUT_POLYLINES) ) {
planeSelect_->slotMouseEvent(_event);
}
}
......@@ -266,6 +266,7 @@ slotPickModeChanged( const std::string& _mode)
{
polyLineAction_->setChecked(_mode == "PolyLine");
cutAction_->setChecked( _mode == CREATE_CUT_POLYLINE );
cutMultipleAction_->setChecked( _mode == CREATE_CUT_POLYLINES );
}
......@@ -280,6 +281,7 @@ pluginsInitialized()
emit addHiddenPickMode("PolyLine");
emit setPickModeMouseTracking("PolyLine", true);
emit addHiddenPickMode( CREATE_CUT_POLYLINE );
emit addHiddenPickMode( CREATE_CUT_POLYLINES );
emit registerKey(Qt::Key_Return, Qt::NoModifier, tr("Terminate creation of poly line."), true);
emit registerKey(Qt::Key_Return, Qt::ShiftModifier, tr("Terminate creation of poly line and create loop."), true);
......@@ -306,6 +308,14 @@ pluginsInitialized()
connect(cutAction_, SIGNAL(triggered()), this, SLOT(slotScissorButton()) );
toolbar_->addAction(cutAction_);
// icon for polyline cutting of objects
cutMultipleAction_ = new QAction(tr("&Create polylines at intersection with plane"), this);
cutMultipleAction_->setCheckable( true );
cutMultipleAction_->setStatusTip(tr("Create polylines by specifying a plane with which the object is then intersected. The polylines will be created at the intersection."));
cutMultipleAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cut_polylines.png") );
connect(cutMultipleAction_, SIGNAL(triggered()), this, SLOT(slotScissorLinesButton()) );
toolbar_->addAction(cutMultipleAction_);
connect(toolBarActions_, SIGNAL(triggered(QAction*)), this, SLOT(slotSetPolyLineMode(QAction*)) );
emit addToolbar(toolbar_);
......@@ -416,6 +426,17 @@ void PolyLinePlugin::slotScissorButton( )
PluginFunctions::pickMode( CREATE_CUT_POLYLINE );
}
//------------------------------------------------------------------------------
/** \brief Scissor Button was hit
*
*/
void PolyLinePlugin::slotScissorLinesButton( )
{
PluginFunctions::actionMode( Viewer::PickingMode );
PluginFunctions::pickMode( CREATE_CUT_POLYLINES );
}
//-----------------------------------------------------------------------------
/** \brief Generate PolyLine after the cutPlane has been drawn
......@@ -423,7 +444,8 @@ void PolyLinePlugin::slotScissorButton( )
*/
void PolyLinePlugin::slotTriggerCutPlaneSelect( )
{
using ACG::SceneGraph::LineNode;
using ACG::SceneGraph::LineNode;
// Iterate over all selected objects
BaseObjectData* object;
......@@ -438,25 +460,50 @@ void PolyLinePlugin::slotTriggerCutPlaneSelect( )
ACG::Vec3d point = planeSelect_->getSourcePoint();
ACG::Vec3d normal = planeSelect_->getNormal();
int objectId = generatePolyLineFromCut(object->id(), point, normal);
if ( PluginFunctions::pickMode() == CREATE_CUT_POLYLINE) {
int objectId = generatePolyLineFromCut(object->id(), point, normal);
QString command = "generatePolyLineFromCut(" + QString::number(object->id()) + ",Vector("
+ QString::number(point[0]) + "," + QString::number(point[1]) + "," + QString::number(point[2]) + "),Vector("
+ QString::number(normal[0]) + "," + QString::number(normal[1]) + "," + QString::number(normal[2]) + "));";
emit scriptInfo(command);
QString command = "generatePolyLineFromCut(" + QString::number(object->id()) + ",Vector("
+ QString::number(point[0]) + "," + QString::number(point[1]) + "," + QString::number(point[2]) + "),Vector("
+ QString::number(normal[0]) + "," + QString::number(normal[1]) + "," + QString::number(normal[2]) + "));";
emit scriptInfo(command);
//remove all other targets
for (PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,
DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); o_it != PluginFunctions::objectsEnd(); ++o_it) {
if (o_it->id() != object->id()) {
o_it->target(false);
//remove all other targets
for (PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,
DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); o_it != PluginFunctions::objectsEnd(); ++o_it) {
if (o_it->id() != object->id()) {
o_it->target(false);
}
}
}
// If we successfully created the polyline, we can inform the core about it.
if ( objectId != -1)
emit updatedObject(objectId,UPDATE_ALL);
// If we successfully created the polyline, we can inform the core about it.
if ( objectId != -1)
emit updatedObject(objectId,UPDATE_ALL);
} else {
std::vector <int> objectIds = generatePolyLinesFromCut(object->id(), point, normal);
QString command = "generatePolyLinesFromCut(" + QString::number(object->id()) + ",Vector("
+ QString::number(point[0]) + "," + QString::number(point[1]) + "," + QString::number(point[2]) + "),Vector("
+ QString::number(normal[0]) + "," + QString::number(normal[1]) + "," + QString::number(normal[2]) + "));";
emit scriptInfo(command);
//remove all other targets
for (PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,
DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); o_it != PluginFunctions::objectsEnd(); ++o_it) {
if (o_it->id() != object->id()) {
o_it->target(false);
}
}
for ( unsigned int i = 0 ; i < objectIds.size() ; ++i ) {
// If we successfully created the polyline, we can inform the core about it.
if ( objectIds[i] != -1)
emit updatedObject(objectIds[i],UPDATE_ALL);
}
}
}
}
......@@ -2048,8 +2095,6 @@ void
PolyLinePlugin::
slotEnablePickMode(QString _name)
{
std::cerr << "slotEnablePickMode\n";
PluginFunctions::pickMode("PolyLine");
PluginFunctions::actionMode(Viewer::PickingMode);
......
......@@ -50,6 +50,7 @@
#include <ObjectTypes/PolyLine/PolyLineBezierSplineData.hh>
#define CREATE_CUT_POLYLINE "Create Polyline"
#define CREATE_CUT_POLYLINES "Create Polylines"
//== CLASS DEFINITION =========================================================
......@@ -241,6 +242,9 @@ private :
/// Called by Toolbar to enable pick mode
void slotSetPolyLineMode(QAction* _action);
/// Called by Toolbar to enable pick mode
void slotSetPolyLinesMode(QAction* _action);
/** @} */
//===========================================================================
......@@ -261,6 +265,7 @@ private :
QAction* mergeAction_;
QAction* splitAction_;
QAction* cutAction_;
QAction* cutMultipleAction_;
private slots:
......@@ -276,11 +281,15 @@ private :
private:
/// get the points from the intersection between mesh and plane
/// get the points from the closest connected intersection between mesh and plane
template< class MeshT > std::vector< ACG::Vec3d >
getIntersectionPoints ( MeshT* _mesh, uint _fh, ACG::Vec3d _planeNormal ,
ACG::Vec3d _planePoint, bool& _closed );
/// get all points from the intersection between mesh and plane
template< class MeshT > std::vector< std::vector< ACG::Vec3d > >
getMultipleIntersectionPoints( MeshT* _mesh, ACG::Vec3d _planeNormal , ACG::Vec3d _planePoint );
/// get an edge of the mesh that is cut by the plane
template< class MeshT >
typename MeshT::EdgeHandle
......@@ -297,11 +306,17 @@ public slots:
/// Generates a polyLine of a plane intersection
int generatePolyLineFromCut( int _objectId, Vector _planePoint, Vector _planeNormal, int _polyLineId = -1 );
/// Generates a polyLine of a plane intersection
std::vector<int> generatePolyLinesFromCut( int _objectId, Vector _planePoint, Vector _planeNormal );
private slots:
/// Scissor Button was hit
void slotScissorButton();
/// Scissor Button for multiple polylines was hit
void slotScissorLinesButton();
/// Generate PolyLine after the cutPlane has been drawn
void slotTriggerCutPlaneSelect();
......
#define POLYLINEPLUGIN_CC
#include "PolyLinePlugin.hh"
#include <queue>
//------------------------------------------------------------------------------
template< class MeshT >
bool cutted(MeshT& _mesh, typename MeshT::HalfedgeHandle _he, const ACG::Vec3d _planeNormal, const ACG::Vec3d _planePoint, ACG::Vec3d* _point = 0) {
//get intersection point with plane
typename MeshT::Point p0 = _mesh.point( _mesh.from_vertex_handle(_he) );
typename MeshT::Point p1 = _mesh.point( _mesh.to_vertex_handle(_he) );
typename MeshT::Point u = p1 - p0;
typename MeshT::Point w = p0 - _planePoint;
double D = (_planeNormal | u);
double N = - (_planeNormal | w);
// compute intersect parameter
double sI = N / D;
if ( _point ) {
*_point = p0 + sI * u;
}
return (sI >= 0.0 && sI <= 1.0 );
}
//------------------------------------------------------------------------------
/**
*
* @param _mesh the mesh
* @param _fh a starting face that is intersected
* @param _planeNormal normal of the cut plane
* @param _planePoint point on the cut plane
* @param _closed TODO find out what it's good for
* @return a list of intersection points
*/
template< class MeshT >
std::vector< ACG::Vec3d > getIntersectionLoop( MeshT* _mesh,
uint _fh,
ACG::Vec3d _planeNormal,
ACG::Vec3d _planePoint,
bool& _closed ) {
OpenMesh::HPropHandleT< bool > cut;
_mesh->get_property_handle(cut,"Plane Cut Property" );
typename MeshT::FaceHandle fh ( _fh );
typename MeshT::FaceHandle current_face = typename MeshT::FaceHandle(_fh);
bool stop = false;
bool nothingFound = true;
int expansionLevel = 0;
bool flip_dir = false;
_closed = true;
std::vector< ACG::Vec3d > linePoints;
std::vector< typename MeshT::FaceHandle > startCandidates;
std::vector< typename MeshT::FaceHandle > expandable;
expandable.push_back( fh );
while (!stop) {
stop = true;
// First check the face we are in
for ( typename MeshT::FaceHalfedgeIter fhe_it( *_mesh, current_face ); fhe_it.is_valid(); ++fhe_it){
if ( _mesh->property(cut,*fhe_it) )
continue;
typename MeshT::Point p0 = _mesh->point( _mesh->from_vertex_handle(*fhe_it) );
typename MeshT::Point p1 = _mesh->point( _mesh->to_vertex_handle(*fhe_it) );
typename MeshT::Point u = p1 - p0;
typename MeshT::Point w = p0 - _planePoint;
double D = (_planeNormal | u);
double N = - (_planeNormal | w);
// compute intersect param
double sI = N / D;
if (sI < 0.0 || sI > 1.0 ) // intersection on ray, but not within line segment
continue;
nothingFound = false;
stop = false;
_mesh->property(cut,*fhe_it) = true;
_mesh->property(cut,_mesh->opposite_halfedge_handle(*fhe_it)) = true;
current_face = _mesh->face_handle(_mesh->opposite_halfedge_handle(*fhe_it));
if (!current_face.is_valid())
stop = true;
typename MeshT::Point cutPoint = p0 + sI * u;
// add new point
if ( !flip_dir )
linePoints.push_back(cutPoint);
else {
linePoints.insert( linePoints.begin() , cutPoint );
_closed = false;
}
break;
}
if ( stop ){
if ( nothingFound ){
if ( startCandidates.empty() ){
if (expansionLevel > 3 )
std::cerr << "Expanded" << expansionLevel << "rings but still nothing found!" << std::endl;
else{
//add the "expansionLevel"-ring of the start-face to the start candidates
for (uint i=0; i < expandable.size(); i++)
for( typename MeshT::FaceFaceIter ff_it(*_mesh, expandable[i]); ff_it.is_valid(); ++ff_it )
startCandidates.push_back( *ff_it );
expandable.clear();
expansionLevel++;
}
}
if ( !startCandidates.empty() ){
fh = startCandidates.back();
expandable.push_back( fh );
startCandidates.pop_back();
stop = false;
}
}else if (! flip_dir ){
flip_dir = true;
stop = false;
}
current_face = fh;
}
}
return linePoints;
}
//------------------------------------------------------------------------------
......@@ -21,106 +167,12 @@ std::vector< ACG::Vec3d > PolyLinePlugin::getIntersectionPoints( MeshT* _mesh,
bool& _closed ) {
OpenMesh::HPropHandleT< bool > cut;
_mesh->add_property(cut,"Plane Cut Property" );
typename MeshT::FaceHandle fh ( _fh );
typename MeshT::FaceHandle current_face = typename MeshT::FaceHandle(_fh);
typename MeshT::HalfedgeIter e_it, e_end = _mesh->halfedges_end();
for( e_it = _mesh->halfedges_begin(); e_it != e_end; ++e_it )
_mesh->property( cut, *e_it ) = false;
// int id = -1;
bool stop = false;
bool nothingFound = true;
int expansionLevel = 0;
bool flip_dir = false;
_closed = true;
std::vector< ACG::Vec3d > linePoints;
std::vector< typename MeshT::FaceHandle > startCandidates;
std::vector< typename MeshT::FaceHandle > expandable;
expandable.push_back( fh );
while (!stop) {
stop = true;
// First check the face we are in
for ( typename MeshT::FaceHalfedgeIter fhe_it( *_mesh, current_face ); fhe_it.is_valid(); ++fhe_it){
if ( _mesh->property(cut,*fhe_it) )
continue;
typename MeshT::Point p0 = _mesh->point( _mesh->from_vertex_handle(*fhe_it) );
typename MeshT::Point p1 = _mesh->point( _mesh->to_vertex_handle(*fhe_it) );
typename MeshT::Point u = p1 - p0;
typename MeshT::Point w = p0 - _planePoint;
double D = (_planeNormal | u);
double N = - (_planeNormal | w);
// compute intersect param
double sI = N / D;
if (sI < 0.0 || sI > 1.0 ) // intersection on ray, but not within line segment
continue;
nothingFound = false;
stop = false;
_mesh->property(cut,*fhe_it) = true;
_mesh->property(cut,_mesh->opposite_halfedge_handle(*fhe_it)) = true;
current_face = _mesh->face_handle(_mesh->opposite_halfedge_handle(*fhe_it));
if (!current_face.is_valid())
stop = true;
typename MeshT::Point cutPoint = p0 + sI * u;
// add new point
if ( !flip_dir )
linePoints.push_back(cutPoint);
else {
linePoints.insert( linePoints.begin() , cutPoint );
_closed = false;
}
break;
}
if ( stop ){
if ( nothingFound ){
if ( startCandidates.empty() ){
if (expansionLevel > 3 )
std::cerr << "Expanded" << expansionLevel << "rings but still nothing found!" << std::endl;
else{
//add the "expansionLevel"-ring of the start-face to the start candidates
for (uint i=0; i < expandable.size(); i++)
for( typename MeshT::FaceFaceIter ff_it(*_mesh, expandable[i]); ff_it.is_valid(); ++ff_it )
startCandidates.push_back( *ff_it );
expandable.clear();
expansionLevel++;
}
}
if ( !startCandidates.empty() ){
fh = startCandidates.back();
expandable.push_back( fh );
startCandidates.pop_back();
stop = false;
}
}else if (! flip_dir ){
flip_dir = true;
stop = false;
}
current_face = fh;
}
}
std::vector< ACG::Vec3d > linePoints = getIntersectionLoop(_mesh,_fh,_planeNormal,_planePoint,_closed);
_mesh->remove_property( cut );
......@@ -178,4 +230,82 @@ PolyLinePlugin::getCuttedEdge(MeshT& _mesh, ACG::Vec3d& _planeNormal, ACG::Vec3d
}
return minEdge;
}
\ No newline at end of file
}
/**
*
* @param _mesh the mesh
* @param _planeNormal normal of the cut plane
* @param _planePoint point on the cut plane
* @return a list of intersection points for each connected intersection ring
*/
template< class MeshT >
std::vector< std::vector<ACG::Vec3d> > PolyLinePlugin::getMultipleIntersectionPoints( MeshT* _mesh,
ACG::Vec3d _planeNormal,
ACG::Vec3d _planePoint) {
std::vector< std::vector<ACG::Vec3d> > lines;
OpenMesh::HPropHandleT< bool > cut;
_mesh->add_property(cut,"Plane Cut Property" );
std::queue< typename MeshT::EdgeHandle > queue;
// Mark all edges as not cut, and remember cutted edges as starting points if we get multiple unconnected cuts
for( typename MeshT::EdgeIter e_it = _mesh->edges_begin(); e_it != _mesh->edges_end(); ++e_it ) {
// Remember cutted edge
if ( cutted(*_mesh, _mesh->halfedge_handle(*e_it, 0),_planeNormal, _planePoint, 0) ) {
queue.push(*e_it);
}
//Initialize halfedge Property
_mesh->property( cut, _mesh->halfedge_handle(*e_it, 0) ) = false;
_mesh->property( cut, _mesh->halfedge_handle(*e_it, 1) ) = false;
}
// Used to catch all connected components
while( !queue.empty() ) {
// Get next element from queue
typename MeshT::HalfedgeHandle hh = _mesh->halfedge_handle( queue.front() , 0);
queue.pop();
// Already visited so skip this one
if ( _mesh->property(cut,hh) )
continue;
// Get the adjacent face
typename MeshT::FaceHandle fh = _mesh->face_handle(hh);
// If we are at a boundary, get next
if ( !fh.is_valid() ) {
fh = _mesh->face_handle(_mesh->opposite_halfedge_handle(hh));
}
// No face anywhere at this edge? This should not happen, so we just skip the edge
if ( !fh.is_valid() )
continue;
bool closed = false;
// Compute the polyline from current face
lines.push_back(getIntersectionLoop(_mesh,fh.idx(),_planeNormal,_planePoint,closed) );
}
// Cleanup
_mesh->remove_property( cut );
return lines;
}
......@@ -109,3 +109,98 @@ int PolyLinePlugin::generatePolyLineFromCut( int _objectId, Vector _planePoint,
return polyLineId;
}
/** \brief Generates polyLines from a plane intersection
*
*
* @param _objectId id of the target object
* @param _planePoint a point on the cut plane
* @param _planeNormal the normal of the cut plane
* @return returns the ids of the polyLine
*/
std::vector<int> PolyLinePlugin::generatePolyLinesFromCut( int _objectId, Vector _planePoint, Vector _planeNormal) {
// List of generated lines
std::vector<int> lines;
// get object
BaseObjectData *obj;
PluginFunctions::getObject(_objectId, obj);
if (obj == 0){
emit log(LOGERR,tr("Unable to get object"));
return lines;
}
//get the intersection points
std::vector< std::vector< ACG::Vec3d > > linePoints;
bool closed = false;
if ( obj->dataType(DATA_TRIANGLE_MESH) ) {
TriMesh* mesh = PluginFunctions::triMesh(obj);
if ( mesh == 0 ) {
emit log(LOGERR,tr("Unable to get mesh"));
return lines;
}
// get all intersection points
linePoints = getMultipleIntersectionPoints( mesh, _planeNormal , _planePoint);
} else {
PolyMesh* mesh = PluginFunctions::polyMesh(obj);
if ( mesh == 0 ) {
emit log(LOGERR,tr("Unable to get mesh"));
return lines;
}
// get all intersection points
linePoints = getMultipleIntersectionPoints( mesh, _planeNormal , _planePoint);
}
// No lines found?
if ( linePoints.empty() ) {
emit log(LOGERR,tr("No cut lines found."));
return lines;
}
for ( unsigned int i = 0 ; i < linePoints.size(); ++i ) {
if ( linePoints[i].empty() )
continue;
//generate a polyLine from the intersection Points
int polyLineId = -1;