ReactPhysics3D 의 광선 교차 테스트

ReactPhysics3D 의 광선 교차 테스트..

#include "reactphysics3d.h"

#include <iostream>
#include <stdexcept>
#include <vector>
#include <map>
#include <sstream>
#include <iomanip>
#include <memory>
#include <algorithm>
#include <set>
#include <string>
#include <fstream>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp> 
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/normal.hpp>


// https://github.com/DanielChappuis/reactphysics3d/blob/master/test/tests/collision/TestAABB.h
using namespace reactphysics3d;


class DynamicTreeRaycastCallback : public DynamicAABBTreeRaycastCallback {

    public:

        std::vector<int> mHitNodes;

        // Called when the AABB of a leaf node is hit by a ray
        virtual decimal raycastBroadPhaseShape(int32 nodeId, const Ray& ray) override {
			printf("--hit-- %d\n", nodeId);
            mHitNodes.push_back(nodeId);
            return 1.0;
        }

        void reset() {
            mHitNodes.clear();
        }

        bool isHit(int nodeId) const {
            return std::find(mHitNodes.begin(), mHitNodes.end(), nodeId) != mHitNodes.end();
        }
};


int main(void)
{
	DynamicTreeRaycastCallback mRaycastCallback;

	DynamicAABBTree tree(MemoryManager::getBaseAllocator());

	AABB aabb;

	std::vector<glm::vec3> vertices;

	int solverId = 1;
	vertices.push_back(glm::vec3(0, -2.5, 0));
	vertices.push_back(glm::vec3(-2.5, 2.5, 0));
	vertices.push_back(glm::vec3(2.5, 2.5, 0));
	aabb = AABB::createAABBForTriangle((Vector3*)&vertices[0]);
	int objectId = tree.addObject(aabb, &solverId);
	printf("%d\n", objectId);

	solverId = 2;
	glm::vec3 points2[] = {
		glm::vec3(0, -2.5, 2), glm::vec3(-2.5, 2.5, 2), glm::vec3(2.5, 2.5, 2)
	};
	aabb = AABB::createAABBForTriangle((Vector3*)points2);
	objectId = tree.addObject(aabb, &solverId);
	printf("%d\n", objectId);
	
	solverId = 3;
	vertices.clear();
	vertices.push_back(glm::vec3(0, -2.5, 4));
	vertices.push_back(glm::vec3(-2.5, 2.5, 4));
	vertices.push_back(glm::vec3(2.5, 2.5, 4));
	aabb = AABB::createAABBForTriangle((Vector3*)&vertices[0]);
	objectId = tree.addObject(aabb, &solverId);
	printf("%d\n", objectId);


	printf("Press any key to ray hit test..\n"); fflush(stdout);
	getchar();

	Ray ray(Vector3(0, 0, 10), Vector3(0, 0, -10));

	// hit test 
	printf("Hit test..\n");
	mRaycastCallback.reset();
	tree.raycast(ray, mRaycastCallback);

	// hit test after remove
	printf("Hit test after remove..\n");
	tree.removeObject(1);
	mRaycastCallback.reset();
	tree.raycast(ray, mRaycastCallback);

#if 0
	printf("%f\n", tree.getMin().x);
	printf("%f\n", tree.getMin().y);
	printf("%f\n", tree.getMin().z);
	printf("%f\n", tree.getMax().x);
	printf("%f\n", tree.getMax().y);
	printf("%f\n", tree.getMax().z);
#endif

#if 0
	printf("%d\n", aabb.testRayIntersect(ray));
#endif

	return 0;
}

determining if a point is inside a polyhedron

#include <vector>
#include <cassert>
#include <iostream>
#include <cmath>

struct Vector {
  double x, y, z;

  Vector operator-(Vector p) const {
    return Vector{x - p.x, y - p.y, z - p.z};
  }

  Vector cross(Vector p) const {
    return Vector{
      y * p.z - p.y * z,
      z * p.x - p.z * x,
      x * p.y - p.x * y
    };
  }

  double dot(Vector p) const {
    return x * p.x + y * p.y + z * p.z;
  }

  double norm() const {
    return std::sqrt(x*x + y*y + z*z);
  }
};

using Point = Vector;

struct Face {
  std::vector<Point> v;

  Vector normal() const {
    assert(v.size() > 2);
    Vector dir1 = v[1] - v[0];
    Vector dir2 = v[2] - v[0];
    Vector n  = dir1.cross(dir2);
    double d = n.norm();
    return Vector{n.x / d, n.y / d, n.z / d};
  }
};

bool isInConvexPoly(Point const& p, std::vector<Face> const& fs) {
  for (Face const& f : fs) {
    Vector p2f = f.v[0] - p;         // f.v[0] is an arbitrary point on f
    double d = p2f.dot(f.normal());
    d /= p2f.norm();                 // for numeric stability

    constexpr double bound = -1e-15; // use 1e15 to exclude boundaries
    if (d < bound)
      return false;
  }

  return true;
}

int main(int argc, char* argv[]) {
  Point p;
  p.x = 0.5;
  p.y = 0.5;
  p.z = 0.5;
  /*
  p.x = 2;
  p.y = 2;
  p.z = 2;
  */

  std::vector<Face> cube{ // faces with 4 points, last point is ignored
    Face{{Point{0,0,0}, Point{1,0,0}, Point{1,0,1}, Point{0,0,1}}}, // front
    Face{{Point{0,1,0}, Point{0,1,1}, Point{1,1,1}, Point{1,1,0}}}, // back
    Face{{Point{0,0,0}, Point{0,0,1}, Point{0,1,1}, Point{0,1,0}}}, // left
    Face{{Point{1,0,0}, Point{1,1,0}, Point{1,1,1}, Point{1,0,1}}}, // right
    Face{{Point{0,0,1}, Point{1,0,1}, Point{1,1,1}, Point{0,1,1}}}, // top
    Face{{Point{0,0,0}, Point{0,1,0}, Point{1,1,0}, Point{1,0,0}}}, // bottom
  };

  std::cout << (isInConvexPoly(p, cube) ? "inside" : "outside") << std::endl;

  return 0;
}

msys2 – gcc/g++ 업데이트 및 설치

msys2 를 처음 설치하고 아래와 같이 기본 gcc/g++ 컴파일러와 필요한 유용한 라이브러리들을 설치한다.

pacman -Syu

pacman -S base-devel
pacman -S gcc
pacman -S development
pacman -S compression

pacman -S mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain

pacman -Sy git
pacman -Sy cmake

아래와 같이 설치된 컴파일러를 확인한다.

$ pacman -Ss gcc
mingw32/mingw-w64-i686-gcc 9.1.0-3 (mingw-w64-i686-toolchain)
GNU Compiler Collection (C,C++,OpenMP) for MinGW-w64
mingw32/mingw-w64-i686-gcc-ada 9.1.0-3 (mingw-w64-i686-toolchain)
GNU Compiler Collection (Ada) for MinGW-w64
...
mingw64/mingw-w64-x86_64-gcc 9.1.0-3 (mingw-w64-x86_64-toolchain) [설치함]
GNU Compiler Collection (C,C++,OpenMP) for MinGW-w64
mingw64/mingw-w64-x86_64-gcc-ada 9.1.0-3 (mingw-w64-x86_64-toolchain) [설치함]
GNU Compiler Collection (Ada) for MinGW-w64
...
msys/mingw-w64-cross-gcc 9.1.0-1 (mingw-w64-cross-toolchain mingw-w64-cross)
Cross GCC for the MinGW-w64

내가 자주사용하는 개발 패키지들도 설치한다.

pacman -Sy mingw-w64-i686-fontconfig mingw-w64-x86_64-fontconfig
pacman -Sy mingw-w64-i686-freeimage mingw-w64-x86_64-freeimage
pacman -Sy mingw-w64-i686-gl2ps mingw-w64-x86_64-gl2ps
pacman -Sy mingw-w64-i686-freetype mingw-w64-x86_64-freetype
pacman -Sy mingw-w64-i686-libpng mingw-w64-x86_64-libpng
pacman -Sy mingw-w64-i686-libtiff mingw-w64-x86_64-libtiff

pacman -Sy mingw-w64-i686-tcl mingw-w64-x86_64-tcl
pacman -Sy mingw-w64-i686-tk mingw-w64-x86_64-tk
pacman -Sy mingw-w64-i686-python2 mingw-w64-x86_64-python2
pacman -Sy mingw-w64-i686-python3 mingw-w64-x86_64-python3

pacman -Sy mingw-w64-i686-qt-creator mingw-w64-x86_64-qt-creator
pacman -Sy mingw-w64-i686-qtbinpatcher mingw-w64-x86_64-qtbinpatcher
# dynamic 버전이 필요하면 아래를 설치..
pacman -Sy mingw-w64-i686-qt5 mingw-w64-x86_64-qt5
# static 버전이 필요하면 아래를 설치..
pacman -Sy mingw-w64-i686-qt5-static mingw-w64-x86_64-qt5-static

pacman -Sy mingw-w64-i686-mpfr mingw-w64-x86_64-mpfr
pacman -Sy mingw-w64-i686-gmp mingw-w64-x86_64-gmp

pacman -Sy mingw-w64-i686-SDL2 mingw-w64-x86_64-SDL2
pacman -Sy mingw-w64-i686-allegro mingw-w64-x86_64-allegro

pacman -Sy mingw-w64-i686-boost mingw-w64-x86_64-boost
pacman -Sy mingw-w64-i686-cgal mingw-w64-x86_64-cgal
pacman -Sy mingw-w64-i686-freeglut mingw-w64-x86_64-freeglut
pacman -Sy mingw-w64-i686-glm mingw-w64-x86_64-glm
pacman -Sy mingw-w64-i686-glfw mingw-w64-x86_64-glfw
pacman -Sy mingw-w64-i686-oce mingw-w64-x86_64-oce
pacman -Sy mingw-w64-i686-glew mingw-w64-x86_64-glew

pacman -Sy mingw-w64-i686-ffmpeg mingw-w64-x86_64-ffmpeg

pacman -Sy mingw-w64-i686-zlib mingw-w64-x86_64-zlib
pacman -Sy mingw-w64-i686-readline mingw-w64-x86_64-readline
pacman -Sy mingw-w64-i686-pdcurses mingw-w64-x86_64-pdcurses

pacman -Sy mingw-w64-i686-libmariadbclient mingw-w64-x86_64-libmariadbclient

참고로 저장소에서 제공하는 패키지는 무엇이 잇는지는 아래의 싸이트에서 검색..
https://packages.msys2.org/search?t=binpkg

만약 옛 버전을 설치 해야 하는 경우는 pacman 은 버전을 지정하여 설치를 할 수 없다.
아래의 페이지에서 옛 버전을 받아서..
http://repo.msys2.org/mingw/x86_64/
다음과 같이 설치한다.

pacman -U mingw-w64-x86_64-qt5-5.10.0-1-any.pkg.tar.xz

이미 상위 버전이 설치되어 있는 경우 자동으로 다운그레이드를 함.. 굿!!

참고로 설치된 패키지의 정보들은 아래의 폴더에 위치해있음.

/var/lib/pacman/local

또.. 다운 받아진 원본 패키지들은 아래에 있음.

/var/cache/pacman/pkg

msys2 개발 환경으로 인해서 개발이 편해지고 개발 비용도 줄일수있긴하지만..
편해진 만큼 개발자들이 게을러지지 않을까.. 생각이든다. -_-;;

get keyboard inputs without blocking

블럭킹없이 키보드 입력 받는 코드..

#include <ros/ros.h>
#include <termios.h>

char getch()
{
	fd_set set;
	struct timeval timeout;
	int rv;
	char buff = 0;
	int len = 1;
	int filedesc = 0;
	FD_ZERO(&set);
	FD_SET(filedesc, &set);
	
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000;

	rv = select(filedesc + 1, &set, NULL, NULL, &timeout);

	struct termios old = {0};
	if (tcgetattr(filedesc, &old) < 0)
		ROS_ERROR("tcsetattr()");
	old.c_lflag &= ~ICANON;
	old.c_lflag &= ~ECHO;
	old.c_cc[VMIN] = 1;
	old.c_cc[VTIME] = 0;
	if (tcsetattr(filedesc, TCSANOW, &old) < 0)
		ROS_ERROR("tcsetattr ICANON");

	if(rv == -1)
		ROS_ERROR("select");
	else if(rv == 0)
		ROS_INFO("no_key_pressed");
	else
		read(filedesc, &buff, len );

	old.c_lflag |= ICANON;
	old.c_lflag |= ECHO;
	if (tcsetattr(filedesc, TCSADRAIN, &old) < 0)
		ROS_ERROR ("tcsetattr ~ICANON");
	return (buff);
}


int main(int argc, char **argv)
{
	ros::init(argc, argv, "key_input_node");
	ros::NodeHandle n;

	ros::Rate loop_rate(10);
	while (ros::ok())
	{
		int c = 0;
		c=getch();
		ROS_INFO("%c", c);

		ros::spinOnce();

		loop_rate.sleep();
	}

	return 0;
}

컴퓨터 랜드 ‘내가 만들었어요’

중학교 시절부터 시작한 프로그래밍..
아주 예전에 학생과학 월간잡지의 별책 부록인
컴퓨터 랜드에 ‘내가 만들었어요’ 라는 코너가 있었다.
이 코너는 당시 주류 언어였던 GW-BASIC이나 Q-BASIC으로 만든 프로그램을
선별하여 싥어주는 코너 였다.
이 코너에 싥린 코드중 선별하여 책으로 묶어 나왔었다.

computer_land

여기에 내가 만든 코드도 싥렸었다.

2

calendar.pdf

예전에 이 책이 있었던것 같은데.. 지금은 어딜 갔는지…

XMODEM, YMODEM, ZMODEM 프로토콜을 이용한 파일 전송 윈도우즈 프로그램

출처: http://www.extraputty.com/features/zmodem.html

sz_tz_zmodem.zip

1990년대 PC통신에 접속해서 파일 업/다운로드 시에 사용된 프로토콜인
XMODEM, YMODEM, ZMODEM 이용한 파일 송/수신 윈도우즈용 프로그램.

C:\Users\user>C:\Temp\rz.exe -help
C:\Temp\rz.exe version
Usage: C:\Temp\rz.exe [options] [filename.if.xmodem]
Receive files with ZMODEM/YMODEM/XMODEM protocol
    (X) = option applies to XMODEM only
    (Y) = option applies to YMODEM only
    (Z) = option applies to ZMODEM only
  -+, --append                append to existing files
  -a, --ascii                 ASCII transfer (change CR/LF to LF)
  -b, --binary                binary transfer
  -B, --bufsize N             buffer N bytes (N==auto: buffer whole file)
  -c, --with-crc              Use 16 bit CRC (X)
  -C, --allow-remote-commands allow execution of remote commands (Z)
  -D, --null                  write all received data to /dev/null
      --delay-startup N       sleep N seconds before doing anything
  -e, --escape                Escape control characters (Z)
  -E, --rename                rename any files already existing
      --errors N              generate CRC error every N bytes (debugging)
  -h, --help                  Help, print this usage message
  -m, --min-bps N             stop transmission if BPS below N
  -M, --min-bps-time N          for at least N seconds (default: 120)
  -O, --disable-timeouts      disable timeout code, wait forever for data
      --o-sync                open output file(s) in synchronous write mode
  -p, --protect               protect existing files
  -q, --quiet                 quiet, no progress reports
  -r, --resume                try to resume interrupted file transfer (Z)
  -R, --restricted            restricted, more secure mode
  -s, --stop-at {HH:MM|+N}    stop transmission at HH:MM or in N seconds
  -S, --timesync              request remote time (twice: set local time)
      --syslog[=off]          turn syslog on or off, if possible
  -t, --timeout N             set timeout to N tenths of a second
  -u, --keep-uppercase        keep upper case filenames
  -U, --unrestrict            disable restricted mode (if allowed to)
  -v, --verbose               be verbose, provide debugging information
  -w, --windowsize N          Window is N bytes (Z)
  -X  --xmodem                use XMODEM protocol
  -y, --overwrite             Yes, clobber existing file if any
      --ymodem                use YMODEM protocol
  -Z, --zmodem                use ZMODEM protocol

리눅스 드라이버의 물리주소와 가상 주소

출처: http://chammoru.egloos.com/v/4168312

다른 프로세스의 메모리 공간 접근
프로세스가 시스템 호출을 통해 커널 모드로 진입하면 프로세스 메모리 공간은 커널의 메모리 공간으로 바뀐다. 커널 모드 상태의 프로세스는 수퍼바이저 권한을 갖기 때문에 시스템 내의 모든 메모리 공간에 접근할 수 있다. 그래서 이 경우에는 다른 프로세스의 메모리 공간에 접근할 수 있는데, 이때 직접 접근은 안 되고, VM에서 제공하는 특정 함수를 통해 접근할 수 있다.

리눅스 메모리 관리
. PGD (Page Directory) : pgt_t
. PMD (Page Mid level Directory) : pmd_t
. PTE (Page Table Entry) : pte_t
* 참고 : PMD는 대부분의 리눅스 시스템에 형식적으로만 존재.

물리 주소 공간을 커널 주소 공간으로 매핑
Memory Mapped I/O 방식의 물리적 주소 공간을 커널에서 사용 가능한 가상 주소로 매핑하거나 해제할 때는 다음과 같은 함수 사용한다.

// 아래 두 함수가 성공적으로 mapping되면 가상 주소의 선두 주소가 반환
void * ioremap(unsigned long offset, unsigned long size); // offset이 물리주소, size는 PAGE_SIZE의 배수
void * ioremap_nocache(unsigned long offset, unsigned long size); // offset이 물리주소, size는 PAGE_SIZE의 배수
void iounmap(void * addr); // addr은 가상주소

I/O 물리 주소와 가상 주소간의 변환 함수
리눅스 커널은 부팅 단계에서 시스템을 제어하기 위해 사용하는 시스템의 모든 I/O 제어 물리 주소나 램 영역의 물리 주소를 MMU 테이블로 미리 작성한다. 이렇게 부팅 단계에서 고정되어 할당된 메모리 주소 영역을 예약 영역(reserved area)이라고 한다. 예약된 물리 주소 영역은 PAGE_OFFSET 매크로 상수값을 이용해 물리 주소와 가상 주소간에 변환을 한다. 상수 연산만으로 물리 주소를 가상 주소로 만들기 위해 사용하는 상수와 매크로는 #include 에 정의된다.

부팅 시 예약된 주소 공간 이외에 ioremap(), kmalloc() 함수에서 반환하는 가상 주소도 PAGE_OFFSET을 이용해 물리 주소와 가상 주소로 변한된다. 이 매크로 상수를 이용하여 주소 변환을 하는 함수들은 다음과 같다.

unsigned long virt_to_phys(volatile void * address);
void * phys_to_virt(unsigned long address);
unsigned long virt_to_bus(volatile void * address);
void * bus_to_virt(unsigned long address);

virt_to_phys(), phys_to_virt()
virt_to_phys() 함수는 가상 주소를 물리 주소로 바꾸고, phys_to_virt() 함수는 물리 주소를 가상 주소로 바꾼다. 그러나 phys_to_virt() 함수는 ioremap()함수와 같은 기능을 수행하지 않는다. ioremap()함수는 요구된 물리 주소로 시작하는 영역을 커널 모드에서 사용할 수 있도록 가상 주소 공간으로 등록하지만, phys_to_virt()함수는 PAGE_OFFSET과 같은 값을 이용하여 변환 처리만 하기 때문이다. 그래서 virt_to_phys()와 phys_to_virt()함수는 커널에서 사용할 수 있도록 등록된 가상 주소와 물리 주소에 대해 사용해야 한다.

virt_to_phys(), phys_to_virt()
virt_to_phys()와 virt_to_bus() 함수는 대부분의 커널이 동작하는 시스템에 대해 동일한 기능을 수행한다. phys_to_virt()와 bus_to_virt()함수 역시 같은 기능을 수행한다. 그러나 시스템에 따라 두 함수를 구별하여 사용하는 경우는 극히 드물지만 존재한다. 그래서 리눅스에서는 이 두 종류의 함수를 구별하여 사용해야 한다. DMA와 관련된 루틴에서는 virt_to_bus()와 bus_to_virt()함수를 사용하기를 권장하고, 램이나 비디오와 같은 메모리 관련 주소 공간에는 virt_to_phys()와 phys_to_virt() 함수를 사용하기를 권장한다. 가급적 이 규칙을 지켜야 여러 시스템과 호환되는 디바이스 드라이버로 포팅할 수 있다.