``````
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// Copyright 2007, Daniel Fontijne, University of Amsterdam -- fontijne@science.uva.nl

#ifdef WIN32
#include <windows.h>
#endif

#include <GL/gl.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>

#include <vector>
#include <set>
#include <string>
#include <utility>

#include <libgasandbox/common.h>
#include <libgasandbox/c2ga.h>
#include <libgasandbox/c2ga_draw.h>
#include <libgasandbox/c2ga_util.h>
#include <libgasandbox/gl_util.h>
#include <libgasandbox/glut_util.h>

using namespace c2ga;
using namespace mv_draw;

const char *WINDOW_TITLE = "Geometric Algebra, Chapter 15, Example 2: Affine Combinations of Points";

// GLUT state information
int g_viewportWidth = 800;
int g_viewportHeight = 600;

// what point to drag (or -1 for none)
int g_dragPoint = -1;

// mouse position on last call to MouseButton() / MouseMotion()
c2ga::vectorE2GA g_prevMousePos;

const int NB_POINTS = 2;
normalizedPoint g_points[NB_POINTS] = {
c2gaPoint(350, 300),
c2gaPoint(450, 300)
};

void display() {
doIntelWarning(); // warn for possible problems with pciking on Intel graphics chipsets

glViewport(0, 0, g_viewportWidth, g_viewportHeight);
glMatrixMode(GL_PROJECTION);
glOrtho(0, g_viewportWidth, 0, g_viewportHeight, -100.0, 100.0);
glMatrixMode(GL_MODELVIEW);

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_LIGHTING);

glMatrixMode(GL_MODELVIEW);
glPushMatrix();

glLineWidth(1.0f);

g_drawState.m_pointSize = 4.0f;
// draw the points:
for (unsigned int i = 0; i < NB_POINTS; i++) {
if (i == 0) glColor3f(1.0f, 0.0f, 0.0f);
else glColor3f(0.0f, 0.0f, 1.0f);
draw(g_points[i]);
}

if (!GLpick::g_pickActive) {
// draw line between the two points:
g_drawState.pushDrawModeOff(OD_ORIENTATION);
g_drawState.m_lineLength = 1000.0f;
glColor3f(0.0f, 1.0f, 0.0f);
draw( g_points[0] - g_points[1]);
g_drawState.popDrawMode();

glLineStipple(1, 0x0F0F);
// draw the circles:
const mv::Float STEP = 0.1f;
for (mv::Float lambda = -1.0f; lambda <= 2.0f; lambda += STEP) {
// set color, stipples:
if ((lambda < 1.0f) && (lambda > 0.0f)) {
// draw imaginary circles stippled
glEnable(GL_LINE_STIPPLE);
glColor3f(1.0f, 0.0f, 1.0f);
}
else {
if (lambda > 1.0f) glColor3f(1.0f, 0.0f, 0.0f);
else glColor3f(0.0f, 0.0f, 1.0f);

glDisable(GL_LINE_STIPPLE);
}

// draw the circle:
draw(lambda * g_points[0] + (1.0f - lambda) * g_points[1]);
}
glDisable(GL_LINE_STIPPLE);
}

glPopMatrix();

if (!GLpick::g_pickActive) {
glColor3f(0.0, 0.0, 0.0);
void *font = GLUT_BITMAP_HELVETICA_12;
renderBitmapString(20, 60, font, "Use the mouse buttons to drag the blue and red points.");
renderBitmapString(20, 40, font, "The circles are the affine combinations (sums) of the two points.");
renderBitmapString(20, 20, font, "The green line is the difference of the two points (pt1 - pt2).");
}

if (!GLpick::g_pickActive) {
glutSwapBuffers();
}
}

void reshape(GLint width, GLint height) {
g_viewportWidth = width;
g_viewportHeight = height;

}

c2ga::vectorE2GA mousePosToVector(int x, int y) {
x -= g_viewportWidth / 2;
y -= g_viewportHeight / 2;
return _vectorE2GA((float)x * e1 - (float)y * e2);
}

void MouseButton(int button, int state, int x, int y) {
g_dragPoint = pick(x, g_viewportHeight - y, display, NULL); // NULL = pointer to distance

g_prevMousePos = mousePosToVector(x, y);

// redraw viewport
glutPostRedisplay();
}

void MouseMotion(int x, int y) {
// get mouse position, motion
c2ga::vectorE2GA mousePos = mousePosToVector(x, y);
c2ga::vectorE2GA motion = _vectorE2GA(mousePos - g_prevMousePos);

if (g_dragPoint >= 0) {
// translate point
normalizedTranslator T = _normalizedTranslator(1.0f - (0.5f * motion ^ ni));
g_points[g_dragPoint] = _normalizedPoint(T * g_points[g_dragPoint] * inverse(T));
}

// remember mouse pos for next motion:
g_prevMousePos = mousePos;

// redraw viewport
glutPostRedisplay();
}

int main(int argc, char*argv[]) {
// profiling for Gaigen 2:
c2ga::g2Profiling::init();

// GLUT Window Initialization:
glutInit (&argc, argv);
glutInitWindowSize(g_viewportWidth, g_viewportHeight);
glutInitDisplayMode( GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow(WINDOW_TITLE);

// Register callbacks:
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(MouseButton);
glutMotionFunc(MouseMotion);

glutMainLoop();

return 0;
}

``````