Algoritmo para colisão entre objeto e linha

Padrão

Objetivo:

Cabeçalhos no .h

ofPolyline square1;
ofPolyline square2;
ofPolyline line;
ofPoint closestTo1;
ofPoint closestTo2;
bool moving1;
bool moving2;
void mountSquare1(ofPoint place);
void mountSquare2(ofPoint place);
void mountLine();

Metodos no .cpp

Setup

void ofApp::setup(){
       mountSquare1(ofPoint(100, 100));
       mountSquare2(ofPoint(400, 100));
       mountLine();

       moving1 = false;
       moving2 = false;

       ofSetLogLevel(OF_LOG_VERBOSE);
}

mountSquare1

void ofApp::mountSquare1(ofPoint place) {
       square1.clear();
       square1.addVertex(place + ofPoint(-40, -30));
       square1.addVertex(place + ofPoint(+40, -30));
       square1.addVertex(place + ofPoint(+40, +30));
       square1.addVertex(place + ofPoint(-40, +30));
       square1.close();
}

mountSquere2

void ofApp::mountSquare2(ofPoint place) {
       square2.clear();
       square2.addVertex(place + ofPoint(-40, -30));
       square2.addVertex(place + ofPoint(+40, -30));
       square2.addVertex(place + ofPoint(+40, +30));
       square2.addVertex(place + ofPoint(-40, +30));
       square2.close();
}

mountLine

void ofApp::mountLine() {
       line.clear();
       //find closestTo1 and closestTo2
       // first look source1 to source2
       closestTo1 = square1.getCentroid2D();
       closestTo2 = square2.getCentroid2D();

       ofPolyline helperLink;
       helperLink.clear();
       helperLink.addVertex(closestTo1);
       helperLink.addVertex(closestTo2);

       int index = 0;

       ofRectangle r = square1.getBoundingBox();
       float w = r.getWidth();
       float h = r.getHeight();
       float max;
       w > h ? max = w : max = h;

       while (true) {
             closestTo1 = helperLink.getPointAtLength(index);
             if (!square1.inside(closestTo1)) break;
             index += 1;
             if (index > max) break;
       }

       // second look source2 to source1
       helperLink.clear();
       helperLink.addVertex(closestTo2);
       helperLink.addVertex(closestTo1);
       index = 0;
       //     ofLogVerbose() << "process link point 2"; r = square2.getBoundingBox(); w = r.getWidth(); h = r.getHeight(); w > h ? max = w : max = h;

       while (true) {
             closestTo2 = helperLink.getPointAtLength(index);
             //     ofLogVerbose() << "closestTo2: " + ofToString(index) + " - " + ofToString(closestTo2); if (!square2.inside(closestTo2)) break; index += 1; if (index > max) break;
       }
       line.addVertex(closestTo1);
       line.addVertex(closestTo2);
}

draw

void ofApp::draw() {
       ofEnableAntiAliasing();
       ofEnableSmoothing();

       ofSetColor(ofColor::blue);
       ofSetLineWidth(1);
       square1.draw();
       square2.draw();
       line.draw();

       ofSetColor(ofColor::red);
       ofCircle(closestTo1, 5);
       ofCircle(closestTo2, 5);

}

mouseEvents

void ofApp::mouseDragged(int x, int y, int button) {

       if (moving1 == true) {
             mountSquare1(ofPoint(x, y));
             mountLine();
             return;
       }

       if (moving2 == true) {
             mountSquare2(ofPoint(x, y));
             mountLine();
             return;
       }
}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {

       if (square1.inside(x, y)) {
             moving1 = true;
             moving2 = false;
             return;
       }
       if (square2.inside(x, y)) {
             moving1 = false;
             moving2 = true;
             return;
       }
       moving1 = moving2 = false;
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button) {
       moving1 = moving2 = false;
}

Criando linhas usando ofPolyline no openFrameworks

Padrão

1.Criar as linhas:

Para criar as linhas pode-se usar duas estruturas básicas, uma para desenhar e a outra para conter a lista de vértices
class ofApp : public ofBaseApp{
        public:
                //----- . . .
                ofPolyline shape;
                vector vertexList;
                //----- . . .
}
Basicamente é só adicionar novos pontos da fila
if (mode == shapeMode::creating) {
        vertexList.push_back(ofPoint(x, y));
        this->createShape();
        return;
}
A rotina de criar o shape, é noobescamente essa:
void ofApp::createShape() {
        shape.clear();
        vector::iterator itV;
        for (itV = vertexList.begin(); itV != vertexList.end(); itV++)
                shape.addVertex((*itV));
}
E o draw:
void ofApp::drawShape() {
        shape.draw();
}

2. Adicionar pontos no meio do campo

Aqui é um pouco mais tricky, deve-se observar algumas coisas
  1. Testar se existe alguma linha
  2. Se perto do ponto zero, ctza que está entre 0 e o 1. (Primeiro trecho)
  3. Se não é perto do primeiro ponto, verificar se está no ponto (local -1) e ponto (local)
  4. Se perto do ponto size( ) -1, ctza que está entre o size( ) - 2 e o size( ) - 1.  (Último trecho)
  5. Se não é perto do último ponto, verificar se está no ponto (local) e ponto (local + 1)
if (mode == shapeMode::editing) {
        unsigned int perto;
        ofPoint c = shape.getClosestPoint(ofPoint(x, y), &perto);

        if (vertexList.empty()) return;

        if (perto == 0) {
                vertexList.insert(vertexList.begin() + perto + 1,c);
                this->createShape();
                return;
        }
        else {
                ofPoint a = vertexList[perto];
                ofPoint b = vertexList[perto - 1];

                if (abs((a.y - c.y) - ((a.y - b.y) / (a.x - b.x))*(a.x - c.x)) < 5) { vertexList.insert(vertexList.begin() + perto, c); this->createShape();
                        return;
                        }
        }

        if (perto == shape.size() - 1) {      
                vertexList.insert(vertexList.begin() + perto, c);
                this->createShape();
                return;
        }
        else {
                ofPoint a = vertexList[perto];
                ofPoint b = vertexList[perto + 1];

                if (abs((a.y - c.y) - ((a.y - b.y) / (a.x - b.x))*(a.x - c.x)) < 5) { vertexList.insert(vertexList.begin() + perto + 1, c); this->createShape();
                        return;
                        }
        }
}

3. Movimentar os pontos

Primeiro tem que ser feita uma mini função ninja para encontrar o ponto mais próximo:
ofPoint * ofApp::closeToVertex(ofPoint p) {
        vector::iterator itV;
        for (itV = vertexList.begin(); itV != vertexList.end(); itV++)
                if (p.squareDistance((*itV)) < 100) return &(*itV);
        return NULL;
}
Para mudar os pontos deve-se fazer duas coisas, na verdade três, mas enfim: selecionar, mover, e liberar. Não considerei a segunda, só ignorei o liberar como parar de fazer qq função.
Selecionar:
void ofApp::mousePressed(int x, int y, int button){
        if (mode == shapeMode::pointSelected) {
                closest = this->closeToVertex(ofPoint(x, y));
                return;
        }
}
Mover:
void ofApp::mouseDragged(int x, int y, int button){
        if (mode == shapeMode::pointSelected){
                if (closest != NULL) {
                        closest->x = x;
                        closest->y = y;
                        this->createShape();
                }
        return;
        }
}

4. Apagar os pontos

Apagar um ponto basta encontrar novamente o ponto, e dar um delete ninja no vetor.
if (mode == shapeMode::removingPoint) {
        ofLogVerbose() << "testing point"; closest = this->closeToVertex(ofPoint(x, y));
        if (closest != NULL) {
                vector::iterator itV;
                for (itV = vertexList.begin(); itV != vertexList.end(); itV++) {
                        if (itV->x == closest->x && itV->y == closest->y) {
                               vertexList.erase(itV);
                               this->createShape();
                               return;
                        }
                }
                }
        return;
}

openFrameworks 0.8.4 + ofxARToolKitPlus

Padrão

Esse post é para descrever o problema/solução que eu tive que fazer para linkar o addon ofxARToolKitPlus no oF0.8.4. Já tinha feito um tutorial para o SVR 2013 ensinando a criar ambientes de RA rapidamente. Mas, na época eu usei a versão do oF 0.7.4, hoje está na 0.8.4, e algumas coisas mudaram, inclusive o compilador, na época era o VS2010, hoje é o VS2012. Nisso o C++ também teve uns updates, então nesse post, tentarei trilhar o caminho das pedras:

1. O que é necessário:

a) oF 0.8.4 - http://openframeworks.cc/download/
b) VS2012 - http://openframeworks.cc/setup/vs/
* Vou considerar que você instalou tudo ok, e que os exemplos funcionaram.
c) ofxARToolKitPlus - (http://ofxaddons.com/) - https://github.com/fishkingsin/ofxARtoolkitPlus

2. O Tutorial

Funciona relativamente bem, mas o problema que ocorre é o erro de versão da lib ofxARToolKitPlus que tem no addons.

Vai dizer que está faltando compatibilidade de algumas coisas, e que não está encontrando nas libs.

3) Resolvendo os erros do ofxARToolKitPlus

Para resolver isso precisa compilar novamente a biblioteca:
a) Baixar o ARToolKitPlus - https://launchpad.net/artoolkitplus
b) Baixar o CMake (não gosto, mas enfim, facilita) - http://www.cmake.org/

c) No CMake você tem que compilar a lib para o VS que está usando. (Tentar pelo menos, pois vai dar um erro).

c.1) Descompacta o ARToolKitPlus-2.3.0 (O ultimo update foi em 2012) - gosto de usar rootDEVEL (ps.: Demora)
c.2) Abrir o CMake, a seguir o print das minhas configurações do CMake

c.3) Clicar em Configure - escolha o compilador desejado, no caso: Visual Studio 11 2012 e “Use default native compilers”

e depois Generate

d) Vá ao diretório DEVELARToolKitPlus-2.3.0bin, e execute a solução criada pelo CMake: ARToolKitPlus.sln

Do projetos criados, só é necessário o ARToolKitPlus.

Não esqueça de passar para Release e mandar dar Build.

Ocorrerá um erro, pois o C++ mudou, por preguiça, compile e espere eles aparecerem, vão ser 3 erros pois não existe mais a função make_pair, agora é só pair. Mude, compile e seja feliz.

Se quiser, vai que, compile o Debug também.

e) Onde as bibliotecas estão:!?

No DEVELARToolKitPlus-2.3.0binbin, tem as dlls Release e Debug

No DEVELARToolKitPlus-2.3.0binlib, tem as libs Realease e Debug

* Se você quiser salvar as respostas em um lugar só, coloque o d na frente só para diferenciar a versão release e a versão debug

4) Atualizando o ofxARToolKitPlus

Bem, agora precisa atualizar as coisas,
a) 1º passo: Copia as libs que você gerou para: addonsofxARtoolkitPluslibsARToolKitPluslibwin32

b) 2º passo: Copia as dlls para a raiz de execução do seu programa, ex: appsmyAppstestARTKP

c) 3º passo: O ofxARToolKitPLus foi escrito para o oF.0.7.x, e agora ao invés de testApp é ofApp, então para rodar o exemplo, você tem que ir um a um e copiar os elementos do cabeçalho e os conteúdos dos métodos.

Ultima coisa, para testar eu criei um projeto no project generator, usando as dicas do tutorial que está no slideshare.

Bem boa sorte, qq dúvida entre em contato.

openFrameworks e MatLab

Padrão

Esse post visa comentar (e ajudar alguém) o caminho para utilizar a MatLab Engine API, não vou explicar os detalhes de funcionamento - pois constam no link. Mas basicamente ela serve para possibilitar a utilização do motor do MatLab por aplicações externas.

O ambiente utilizado foi:

  1. Windows 7 64 bits instalado numa máquina virtual usando VMWare, é grátis para fins não comerciais.
  2. MatLab Student 2013a Versão 32 bits
  3. Visual Studio 2012 Express.
  4. openFrameworks - http://openframeworks.cc/ - versão 0.8.3 para Windows - Visual Studio

Foram utilizados os seguintes links para ajudar:

Após todas as ferramentas instaladas,

  1. Criar um projeto usando o projectGenerator do openFrameworks.
  2. Entrar no Solution criado pelo projectGenerator
  3. Ajustar IDE.
    1. Dentro do Visual Studio, abra as Propriedades (Properties) da solução criada.
    2. Em Configuration Properties -> Debugging -> Command, adicionar o caminho PATH=$C:Program Files (x86)MATLABR2013abin . Lembrem que instalei a versão 32bits do Matlab.  DICA: Crie uma variável MATLABROOT que direcione para o raiz do MatLab - facilita.
    3. Em Configuration Properties -> C/C++ -> General, adicione os endereços dos diretórios com includes em “Additional Include Directories”:
      1. C:Program Files %28×86%29MATLABR2013aexternincludewin32;
      2. C:Program Files %28×86%29MATLABR2013aexterninclude
    4. Em Configuration Properties -> C/C++ -> Precompiled Headers verifique se Precompiled Headers está em “Not Using Precompiled Headers”
    5. Em Configuration Properties -> Linker -> General, adicione o endereço em “Additional Library Directories”:
      1. C:Program Files %28×86%29MATLABR2013aexternlibwin32microsoft
    6. Em Configuration Properties -> Linker -> Input, adicionar as dependencias em “Additional Dependencies”,
      1. libmx.lib
      2. libmat.lib
      3. libeng.lib
  4. Ajustar SO.
    1. Vá em “Configurações Avançadas de Sistema” -> “Variáveis de Ambiente”, em Variáveis do sistema, encontre a variável PATH, e adicione:
      1. C:Program Files (x86)MATLABR2013aruntimewin32;
      2. C:Program Files (x86)MATLABR2013abin;
      3. C:Program Files (x86)MATLABR2013abinWIN32
    2. Aproveite e crie uma variável de usuário MATLABROOT apontando para:
      1.  C:Program Files (x86)MATLABR2013a

Arquivos exemplos da Engine API encontram-se dentro: C:Program Files (x86)MATLABR2013aexternexampleseng_mat

Para testar o ambiente utilizei o engdemo.cpp, copiado na integra aqui:
Seguindo, no openFrameworks, no arquibo ofApp.h, inclua os cabeçalhos, engine.h e matrix.h e faça a instancia do apontamento para a Engine, o trecho de código do cabeçalho segue abaixo

#pragma once

#include "engine.h"
#include "matrix.h"
#include "ofMain.h"
#define  BUFSIZE 256

class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();

void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);

Engine* pEng;
};

No arquivo ofApp.cpp, para este teste, copie o trecho do exemplo dado pelo MatLab dentro do ofApp::setup();

//--------------------------------------------------------------
void ofApp::setup(){

Engine *ep;
mxArray *T = NULL, *result = NULL;
char buffer[BUFSIZE+1];
double time[10] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 };

cout&lt;
/*
* Call engOpen with a NULL string. This starts a MATLAB process
* on the current host using the command "matlab".
*/
if (!(ep = engOpen(""))) {
fprintf(stderr, "nCan't start MATLAB enginen");
exit();
}

cout&lt;    /*
* PART I
*
* For the first half of this demonstration, we will send data
* to MATLAB, analyze the data, and plot the result.
*/

/*
* Create a variable for our data
*/
T = mxCreateDoubleMatrix(1, 10, mxREAL);
memcpy((void *)mxGetPr(T), (void *)time, sizeof(time));
/*
* Place the variable T into the MATLAB workspace
*/
engPutVariable(ep, "T", T);

/*
* Evaluate a function of time, distance = (1/2)g.*t.^2
* (g is the acceleration due to gravity)
*/
engEvalString(ep, "D = .5.*(-9.8).*T.^2;");

/*
* Plot the result
*/
engEvalString(ep, "plot(T,D);");
engEvalString(ep, "title('Position vs. Time for a falling object');");
engEvalString(ep, "xlabel('Time (seconds)');");
engEvalString(ep, "ylabel('Position (meters)');");

/*
* use fgetc() to make sure that we pause long enough to be
* able to see the plot
*/
printf("Hit return to continuenn");
fgetc(stdin);
/*
* We're done for Part I! Free memory, close MATLAB figure.
*/
printf("Done for Part I.n");
mxDestroyArray(T);
//engEvalString(ep, "close;");

/*
* PART II
*
* For the second half of this demonstration, we will request
* a MATLAB string, which should define a variable X.  MATLAB
* will evaluate the string and create the variable.  We
* will then recover the variable, and determine its type.
*/

/*
* Use engOutputBuffer to capture MATLAB output, so we can
* echo it back.  Ensure first that the buffer is always NULL
* terminated.
*/

buffer[BUFSIZE] = '';
engOutputBuffer(ep, buffer, BUFSIZE);
while (result == NULL) {
char str[BUFSIZE+1];
/*
* Get a string input from the user
*/
printf("Enter a MATLAB command to evaluate.  This command shouldn");
printf("create a variable X.  This program will then determinen");
printf("what kind of variable you created.n");
printf("For example: X = 1:5n");
printf("&gt;&gt; ");

fgets(str, BUFSIZE, stdin);

/*
* Evaluate input with engEvalString
*/
engEvalString(ep, str);

/*
* Echo the output from the command.
*/
printf("%s", buffer);

/*
* Get result of computation
*/
printf("nRetrieving X...n");
if ((result = engGetVariable(ep,"X")) == NULL)
printf("Oops! You didn't create a variable X.nn");
else {
printf("X is class %stn", mxGetClassName(result));
}
}

/*
* We're done! Free memory, close MATLAB engine and exit.
*/
printf("Done!n");
mxDestroyArray(result);
engClose(ep);
}

Em tese tem que funcionar tudo. 🙂

openFrameworks help – ofEasyCam + ofPointPicker

Padrão

Pra tentar ajudar alguém:

Como fazer escolha de objetos em 3D, usando o openFrameworks. Unindo o exemplo pointPicker a múltiplos objetos

Primeiro criar os objetos.

class testApp : public ofBaseApp{

 public:
  void setup();
  void update();
  void draw();

  void keyPressed  (int key);
  void keyReleased(int key);
  void mouseMoved(int x, int y );
  void mouseDragged(int x, int y, int button);
  void mousePressed(int x, int y, int button);
  void mouseReleased(int x, int y, int button);
  void windowResized(int w, int h);
  void dragEvent(ofDragInfo dragInfo);
  void gotMessage(ofMessage msg);

  ofEasyCam cam;

  vector iPoints; 
  bool click;
  int box;
};

Depois configurar

#include "testApp.h"

void testApp::setup(){
 ofSeedRandom();
 for (int x = 0; x < 5; x++){
  ofPoint *p = new ofPoint;
  p->x = ofRandom(-100.0,+100.0);
  p->y = ofRandom(-100.0,+100.0);
  p->z = ofRandom(-100.0,+100.0);
  iPoints.push_back(p);
 }
}

e depois a função draw, com a busca do box mais próximo

void testApp::draw(){
 cam.begin();
  vector::iterator a;
  for( a = iPoints.begin(); a != iPoints.end(); a++){
   //ofTranslate(0,0,ofRandom(-100.0,+100.0));
   ofEnableAlphaBlending();
   ofFill();
   ofSetColor(ofColor::blue,127);
   ofBox(*(*a),30);
   ofDisableAlphaBlending();
  }
  ofDrawGrid(100);
 cam.end();

 int i = 0;
 float nearestDistance = 0;
 ofVec2f nearestVertex;
 int nearestIndex;
 ofVec2f mouse(mouseX, mouseY);
 for( a = iPoints.begin(); a != iPoints.end(); a++) {
  ofVec3f boxPos;
  boxPos.x = (*a)->x;boxPos.y = (*a)->y;boxPos.z = (*a)->z;
  ofVec3f cur = cam.worldToScreen(boxPos);
  float distance = cur.distance(mouse);
  if( i==0 || distance < nearestDistance) {
   nearestDistance = distance;
   nearestVertex = cur;
   nearestIndex = i;
  }
  i++;
 }
 
 ofSetColor(ofColor::gray);
 ofLine(nearestVertex, mouse);
 
 ofNoFill();
 ofSetColor(ofColor::yellow);
 ofSetLineWidth(2);
 ofCircle(nearestVertex, 4);
 ofSetLineWidth(1);
 
 ofVec2f offset(10, -10);
 ofDrawBitmapStringHighlight(ofToString(nearestIndex), mouse + offset);
}

Como é a glRotatef por dentro… rs

Padrão

Ideia:

[m]
A=matrix{4}{3}{
x^2*(1-c)+c x*y*(1-c)-z*sx*z*(1-c)+y*s 0 y*x*(1-c)+z*s y^2*(1-c)+c y*z*(1-c)-x*s 0 x*z*(1-c)-y*s y*z*(1-c)+x*s z^2*(1-c)+c 0 0 0 0 1}
[/m]

[x, y, z] - a vector about which the rotation should be done
c - cos(alpha)

s - sin(alpha)

alpha - rotation angle

Solução:

function CreateGlRotateMatrix(angle, x, y, z: single) : TMatrix;
var
axis: TVector3f;
b, c, ac, s: single;
invLen : Single;
begin

angle:= vectorgeometry.degtorad(angle);

invLen:= RSqrt(x * x + y * y + z * z);
x:= x * invLen;
y:= y * invLen;
z:= z * invLen;

result:= IdentityHmgMatrix;

c:= cos(angle);
s:= sin(angle);

result[0,0] := (x*x) * (1-c)+c;
result[1,0] := x*y * (1-c)-z*s;
result[2,0] := x*z * (1-c)+y*s;

result[0,1] := y*x * (1-c)+z*s;
result[1,1] := (y*y) * (1-c)+c;
result[2,1] := y*z * (1-c)-x*s;

result[0,2] := x*z * (1-c)-y*s;
result[1,2] := y*z * (1-c)+x*s;
result[2,2] := (z*z) * (1-c)+c;
end;

Retirado de: link

Usando Modelos MD2

Padrão

Dicas dicas


MD2 é um formato de modelos 3D utilizado na engine do Quake 2. Os principais motivos para sua utilização são a simplicidade do formato e a gratuidade do mesmo.


Para compilar o loader de modelos MD2 deste site : http://tfc.duke.free.fr/old/models/md2.htm .


No Visual Studio C++ 2010 Express.


São necessárias algumas configurações:


No Solution Explorer -&gt; C/C++ -&gt; Preprocessor -&gt; Preprocessor Definitions adicione GLUT_BUILDING_LIB .


No Solution Explorer -&gt; Linker -&gt; Input -&gt; Additional Dependences adicione opengl32.lib, glu32.lib e glut32.lib


E por fim no Solution Explorer -&gt; Linker -&gt; System -&gt; Sybsystem colocar Console(/Subsystem:CONSOLE)