// Copyright (C) 2008 Steven Katic
#pragma once
using namespace System;
using namespace System::Windows::Forms;
using namespace FileViewerTypes;
// something small to avoid division overflow but the granularity is to small to be detected in the OpenGL modelview matrix elements
//#define EPSILON 1.0e-8
#define EPSILON 2.5e-8 // something still very small to avoid division overflow but now also big enough to detect OpenGL modelview matrix elements
#define ZERO EPSILON
//===========================================================================================
// Plane defined by a point and a normal
// The normal and point are expressed in non-opengl 3D cartesian co-ordinates.
// where the Z axis in vertical. In OpenGL the Y axis is vertical.
//===========================================================================================
public ref class Plane
{
public:
Vector3^ Normal;
Vector3^ Position;
DWORD axesAlignment;
Plane(void)
{
Normal = Vector3::Zero();
Position = Vector3::Zero();
}
Plane(Vector3^ norm,Vector3^ pos, DWORD axes)
{
Normal = gcnew Vector3(norm->X,norm->Y,norm->Z);
Position = gcnew Vector3(pos->X,pos->Y,pos->Z);
AxesAlignment = axes;
}
void DrawNormal()
{
glDisable(GL_LIGHTING);
glEnable(GL_LINE_SMOOTH);
glDisable( GL_TEXTURE_2D );
glLineWidth(2.0);
glBegin(GL_LINES);
glColor3f(1.0f,1.0f,0.0f);
glVertex3f(Position->X,Position->Z,Position->Y);
glVertex3f(Normal->X*10+Position->X,Normal->Z*10+Position->Z,Normal->Y*10+Position->Y);
glEnd();
glEnable(GL_LIGHTING);
glDisable(GL_LINE_SMOOTH);
glEnable( GL_TEXTURE_2D );
}
void Draw()
{
glDisable(GL_LIGHTING);
glEnable(GL_LINE_SMOOTH);
glDisable( GL_TEXTURE_2D );
glEnable(GL_COLOR_MATERIAL);
glLineWidth(1.0);
//glColor3f(1.0f,0.0f,0.0f);
float size = 5.0f;
// xy plane default
float x = Position->X;
float y = Position->Z;
float z = Position->Y;
glPushMatrix();
if(axesAlignment == XYTRANS)
{
x = Position->X;
y = Position->Z;
z = Position->Y;
}
else if(axesAlignment == ZXTRANS)
{
glRotatef(90.0f,1.0f,0.0f,0.0f);
x = Position->X;
y = Position->Y;
z = -Position->Z;
}
else if(axesAlignment == YZTRANS)
{
glRotatef(-90.0f,0.0f,0.0f,1.0f);
x = -Position->Z;
y = Position->X;
z = Position->Y;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f,0.0f,1.0f,0.2f);
glBegin(GL_QUADS);
glVertex3f(x-size,y,z-size);
glVertex3f(x-size,y,z+size);
glVertex3f(x+size,y,z+size);
glVertex3f(x+size,y,z-size);
glEnd();
glDisable(GL_BLEND);
glColor3f(1.0f,0.0f,0.0f);
glBegin(GL_LINES);
glVertex3f(x-size,y,z-size);
glVertex3f(x-size,y,z+size);
glVertex3f(x+size,y,z-size);
glVertex3f(x+size,y,z+size);
glVertex3f(x-size,y,z-size);
glVertex3f(x+size,y,z-size);
glVertex3f(x-size,y,z+size);
glVertex3f(x+size,y,z+size);
glEnd();
glPopMatrix();
glEnable(GL_LIGHTING);
glDisable(GL_LINE_SMOOTH);
glEnable( GL_TEXTURE_2D );
}
property DWORD AxesAlignment
{
void set(DWORD value)
{
axesAlignment = value;
}
DWORD get(){ return axesAlignment; }
}
};
//===========================================================================================
// Ray defined by 2 points (can we call it a segment?)
//
// The 2 points p0 and p1 are expressed in non-opengl cartesian co-ordinates.
// where the Z axis in vertical. In opengl the screen and the Y axis is vertical.
//===========================================================================================
public ref class Ray
{
public:
Vector3^ p0;
Vector3^ p1;
Ray(void)
{
p0 = Vector3::Zero();
p1 = Vector3::Zero();
}
Ray(Vector3^ P0,Vector3^ P1)
{
p0 = Vector3::Zero();
p1 = Vector3::Zero();
p0->X = P0->X;
p0->Y = P0->Y;
p0->Z = P0->Z;
p1->X = P1->X;
p1->Y = P1->Y;
p1->Z = P1->Z;
}
Ray(int x2D, int y2D)
{
p0 = Vector3::Zero();
p1 = Vector3::Zero();
Generate3DRay(x2D, y2D);
}
void Generate3DRay(int x2D, int y2D)
{
if(p0 == nullptr)
p0 = Vector3::Zero();
if(p1 == nullptr)
p1 = Vector3::Zero();
int x =x2D;
int y =y2D;
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLdouble winX, winY;
GLdouble winZ0 = 0.0f; GLdouble winZ1 = 1.0f;
GLdouble posX0, posY0, posZ0;
GLdouble posX1, posY1, posZ1;
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
winX = (GLdouble)x;
winY = (GLdouble)viewport[3] - (GLdouble)y;
glReadBuffer( GL_BACK );
gluUnProject( winX, winY, winZ0, modelview, projection, viewport, &posX0, &posY0, &posZ0);
gluUnProject( winX, winY, winZ1, modelview, projection, viewport, &posX1, &posY1, &posZ1);
// flip opengl co-ordinates to flight simulator co-ordinates
p0->X = (float)posX0;
p0->Y = (float)posZ0;
p0->Z = (float)posY0;
//
p1->X = (float)posX1;
p1->Y = (float)posZ1;
p1->Z = (float)posY1;
}
//=======================================================
// Intersects(): intersect a segment and a plane
// Input: p = a plane
// Output: I = the intersection point (when it exists)
// Return: 0 = disjoint (no intersection)
// 1 = intersection in the unique point I
// 2 = the segment lies in the plane
//
// Adapted from:
// http://www.softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm#Line-Plane%20Intersection
//
// Preconditions:
//
// - the plane is in flight simulator co-ordinate system form, where the Z axis in vertical
// (whereas in OpenGL the Y axis is vertical ).
//
//=======================================================
int Intersects(Plane^ p, Vector3^ I)
{
Vector3^ intersectPoint;
Vector3^ u = p1 - p0;
Vector3^ w = p0 - p->Position;
float D = p->Normal->Dot(u);
float N = -p->Normal->Dot(w);
if (Math::Abs(D) < ZERO) // segment is parallel to plane
{
if (N == 0) // segment lies in plane
return 2;
else
return 0; // no intersection
}
float s = N / D;
if (s < 0 || s > 1)
return 0; // no intersection
intersectPoint = p0 + u*s; // compute segment intersect point
I->X = intersectPoint->X;
I->Y = intersectPoint->Y;
I->Z = intersectPoint->Z;
return 1;
}
};