HW4 Solutions
Page
Return to homework
page.
In the interest of getting up solutions in a timely fashion and since I had
a cold for a couple weeks, I am using student solutions for HW4 and HW5.
Below is the homework the grader thought was the best:
/*************************************************
Project: CS116A Homework #4
File: viewport.cpp
Purpose: to play with clipping window
Date: Nov, 17, 2004
Programmer: Gabriel Laden
**************************************************/
#include <stdlib.h>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <GL/glut.h>
using namespace std;
#define XSTATE 1
#define YSTATE 2
#define ZSTATE 3
#define LEFT 0
#define RIGHT 1
#define STRAIGHT 2
#define FORWARD 0
#define REVERSE 1
static int windowID1, windowID2;
static int state = ZSTATE;
static int xMax, yMax, zMax;
static int xMaxScreen, yMaxScreen;
static int theta;
static float xTrans, yTrans;
static int** list;
static GLint*** ptsWindow1;
static GLint*** ptsWindow2;
static GLint* rectangle;
static GLint* origRectangle;
/*************************************************/
void init1(void)
/*
PURPOSE: Initializes window1 with some OpenGL methods
*/
{
glutSetWindow(windowID1);
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//rotation accumulator
theta = 0;
//translation accumulator
xTrans = 0;
yTrans = 0;
//this is the red dashed rectangle
rectangle = (GLint*)malloc(sizeof(GLint)*8);
rectangle[0] = 0;
rectangle[1] = 0;
rectangle[2] = 0;
rectangle[7] = 0;
if(state == XSTATE){
xMaxScreen = yMax;
yMaxScreen = zMax;
glutReshapeWindow(yMax, zMax);
gluOrtho2D(0.0, yMax, 0.0, zMax);
rectangle[3] = zMax/2;
rectangle[4] = yMax/2;
rectangle[5] = zMax/2;
rectangle[6] = yMax/2;
}
if(state == YSTATE){
xMaxScreen = zMax;
yMaxScreen = xMax;
glutReshapeWindow(zMax, xMax);
gluOrtho2D(0.0, zMax, 0.0, xMax);
rectangle[3] = xMax/2;
rectangle[4] = zMax/2;
rectangle[5] = xMax/2;
rectangle[6] = zMax/2;
}
if(state == ZSTATE){
xMaxScreen = xMax;
yMaxScreen = yMax;
glutReshapeWindow(xMax, yMax);
gluOrtho2D(0.0, xMax, 0.0, yMax);
rectangle[3] = yMax/2;
rectangle[4] = xMax/2;
rectangle[5] = yMax/2;
rectangle[6] = xMax/2;
}
//save a copy of this original
origRectangle = (GLint*)malloc(sizeof(GLint)*8);
for(int i=0; i<8; i++){
origRectangle[i] = rectangle[i];
}
}
/*************************************************/
void init2(void)
//PURPOSE: Initializes window2 with some OpenGL methods
{
glutSetWindow(windowID2);
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(state == XSTATE){
gluOrtho2D(0.0, yMax/2, 0.0, zMax/2);
glutReshapeWindow(yMax/2, zMax/2);
}
if(state == YSTATE){
gluOrtho2D(0.0, zMax/2, 0.0, xMax/2);
glutReshapeWindow(zMax/2, xMax/2);
}
if(state == ZSTATE){
gluOrtho2D(0.0, xMax/2, 0.0, yMax/2);
glutReshapeWindow(xMax/2, yMax/2);
}
}
/*************************************************/
void drawview1(void)
/*
PURPOSE: draw the two windows with view of scene
*/
{
glutSetWindow(windowID1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 1.0);
int listLength = list[0][0];
ptsWindow1 = (int***)malloc(sizeof(int**)*listLength);
for(int i=0; i<listLength; i++){
int rowLength = list[i+1][0];
ptsWindow1[i] = (int**)malloc(sizeof(int*)*rowLength);
if(state == XSTATE){
//pick out the y-z coords
int index = 2;
for(int j=0; j<rowLength; j++, index+=3){
ptsWindow1[i][j] = (int*)malloc(sizeof(int)*2);
ptsWindow1[i][j][0] = list[i+1][index];
ptsWindow1[i][j][1] = list[i+1][index+1];
}
}
if(state == YSTATE){
//pick out the z-x coords
int index = 3;
for(int j=0; j<rowLength; j++, index+=3){
ptsWindow1[i][j] = (int*)malloc(sizeof(int)*2);
ptsWindow1[i][j][0] = list[i+1][index];
ptsWindow1[i][j][1] = list[i+1][index-2];
}
}
if(state == ZSTATE){
//pick out the x-y coords
int index = 1;
for(int j=0; j<rowLength; j++, index+=3){
ptsWindow1[i][j] = (int*)malloc(sizeof(int)*2);
ptsWindow1[i][j][0] = list[i+1][index];
ptsWindow1[i][j][1] = list[i+1][index+1];
}
}
}
//ok, now draw the lines in window1
for(int i=0; i<listLength; i++){
glBegin(GL_LINE_LOOP);
for(int j=0; j<list[i+1][0]; j++){
glVertex2iv(ptsWindow1[i][j]);
}
glEnd();
}
//draw the red rectangle box
glColor3f(1.0, 0.0, 0.0);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x00FF);
glBegin(GL_LINE_LOOP);
glVertex2i(rectangle[0],rectangle[1]);
glVertex2i(rectangle[2],rectangle[3]);
glVertex2i(rectangle[4],rectangle[5]);
glVertex2i(rectangle[6],rectangle[7]);
glEnd();
glDisable(GL_LINE_STIPPLE);
glFlush();
}
/*************************************************/
void drawview2(void)
//PURPOSE: draw the two windows with view of scene
{
glutSetWindow(windowID2);
glutPositionWindow(400, 400);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 1.0);
int listLength = list[0][0];
ptsWindow2 = (int***)malloc(sizeof(int**)*listLength);
for(int i=0; i<listLength; i++){
int rowLength = list[i+1][0];
ptsWindow2[i] = (int**)malloc(sizeof(int*)*rowLength);
if(state == XSTATE){
//pick out the y-z coords
int index = 2;
for(int j=0; j<rowLength; j++, index+=3){
ptsWindow2[i][j] = (int*)malloc(sizeof(int)*2);
ptsWindow2[i][j][0] = list[i+1][index];
ptsWindow2[i][j][1] = list[i+1][index+1];
}
}
if(state == YSTATE){
//pick out the z-x coords
int index = 3;
for(int j=0; j<rowLength; j++, index+=3){
ptsWindow2[i][j] = (int*)malloc(sizeof(int)*2);
ptsWindow2[i][j][0] = list[i+1][index];
ptsWindow2[i][j][1] = list[i+1][index-2];
}
}
if(state == ZSTATE){
//pick out the x-y coords
int index = 1;
for(int j=0; j<rowLength; j++, index+=3){
ptsWindow2[i][j] = (int*)malloc(sizeof(int)*2);
ptsWindow2[i][j][0] = list[i+1][index];
ptsWindow2[i][j][1] = list[i+1][index+1];
}
}
}
//reverse translate the points
//reverse rotate the points
float x, y;
float COSDEG = cos(-theta * 3.1415926536/180);
float SINDEG = sin(-theta * 3.1415926536/180);
for(int i=0; i<list[0][0]; i++){
glBegin(GL_LINE_LOOP);
for(int j=0; j<list[i+1][0]; j++){
x = ptsWindow2[i][j][0] - xTrans;
y = ptsWindow2[i][j][1] - yTrans;
glVertex2i(x*COSDEG - y*SINDEG, x*SINDEG + y*COSDEG);
}
glEnd();
}
glFlush();
}
/*-----------------------------------------------*/
bool rotate(int direction)
/*
PURPOSE: Rotates the rectangle, if possible
RECEIVES: direction - use LEFT or RIGHT
*/
{
/* translate first point back to origin
and translate other points by that amount
first point is fixed at origin,
rotate the other points +/-
translate points back
check to see if in bounds
*/
//save a copy of rectangle, if we have to restore
GLint* temp =(GLint*)malloc(sizeof(GLint)*8);
for(int i=0; i<8; i++){
temp[i] = rectangle[i];
}
int tempTheta = theta;
//rotate initial rectangle by accumulated theta
if(direction == LEFT){
theta++;
}
else if(direction == RIGHT){
theta--;
}
float x, y;
float COSDEG = cos(theta * 3.1415926536/180);
float SINDEG = sin(theta * 3.1415926536/180);
for(int i=2; i<8; i+=2){
x = origRectangle[i]*COSDEG - origRectangle[i+1]*SINDEG;
y = origRectangle[i]*SINDEG + origRectangle[i+1]*COSDEG;
rectangle[i] = x;
rectangle[i+1] = y;
}
//translate back
for(int i=2; i<8; i+=2){
rectangle[i] += xTrans;
rectangle[i+1] += yTrans;
}
//check if points still inbounds
bool fail = false;
for(int i=0; i<8 && !fail; i+=2){
if(rectangle[i] < 0 || rectangle[i] > xMaxScreen){
fail = true;
}
if(rectangle[i+1] < 0 || rectangle[i+1] > yMaxScreen){
fail = true;
}
}
if(fail){
//write back the temp array to the rectangle
for(int i=0; i<8; i++){
rectangle[i] = temp[i];
}
theta = tempTheta;
return false;
}
return true;
}
/*-----------------------------------------------*/
void move(int direction)
/*
PURPOSE: Moves the rectangle, if possible
RECEIVES: direction - use FORWARD or REVERSE
*/
{
//save a copy of rectangle, if we have to restore
GLint* temp =(GLint*)malloc(sizeof(GLint)*8);
for(int i=0; i<8; i++){
temp[i] = rectangle[i];
}
int tempXTrans = xTrans;
int tempYTrans = yTrans;
//points to use for slope
int x0 = rectangle[0];
int y0 = rectangle[1];
int xEnd = rectangle[2];
int yEnd = rectangle[3];
//handle special cases first
if(x0 == xEnd)
{
//vertical
if(direction == FORWARD){
if(yEnd > y0){
yTrans++;
}
else{
yTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
else if(direction == REVERSE){
if(yEnd < y0){
yTrans++;
}
else{
yTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
}
else if(y0 == yEnd)
{
//horizontal
if(direction == FORWARD){
if(xEnd > x0){
xTrans++;
}
else{
xTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
}
}
else if(direction == REVERSE){
if(xEnd < x0){
xTrans++;
}
else{
xTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
}
}
}
else
{
if((yEnd-y0)/(xEnd-x0) == 1){
//positive diagonal
if(direction == FORWARD){
if(yEnd > y0){
xTrans++;
yTrans++;
}
else{
xTrans--;
yTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
else if(direction == REVERSE){
if(yEnd < y0){
xTrans++;
yTrans++;
}
else{
xTrans--;
yTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
}
if((yEnd-y0)/(xEnd-x0) == -1){
//negative diagonal
if(direction == FORWARD){
if(yEnd > y0){
xTrans--;
yTrans++;
}
else{
xTrans++;
yTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
else if(direction == REVERSE){
if(yEnd < y0){
xTrans--;
yTrans++;
}
else{
xTrans++;
yTrans--;
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
}
//non special cases
float dy = yEnd - y0;
float dx = xEnd - x0;
float m = dy / dx;
if(m > 0 && m < 1){
if((dy > 0 && direction == FORWARD) || (dy < 0 && direction == REVERSE)){
xTrans++;
yTrans += m;
}
else{
xTrans--;
yTrans -= m;
}
}
else if(m > 1){
if((dy > 0 && direction == FORWARD) || (dy < 0 && direction == REVERSE)){
yTrans++;
xTrans += 1/m;
}
else{
yTrans--;
xTrans -= 1/m;
}
}
else if(m > -1 && m < 0){
if((dy < 0 && direction == FORWARD) || (dy > 0 && direction == REVERSE)){
xTrans++;
yTrans += m;
}
else{
xTrans--;
yTrans -= m;
}
}
else if (m < -1){
if((dy < 0 && direction == FORWARD) || (dy > 0 && direction == REVERSE)){
yTrans--;
xTrans -= 1/m;
}
else{
yTrans++;
xTrans += 1/m;
}
}
for(int i=0; i<8; i+=2){
rectangle[i] = origRectangle[i] + xTrans;
rectangle[i+1] = origRectangle[i+1] + yTrans;
}
}
bool fail = false;
//now rotate rectangle
if(!rotate(STRAIGHT)){
fail = true;
}
//test xy coords
for(int i=0; i<8 && !fail; i+=2){
if(rectangle[i] < 0 || rectangle[i] > xMaxScreen){
fail = true;
}
if(rectangle[i+1] < 0 || rectangle[i+1] > yMaxScreen){
fail = true;
}
if(xTrans < 0 || xTrans > xMaxScreen){
fail = true;
}
if(yTrans < 0 || yTrans > yMaxScreen){
fail = true;
}
}
if(fail){
//write back the temp array to the rectangle
for(int i=0; i<8; i++){
rectangle[i] = temp[i];
}
xTrans = tempXTrans;
yTrans = tempYTrans;
}
}
/*-----------------------------------------------*/
void keyHandleFn(int key, int x, int y)
/*
PURPOSE: Handles keyboard events. The keyboard was very useful in testing this project
RECEIVES: key - the special key (non a-z letter) pressed
*/
{
switch(key)
{
case GLUT_KEY_LEFT:
//rotate left
rotate(LEFT);
break;
case GLUT_KEY_RIGHT:
//rotate right
rotate(RIGHT);
break;
case GLUT_KEY_UP:
//forward
move(FORWARD);
break;
case GLUT_KEY_DOWN:
//reverse
move(REVERSE);
break;
}
glutPostRedisplay();
glutSetWindow(windowID2);
glutPostRedisplay();
}
/*-----------------------------------------------*/
void keyHandleFn1(unsigned char key, int x, int y)
/*
PURPOSE: Handles keyboard events like space and esc.
The keyboard was very useful in testing this project
RECEIVES: key - the special key (non a-z letter) pressed
x - screen X position
y - screen Y position
RETURNS: nothing
REMARKS:
*/
{
switch(key)
{
case 'x':
state = XSTATE;
break;
case 'y':
state = YSTATE;
break;
case 'z':
state = ZSTATE;
break;
}
init1();
init2();
}
/*************************************************/
void readParam(char f[])
/*
PURPOSE: reads input parameters.txt, writes to globals
*/
{
//read the txt file
ifstream file(f, ios::in);
char line[80];
//x, y window dimensions
file.getline(line, 80);
xMax = atoi(strtok(line, " "));
yMax = atoi(strtok(NULL, " "));
zMax = atoi(strtok(NULL, " "));
//# of polylines
file.getline(line, 80);
int length = atoi(strtok(line, " "));
list = (int**)malloc(sizeof(int*)*(length + 1));
list[0] = (int*)malloc(sizeof(int));
list[0][0] = length;
for(int i=1; i<=length; i++){
file.getline(line, 80);
int polyLength = atoi(strtok(line, " "));
list[i] = (int*)malloc(sizeof(int)*(polyLength * 3 + 1));
list[i][0] = polyLength;
for(int j=1; j<polyLength*3+1; j++){
list[i][j] = atoi(strtok(NULL, " "));
}
}
file.close();
}
/*************************************************/
void main(int argc, char** argv)
/*
PURPOSE: boilerplate code which launches windows
*/
{
if(argc != 2){
cout << "Usage: viewport file\n";
}
else{
readParam(argv[1]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(0, 0);
//second window
windowID2 = glutCreateWindow("Second Window");
init2();
glutDisplayFunc(drawview2);
//first window
windowID1 = glutCreateWindow("First Window");
init1();
glutDisplayFunc(drawview1);
//Set up keyboard handlers
glutSpecialFunc(keyHandleFn); // for arrow keys
glutKeyboardFunc(keyHandleFn1); // for space esc
glutMainLoop();
}
}
Return to homework page.
|