2012年6月24日日曜日

C++/CLI テキストの置換

main.cpp

using namespace System;

// テキストファイルを開いて文字列置換を行うテスト
void ReplaceText(String^ path, String^ strOld, String^ strNew)
{
  if (!IO::File::Exists(path)) return;

  Text::Encoding^ enc = Text::Encoding::GetEncoding("shift_jis");

  // テキストファイルの読み込み
  IO::StreamReader^ sr = gcnew IO::StreamReader(path, enc);
  String^ textInput = sr->ReadToEnd();
  sr->Close();

  // 置換する
  String^ textOutput = textInput->Replace(strOld, strNew);

  // テキストファイルの書き込み
  IO::StreamWriter^ sw = gcnew IO::StreamWriter(path, false, enc);
  sw->Write(textOutput);
  sw->Close();
}

int main(array ^args)
{
  if(args->Length == 3) {
    ReplaceText(args[0], args[1], args[2]);
  }
    return 0;
}

2012年5月27日日曜日

MAXScript 文字列 コピー 置換

オブジェクト名に禁則文字が含まれていたので、エクスポート時に _で置換

文字列のコピーと置換のテスト


-- name に禁則文字 があったら rCh で置換する
fn ReplaceProhibitChar name rCh = (
  -- 禁則文字 仮
  prohibit = "\\/:,;*?\"<>|"

  -- 名前をコピーする
  newName = copy name
  
  -- 禁則文字を rCh に置換
  for j = 1 to prohibit.count do (
    for i = 1 to newName.count do (
      if prohibit[j] == newName[i] do (
        newName[i] = rCh
      )
    )
  )
  
  format "oldName %\n" name
  format "newName %\n" newName
  
  newName
)

str1 = ReplaceProhibitChar "aaa:0" "_"

2012年4月30日月曜日

Bullet 衝突回数のカウント

衝突回数をカウントして、剛体を削除するテスト bullet-2.79

main.cpp

#include <crtdbg.h>
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>

#ifdef _DEBUG
#pragma comment(lib, "BulletCollision_debug.lib")
#pragma comment(lib, "BulletDynamics_debug.lib")
#pragma comment(lib, "LinearMath_debug.lib")
#else
#pragma comment(lib, "BulletCollision.lib")
#pragma comment(lib, "BulletDynamics.lib")
#pragma comment(lib, "LinearMath.lib")
#endif

// ↓コンタクトのコールバック
extern ContactProcessedCallback gContactProcessedCallback;

struct TestData {
  int count; // 衝突回数
  TestData() : count(0) {}
};

class TestBullet {
  btDiscreteDynamicsWorld*        m_pWorld;
  btVector3 m_vWorldSize;

    btDefaultCollisionConfiguration     m_config;
    btCollisionDispatcher         m_dispatcher;
    btAxisSweep3              m_broadphase;
    btSequentialImpulseConstraintSolver   m_solver;
  btAlignedObjectArray<btCollisionShape*> m_collisionShapes;

  btRigidBody*  m_Body1;
  TestData    m_BodyData1;
public:
  TestBullet() :
    m_dispatcher(&m_config),
    m_vWorldSize(1000.0f, 1000.0f, 1000.0f),
    m_broadphase(m_vWorldSize * -0.5f, m_vWorldSize * 0.5f, 1024),
    m_pWorld(0), m_Body1(0)
  {}
  ~TestBullet();

  void Init();
  void Update();
  void DeleteBody(btRigidBody** pBody);
  static bool HandleContactProcess(btManifoldPoint& p, void* a, void* b);
};

TestBullet::~TestBullet() {
  for (int i = m_pWorld->getNumCollisionObjects() - 1; i >= 0 ; i--) {
    btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];
    btRigidBody* body = btRigidBody::upcast(obj);
    DeleteBody(&body);
  }
  for (int j = 0; j < m_collisionShapes.size(); j++) {
    btCollisionShape* shape = m_collisionShapes[j];
    m_collisionShapes[j] = 0;
    delete shape;
  }
  delete m_pWorld;
}

void TestBullet::Init() {
  m_pWorld = new btDiscreteDynamicsWorld(&m_dispatcher, &m_broadphase, &m_solver, &m_config);
  m_pWorld->setGravity(btVector3(0.0f, -9.8f * 1.0f, 0.0f));
  m_pWorld->getSolverInfo().m_numIterations = 2;

  // 地面の形状
  btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));
  m_collisionShapes.push_back(groundShape);

  btTransform groundTransform;
  groundTransform.setIdentity();
  groundTransform.setOrigin(btVector3(0.0f, -50.0f, 0.0f));

  // 地面の作成
  btScalar mass(0.0f);
  bool isDynamic = (mass != 0.f);

  btVector3 localInertia(0,0,0);
  if (isDynamic) groundShape->calculateLocalInertia(mass, localInertia);

  btDefaultMotionState* myMotionState = new btDefaultMotionState( groundTransform );
  btRigidBody::btRigidBodyConstructionInfo rbInfo0(mass, myMotionState, groundShape, localInertia);

  btRigidBody* pGroundBody = new btRigidBody(rbInfo0);
  m_pWorld->addRigidBody(pGroundBody);


  // 削除テスト用の剛体の作成
  btCollisionShape* colShape = new btSphereShape( 2.0f );
  m_collisionShapes.push_back(colShape);

  btTransform startTransform;
  startTransform.setIdentity();

  mass  = 100.0f;
  isDynamic = (mass != 0.f);
  if (isDynamic)  colShape->calculateLocalInertia(mass, localInertia);

  startTransform.setOrigin(btVector3(2, 5, 0));

  myMotionState = new btDefaultMotionState(startTransform);
  btRigidBody::btRigidBodyConstructionInfo rbInfo1(mass, myMotionState, colShape, localInertia);

  m_Body1 = new btRigidBody(rbInfo1);
  m_Body1->setUserPointer(&m_BodyData1);  // ユーザーデータをセット
  m_pWorld->addRigidBody(m_Body1);
}

void TestBullet::Update() {
  const btScalar dt = 1.0f / 30.0f;
  m_pWorld->stepSimulation(dt);

  btTransform trans;
  for (int i = m_pWorld->getNumCollisionObjects() - 1; i >= 0; i--) {
    btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];
    btRigidBody* body = btRigidBody::upcast(obj);

    if(body && !body->isStaticObject()) {
      body->getMotionState()->getWorldTransform(trans);
      btVector3& pos = trans.getOrigin();

      printf("%f, %f, %f\n", pos.getX(), pos.getY(), pos.getZ());
    }
  }
  if(m_Body1 != NULL && m_BodyData1.count > 6) {
    DeleteBody(&m_Body1); // 削除テスト
  }
}

void TestBullet::DeleteBody(btRigidBody** ppBody) {
  btRigidBody* pBody = *ppBody;
  m_pWorld->removeRigidBody( pBody );
  btMotionState* pMotionState = pBody->getMotionState();
  if(pMotionState) {
    delete pMotionState;
  }
  delete pBody;
  *ppBody = NULL;
}

bool TestBullet::HandleContactProcess(btManifoldPoint& p, void* a, void* b) {
  btRigidBody* pBody0 = (btRigidBody*)a;
  btRigidBody* pBody1 = (btRigidBody*)b;

  TestData* pUserData0 = (TestData*)pBody0->getUserPointer();
  TestData* pUserData1 = (TestData*)pBody1->getUserPointer();

  // カウント
  if(pUserData0) pUserData0->count++;
  if(pUserData1) pUserData1->count++;
  return true;
}

int main() {
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
  TestBullet test;
  test.Init();
  // 衝突のコールバック関数をセット
  gContactProcessedCallback = TestBullet::HandleContactProcess;

  for (int i = 0; i < 100; i++) {
    test.Update();
  }
  return 0;
}

2012年4月29日日曜日

dcollide Kdopのテスト

K-DOP (K discrete oriented polytope)

main.cpp

#define _USE_MATH_DEFINES
#include <d-collide/dcollide.h>
#include <d-collide/proxyfactory.h>
#include <d-collide/math/vector.h>
#include <d-collide/shapes/mesh/meshfactory.h>

int main()
{
  // ワールド
  dcollide::World world;

  // プロキシファクトリを取得
  dcollide::ProxyFactory* pPf = world.getProxyFactory();

  // プロキシを作成
  dcollide::Proxy* pProxy = pPf->createProxy();

  // メッシュの頂点
  dcollide::Vertex vtx_array[] = {
    dcollide::Vertex(0, 10.18f, 0),
    dcollide::Vertex(-10, 0, -10),
    dcollide::Vertex( 10, 0, -10),
    dcollide::Vertex(-10, 0,  10),
    dcollide::Vertex( 10, 0,  10),
  };

  std::vector vertices;
  vertices.push_back( &vtx_array[0] );
  vertices.push_back( &vtx_array[1] );
  vertices.push_back( &vtx_array[2] );
  vertices.push_back( &vtx_array[3] );
  vertices.push_back( &vtx_array[4] );

  // メッシュのインデックス
  std::vector indices;
  indices.push_back(1); indices.push_back(2); indices.push_back(0);
  indices.push_back(3); indices.push_back(4); indices.push_back(0);

  // メッシュ
  dcollide::Mesh mesh(vertices, indices);
  mesh.setProxy( pProxy );

  // メッシュファクトリ
  dcollide::MeshFactory mf;

  // メッシュファクトリから球のメッシュを作成
  dcollide::Mesh* pSphereMesh = mf.createSphere(4.56f, 5.0f);
  pSphereMesh->setProxy( pProxy );

  // kdopのk
  int k = 6;    // 6:AABB 14, 18, 26
  // kdop
  dcollide::Kdop kdop(k);
  kdop.adjustToShape(&mesh);    // プロキシが無いとerror
//  kdop.adjustToShape(pSphereMesh);

  // AABB
  dcollide::Vector3 vMin =  kdop.getSurroundingAabbMin();
  dcollide::Vector3 vMax = kdop.getSurroundingAabbMax();
 
  printf("k = %d\n", k);
  for(int i = 0; i < k; ++i) 
  {
    // 原点から平面までの距離
    dcollide::real dist = kdop.getDistanceOfPlaneToOrigin(i);
    // 平面の法線ベクトル
    dcollide::Vector3 vN = kdop.getPlaneNormal(i);
    printf("%d [%f %f %f %f]\n", i, vN.getX(), vN.getY(), vN.getZ(), dist);
  }
  return 0;
}

2012年4月28日土曜日

MAXScript テキストファイルに書き出す

シーン内で使用しているテクスチャ画像の絶対パスをファイルに書き出す テスト

WriteDiffuseTexFilePath.ms

-- マテリアルのDiffuseテクスチャ画像の絶対パスをファイルに出力
fn WriteMtlInfo fs mtl = (
  d = mtl.DiffuseMap
  if undefined == d do return -2
  
  bm = d.bitmap
  if undefined == bm do return -3
  
  filePath = d.fileName
  
  -- ファイルの絶対パスを取得
  FileResolutionManager.getFullFilePath &filePath #Bitmap

  -- ¥ を /に変換
  strArray = filterString filePath "¥¥"
  filePath = ""
  for i = 1 to strArray.count do (
    filePath += strArray[i]
    if i < strArray.count do (
      filePath += "/"
    )
  )
  -- 画像の幅、高さ
  w = bm.width
  h = bm.height
  format "%¥n" filePath to:fs -- 絶対パスをファイルに出力
)

-- シーン内のマテリアル情報の取得
fn WriteDiffuseTexFilePath fileName = (
  if 0 == sceneMaterials.count do (
    format "sceneMaterials.count is 0¥n"
    return -1
  )

  -- ファイル出力先のディレクトリ
  fPath =  GetDir #export
  fPath += "¥¥" + fileName

  -- ファイルオープン
  fs = openFile fPath mode:"wt"
  if undefined  == fs do return -1
  
  for i = 1 to sceneMaterials.count do (
    mtl = sceneMaterials[ i ]   -- マテリアルを取得
    c = classof mtl     -- マテリアルのクラス名を取得

    if c == Standardmaterial do (
      WriteMtlInfo fs mtl
    )
    if c == Multimaterial do (
      nSubMtl = getNumSubMtls mtl -- マテリアルのサブマテリアル数を取得
      for j = 1 to nSubMtl do (
        subMtl = getSubMtl mtl j
        WriteMtlInfo fs subMtl
      )
    )
  )
  -- ファイルクローズ
  close fs  
)
-- exportフォルダにTexFilePath.txtが作成される
WriteDiffuseTexFilePath "TexFilePath.txt"

Win32++ (1) ボタン

main.cpp

// ボタンのテスト
#include <stdcontrols.h>
#include <controls.h>
#include <cstring.h>
#pragma comment(lib, "comctl32.lib")

// メッセージ
#define MY_MSG_001  (WM_APP + 1)

// ボタン
class MyButton : public CButton {
protected:
  int   m_nID;
public:
  MyButton(int id) : m_nID(id), CButton() {}
  virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) {
    switch (HIWORD(wParam)) {
    case BN_CLICKED:
      {
        CWnd* pParent = this->GetParent();
        if(pParent) {
          this->SendMessage(pParent->GetHwnd(), MY_MSG_001, m_nID, 0);
        }
      }
      return TRUE;
    }
    return FALSE;
  }
};

// ビュー
class CView : public CWnd {
public:
  CView()       {}
  virtual ~CView()  {
    delete m_pButton1;
    delete m_pButton2;
  }

  virtual void OnCreate() {
    // ボタンを作成
    m_pButton1 = new MyButton(1);
    m_pButton1->Create(this);
    m_pButton1->MoveWindow(10, 10, 100, 24);
    m_pButton1->SetWindowTextW(L"ボタン1");

    m_pButton2 = new MyButton(2);
    m_pButton2->Create(this);
    m_pButton2->MoveWindow(10, 50, 100, 24);
    m_pButton2->SetWindowTextW(L"ボタン2");
  }
protected:
  virtual LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);

  MyButton* m_pButton1;
  MyButton* m_pButton2;
};

LRESULT CView::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) {
  CString str;

  switch (uMsg) {
  case MY_MSG_001:
    str.Format(L"%d %d\n", uMsg, wParam);
    TRACE(str);
    break;
  case WM_DESTROY:
    m_pButton1->Destroy();
    m_pButton2->Destroy();
    ::PostQuitMessage(0);
    break;
  }
  return WndProcDefault(uMsg, wParam, lParam);
}

class MyApp : public CWinApp {
public:
  MyApp() {}
    virtual ~MyApp() {}
  virtual BOOL InitInstance() {
    m_View.Create();
    return TRUE;
  }
private:
    CView m_View;
};

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 
{
    MyApp MyApp;
    return MyApp.Run();
}

2012年4月27日金曜日

OpenCV 画像の90度回転

テキストをパースして、複数の画像を1枚にまとめてみる テスト

パース処理にboostのtokenizerを使用

貼り付ける画像が、貼り付け先の画像からはみ出るとエラーになるよ


テキストファイルの例

2                     <-- 貼り付ける画像数
1024 512              <-- 貼り付け先の画像の幅, 高さ
c:/temp/test1.bmp"    <-- 画像の絶対パス
0 0 0 200 200 0       <-- [画像のインデックス] [X座標] [Y座標] [幅] [高さ] [※回転]
c:/temp/test2.bmp"
1 210 0 32 128 1

main.cpp

#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

// 貼り付ける画像情報
struct ImageInfo {
  std::string   path;   // ファイルの絶対パス
  int       param[6]; // パラメータ
};

// src_imgをdst_imgのrect領域にコピー
void MatCopyPaste(const cv::Rect& rect, cv::Mat& dst_img, cv::Mat& src_img) {
  cv::Mat d = dst_img(rect);    // 貼り付け先のMatを取得
  src_img.copyTo(d);        // 貼り付け画像をコピーする
}

// 1画像の処理
void ImageProc(cv::Mat& dst_img, const ImageInfo& info) {
  // 貼り付ける画像を読み込む
  cv::Mat src_img = cv::imread(info.path, 1);
  assert(!src_img.empty());

  // 貼り付け先の画像のサイズ
  int imgWidth = info.param[3];
  int imgHeight = info.param[4];
  // 貼り付け位置
  int imgX = info.param[1];
  int imgY = info.param[2];

  // 貼り付け画像
  cv::Mat tmp_img(cv::Size(imgWidth, imgHeight), src_img.type());

  if(info.param[5] == 1) {
    // 画像を回転
    int src_w = src_img.size().width;
    int src_h = src_img.size().height;
    
    cv::Mat rot_img(cv::Size(src_h, src_w), src_img.type(), cv::Scalar(0, 0, 0));
    cv::transpose(src_img, rot_img);  // 転置 左回り 反時計回りに90度回転 
    cv::flip(rot_img, rot_img, 1);    // 左右反転 時計回りに90度回転

    cv::resize(rot_img, tmp_img, tmp_img.size(), cv::INTER_CUBIC);
  } else {
    // サイズ変更
    cv::resize(src_img, tmp_img, tmp_img.size(), cv::INTER_CUBIC);
  }

  // 指定した矩形に画像を貼り付ける
  cv::Rect rect(imgX, imgY, imgWidth, imgHeight); 
  MatCopyPaste(rect, dst_img, tmp_img);
}

int main( int argc, char **argv ) {
  int count = 0;
  std::string str;
  // 貼り付ける画像を記述したテキストファイルを読み込む
  std::ifstream ifs( "./data/ImgList.txt" );

  typedef boost::char_separator char_sep;
  typedef boost::tokenizer tokenizer;
  char_sep sep(" ");    // スペース区切り

  int imgNum, imgWidth, imgHeight;
  std::vector  imgDataArray;
  ImageInfo imgData;

  while(std::getline(ifs, str)) {
    std::vector tokenArray;

    // 読み込んだ文字列をトークンに分割して配列に格納
    tokenizer tok(str, sep);
    for (tokenizer::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) {
      tokenArray.push_back( *tok_iter );
    }

    switch(count) {
    case 0:  // 画像数
      // int にキャスト
      imgNum = boost::lexical_cast(tokenArray[0]);
      break;
    case 1:  // 画像の幅と高さ
      imgWidth = boost::lexical_cast(tokenArray[0]);
      imgHeight = boost::lexical_cast(tokenArray[1]);
      break;
    default: // 画像のパラメータ
      if(0 == count % 2) {
        // ファイルパス
        imgData.path = tokenArray[0];
      } else {
        // パラメータ
        for(int i = 0; i < 6; i++) {
          imgData.param[i] = boost::lexical_cast(tokenArray[i]);
        }
        imgDataArray.push_back(imgData);
      }
      break;
    }
    count++;
  }

  // 貼り付け先の画像
  cv::Mat dstImg(cv::Size(imgWidth, imgHeight), CV_8UC3, cv::Scalar(0, 0, 0));

  // 画像処理
  for(size_t i = 0; i < imgDataArray.size(); i++) {
    ImageProc(dstImg, imgDataArray[i]);
  }

  // 結果を保存
//  cv::imwrite("./data/result.png", dstImg);

  // 結果を表示
  cv::namedWindow("Result", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  cv::imshow("Result", dstImg);
  cv::waitKey(0);
  return 0;
}