/**************************************************************************** * Rgb Triangulations Plugin * * * * Author: Daniele Panozzo (daniele.panozzo@gmail.com) * * Copyright(C) 2007 * * DISI - Department of Computer Science * * University of Genova * * * * 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. * ****************************************************************************/ /**************************************************************************** * The code of the class InteractiveEdit is based on the plugin editpaint, * * developed by Gfrei Andreas. * ****************************************************************************/ #include "interactiveEdit.h" namespace rgbt { InteractiveEdit::InteractiveEdit() { pixels = 0; first = 1; isDragging = false; } InteractiveEdit::~InteractiveEdit() { } inline int isIn(const QPointF &p0, const QPointF &p1, float dx, float dy, float radius, float *dist) { if (p0!=p1) { /** this must be checked first, because of the color decrease tool */ float x2=(p1.x()-p0.x()); float y2=(p1.y()-p0.y()); //double l=sqrt(x2*x2+y2*y2); float l_square=x2*x2+y2*y2; float r=(dx-p0.x())*(p1.x()-p0.x())+(dy-p0.y())*(p1.y()-p0.y()); //r=r/(l*l); r=r/l_square; float px=p0.x()+r*(p1.x()-p0.x()); float py=p0.y()+r*(p1.y()-p0.y()); px=px-dx; py=py-dy; if (r>=0 && r<=1 && (px*px+py*py0 && fbc*fca>0) return true; return false; } inline bool pointInTriangle(const float p_x, const float p_y, const float a_x, const float a_y, const float b_x, const float b_y, const float c_x, const float c_y) { float fab=(p_y-a_y)*(b_x-a_x) - (p_x-a_x)*(b_y-a_y); float fbc=(p_y-c_y)*(a_x-c_x) - (p_x-c_x)*(a_y-c_y); float fca=(p_y-b_y)*(c_x-b_x) - (p_x-b_x)*(c_y-b_y); if (fab*fbc>0 && fbc*fca>0) return true; return false; } /** checks if a triangle is front or backfaced */ inline bool isFront(const QPointF &a, const QPointF &b, const QPointF &c) { return (b.x()-a.x())*(c.y()-a.y())-(b.y()-a.y())*(c.x()-a.x())>0; } /** checks if a triangle is front or backfaced */ inline bool isFront(const float a_x, const float a_y, const float b_x, const float b_y, const float c_x, const float c_y) { return (b_x-a_x)*(c_y-a_y)-(b_y-a_y)*(c_x-a_x)>0; } inline bool lineHitsCircle(QPointF& LineStart, QPointF& LineEnd, QPointF& CircleCenter, float Radius, QPointF* const pOut = 0) { const float RadiusSq = Radius * Radius; QPointF PMinusM =LineStart - CircleCenter; float pm_squ=PMinusM.x()*PMinusM.x()+PMinusM.y()*PMinusM.y(); if (pm_squ <= RadiusSq) { /// startpoint in circle if (pOut) *pOut = LineStart; return true; } QPointF LineDir=LineEnd - LineStart; /// line direction // u * (p - m) const float UDotPMinusM = LineDir.x()*PMinusM.x()+LineDir.y()*PMinusM.y();//Vector2D_Dot(LineDir, PMinusM); // u*u const float LineDirSq = LineDir.x()*LineDir.x()+LineDir.y()*LineDir.y(); // (u * (p - m))^2 // - (u*u * ((p - m)^2 - r^2)) const float d = UDotPMinusM * UDotPMinusM - LineDirSq * (pm_squ - RadiusSq); if (d < 0.0f) return false; else if (d < 0.0001f) { const float s = -UDotPMinusM / LineDirSq; if (s< 0.0f || s> 1.0f)return false; else { if(pOut) *pOut = LineStart + s * LineDir; return true; } } else { const float s = (-UDotPMinusM - sqrtf(d)) / LineDirSq; if(s < 0.0f || s > 1.0f) return false; else { if(pOut) *pOut = LineStart + s * LineDir; return true; } } } void InteractiveEdit::DrawXORCircle(GLArea * gla, bool doubleDraw) { int PEZ=18; /** paint the normal circle in pixel-mode */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0,gla->curSiz.width(),gla->curSiz.height(),0,-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_XOR); glColor3f(1,1,1); QPoint mid= QPoint(cur.x(),/*gla->curSiz.height()-*/cur.y()); if(doubleDraw) { glBegin(GL_LINE_LOOP); for (int lauf=0; lauf *actual,vector * risult, vector * face_risult, GLArea * gla,Penn &pen,QPoint &cur, QPoint &prev, GLfloat * pixels, double mvmatrix[16],double projmatrix[16],GLint viewport[4]) { QHash selected; QHash sel_vert; list::iterator fpi; vector temp_po; if (actual->size()==0) { CMeshO::FaceIterator fi; for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) { temp_po.push_back((&*fi)); } } else for(fpi=actual->begin();fpi!=actual->end();++fpi) { temp_po.push_back(&(m.cm.face[*fpi])); } actual->clear(); QPointF mid=QPointF(cur.x(),gla->curSiz.height()- cur.y()); QPointF mid_prev=QPointF(prev.x(),gla->curSiz.height()- prev.y()); QPointF p[3],z[3]; double tx,ty,tz; bool backface=pen.backface; bool invisible=pen.invisible; for (unsigned int lauf2=0; lauf2IsD() << std::endl; int intern=0; int checkable=0; /// to avoid problems when the pen is smaller then the polys for (int lauf=0; lauf<3; lauf++) { //if ((fac)->V(lauf) - &(m.cm.vert[0]) < 0 || (fac)->V(lauf) - &(m.cm.vert[0]) >= m.cm.vert.size()) // continue; if (gluProject((fac)->V(lauf)->P()[0],(fac)->V(lauf)->P()[1],(fac)->V(lauf)->P()[2], mvmatrix,projmatrix,viewport,&tx,&ty,&tz)==GL_TRUE) { checkable++; } if (tz<0 || tz>1) { checkable--; } p[lauf].setX(tx); p[lauf].setY(ty); if (tx>=0 && tx=0 && tyV(lauf))) { Vert_Data d; d.v=fac->V(lauf); d.distance=dist; risult->push_back(/*fac->V(lauf)*/d); sel_vert.insert(fac->V(lauf),fac->V(lauf)); } } QPointF pos_res; //if (pen.paintutensil==SELECT && intern==0 && lineHitsCircle(p[lauf],p[(lauf+1)%3],mid,pen.radius,&pos_res)) if (intern==0 && lineHitsCircle(p[lauf],p[(lauf+1)%3],mid,pen.radius,&pos_res)) { intern=1; continue; } } } if (checkable==3 && intern==0 && (pointInTriangle(mid,p[0],p[1],p[2]) || pointInTriangle(mid_prev,p[0],p[1],p[2]))) { intern=-1; } } if (checkable==3 && intern!=0 && !selected.contains(fac)) { selected.insert((fac),(fac)); actual->push_back(fac->Index()); vector surround; for (int lauf=0; lauf<3; lauf++) if (!selected.contains(fac->FFp(lauf))) temp_po.push_back(fac->FFp(lauf)); if (intern!=0) face_risult->push_back(fac); } } } RgbInteractiveEdit::RgbInteractiveEdit(CMeshO& m, RgbInfo& i, TopologicalOpC& to) { this->m = &m; this->info = &i; this->to = &to; } RgbInteractiveEdit::~RgbInteractiveEdit() { } bool RgbInteractiveEdit::vertexToRemove(RgbVertexC& v, int* level, double* lenght) { bool blenght; bool blevel; if (lenght) { double edgelenght = maxEdge(v); blenght = edgelenght < *lenght; } else blenght = false; if (level) { //int edgelevel = maxEdgeLevel(v); int edgelevel = v.getLevel(); blevel = edgelevel > *level; } else blevel = false; //std::cout << blenght << " " << blevel << std::endl; return (blenght || blevel); } bool RgbInteractiveEdit::edgeToSplit(RgbTriangleC& t,int index, int* level, double* lenght) { bool blenght; bool blevel; if (lenght) { double edgelenght = edgeLenght(t,index); blenght = edgelenght > *lenght; } else blenght = false; if (level) { int edgelevel = t.getEdgeLevel(index); blevel = edgelevel < *level; } else blevel = false; return (blenght || blevel); } void RgbInteractiveEdit::processVertex(int v, int* level, double* lenght) { RgbTriangleC t; int index; if (IsValidVertex(v,m,info,&t,&index,true)) { if (vertexToRemove(t.V(index),level,lenght)) { if (RgbPrimitives::vertexRemoval_Possible(t,index)) { //vector vt; //vt.reserve(4); RgbPrimitives::vertexRemoval(t,index,*to); } } } } void RgbInteractiveEdit::processEdge(int v1,int v2, int* level, double* lenght) { RgbTriangleC t; int index; if (IsValidEdge(v1,v2,m,info,&t,&index)) { if (edgeToSplit(t,index,level,lenght)) { vector vt; RgbPrimitives::recursiveEdgeSplit(t,index,*to,&vt); } } } int RgbInteractiveEdit::minEdgeLevel(RgbVertexC& v) { vector ve; vector::iterator it; v.VF(ve); int tmp = ve[0].t.getEdgeLevel(ve[0].index); for (it = ve.begin();it != ve.end(); it++) { int l = it->t.getEdgeLevel(it->index); if (tmp > l) tmp = l; } return tmp; } bool RgbInteractiveEdit::maxEdgeLevel(RgbVertexC& v) { vector ve; vector::iterator it; v.VF(ve); //std::cout << ve.size() << std::endl; int tmp = ve[0].t.getEdgeLevel(ve[0].index); for (it = ve.begin();it != ve.end(); it++) { int l = it->t.getEdgeLevel(it->index); if (tmp > l) tmp = l; } return tmp; } double RgbInteractiveEdit::maxEdge(RgbVertexC& v) { vector vv; vv.reserve(6); VE(v,vv); double value = vv[0]; for (unsigned int i = 1; i < vv.size(); ++i) { if (vv[i] > value) value = vv[i]; } return value; } double RgbInteractiveEdit::edgeLenght(RgbTriangleC& t, int index) { Point v1 = t.getVertexCoord(index); Point v2 = t.getVertexCoord((index+1)%3); return (v2-v1).Norm(); } bool RgbInteractiveEdit::IsValidVertex(int vp, CMeshO* m,RgbInfo* info, RgbTriangleC* t, int* ti, bool ignoreNew) { assert((unsigned int)vp < m->vert.size()); if (m->vert[vp].IsD()) return false; VertexType& v = m->vert[vp]; if (!v.VFp()) return false; RgbTriangleC tf = RgbTriangleC(m,info,v.VFp()->Index()); assert(!tf.face()->IsD()); int tfi = v.VFi(); assert(tf.V(tfi).index == vp); if (tf.getVertexIsNew(tfi) && !ignoreNew) return false; if (t) *t = tf; if (ti) *ti = tfi; return true; } bool RgbInteractiveEdit::IsValidEdge(int v1,int v2, CMeshO* m,RgbInfo* info, RgbTriangleC* t, int* ti) { assert((unsigned int)v1 < m->vert.size()); assert((unsigned int)v2 < m->vert.size()); if (m->vert[v1].IsD() || m->vert[v2].IsD()) return false; VertexType& v = m->vert[v1]; RgbTriangleC tf = RgbTriangleC(m,info,v.VFp()->Index()); int tfi = v.VFi(); assert(tf.V(tfi).index == v1); VertexType& va = m->vert[v2]; RgbTriangleC tfa = RgbTriangleC(m,info,va.VFp()->Index()); int tfia = va.VFi(); assert(tfa.V(tfia).index == v2); vector vf; RgbPrimitives::vf(tf,tfi,vf); for (unsigned int i = 0; i < vf.size(); ++i) { RgbTriangleC& tt = vf[i]; int k = 0; while(tt.V(k).index != v1) { assert(k <= 2); k++; } if (tt.V((k+1)%3).index == v2) { if (t) *t = tt; if (ti) *ti = k; return true; } } return false; } void RgbInteractiveEdit::VE(RgbVertexC& v, vector& vv) { int i; FacePointer fp = v.vert().VFp(); int fi = v.vert().VFi(); vcg::face::Pos pos(fp,fi); CMeshO::FacePointer first = pos.F(); RgbTriangleC tmp = RgbTriangleC(v.m,v.rgbInfo,pos.F()->Index()); assert(tmp.containVertex(v.index)); tmp.containVertex(v.index,&i); assert(i>=0 && i<= 2); vv.push_back(edgeLenght(tmp,i)); pos.FlipF(); pos.FlipE(); while(pos.F() && (pos.F() != first)) { RgbTriangleC tmp = RgbTriangleC(v.m,v.rgbInfo,pos.F()->Index()); assert(tmp.containVertex(v.index)); tmp.containVertex(v.index,&i); assert(i>=0 && i<= 2); vv.push_back(edgeLenght(tmp,i)); pos.FlipF(); pos.FlipE(); assert(pos.F()->V(0) == fp->V(fi) || pos.F()->V(1) == fp->V(fi) || pos.F()->V(2) == fp->V(fi)); assert(!fp->IsD()); } } }