スポンサーリンク

VCG LibでOpenEdgeのループを検出する

MyMesh

#pragma once

// vcg コア
#include <vcg/complex/complex.h>

// vcg input output
#include <wrap/io_trimesh/import_ply.h>
#include <wrap/io_trimesh/export_ply.h>
#include <wrap/io_trimesh/import_stl.h>


using namespace vcg;
using namespace std;

/////////////////////////////////////////////////
/////////////////////////////////////////////////
// メッシュデータ型
/////////////////////////////////////////////////
/////////////////////////////////////////////////
class MyFace;
class MyVertex;
class MyEdge;

struct MyUsedTypes : public
  UsedTypes<
  Use<MyVertex>::AsVertexType,
  Use<MyFace>::AsFaceType,
  Use<MyEdge>::AsEdgeType

  >
{};

class MyVertex :
  public Vertex<
  MyUsedTypes,
  vertex::Coord3f,
  vertex::Color4b,
  vertex::Normal3f,
  vertex::BitFlags,
  vertex::VEAdj,// needed
  vertex::Mark>
{
public:
  bool m_loopchecked;
  MyVertex() {
    m_loopchecked = false;
  }

};

class MyEdge : public vcg::Edge<
  MyUsedTypes,
  vcg::edge::VertexRef,
  vcg::edge::VEAdj,// needed
  vcg::edge::BitFlags> {

public:
  MyEdge() {
  }
};

class MyFace :
  public Face  <
  MyUsedTypes,
  face::VertexRef,
  face::Normal3f,
  face::FFAdj,// needed
  face::BitFlags >
{};


class MyMesh :
  public vcg::tri::TriMesh<
  vector<MyVertex>,
  vector<MyFace>,
  vector<MyEdge>
  >
{};

実装

#pragma once
#include <windows.h>
#include <GL/gl.h>
#include <GL/freeglut.h>
#include "nurotate.h"


#include "MyMesh.h"

//! @brief 穴構成頂点の配列をhole_tとする。
using hole_t = std::vector<int>;

//! @brief 穴の配列
std::vector<hole_t> holes;

//! @brief 穴を検出する関数 //! @param [in] mesh メッシュデータ //! @param [out] hole 穴構成頂点の格納先 //! @param [in] vid 検索開始地点の頂点ID //! @retval false 穴が見つからなかった //! @retval true 穴が見つかった bool search_near_edge(MyMesh& mesh, hole_t& hole,int vid) { vcg::edge::VEIterator<MyEdge> vfe(&mesh.vert[vid]); for (; !vfe.End(); ++vfe) { MyEdge* e = vfe.E(); // OpenEdge以外は読み飛ばす if (e->IsB() == false) { continue; } //現在検索中の頂点ともう一方に分ける int from, to; if (vcg::tri::Index(mesh, e->cV(0)) == vid) { from = vid; to = vcg::tri::Index(mesh, e->cV(1)); } else { from = vid; to = vcg::tri::Index(mesh, e->cV(0)); } if (hole.size() != 0) { if (hole[0] == to) { hole.push_back(from); return true; } } if (mesh.vert[to].m_loopchecked == true) continue; mesh.vert[from].m_loopchecked = true; hole.push_back(from); if (search_near_edge(mesh, hole, to) == true) { return true; } } return false; }
MyMesh m; int width, height; //回転オブジェクト定義 nu::mrotate camr; //! @brief 表示関数 //! @return なし void disp(void) { glClearColor(0.3, 0.3, 0.3, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45,width / (double)height, 0.1, 5); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); GLfloat lpos[4] = { 0,1,1,1 }; GLfloat ambw[4] = { 0.5,0.5,0.5,1 }; GLfloat color[4] = { 1,1,1,1 }; GLfloat lspec[4] = { 1,1,1,1 }; GLfloat mspec[4] = { 0.5,0.5,0.5,1 }; ///////////////////////////////////////////// glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, ambw); glLightfv(GL_LIGHT0, GL_SPECULAR, lspec); glLightfv(GL_LIGHT0, GL_POSITION, lpos); ///////////////////////////////////////////// glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mspec); glPushMatrix(); //原点を視線方向に0.5ずらす glTranslated(0, 0, -2); //回転行列を適用 double mat[16]; glMultMatrixd(camr.getmatrix(mat));
glPushMatrix(); glScaled(2.0 / m.bbox.Diag(), 2.0 / m.bbox.Diag(), 2.0 / m.bbox.Diag()); { //全ての面を表示 glBegin(GL_TRIANGLES); for (auto& f : m.face) { glNormal3f(f.cN().X(), f.cN().Y(), f.cN().Z()); glVertex3d(f.cV(0)->cP().X(), f.cV(0)->cP().Y(), f.cV(0)->cP().Z()); glVertex3d(f.cV(1)->cP().X(), f.cV(1)->cP().Y(), f.cV(1)->cP().Z()); glVertex3d(f.cV(2)->cP().X(), f.cV(2)->cP().Y(), f.cV(2)->cP().Z()); } glEnd(); } { //全てのエッジを表示 glDisable(GL_LIGHTING); glLineWidth(1); glColor3d(0, 0, 0); for (auto& f : m.face) { glBegin(GL_LINE_LOOP); glVertex3d(f.cV(0)->cP().X(), f.cV(0)->cP().Y(), f.cV(0)->cP().Z()); glVertex3d(f.cV(1)->cP().X(), f.cV(1)->cP().Y(), f.cV(1)->cP().Z()); glVertex3d(f.cV(2)->cP().X(), f.cV(2)->cP().Y(), f.cV(2)->cP().Z()); glEnd(); } } { //見つかった穴だけを表示 glDisable(GL_LIGHTING); glLineWidth(3); glColor3d(0, 0, 1); for (auto& hole : holes) { glBegin(GL_LINE_STRIP); for (auto& v : hole) { glVertex3d( m.vert[v].cP().X(), m.vert[v].cP().Y(), m.vert[v].cP().Z() ); } glEnd(); } } glPopMatrix();

glPopMatrix(); glFlush(); } void reshape(int w, int h) { width = w; height = h; //クライアント領域のサイズを指定 //Win32APIの場合はGetClientRectで求めたrightとbottomだがglutではwとh camr.setWindowSize(width, height); //クライアント領域のどこの範囲に描画しているかを指定。 //glViewportで一画面丸々描画しているので、クライアント領域の(0,0)-(width,height)に書いていることになる camr.setRenderRect(0, 0, width, height); disp(); } //マウスクリック時のイベント void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { camr.dragstart(x, y);//最初の回転軸を決定 } else if (state == GLUT_UP) { camr.dragend();//ドラッグ終了 } glutPostRedisplay(); } //ドラッグ時のイベント void motion(int x, int y) { camr.dragto(x, y);//移動中の回転軸を更新 disp(); } //エントリポイント int main(int argc, char ** argv) { glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(400, 300); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutCreateWindow("MouseRotateSample"); glutDisplayFunc(disp); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion);
vcg::tri::io::ImporterPLY<MyMesh>::Open(m, "sample.ply"); vcg::tri::Clean<MyMesh>::RemoveDuplicateVertex(m); vcg::tri::UpdateBounding<MyMesh>::Box(m); vcg::tri::UpdateNormal<MyMesh>::PerFace(m); vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); vcg::tri::UpdateTopology<MyMesh>::AllocateEdge(m); vcg::tri::UpdateTopology<MyMesh>::VertexEdge(m); vcg::tri::UpdateFlags<MyMesh>::VertexBorderFromFaceAdj(m);
 
///////////////////////////////// // 穴検出 /////////////////////// bool ret; for (size_t i = 0; i < m.vert.size(); i++) { //OpenEdgeのフラグが立っていないなら何もしない if (m.vert[i].IsB() == false) continue; //すでにループかどうかの評価をしたフラグが立っていれば何もしない if (m.vert[i].m_loopchecked) continue; m.vert[i].m_loopchecked = true; hole_t hole; ret = search_near_edge(m, hole,i);//未チェックのOpenEdge構成頂点を渡して穴かどうかの評価 if (ret == true) { holes.push_back(hole);//穴一覧を更新 } }
 
glutMainLoop(); return 0; }

回転について

以下を参照

実行結果

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: