mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-20 03:16:10 +00:00
716 lines
28 KiB
C++
716 lines
28 KiB
C++
/****************************************************************************
|
|
* MeshLab o o *
|
|
* A versatile mesh processing toolbox o o *
|
|
* _ O _ *
|
|
* Copyright(C) 2005 \/)\/ *
|
|
* Visual Computing Lab /\/| *
|
|
* ISTI - Italian National Research Council | *
|
|
* \ *
|
|
* All rights reserved. *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
|
* for more details. *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
#include "ml_default_decorators.h"
|
|
#include <vector>
|
|
#include <wrap/gl/gl_type_name.h>
|
|
#include <wrap/gui/coordinateframe.h>
|
|
#include <wrap/qt/gl_label.h>
|
|
|
|
bool MLDefaultMeshDecorators::updateMeshDecorationData( MeshModel& mesh,const MLRenderingData& previousdata,const MLRenderingData& currentdata )
|
|
{
|
|
MLPerViewGLOptions oldopts;
|
|
MLPerViewGLOptions currentopts;
|
|
bool oldvalid = previousdata.get(oldopts);
|
|
bool currentvalid = currentdata.get(currentopts);
|
|
if ((!oldvalid) || (!currentvalid))
|
|
return false;
|
|
|
|
/*the boolean conditions should make the following code lines mutually exclusive.....hopefully*/
|
|
initBoundaryDecoratorData(mesh,currentopts._peredge_edgeboundary_enabled && !oldopts._peredge_edgeboundary_enabled,
|
|
currentopts._peredge_faceboundary_enabled && !oldopts._peredge_faceboundary_enabled);
|
|
cleanBoundaryDecoratorData(mesh,!currentopts._peredge_edgeboundary_enabled && oldopts._peredge_edgeboundary_enabled,
|
|
!currentopts._peredge_faceboundary_enabled && oldopts._peredge_faceboundary_enabled);
|
|
|
|
|
|
if (currentopts._peredge_edgemanifold_enabled && !oldopts._peredge_edgemanifold_enabled)
|
|
initNonManifEdgeDecoratorData(mesh);
|
|
else
|
|
if (!currentopts._peredge_edgemanifold_enabled && oldopts._peredge_edgemanifold_enabled)
|
|
cleanNonManifEdgeDecoratorData(mesh);
|
|
|
|
if (currentopts._peredge_text_boundary_enabled && !oldopts._peredge_text_boundary_enabled)
|
|
initBoundaryTextDecoratorData(mesh);
|
|
else
|
|
if (!currentopts._peredge_text_boundary_enabled && oldopts._peredge_text_boundary_enabled)
|
|
cleanBoundaryTextDecoratorData(mesh);
|
|
}
|
|
|
|
bool MLDefaultMeshDecorators::initMeshDecorationData( MeshModel& m,const MLRenderingData& dt )
|
|
{
|
|
MLPerViewGLOptions opts;
|
|
bool valid = dt.get(opts);
|
|
if (!valid)
|
|
return false;
|
|
|
|
initBoundaryDecoratorData(m,opts._peredge_edgeboundary_enabled,opts._peredge_faceboundary_enabled);
|
|
|
|
if (opts._peredge_edgemanifold_enabled)
|
|
initNonManifEdgeDecoratorData(m);
|
|
|
|
if (opts._peredge_text_boundary_enabled)
|
|
initBoundaryTextDecoratorData(m);
|
|
|
|
return true;
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::decorateMesh( MeshModel & m,const MLRenderingData& dt, QPainter* painter, GLLogStream& log )
|
|
{
|
|
MLPerViewGLOptions opts;
|
|
bool valid = dt.get(opts);
|
|
if (!valid)
|
|
return;
|
|
|
|
if (opts._peredge_extra_enabled)
|
|
{
|
|
if (opts._peredge_edgeboundary_enabled || opts._peredge_faceboundary_enabled)
|
|
{
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > bvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,boundaryVertAttName());
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > beH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,boundaryEdgeAttName());
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > bfH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,boundaryFaceAttName());
|
|
drawLineVector(beH());
|
|
if(opts._peredge_faceboundary_enabled)
|
|
drawTriVector(bfH());
|
|
drawDotVector(bvH(),5);
|
|
|
|
if (opts._peredge_edgeboundary_enabled)
|
|
{
|
|
QString inf;
|
|
if(m.cm.fn==0)
|
|
inf += "<b>" + QString::number(bvH().size()) + " </b> vertex";
|
|
else
|
|
inf += "<b>" + QString::number(beH().size()/2) + " </b> edges";
|
|
log.RealTimeLog("Boundary",m.shortName(),inf);
|
|
}
|
|
|
|
if (opts._peredge_faceboundary_enabled)
|
|
{
|
|
QString inf;
|
|
if(m.cm.fn==0)
|
|
inf += "<b>" + QString::number(bvH().size()) + " </b> vertex";
|
|
else
|
|
inf += "<b>" + QString::number(bfH().size()/3) + " </b> faces";
|
|
log.RealTimeLog("Boundary Faces",m.shortName(),inf);
|
|
}
|
|
}
|
|
|
|
if (opts._peredge_vertmanifold_enabled)
|
|
{
|
|
// Note the standard way for adding extra per-mesh data using the per-mesh attributes.
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > vvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,"NonManifVertVertVector");
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > tvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,"NonManifVertTriVector");
|
|
drawDotVector(vvH());
|
|
drawTriVector(tvH());
|
|
|
|
QString inf;
|
|
inf += "<b>" + QString::number(vvH().size()) + " </b> non manifold vertices<br><b>" + QString::number(tvH().size()) + "</b> faces over non manifold edges";
|
|
log.RealTimeLog("Non Manifold Vertices",m.shortName(),inf);
|
|
}
|
|
|
|
if (opts._peredge_edgemanifold_enabled)
|
|
{
|
|
//Note the standard way for adding extra per-mesh data using the per-mesh attributes.
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > bvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,nonManifEdgeAttName());
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > fvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<PointPC> >(m.cm,nonManifEdgeFaceAttName());
|
|
drawLineVector(bvH());
|
|
drawTriVector(fvH());
|
|
QString inf;
|
|
inf += "<b>" + QString::number(bvH().size()/2) + " </b> non manifold edges<br><b>" + QString::number(fvH().size()/3) + "</b> faces over non manifold edges";
|
|
log.RealTimeLog("Non Manifold Edges",m.shortName(),inf);
|
|
}
|
|
|
|
if (opts._peredge_text_boundary_enabled)
|
|
{
|
|
CMeshO::PerMeshAttributeHandle< std::vector<Point3m> > btvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::vector<Point3m> >(m.cm,boundaryTextVertAttName());
|
|
std::vector<Point3m> *BTVp = &btvH();
|
|
if (BTVp->size() != 0)
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT|GL_VIEWPORT_BIT| GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glLineWidth(1.f);
|
|
glColor(vcg::Color4b(vcg::Color4b::Magenta));
|
|
glDepthRange (0.0, 0.999);
|
|
glEnableClientState (GL_VERTEX_ARRAY);
|
|
glVertexPointer(3,vcg::GL_TYPE_NM<Scalarm>::SCALAR(),sizeof(Point3m),&(BTVp->begin()[0]));
|
|
glDrawArrays(GL_LINES,0,BTVp->size());
|
|
glDisableClientState (GL_VERTEX_ARRAY);
|
|
glPopAttrib();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (opts._sel_enabled)
|
|
{
|
|
if (opts._face_sel)
|
|
{
|
|
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glDepthMask(GL_FALSE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
|
|
glColor4f(1.0f,0.0,0.0,.3f);
|
|
glPolygonOffset(-1.0, -1);
|
|
CMeshO::FaceIterator fi;
|
|
glPushMatrix();
|
|
glMultMatrix(m.cm.Tr);
|
|
glBegin(GL_TRIANGLES);
|
|
m.cm.sfn=0;
|
|
//for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi)
|
|
//{
|
|
// if(!(*fi).IsD() && (*fi).IsS())
|
|
// {
|
|
// /*glVertex((*fi).cP(0));
|
|
// glVertex((*fi).cP(1));
|
|
// glVertex((*fi).cP(2));*/
|
|
// ++m.cm.sfn;
|
|
// }
|
|
//}
|
|
glEnd();
|
|
glPopMatrix();
|
|
glPopAttrib();
|
|
}
|
|
}
|
|
|
|
if (opts._perbbox_enabled)
|
|
{
|
|
if (opts._perbbox_quoted_info_enabled)
|
|
{
|
|
QFont qf;
|
|
drawQuotedBox(m,painter,qf);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::drawQuotedBox(MeshModel &m,QPainter *gla,QFont& qf)
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT );
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_POINT_SMOOTH);
|
|
|
|
// Get gl state values
|
|
double mm[16],mp[16];
|
|
GLint vp[4];
|
|
glGetDoublev(GL_PROJECTION_MATRIX,mp);
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,mm);
|
|
glGetIntegerv(GL_VIEWPORT,vp);
|
|
|
|
// Mesh boundingBox
|
|
Box3m b(m.cm.bbox);
|
|
|
|
glLineWidth(1.f);
|
|
glPointSize(3.f);
|
|
|
|
vcg::Point3d p1,p2;
|
|
|
|
Point3m c = b.Center();
|
|
|
|
float s = 1.15f;
|
|
const float LabelSpacing = 30;
|
|
chooseX(b,mm,mp,vp,p1,p2); // Selects x axis candidate
|
|
glPushMatrix();
|
|
glScalef(1,s,s);
|
|
glTranslatef(0,c[1]/s-c[1],c[2]/s-c[2]);
|
|
drawQuotedLine(p1,p2,b.min[0],b.max[0],vcg::CoordinateFrame::calcSlope(p1,p2,b.DimX(),LabelSpacing,mm,mp,vp),gla,qf); // Draws x axis
|
|
glPopMatrix();
|
|
|
|
chooseY(b,mm,mp,vp,p1,p2); // Selects y axis candidate
|
|
glPushMatrix();
|
|
glScalef(s,1,s);
|
|
glTranslatef(c[0]/s-c[0],0,c[2]/s-c[2]);
|
|
drawQuotedLine(p1,p2,b.min[1],b.max[1],vcg::CoordinateFrame::calcSlope(p1,p2,b.DimY(),LabelSpacing,mm,mp,vp),gla,qf); // Draws y axis
|
|
glPopMatrix();
|
|
|
|
chooseZ(b,mm,mp,vp,p1,p2); // Selects z axis candidate
|
|
glPushMatrix();
|
|
glScalef(s,s,1);
|
|
glTranslatef(c[0]/s-c[0],c[1]/s-c[1],0);
|
|
drawQuotedLine(p1,p2,b.min[2],b.max[2],vcg::CoordinateFrame::calcSlope(p1,p2,b.DimZ(),LabelSpacing,mm,mp,vp),gla,qf); // Draws z axis
|
|
glPopMatrix();
|
|
|
|
glPopAttrib();
|
|
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::drawQuotedLine(const vcg::Point3d &a,const vcg::Point3d &b, float aVal, float bVal, float tickScalarDistance, QPainter *painter, QFont& qf,float angle,bool rightAlign)
|
|
{
|
|
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_CULL_FACE);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_LIGHT0);
|
|
glDisable(GL_NORMALIZE);
|
|
float labelMargin =tickScalarDistance /4.0;
|
|
float firstTick;
|
|
// fmod returns the floating-point remainder of numerator/denominator (with the sign of the dividend)
|
|
// fmod ( 104.5 , 10) returns 4.5 --> aVal - fmod(aval/tick) = 100
|
|
// fmod ( -104.5 , 10) returns -4.5
|
|
// So it holds that
|
|
|
|
if(aVal > 0 ) firstTick = aVal - fmod(aVal,tickScalarDistance) + tickScalarDistance;
|
|
if(aVal ==0 ) firstTick = tickScalarDistance;
|
|
if(aVal < 0 ) firstTick = aVal + fmod(fabs(aVal),tickScalarDistance);
|
|
|
|
// now we are sure that aVal < firstTick
|
|
// let also be sure that there is enough space
|
|
if ( (firstTick-aVal) < (labelMargin) )
|
|
firstTick +=tickScalarDistance;
|
|
|
|
|
|
float tickDistTen=tickScalarDistance /10.0f;
|
|
float firstTickTen;
|
|
if(aVal > 0) firstTickTen = aVal - fmod(aVal,tickDistTen) + tickDistTen;
|
|
else firstTickTen = aVal - fmod(aVal,tickDistTen);
|
|
|
|
int neededZeros=0;
|
|
|
|
vcg::Point3d Zero = a-((b-a)/(bVal-aVal))*aVal; // 3D Position of Zero.
|
|
vcg::Point3d v(b-a);
|
|
//v.Normalize();
|
|
v = v*(1.0/(bVal-aVal));
|
|
vcg::glLabel::Mode md(qf,vcg::Color4b(vcg::Color4b::White),angle,rightAlign);
|
|
if(tickScalarDistance > 0) // Draw lines only if the two endpoint are not coincident
|
|
{
|
|
neededZeros = std::ceil(std::max(0.0,-std::log10(double(tickScalarDistance))));
|
|
glPointSize(3);
|
|
float i;
|
|
glBegin(GL_POINTS);
|
|
for(i=firstTick;i<bVal;i+=tickScalarDistance)
|
|
glVertex(Zero+v*i);
|
|
glEnd();
|
|
for(i=firstTick; (i+labelMargin)<bVal;i+=tickScalarDistance)
|
|
vcg::glLabel::render(painter,Point3m::Construct(Zero+v*i),QString("%1 ").arg(i,4+neededZeros,'f',neededZeros),md);
|
|
glPointSize(1);
|
|
glBegin(GL_POINTS);
|
|
for(i=firstTickTen;i<bVal;i+=tickDistTen)
|
|
glVertex(Zero+v*i);
|
|
glEnd();
|
|
}
|
|
|
|
// Draws bigger ticks at 0 and at max size
|
|
glPointSize(6);
|
|
|
|
glBegin(GL_POINTS);
|
|
glVertex(a);
|
|
glVertex(b);
|
|
if(bVal*aVal<0) glVertex(Zero);
|
|
glEnd();
|
|
|
|
|
|
// bold font at beginning and at the end
|
|
md.qFont.setBold(true);
|
|
vcg::glLabel::render(painter,vcg::Point3f::Construct(a), QString("%1 ").arg(aVal,4+neededZeros,'f',neededZeros) ,md);
|
|
vcg::glLabel::render(painter,vcg::Point3f::Construct(b), QString("%1 ").arg(bVal,4+neededZeros,'f',neededZeros) ,md);
|
|
|
|
glPopAttrib();
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::chooseX(Box3m &box,double *mm,double *mp,GLint *vp,vcg::Point3d &x1,vcg::Point3d &x2)
|
|
{
|
|
float d = -std::numeric_limits<float>::max();
|
|
vcg::Point3d c;
|
|
// Project the bbox center
|
|
gluProject(box.Center()[0],box.Center()[1],box.Center()[2],mm,mp,vp,&c[0],&c[1],&c[2]);
|
|
c[2] = 0;
|
|
|
|
vcg::Point3d out1,out2;
|
|
Point3m in1,in2;
|
|
|
|
for (int i=0;i<8;i+=2)
|
|
{
|
|
// find the furthest axis
|
|
in1 = box.P(i);
|
|
in2 = box.P(i+1);
|
|
|
|
gluProject((double)in1[0],(double)in1[1],(double)in1[2],mm,mp,vp,&out1[0],&out1[1],&out1[2]);
|
|
gluProject((double)in2[0],(double)in2[1],(double)in2[2],mm,mp,vp,&out2[0],&out2[1],&out2[2]);
|
|
out1[2] = out2[2] = 0;
|
|
|
|
float currDist = Distance(c,(out1+out2)*.5f);
|
|
|
|
if(currDist > d)
|
|
{
|
|
d = currDist;
|
|
x1.Import(in1);
|
|
x2.Import(in2);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MLDefaultMeshDecorators::chooseY(Box3m &box,double *mm,double *mp,GLint *vp,vcg::Point3d &y1,vcg::Point3d &y2)
|
|
{
|
|
float d = -std::numeric_limits<float>::max();
|
|
vcg::Point3d c;
|
|
// Project the bbox center
|
|
gluProject(box.Center()[0],box.Center()[1],box.Center()[2],mm,mp,vp,&c[0],&c[1],&c[2]);
|
|
c[2] = 0;
|
|
|
|
vcg::Point3d out1,out2;
|
|
Point3m in1,in2;
|
|
|
|
for (int i=0;i<6;++i)
|
|
{
|
|
if(i==2) i = 4; // skip
|
|
// find the furthest axis
|
|
in1 = box.P(i);
|
|
in2 = box.P(i+2);
|
|
|
|
gluProject((double)in1[0],(double)in1[1],(double)in1[2],mm,mp,vp,&out1[0],&out1[1],&out1[2]);
|
|
gluProject((double)in2[0],(double)in2[1],(double)in2[2],mm,mp,vp,&out2[0],&out2[1],&out2[2]);
|
|
out1[2] = out2[2] = 0;
|
|
|
|
float currDist = Distance(c,(out1+out2)*.5f);
|
|
|
|
if(currDist > d)
|
|
{
|
|
d = currDist;
|
|
y1.Import(in1);
|
|
y2.Import(in2);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::chooseZ(Box3m &box,double *mm,double *mp,GLint *vp,vcg::Point3d &z1,vcg::Point3d &z2)
|
|
{
|
|
float d = -std::numeric_limits<float>::max();
|
|
vcg::Point3d c;
|
|
// Project the bbox center
|
|
gluProject(box.Center()[0],box.Center()[1],box.Center()[2],mm,mp,vp,&c[0],&c[1],&c[2]);
|
|
c[2] = 0;
|
|
|
|
vcg::Point3d out1,out2;
|
|
Point3m in1,in2;
|
|
|
|
vcg::Point3d m;
|
|
|
|
for (int i=0;i<4;++i)
|
|
{
|
|
// find the furthest axis
|
|
in1 = box.P(i);
|
|
in2 = box.P(i+4);
|
|
|
|
|
|
gluProject((double)in1[0],(double)in1[1],(double)in1[2],mm,mp,vp,&out1[0],&out1[1],&out1[2]);
|
|
gluProject((double)in2[0],(double)in2[1],(double)in2[2],mm,mp,vp,&out2[0],&out2[1],&out2[2]);
|
|
out1[2] = out2[2] = 0;
|
|
|
|
float currDist = Distance(c,(out1+out2)*.5f);
|
|
|
|
if(currDist > d)
|
|
{
|
|
d = currDist;
|
|
z1.Import(in1);
|
|
z2.Import(in2);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MLDefaultMeshDecorators::cleanMeshDecorationData( MeshModel& mesh,const MLRenderingData& dt )
|
|
{
|
|
MLPerViewGLOptions opts;
|
|
bool valid = dt.get(opts);
|
|
if (!valid)
|
|
return false;
|
|
|
|
if (opts._peredge_edgeboundary_enabled || opts._peredge_faceboundary_enabled)
|
|
cleanBoundaryDecoratorData(mesh,!opts._peredge_edgeboundary_enabled,!opts._peredge_faceboundary_enabled);
|
|
|
|
if (opts._peredge_edgemanifold_enabled)
|
|
cleanNonManifEdgeDecoratorData(mesh);
|
|
|
|
if (opts._peredge_text_boundary_enabled)
|
|
cleanBoundaryTextDecoratorData(mesh);
|
|
return true;
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::initBoundaryDecoratorData( MeshModel& m,bool edgeboundary,bool faceboundary)
|
|
{
|
|
if (!edgeboundary && !faceboundary)
|
|
return;
|
|
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > bvH;
|
|
bvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute< std::vector<PointPC> >(m.cm,boundaryVertAttName());
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > beH;
|
|
if (edgeboundary)
|
|
beH= vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute< std::vector<PointPC> >(m.cm,boundaryEdgeAttName());
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > bfH;
|
|
if (faceboundary)
|
|
bfH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute< std::vector<PointPC> >(m.cm,boundaryFaceAttName());
|
|
|
|
std::vector<PointPC> *BVp = &bvH();
|
|
std::vector<PointPC> *BEp = NULL;
|
|
if (edgeboundary)
|
|
BEp = &beH();
|
|
|
|
std::vector<PointPC> *BFp = NULL;
|
|
if (faceboundary)
|
|
BFp = &bfH();
|
|
|
|
if (BVp != NULL)
|
|
BVp->clear();
|
|
|
|
if ((BEp != NULL) && (edgeboundary))
|
|
BEp->clear();
|
|
|
|
if ((BFp != NULL) && (faceboundary))
|
|
BFp->clear();
|
|
|
|
vcg::Color4b bCol=vcg::Color4b(0,255,0,32);
|
|
|
|
if(!m.cm.edge.empty())
|
|
{
|
|
std::vector<int> cntVec(m.cm.vert.size(),0);
|
|
for(CMeshO::EdgeIterator ei=m.cm.edge.begin(); ei!= m.cm.edge.end();++ei) if(!(*ei).IsD())
|
|
{
|
|
cntVec[vcg::tri::Index(m.cm,ei->V(0))]++;
|
|
cntVec[vcg::tri::Index(m.cm,ei->V(1))]++;
|
|
}
|
|
|
|
if (BVp != NULL)
|
|
{
|
|
for(size_t i=0;i<cntVec.size();++i)
|
|
if (cntVec[i]==1)
|
|
BVp->push_back(std::make_pair(m.cm.vert[i].P(),vcg::Color4b(vcg::Color4b::Green)));
|
|
}
|
|
}
|
|
vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(m.cm);
|
|
for(CMeshO::FaceIterator fi = m.cm.face.begin(); fi!= m.cm.face.end();++fi)
|
|
{
|
|
if(!(*fi).IsD())
|
|
{
|
|
bool isB=false;
|
|
for(int i=0;i<3;++i)
|
|
{
|
|
if((*fi).IsB(i))
|
|
{
|
|
isB=true;
|
|
if ((BEp != NULL) && (edgeboundary))
|
|
{
|
|
BEp->push_back(std::make_pair((*fi).V0(i)->P(),vcg::Color4b(vcg::Color4b::Green)));
|
|
BEp->push_back(std::make_pair((*fi).V1(i)->P(),vcg::Color4b(vcg::Color4b::Green)));
|
|
}
|
|
}
|
|
}
|
|
if ((isB) && (BFp != NULL) && (faceboundary))
|
|
{
|
|
BFp->push_back(std::make_pair((*fi).V(0)->P(),bCol));
|
|
BFp->push_back(std::make_pair((*fi).V(1)->P(),bCol));
|
|
BFp->push_back(std::make_pair((*fi).V(2)->P(),bCol));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MLDefaultMeshDecorators::cleanBoundaryDecoratorData( MeshModel& m,bool edgeboundary,bool faceboundary)
|
|
{
|
|
if (edgeboundary && faceboundary)
|
|
vcg::tri::Allocator<CMeshO>::DeletePerMeshAttribute(m.cm,boundaryVertAttName());
|
|
if (edgeboundary)
|
|
vcg::tri::Allocator<CMeshO>::DeletePerMeshAttribute(m.cm,boundaryEdgeAttName());
|
|
if (faceboundary)
|
|
vcg::tri::Allocator<CMeshO>::DeletePerMeshAttribute(m.cm,boundaryFaceAttName());
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::initNonManifEdgeDecoratorData( MeshModel& m )
|
|
{
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > bvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute< std::vector<PointPC> >(m.cm,nonManifEdgeAttName());
|
|
CMeshO::PerMeshAttributeHandle< std::vector<PointPC> > fvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute< std::vector<PointPC> >(m.cm,nonManifEdgeFaceAttName());
|
|
std::vector<PointPC> *BVp = &bvH();
|
|
std::vector<PointPC> *FVp = &fvH();
|
|
BVp->clear();
|
|
FVp->clear();
|
|
|
|
m.updateDataMask(MeshModel::MM_FACEFACETOPO);
|
|
|
|
vcg::Color4b edgeCol[5]={vcg::Color4b(vcg::Color4b::Black), vcg::Color4b(vcg::Color4b::Green), vcg::Color4b(vcg::Color4b::Black), vcg::Color4b(vcg::Color4b::Red),vcg::Color4b(vcg::Color4b::Magenta)};
|
|
vcg::Color4b faceCol[5]={vcg::Color4b(vcg::Color4b::Black), vcg::Color4b(vcg::Color4b::Green), vcg::Color4b(vcg::Color4b::Black), vcg::Color4b(vcg::Color4b::Red),vcg::Color4b(vcg::Color4b::Magenta)};
|
|
vcg::Color4b faceVer[5];
|
|
for(int i=0;i<5;++i)
|
|
faceCol[i]=vcg::Color4b(faceCol[i][0],faceCol[i][1],faceCol[i][2],96);
|
|
for(int i=0;i<5;++i)
|
|
faceVer[i]=vcg::Color4b(faceCol[i][0],faceCol[i][1],faceCol[i][2],0);
|
|
std::set<std::pair<CVertexO*,CVertexO*> > edgeSet; // this set is used to unique count the number of non manifold edges
|
|
for(CMeshO::FaceIterator fi = m.cm.face.begin(); fi!= m.cm.face.end();++fi) if(!(*fi).IsD())
|
|
{
|
|
for(int i=0;i<3;++i)
|
|
{
|
|
vcg::face::Pos<CFaceO> pos(&*fi,i);
|
|
const int faceOnEdgeNum = std::min(pos.NumberOfFacesOnEdge(),4);
|
|
|
|
if(faceOnEdgeNum == 2 || faceOnEdgeNum == 1) continue;
|
|
|
|
bool edgeNotPresent; // true if the edge was not present in the set
|
|
if ( (*fi).V0(i)<(*fi).V1(i)) edgeNotPresent = edgeSet.insert(std::make_pair((*fi).V0(i),(*fi).V1(i))).second;
|
|
else edgeNotPresent = edgeSet.insert(std::make_pair((*fi).V1(i),(*fi).V0(i))).second;
|
|
|
|
if(edgeNotPresent){
|
|
BVp->push_back(std::make_pair((*fi).V0(i)->P(),edgeCol[faceOnEdgeNum]));
|
|
BVp->push_back(std::make_pair((*fi).V1(i)->P(),edgeCol[faceOnEdgeNum]));
|
|
}
|
|
FVp->push_back(std::make_pair((*fi).V0(i)->P(),faceCol[faceOnEdgeNum]));
|
|
FVp->push_back(std::make_pair((*fi).V1(i)->P(),faceCol[faceOnEdgeNum]));
|
|
FVp->push_back(std::make_pair((*fi).V2(i)->P(),faceVer[faceOnEdgeNum]));
|
|
}
|
|
}
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::cleanNonManifEdgeDecoratorData( MeshModel& m )
|
|
{
|
|
vcg::tri::Allocator<CMeshO>::DeletePerMeshAttribute(m.cm,nonManifEdgeAttName());
|
|
vcg::tri::Allocator<CMeshO>::DeletePerMeshAttribute(m.cm,nonManifEdgeFaceAttName());
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::initBoundaryTextDecoratorData( MeshModel& m)
|
|
{
|
|
m.updateDataMask(MeshModel::MM_FACEFACETOPO);
|
|
CMeshO::PerMeshAttributeHandle< std::vector<Point3m> > btvH = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute< std::vector<Point3m> >(m.cm,boundaryTextVertAttName());
|
|
std::vector<Point3m> *BTVp = &btvH();
|
|
BTVp->clear();
|
|
std::vector<std::pair<CMeshO::FacePointer,int> > SaveTopoVec;
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = m.cm.face.begin(); fi!= m.cm.face.end();++fi) if(!(*fi).IsD())
|
|
{
|
|
for(int i=0;i<3;++i)
|
|
SaveTopoVec.push_back(std::make_pair((*fi).FFp(i),(*fi).FFi(i)));
|
|
}
|
|
vcg::tri::UpdateTopology<CMeshO>::FaceFaceFromTexCoord(m.cm);
|
|
for(fi = m.cm.face.begin(); fi!= m.cm.face.end();++fi) if(!(*fi).IsD())
|
|
{
|
|
for(int i=0;i<3;++i)
|
|
if(vcg::face::IsBorder(*fi,i))
|
|
{
|
|
BTVp->push_back((*fi).V0(i)->P());
|
|
BTVp->push_back((*fi).V1(i)->P());
|
|
}
|
|
}
|
|
std::vector<std::pair<CMeshO::FacePointer,int> >::iterator iii;
|
|
for(fi = m.cm.face.begin(), iii=SaveTopoVec.begin(); fi!= m.cm.face.end();++fi) if(!(*fi).IsD())
|
|
{
|
|
for(int i=0;i<3;++i)
|
|
{
|
|
(*fi).FFp(i)= iii->first;
|
|
(*fi).FFi(i)= iii->second;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::cleanBoundaryTextDecoratorData( MeshModel& m)
|
|
{
|
|
vcg::tri::Allocator<CMeshO>::DeletePerMeshAttribute(m.cm,boundaryTextVertAttName());
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::drawLineVector(std::vector<PointPC> &EV)
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT|GL_VIEWPORT_BIT| GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glDisable(GL_LIGHTING);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glLineWidth(1.f);
|
|
glDepthRange (0.0, 0.999);
|
|
if (EV.size() > 0)
|
|
{
|
|
glEnableClientState (GL_VERTEX_ARRAY);
|
|
glEnableClientState (GL_COLOR_ARRAY);
|
|
|
|
glVertexPointer(3,vcg::GL_TYPE_NM<Scalarm>::SCALAR(),sizeof(PointPC),&(EV.begin()[0].first));
|
|
glColorPointer(4,GL_UNSIGNED_BYTE,sizeof(PointPC),&(EV.begin()[0].second));
|
|
glDrawArrays(GL_LINES,0,EV.size());
|
|
glDisableClientState (GL_COLOR_ARRAY);
|
|
glDisableClientState (GL_VERTEX_ARRAY);
|
|
}
|
|
glPopAttrib();
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::drawTriVector(std::vector<PointPC> &TV)
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT|GL_VIEWPORT_BIT| GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glDisable(GL_LIGHTING);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glLineWidth(1.f);
|
|
glDepthRange (0.0, 0.999);
|
|
if (TV.size() > 0)
|
|
{
|
|
glEnableClientState (GL_VERTEX_ARRAY);
|
|
glEnableClientState (GL_COLOR_ARRAY);
|
|
glVertexPointer(3,vcg::GL_TYPE_NM<Scalarm>::SCALAR(),sizeof(PointPC),&(TV.begin()[0].first));
|
|
glColorPointer(4,GL_UNSIGNED_BYTE,sizeof(PointPC),&(TV.begin()[0].second));
|
|
glDrawArrays(GL_TRIANGLES,0,TV.size());
|
|
glDisableClientState (GL_COLOR_ARRAY);
|
|
glDisableClientState (GL_VERTEX_ARRAY);
|
|
}
|
|
glPopAttrib();
|
|
}
|
|
|
|
void MLDefaultMeshDecorators::drawDotVector(std::vector<PointPC> &TV, float baseSize)
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT|GL_VIEWPORT_BIT| GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glDisable(GL_LIGHTING);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glLineWidth(1.f);
|
|
glDepthRange (0.0, 0.999);
|
|
if (TV.size() > 0)
|
|
{
|
|
glEnableClientState (GL_VERTEX_ARRAY);
|
|
glEnableClientState (GL_COLOR_ARRAY);
|
|
glPointSize(baseSize+0.5);
|
|
glVertexPointer(3,vcg::GL_TYPE_NM<Scalarm>::SCALAR(),sizeof(PointPC),&(TV.begin()[0].first));
|
|
glColorPointer(4,GL_UNSIGNED_BYTE,sizeof(PointPC),&(TV.begin()[0].second));
|
|
glDisableClientState (GL_COLOR_ARRAY);
|
|
glColor(vcg::Color4b(vcg::Color4b::DarkGray));
|
|
glDrawArrays(GL_POINTS,0,TV.size());
|
|
glPointSize(baseSize-1);
|
|
glEnableClientState (GL_COLOR_ARRAY);
|
|
glDrawArrays(GL_POINTS,0,TV.size());
|
|
glDisableClientState (GL_VERTEX_ARRAY);
|
|
}
|
|
glPopAttrib();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|