lab 6 start
This commit is contained in:
21
Lab6/drawbase.h
Normal file
21
Lab6/drawbase.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef DRAWBASE_H
|
||||
#define DRAWBASE_H
|
||||
|
||||
// forward reference
|
||||
class GraphicsContext;
|
||||
|
||||
class DrawingBase
|
||||
{
|
||||
public:
|
||||
// prevent warnings
|
||||
virtual ~DrawingBase(){}
|
||||
virtual void paint(GraphicsContext* gc){}
|
||||
virtual void keyDown(GraphicsContext* gc, unsigned int keycode){}
|
||||
virtual void keyUp(GraphicsContext* gc, unsigned int keycode){}
|
||||
virtual void mouseButtonDown(GraphicsContext* gc,
|
||||
unsigned int button, int x, int y){}
|
||||
virtual void mouseButtonUp(GraphicsContext* gc,
|
||||
unsigned int button, int x, int y){}
|
||||
virtual void mouseMove(GraphicsContext* gc, int x, int y){}
|
||||
};
|
||||
#endif
|
||||
26
Lab6/gcontext.cpp
Normal file
26
Lab6/gcontext.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/* This is an abstract base class representing a generic graphics
|
||||
* context. Most implementation specifics will need to be provided by
|
||||
* a concrete implementation. See header file for specifics. */
|
||||
|
||||
#define _USE_MATH_DEFINES // for M_PI
|
||||
#include <cmath> // for trig functions
|
||||
#include "gcontext.h"
|
||||
|
||||
/*
|
||||
* Destructor - does nothing
|
||||
*/
|
||||
GraphicsContext::~GraphicsContext()
|
||||
{
|
||||
// nothing to do
|
||||
// here to insure subclasses handle destruction properly
|
||||
}
|
||||
|
||||
//does nothing
|
||||
void GraphicsContext::drawLine(int x0, int y0, int x1, int y1){}
|
||||
void GraphicsContext::drawCircle(int x0, int y0, unsigned int radius){}
|
||||
|
||||
|
||||
void GraphicsContext::endLoop()
|
||||
{
|
||||
run = false;
|
||||
}
|
||||
141
Lab6/gcontext.h
Normal file
141
Lab6/gcontext.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef GCONTEXT_H
|
||||
#define GCONTEXT_H
|
||||
|
||||
/**
|
||||
* This class is intended to be the abstract base class
|
||||
* for a graphical context for various platforms. Any
|
||||
* concrete subclass will need to implement the pure virtual
|
||||
* methods to support setting pixels, getting pixel color,
|
||||
* setting the drawing mode, and running an event loop to
|
||||
* capture mouse and keyboard events directed to the graphics
|
||||
* context (or window). Specific expectations for the various
|
||||
* methods are documented below.
|
||||
*
|
||||
* */
|
||||
|
||||
|
||||
// forward reference - needed because runLoop needs a target for events
|
||||
class DrawingBase;
|
||||
|
||||
|
||||
class GraphicsContext
|
||||
{
|
||||
public:
|
||||
/*********************************************************
|
||||
* Some constants and enums
|
||||
*********************************************************/
|
||||
// This enumerated type is an argument to setMode and allows
|
||||
// us to support two different drawing modes. MODE_NORMAL is
|
||||
// also call copy-mode and the affect pixel(s) are set to the
|
||||
// color requested. XOR mode will XOR the new color with the
|
||||
// existing color so that the change is reversible.
|
||||
enum drawMode {MODE_NORMAL, MODE_XOR};
|
||||
|
||||
// Some colors - for fun
|
||||
static const unsigned int BLACK = 0x000000;
|
||||
static const unsigned int BLUE = 0x0000FF;
|
||||
static const unsigned int GREEN = 0x00FF00;
|
||||
static const unsigned int RED = 0xFF0000;
|
||||
static const unsigned int CYAN = 0x00FFFF;
|
||||
static const unsigned int MAGENTA = 0xFF00FF;
|
||||
static const unsigned int YELLOW = 0xFFFF00;
|
||||
static const unsigned int GRAY = 0x808080;
|
||||
static const unsigned int WHITE = 0xFFFFFF;
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Construction / Destruction
|
||||
*********************************************************/
|
||||
// Implementations of this class should include a constructor
|
||||
// that creates the drawing canvas (window), sets a background
|
||||
// color (which may be configurable), sets a default drawing
|
||||
// color (which may be configurable), and start with normal
|
||||
// (copy) drawing mode.
|
||||
|
||||
// need a virtual destructor to ensure subclasses will have
|
||||
// their destructors called properly. Must be virtual.
|
||||
virtual ~GraphicsContext();
|
||||
|
||||
/*********************************************************
|
||||
* Drawing operations
|
||||
*********************************************************/
|
||||
|
||||
// Allows the drawing mode to be changed between normal (copy)
|
||||
// and xor. The implementing context should default to normal.
|
||||
virtual void setMode(drawMode newMode) = 0;
|
||||
|
||||
// Set the current color. Implementations should default to white.
|
||||
// color is 24-bit RGB value
|
||||
virtual void setColor(unsigned int color) = 0;
|
||||
|
||||
// Set pixel to the current color
|
||||
virtual void setPixel(int x, int y) = 0;
|
||||
|
||||
// Get 24-bit RGB pixel color at specified location
|
||||
// unsigned int will likely be 32-bit on 32-bit systems, and
|
||||
// possible 64-bit on some 64-bit systems. In either case,
|
||||
// it is large enough to hold a 16-bit color.
|
||||
virtual unsigned int getPixel(int x, int y) = 0;
|
||||
|
||||
// This should reset entire context to the current background
|
||||
virtual void clear()=0;
|
||||
|
||||
// These are the naive implementations that use setPixel,
|
||||
// but are overridable should a context have a better-
|
||||
// performing version available.
|
||||
|
||||
/* will need to be provided by the concrete
|
||||
* implementation.
|
||||
*
|
||||
* Parameters:
|
||||
* x0, y0 - origin of line
|
||||
* x1, y1 - end of line
|
||||
*
|
||||
* Returns: void
|
||||
*/
|
||||
virtual void drawLine(int x0, int y0, int x1, int y1);
|
||||
|
||||
/* will need to be provided by the concrete
|
||||
* implementation.
|
||||
*
|
||||
* Parameters:
|
||||
* x0, y0 - origin/center of circle
|
||||
* radius - radius of circle
|
||||
*
|
||||
* Returns: void
|
||||
*/
|
||||
virtual void drawCircle(int x0, int y0, unsigned int radius);
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Event loop operations
|
||||
*********************************************************/
|
||||
|
||||
// Run Event loop. This routine will receive events from
|
||||
// the implementation and pass them along to the drawing. It
|
||||
// will return when the window is closed or other implementation-
|
||||
// specific sequence.
|
||||
virtual void runLoop(DrawingBase* drawing) = 0;
|
||||
|
||||
// This method will end the current loop if one is running
|
||||
// a default version is supplied
|
||||
virtual void endLoop();
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Utility operations
|
||||
*********************************************************/
|
||||
|
||||
// returns the width of the window
|
||||
virtual int getWindowWidth() = 0;
|
||||
|
||||
// returns the height of the window
|
||||
virtual int getWindowHeight() = 0;
|
||||
|
||||
protected:
|
||||
// this flag is used to control whether the event loop
|
||||
// continues to run.
|
||||
bool run;
|
||||
};
|
||||
|
||||
#endif
|
||||
164
Lab6/image.cpp
Normal file
164
Lab6/image.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file image.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-19
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
Image::Image(){
|
||||
shapes.clear();
|
||||
}
|
||||
|
||||
Image::Image(const Image& from){
|
||||
for(int i = 0; i < from.shapes.size(); i++){
|
||||
shapes.push_back(from.shapes[i]->clone());
|
||||
}
|
||||
}
|
||||
|
||||
Image::~Image(){
|
||||
for(int i = 0; i < shapes.size(); i++){
|
||||
delete shapes[i];
|
||||
}
|
||||
shapes.clear();
|
||||
}
|
||||
|
||||
Image &Image::operator=(const Image& rhs){
|
||||
if(this != &rhs){
|
||||
for(int i = 0; i < shapes.size(); i++){
|
||||
delete shapes[i];
|
||||
}
|
||||
shapes.clear();
|
||||
for(int i = 0; i < rhs.shapes.size(); i++){
|
||||
shapes.push_back(rhs.shapes[i]->clone());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Image::add(Shape* shape){
|
||||
shapes.push_back(shape->clone());
|
||||
}
|
||||
|
||||
void Image::draw(GraphicsContext* gc, const ViewContext* vc){
|
||||
for(int i = 0; i < shapes.size(); i++){
|
||||
shapes[i]->draw(gc,vc);
|
||||
}
|
||||
}
|
||||
|
||||
void Image::out(std::ostream& os){
|
||||
for(int i = 0; i < shapes.size(); i++){
|
||||
shapes[i]->out(os);
|
||||
os << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Image::in(std::istream& is){
|
||||
string line;
|
||||
string token;
|
||||
int shapeCoords[3][3];
|
||||
getline(is, line);
|
||||
istringstream lineStream(line);
|
||||
do{
|
||||
lineStream >> token;
|
||||
switch(token[0]){
|
||||
case 'L':
|
||||
{
|
||||
// Next Line
|
||||
getline(is, line);
|
||||
lineStream.str(line);
|
||||
lineStream.clear();
|
||||
// Iterate past "Color:"
|
||||
lineStream >> token;
|
||||
// Get actual color code
|
||||
lineStream >> token;
|
||||
stringstream hexColor(token);
|
||||
// Convert hex code to unsigned int
|
||||
uint32_t color;
|
||||
hexColor >> hex >> color;
|
||||
// hexColor >> color;
|
||||
// Points
|
||||
for(int i = 0; i < 2; i++){
|
||||
getline(is, line);
|
||||
lineStream.str(line);
|
||||
lineStream.clear();
|
||||
// Iterate past "P#:"
|
||||
lineStream >> token;
|
||||
// Get each coord
|
||||
for(int j = 0; j < 3; j++){
|
||||
lineStream >> token;
|
||||
shapeCoords[i][j] = stoi(token);
|
||||
}
|
||||
}
|
||||
shapes.push_back(
|
||||
new Line(shapeCoords[0][0],shapeCoords[0][1],
|
||||
shapeCoords[1][0],shapeCoords[1][1],color)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'T':
|
||||
{
|
||||
// Next Line
|
||||
getline(is, line);
|
||||
lineStream.str(line);
|
||||
lineStream.clear();
|
||||
// Iterate past "Color:"
|
||||
lineStream >> token;
|
||||
// Get actual color code
|
||||
lineStream >> token;
|
||||
stringstream hexColor(token);
|
||||
// Convert hex code to unsigned int
|
||||
uint32_t color;
|
||||
hexColor >> hex >> color;
|
||||
// hexColor >> color;
|
||||
// Points
|
||||
for(int i = 0; i < 3; i++){
|
||||
getline(is, line);
|
||||
lineStream.str(line);
|
||||
lineStream.clear();
|
||||
// Iterate past "P#:"
|
||||
lineStream >> token;
|
||||
// Get each coord
|
||||
for(int j = 0; j < 3; j++){
|
||||
lineStream >> token;
|
||||
shapeCoords[i][j] = stoi(token);
|
||||
}
|
||||
}
|
||||
shapes.push_back(
|
||||
new Triangle(shapeCoords[0][0],shapeCoords[0][1],
|
||||
shapeCoords[1][0],shapeCoords[1][1],
|
||||
shapeCoords[2][0],shapeCoords[2][1],color)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
cout << "Invalid Shape";
|
||||
}
|
||||
|
||||
}
|
||||
// Go to blank line
|
||||
getline(is, line);
|
||||
lineStream.str(line);
|
||||
lineStream.clear();
|
||||
// Get next line
|
||||
getline(is, line);
|
||||
lineStream.str(line);
|
||||
lineStream.clear();
|
||||
lineStream >> token;
|
||||
} while(!is.eof()); // Loop until end of file
|
||||
}
|
||||
|
||||
void Image::erase(){
|
||||
for(int i = 0; i < shapes.size(); i++){
|
||||
delete shapes[i];
|
||||
}
|
||||
shapes.clear();
|
||||
}
|
||||
54
Lab6/image.h
Normal file
54
Lab6/image.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef image_h
|
||||
#define image_h
|
||||
/**
|
||||
* @file image.h
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-19
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "line.h"
|
||||
#include "triangle.h"
|
||||
using namespace std;
|
||||
|
||||
class Shape;
|
||||
|
||||
class Image{
|
||||
public:
|
||||
// Image constructor
|
||||
Image();
|
||||
|
||||
// Image copy constructor
|
||||
Image(const Image& from);
|
||||
|
||||
// Image destructor
|
||||
~Image();
|
||||
|
||||
// Image assignment operator
|
||||
Image& operator=(const Image& rhs);
|
||||
|
||||
// Adds a passed in shape to the image
|
||||
void add(Shape* shape);
|
||||
|
||||
// Draws all the shapes in the image
|
||||
void draw(GraphicsContext* gc, const ViewContext* vc);
|
||||
|
||||
// Outputs all of the shape data to an output stream
|
||||
void out(std::ostream& os);
|
||||
|
||||
// Inputs all the shape data from a given input stream
|
||||
void in(std::istream& is);
|
||||
|
||||
// Erases all the shapes in the image
|
||||
void erase();
|
||||
|
||||
private:
|
||||
vector<Shape*> shapes;
|
||||
};
|
||||
|
||||
#endif
|
||||
87
Lab6/line.cpp
Normal file
87
Lab6/line.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file line.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#include "line.h"
|
||||
#include <iomanip>
|
||||
|
||||
Line::Line(int x0, int y0, int x1, int y1, uint32_t color){
|
||||
coords = new Matrix(3, 3);
|
||||
|
||||
// Point 1
|
||||
(*coords)[0][0] = x0;
|
||||
(*coords)[0][1] = y0;
|
||||
(*coords)[0][2] = 0.0;
|
||||
|
||||
// Point 2
|
||||
(*coords)[1][0] = x1;
|
||||
(*coords)[1][1] = y1;
|
||||
(*coords)[1][2] = 0.0;
|
||||
|
||||
// Ones
|
||||
(*coords)[2][0] = 1.0;
|
||||
(*coords)[2][1] = 1.0;
|
||||
(*coords)[2][2] = 1.0;
|
||||
|
||||
this->color = color & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
Line::Line(const Line &from){
|
||||
this->color = from.color;
|
||||
this->coords = new Matrix(3,3);
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
(*coords)[i][j] = (*from.coords)[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Line::~Line(){
|
||||
delete coords;
|
||||
}
|
||||
|
||||
Line &Line::operator=(const Line &rhs){
|
||||
if (&rhs != this)
|
||||
{
|
||||
this->color = rhs.color;
|
||||
delete coords;
|
||||
coords = new Matrix(3,3);
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
(*coords)[i][j] = (*rhs.coords)[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Line::draw(GraphicsContext *gc, const ViewContext* vc){
|
||||
gc->setColor(color);
|
||||
gc->drawLine((*coords)[0][0], (*coords)[0][1],
|
||||
(*coords)[1][0], (*coords)[1][1]);
|
||||
}
|
||||
|
||||
void Line::out(std::ostream& os) const{
|
||||
os << "Line" << endl;
|
||||
os << "Color: " << hex << setw(6) << setfill('0') << color << endl;
|
||||
os << "P1: " << (*coords)[0][0] << " " << (*coords)[0][1];
|
||||
os << " " << (*coords)[0][2] << endl;
|
||||
os << "P2: " << (*coords)[1][0] << " " << (*coords)[1][1];
|
||||
os << " " << (*coords)[1][2] << endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Shape* Line::clone(){
|
||||
return new Line(*this);
|
||||
}
|
||||
43
Lab6/line.h
Normal file
43
Lab6/line.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef line_h
|
||||
#define line_h
|
||||
/**
|
||||
* @file line.h
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shape.h"
|
||||
|
||||
class ViewContext;
|
||||
|
||||
class Line: public Shape{
|
||||
public:
|
||||
// Line constructor
|
||||
Line(int x0, int y0, int x1, int y1, uint32_t color);
|
||||
|
||||
// Line copy constructor
|
||||
Line(const Line& from);
|
||||
|
||||
// Line destructor
|
||||
~Line();
|
||||
|
||||
// Line assignment operator
|
||||
Line& operator=(const Line& rhs);
|
||||
|
||||
// Draw function
|
||||
void draw(GraphicsContext *gc, const ViewContext* vc);
|
||||
|
||||
// Outputs line data to os
|
||||
void out(std::ostream& os) const;
|
||||
|
||||
// Clones a line
|
||||
Shape* clone();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
30
Lab6/main.cpp
Normal file
30
Lab6/main.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-26
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include "x11context.h"
|
||||
#include "mydrawing.h"
|
||||
using namespace std;
|
||||
|
||||
int main(void){
|
||||
|
||||
GraphicsContext* gc = new X11Context(800,600,GraphicsContext::BLACK);
|
||||
gc->setColor(GraphicsContext::GREEN);
|
||||
|
||||
MyDrawing md;
|
||||
|
||||
gc->runLoop(&md);
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
Lab6/makefile
Normal file
25
Lab6/makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
# lab6 Makefile
|
||||
|
||||
CC = g++
|
||||
CFLAGS = -c -MMD -g
|
||||
LFLAGS = -lX11
|
||||
# Change w/ every new project
|
||||
SOURCES = main.cpp gcontext.cpp x11context.cpp row.cpp matrix.cpp shape.cpp line.cpp triangle.cpp image.cpp mydrawing.cpp viewcontext.cpp
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
# Change w/ every new project
|
||||
EXECUTABLE = Lab6
|
||||
|
||||
all: $(EXECUTABLE) $(SOURCES)
|
||||
|
||||
$(EXECUTABLE): $(OBJECTS)
|
||||
$(CC) -o $@ $(OBJECTS) $(LFLAGS)
|
||||
|
||||
-include *.d
|
||||
|
||||
%.o:%.cpp
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXECUTABLE)
|
||||
rm -f $(OBJECTS)
|
||||
rm -f *.d
|
||||
205
Lab6/matrix.cpp
Normal file
205
Lab6/matrix.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @file matrix.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief Contains the main functionality for matrices of double values
|
||||
* @version 1.0
|
||||
* @date 2022-03-29
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
#include "matrix.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// constructor
|
||||
Matrix::Matrix(unsigned int rows, unsigned int cols){
|
||||
// Ensure size is valid
|
||||
if(rows < 1 || cols < 1){
|
||||
throw(out_of_range("rows and cols must be greater than 0"));
|
||||
}
|
||||
// Assign given row and col size to matrix
|
||||
this->rows = rows;
|
||||
this->cols = cols;
|
||||
// Create the row pointer
|
||||
this->the_matrix = new Row*[rows];
|
||||
for(int i = 0; i < rows; i++){
|
||||
// Assign the rows of the matrix to new memory
|
||||
this->the_matrix[i] = new Row(cols);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
Matrix::Matrix(const Matrix& from){
|
||||
// New matrix gets row amount from "from" matrix
|
||||
this->rows = from.rows;
|
||||
// New matrix gets col amount from "from" matrix
|
||||
this->cols = from.cols;
|
||||
// Create the row pointer with new row amount
|
||||
this->the_matrix = new Row*[rows];
|
||||
for(int i = 0; i < rows; i++){
|
||||
// Set the pointer to each copied row
|
||||
this->the_matrix[i] = new Row(from[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Matrix::~Matrix(){
|
||||
// Iterates through the pointer array and deletes each row's array
|
||||
for(int i = 0; i < rows; i++) {
|
||||
delete this->the_matrix[i];
|
||||
}
|
||||
// Deletes the matrix itself
|
||||
delete[] the_matrix;
|
||||
}
|
||||
|
||||
// Assignment operator
|
||||
Matrix& Matrix::operator=(const Matrix& rhs){
|
||||
if(&rhs != this){
|
||||
if(rows > 0 && cols > 0){
|
||||
// Iterates through the pointer array and deletes each row's array
|
||||
for(int i = 0; i < rows; i++) {
|
||||
delete this->the_matrix[i];
|
||||
}
|
||||
// Deletes the matrix itself
|
||||
delete[] the_matrix;
|
||||
}
|
||||
this->rows = rhs.rows;
|
||||
this->cols = rhs.cols;
|
||||
this->the_matrix = new Row*[rows];
|
||||
for(int i = 0; i < rows; i++){
|
||||
// Set the pointer to each copied row
|
||||
the_matrix[i] = new Row(rhs[i]);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Named Constructor
|
||||
Matrix Matrix::identity(unsigned int size){
|
||||
// Ensure size is valid
|
||||
if(size < 1){
|
||||
throw(out_of_range("rows and cols must be greater than 0"));
|
||||
}
|
||||
// Create square matrix
|
||||
Matrix result(size, size);
|
||||
for(int i = 0; i < size; i++){
|
||||
// Fill each diagonal value with 1
|
||||
result[i][i] = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Matrix addition
|
||||
Matrix Matrix::operator+(const Matrix& rhs) const{
|
||||
if(rows != rhs.rows || cols != rhs.cols){
|
||||
throw(out_of_range("Matrices must be the same size"));
|
||||
}
|
||||
Matrix result(this->rows, this->cols);
|
||||
for(int i = 0; i < rows; i++){
|
||||
for(int j = 0; j < cols; j++){
|
||||
result[i][j] = (*the_matrix[i])[j] + rhs[i][j];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Matrix multiplication
|
||||
Matrix Matrix::operator*(const Matrix& rhs) const{
|
||||
if(cols != rhs.rows){
|
||||
throw(out_of_range("1st matrix rows must equal 2nd matrix cols"));
|
||||
}
|
||||
Matrix result(this->rows, rhs.cols);
|
||||
for(int i = 0; i < this->rows; i++){
|
||||
for(int j = 0; j < rhs.cols; j++){
|
||||
result[i][j] = 0.0;
|
||||
for(int k = 0; k < rhs.rows; k++){
|
||||
result[i][j] += (*the_matrix[i])[k]*rhs[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Scalar multiplication
|
||||
Matrix Matrix::operator*(const double scale) const{
|
||||
Matrix result(this->rows, this->cols);
|
||||
for(int i = 0; i < rows; i++){
|
||||
for(int j = 0; j < cols; j++){
|
||||
result[i][j] = (*the_matrix[i])[j]*scale;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Transpose of a Matrix
|
||||
Matrix Matrix::operator~() const{
|
||||
Matrix result(this->cols, this->rows);
|
||||
for(int i = 0; i < rows; i++){
|
||||
for(int j = 0; j < cols; j++){
|
||||
result[j][i] = (*the_matrix[i])[j];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Clear Matrix
|
||||
void Matrix::clear(){
|
||||
for(int i = 0; i < rows; i++) {
|
||||
the_matrix[i]->clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Access Operators - non-const
|
||||
Row& Matrix::operator[](unsigned int row){
|
||||
// Ensure the row is in range
|
||||
if(row > rows){
|
||||
throw(out_of_range("Row is out of range"));
|
||||
}
|
||||
return *(the_matrix[row]);
|
||||
}
|
||||
|
||||
// Access Operators - const
|
||||
const Row& Matrix::operator[](unsigned int row) const{
|
||||
// Ensure the row is in range
|
||||
if(row > rows){
|
||||
throw(out_of_range("Row is out of range"));
|
||||
}
|
||||
return *(the_matrix[row]);
|
||||
}
|
||||
|
||||
// print to output stream
|
||||
void Matrix::out(std::ostream& os) const{
|
||||
os << setprecision(4);
|
||||
os << "[";
|
||||
for(int i = 0; i < rows; i++) {
|
||||
if(i != 0){
|
||||
cout << " ";
|
||||
}
|
||||
os << "[ ";
|
||||
for(int j = 0; j < cols; j++) {
|
||||
os << (*the_matrix[i])[j];
|
||||
if(j != cols-1){
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
os << " ]";
|
||||
if(i != rows-1){
|
||||
os << endl;
|
||||
}
|
||||
}
|
||||
os << "]" << endl;
|
||||
}
|
||||
|
||||
// global insertion operator
|
||||
std::ostream& operator<<(std::ostream& os, const Matrix& rhs){
|
||||
rhs.out(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
// global scalar multiplication
|
||||
Matrix operator*(const double scale, const Matrix& rhs){
|
||||
return rhs*scale;
|
||||
}
|
||||
103
Lab6/matrix.h
Normal file
103
Lab6/matrix.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef matrix_h
|
||||
#define matrix_h
|
||||
|
||||
#include <iostream>
|
||||
#include "row.h"
|
||||
class Matrix
|
||||
{
|
||||
public:
|
||||
// No default (no argument) constructor. It doesn't really make
|
||||
// sense to have one as we cannot rely on a size. This may trip
|
||||
// us up later, but it will lead to a better implementation.
|
||||
// matrix();
|
||||
|
||||
// Constructor - create Matrix and clear cells. If rows or
|
||||
// cols is < 1, throw an exception
|
||||
Matrix(unsigned int rows, unsigned int cols);
|
||||
|
||||
// Copy constructor - make a new Matrix just like rhs
|
||||
Matrix(const Matrix& from);
|
||||
|
||||
// Destructor. Free allocated memory
|
||||
~Matrix();
|
||||
|
||||
// Assignment operator - make this just like rhs. Must function
|
||||
// correctly even if rhs is a different size than this.
|
||||
Matrix& operator=(const Matrix& rhs);
|
||||
|
||||
// Named Constructor - produce a square identity matrix of the
|
||||
// requested size. Since we do not know how the object produced will
|
||||
// be used, we pretty much have to return by value. A size of 0
|
||||
// would not make sense and should throw an exception.
|
||||
static Matrix identity(unsigned int size);
|
||||
|
||||
// Matrix addition - lhs and rhs must be same size otherwise
|
||||
// an exception shall be thrown
|
||||
Matrix operator+(const Matrix& rhs) const;
|
||||
|
||||
// Matrix multiplication - lhs and rhs must be compatible
|
||||
// otherwise an exception shall be thrown
|
||||
Matrix operator*(const Matrix& rhs) const;
|
||||
|
||||
// Scalar multiplication. Note, this function will support
|
||||
// someMatrixObject * 5.0, but not 5.0 * someMatrixObject.
|
||||
Matrix operator*(const double scale) const;
|
||||
|
||||
// Transpose of a Matrix - should always work, hence no exception
|
||||
Matrix operator~() const;
|
||||
|
||||
// Clear Matrix to all members 0.0
|
||||
void clear();
|
||||
|
||||
// Access Operators - throw an exception if index out of range
|
||||
Row& operator[](unsigned int row);
|
||||
|
||||
// const version of above - throws an exception if indices are out of
|
||||
// range
|
||||
const Row& operator[](unsigned int row) const;
|
||||
|
||||
// I/O - for convenience - this is intended to be called by the global
|
||||
// << operator declared below.
|
||||
void out(std::ostream& os) const;
|
||||
|
||||
private:
|
||||
// An array of Row pointers size "rows" that each point to a double array
|
||||
// of size "cols"
|
||||
Row** the_matrix;
|
||||
unsigned int rows;
|
||||
unsigned int cols;
|
||||
|
||||
/** routines **/
|
||||
|
||||
// add any "helper" routine here, such as routines to support
|
||||
// matrix inversion
|
||||
|
||||
};
|
||||
|
||||
/** Some Related Global Functions **/
|
||||
|
||||
// Overloaded global << with std::ostream as lhs, Matrix as rhs. This method
|
||||
// should generate output compatible with an ostream which is commonly used
|
||||
// with console (cout) and files. Something like:
|
||||
// [[ r0c0, r0c1, r0c2 ]
|
||||
// [ r1c0, r1c1, r1c2 ]
|
||||
// [ r0c0, r0c1, r0c2 ]]
|
||||
// would be appropriate.
|
||||
//
|
||||
// Since this is a global function, it does not have access to the private
|
||||
// data of a Matrix object. So, it will need to use the public interface of
|
||||
// Matrix to do its job. The method Matrix::out was added to Matrix
|
||||
// specifically for this purpose. The other option would have been to make
|
||||
// it a "friend"
|
||||
std::ostream& operator<<(std::ostream& os, const Matrix& rhs);
|
||||
|
||||
// We would normally have a corresponding >> operator, but
|
||||
// will defer that exercise that until a later assignment.
|
||||
|
||||
|
||||
// Scalar multiplication with a global function. Note, this function will
|
||||
// support 5.0 * someMatrixObject, but not someMatrixObject * 5.0
|
||||
Matrix operator*(const double scale, const Matrix& rhs);
|
||||
|
||||
#endif
|
||||
// Based on lab by Dr. Darrin Rothe ((c) 2015 Dr. Darrin Rothe)
|
||||
126
Lab6/mydrawing.cpp
Normal file
126
Lab6/mydrawing.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "mydrawing.h"
|
||||
//#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
MyDrawing::MyDrawing()
|
||||
{
|
||||
cout << "COLORS: 'b' = blue, 'r' = red, 'g' = green \n";
|
||||
cout << "MODES: 'l' = lines, 'm' = mirror, 'd' = dotted, 'c' = connected\n";
|
||||
cout << "OTHER: 'Delete' = clear image\n";
|
||||
}
|
||||
void MyDrawing::keyDown(GraphicsContext *gc, unsigned int keycode)
|
||||
{
|
||||
switch (keycode)
|
||||
{
|
||||
case 114: // 'r', change color to red
|
||||
color = GraphicsContext::RED;
|
||||
break;
|
||||
case 103: // 'g', change color to green
|
||||
color = GraphicsContext::GREEN;
|
||||
break;
|
||||
case 98: // 'b', change color to blues
|
||||
color = GraphicsContext::BLUE;
|
||||
break;
|
||||
case 65535: // 'delete', clear window
|
||||
gc->clear();
|
||||
break;
|
||||
case 108: // 'l', set mode to "lines"
|
||||
mode = "lines";
|
||||
break;
|
||||
case 109: // 'm', set mode to "mirror"
|
||||
mode = "mirror";
|
||||
break;
|
||||
case 99: // 'c', set mode to connected
|
||||
connected = true;
|
||||
break;
|
||||
case 100: // 'd', set mode to dotted
|
||||
connected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void MyDrawing::mouseButtonDown(GraphicsContext *gc, unsigned int button, int x,
|
||||
int y)
|
||||
{
|
||||
hold = true; // user is holding down mouse
|
||||
}
|
||||
void MyDrawing::mouseMove(GraphicsContext *gc, int x, int y)
|
||||
{
|
||||
int dx = gc->getWindowWidth();
|
||||
int dy = gc->getWindowHeight();
|
||||
if (hold)
|
||||
{ // only draw when user is holding down mouse
|
||||
if (mode == "lines")
|
||||
{
|
||||
gc->setColor(color);
|
||||
//. draw line from center of window to mouse location
|
||||
gc->drawLine(dx / 2, dy / 2, x, y);
|
||||
}
|
||||
else if (mode == "mirror")
|
||||
{
|
||||
gc->setColor(color);
|
||||
if (firstdraw)
|
||||
{
|
||||
xprev = x;
|
||||
yprev = y;
|
||||
firstdraw = false;
|
||||
}
|
||||
// mirror 8 times around center in dotted or connected mode
|
||||
if (!connected)
|
||||
{
|
||||
setLargePixel(gc, x, y);
|
||||
setLargePixel(gc, y + dx / 2 - dy / 2, -x + dx / 2 + dy / 2);
|
||||
setLargePixel(gc, -y + dx / 2 + dy / 2, x - dx / 2 + dy / 2);
|
||||
setLargePixel(gc, -x + dx, -y + dy);
|
||||
setLargePixel(gc, y + dx / 2 - dy / 2, x - dx / 2 + dy / 2);
|
||||
setLargePixel(gc, -y + dx / 2 + dy / 2, -x + dx / 2 + dy / 2);
|
||||
setLargePixel(gc, x, -y + dy);
|
||||
setLargePixel(gc, -x + dx, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawLargeLine(gc, xprev, yprev, x, y);
|
||||
drawLargeLine(gc, yprev + dx / 2 - dy / 2, -xprev + dx / 2 + dy / 2,
|
||||
y + dx / 2 - dy / 2, -x + dx / 2 + dy / 2);
|
||||
drawLargeLine(gc, -yprev + dx / 2 + dy / 2, xprev - dx / 2 + dy / 2,
|
||||
-y + dx / 2 + dy / 2, x - dx / 2 + dy / 2);
|
||||
drawLargeLine(gc, -xprev + dx, -yprev + dy, -x + dx, -y + dy);
|
||||
drawLargeLine(gc, yprev + dx / 2 - dy / 2, xprev - dx / 2 + dy / 2,
|
||||
y + dx / 2 - dy / 2, x - dx / 2 + dy / 2);
|
||||
drawLargeLine(gc, -yprev + dx / 2 + dy / 2, -xprev + dx / 2 + dy / 2,
|
||||
-y + dx / 2 + dy / 2, -x + dx / 2 + dy / 2);
|
||||
drawLargeLine(gc, xprev, -yprev + dy, x, -y + dy);
|
||||
drawLargeLine(gc, -xprev + dx, yprev, -x + dx, y);
|
||||
}
|
||||
// draw line from previous mouse coordinate
|
||||
xprev = x;
|
||||
yprev = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
void MyDrawing::mouseButtonUp(GraphicsContext *gc,
|
||||
unsigned int button, int x, int y)
|
||||
{
|
||||
// user has released mouse button
|
||||
hold = false;
|
||||
firstdraw = true;
|
||||
}
|
||||
|
||||
void drawLargeLine(GraphicsContext *gc, int x0, int y0, int x1, int y1)
|
||||
{
|
||||
// draw 3 pixel wide line
|
||||
gc->drawLine(x0, y0, x1, y1);
|
||||
gc->drawLine(x0 + 1, y0, x1 + 1, y1);
|
||||
gc->drawLine(x0 - 1, y0, x1 - 1, y1);
|
||||
}
|
||||
void setLargePixel(GraphicsContext *gc, int x, int y)
|
||||
{
|
||||
// draw 9x9 square around pixel
|
||||
gc->setPixel(x, y);
|
||||
gc->setPixel(x + 1, y);
|
||||
gc->setPixel(x + 1, y + 1);
|
||||
gc->setPixel(x, y + 1);
|
||||
gc->setPixel(x - 1, y + 1);
|
||||
gc->setPixel(x - 1, y);
|
||||
gc->setPixel(x - 1, y - 1);
|
||||
gc->setPixel(x, y - 1);
|
||||
gc->setPixel(x + 1, y - 1);
|
||||
45
Lab6/mydrawing.h
Normal file
45
Lab6/mydrawing.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef mydrawing_h
|
||||
#define mydrawing_h
|
||||
|
||||
#include <iostream>
|
||||
#include "drawbase.h"
|
||||
#include "gcontext.h"
|
||||
#include "image.h"
|
||||
#include "matrix.h"
|
||||
using namespace std;
|
||||
|
||||
class MyDrawing: public DrawingBase{
|
||||
|
||||
public:
|
||||
MyDrawing();
|
||||
void keyDown(GraphicsContext* gc, unsigned int keycode);
|
||||
void mouseMove(GraphicsContext* gc, int x, int y);
|
||||
void mouseButtonDown(GraphicsContext* gc,
|
||||
unsigned int button, int x, int y);
|
||||
void mouseButtonUp(GraphicsContext* gc,
|
||||
unsigned int button, int x, int y);
|
||||
|
||||
private:
|
||||
// default is red
|
||||
unsigned int color = GraphicsContext::RED;
|
||||
// indicates whether user is holding down the mouse
|
||||
bool hold = false;
|
||||
// "lines" mode - lines from center
|
||||
// "mirror" mode - mirror 8 times around center
|
||||
string mode = "lines";
|
||||
|
||||
// start of line drawn in mirror mode
|
||||
int xprev;
|
||||
int yprev;
|
||||
// first pixel drawn in mirror mode
|
||||
bool firstdraw = true;
|
||||
// dotted or connected mode
|
||||
bool connected = true;
|
||||
Image image;
|
||||
|
||||
};
|
||||
|
||||
void setLargePixel(GraphicsContext* gc, int x, int y);
|
||||
void drawLargeLine(GraphicsContext* gc, int x0, int y0, int x1, int y1);
|
||||
|
||||
#endif
|
||||
87
Lab6/row.cpp
Normal file
87
Lab6/row.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file row.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief Contains the main functionality for row matrices utilizing arrays of
|
||||
* double values
|
||||
* @version 1.0
|
||||
* @date 2022-03-22
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#include <stdexcept>
|
||||
#include "row.h"
|
||||
using namespace std;
|
||||
|
||||
// parameterized constructor
|
||||
Row::Row(unsigned int length){
|
||||
// Set matrix length private variable to passed in length
|
||||
this->length = length;
|
||||
// Create new array in heap for row_data
|
||||
this->row_data = new double[length];
|
||||
// Clear all values in new array to 0
|
||||
clear();
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
Row::Row(const Row& from){
|
||||
// New row matrix gets length from previous matrix
|
||||
this->length = from.length;
|
||||
// Create new array in heap with new length
|
||||
this->row_data = new double[this->length];
|
||||
// Copy all row_data values over to new array
|
||||
for(int i = 0; i < this->length; i++) {
|
||||
this->row_data[i] = from[i];
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
Row::~Row(){
|
||||
// Check for valid length then free the heap memory
|
||||
if(length > 0 ) {
|
||||
delete[] row_data;
|
||||
}
|
||||
}
|
||||
|
||||
// access operator (const)
|
||||
double Row::operator[](unsigned int column) const{
|
||||
if (column >= length) {
|
||||
throw(out_of_range("Column is out of range"));
|
||||
}
|
||||
return row_data[column];
|
||||
}
|
||||
|
||||
// access operator (non-const)
|
||||
double& Row::operator[](unsigned int column){
|
||||
if (column >= length) {
|
||||
throw(out_of_range("Column is out of range"));
|
||||
}
|
||||
return row_data[column];
|
||||
}
|
||||
|
||||
// assignment operator
|
||||
Row& Row::operator= (const Row& rhs){
|
||||
if(&rhs != this){
|
||||
// Delete the current row matrix
|
||||
if(length > 0){
|
||||
delete[] this->row_data;
|
||||
}
|
||||
// New row matrix gets length from previous matrix
|
||||
this->length = rhs.length;
|
||||
// Create new array in heap with new length
|
||||
this->row_data = new double[this->length];
|
||||
// Copy all row_data values over to new array
|
||||
for(int i = 0; i < this->length; i ++) {
|
||||
this->row_data[i] = rhs.row_data[i];
|
||||
}
|
||||
}
|
||||
// Return address of the Row
|
||||
return *this;
|
||||
}
|
||||
|
||||
// clear row data
|
||||
void Row::clear(){
|
||||
for(int i = 0; i < length; i++) {
|
||||
this->row_data[i] = 0;
|
||||
}
|
||||
}
|
||||
51
Lab6/row.h
Normal file
51
Lab6/row.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef row_h
|
||||
#define row_h
|
||||
class Row{
|
||||
public:
|
||||
/* Parameterized constructor
|
||||
* Takes in length and creates a row matrix with values cleared
|
||||
* to zero
|
||||
*/
|
||||
Row(unsigned int length);
|
||||
|
||||
/* Copy constructor
|
||||
* Create a new row matrix with the same size and values as the
|
||||
* from matrix
|
||||
*/
|
||||
Row(const Row& from);
|
||||
|
||||
/* Destructor
|
||||
* Correctly delete any heap memory
|
||||
*/
|
||||
~Row();
|
||||
|
||||
/* Access operator (const version)
|
||||
* Allow access to row matrix data
|
||||
* Should return an exception if column is too large
|
||||
*/
|
||||
double operator[](unsigned int column) const;
|
||||
|
||||
/* Access operator (non const version)
|
||||
* Allow access to row matrix data
|
||||
* Should return an exception if column is too large
|
||||
*/
|
||||
double& operator[] (unsigned int column);
|
||||
|
||||
/* Assignment operator
|
||||
* 1. Check if two sides are the same object
|
||||
* 2. Delete the current row matrix
|
||||
* 3. Create a new row matrix with the same size and values as
|
||||
* the rhs matrix
|
||||
*/
|
||||
Row& operator= (const Row& rhs);
|
||||
|
||||
/* Clear all data values to zero
|
||||
*/
|
||||
void clear();
|
||||
private:
|
||||
// Row matrix data
|
||||
double * row_data;
|
||||
// Size of row matrix
|
||||
unsigned int length;
|
||||
};
|
||||
#endif
|
||||
22
Lab6/shape.cpp
Normal file
22
Lab6/shape.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @file shape.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#include "shape.h"
|
||||
|
||||
Shape::Shape(){
|
||||
this->color = (uint32_t) 0x00FFFFFF;
|
||||
}
|
||||
Shape::Shape(const Shape& from){};
|
||||
|
||||
Shape::~Shape(){};
|
||||
|
||||
Shape& Shape::operator=(const Shape& rhs){
|
||||
return *this;
|
||||
}
|
||||
52
Lab6/shape.h
Normal file
52
Lab6/shape.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef shape_h
|
||||
#define shape_h
|
||||
/**
|
||||
* @file shape.h
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#include <iostream>
|
||||
#include "x11context.h"
|
||||
#include "matrix.h"
|
||||
#include "mydrawing.h"
|
||||
//#include "viewcontext.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Shape{
|
||||
public:
|
||||
// Constructor
|
||||
Shape();
|
||||
|
||||
// Copy Constructor
|
||||
Shape(const Shape& from);
|
||||
|
||||
// Destructor
|
||||
virtual ~Shape();
|
||||
|
||||
// Draw shape
|
||||
virtual void draw(GraphicsContext *gc, const ViewContext* vc) = 0;
|
||||
|
||||
// Print to output stream
|
||||
virtual void out(std::ostream& os)const = 0;
|
||||
|
||||
// Virtual Constructor
|
||||
virtual Shape* clone() = 0; // Pure virtual "=0"
|
||||
protected:
|
||||
// Matrix containing the coords of each point in the shape
|
||||
Matrix* coords;
|
||||
|
||||
// RGB color
|
||||
uint32_t color;
|
||||
|
||||
// Assignment Operator
|
||||
virtual Shape& operator=(const Shape& rhs);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
95
Lab6/triangle.cpp
Normal file
95
Lab6/triangle.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file triangle.cpp
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
//#include "shape.h"
|
||||
#include <iomanip>
|
||||
#include "triangle.h"
|
||||
|
||||
Triangle::Triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color){
|
||||
coords = new Matrix(4,3);
|
||||
|
||||
// Point 1
|
||||
(*coords)[0][0] = x0;
|
||||
(*coords)[0][1] = y0;
|
||||
(*coords)[0][2] = 0.0;
|
||||
|
||||
// Point 2
|
||||
(*coords)[1][0] = x1;
|
||||
(*coords)[1][1] = y1;
|
||||
(*coords)[1][2] = 0.0;
|
||||
|
||||
// Point 3
|
||||
(*coords)[2][0] = x2;
|
||||
(*coords)[2][1] = y2;
|
||||
(*coords)[2][2] = 0.0;
|
||||
|
||||
// Ones
|
||||
(*coords)[3][0] = 1.0;
|
||||
(*coords)[3][1] = 1.0;
|
||||
(*coords)[3][2] = 1.0;
|
||||
|
||||
this->color = color & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
Triangle::Triangle(const Triangle &from){
|
||||
this->coords = new Matrix(4,3);
|
||||
(*this).color = from.color;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
(*coords)[i][j] = (*from.coords)[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Triangle::~Triangle(){
|
||||
delete coords;
|
||||
}
|
||||
|
||||
Triangle& Triangle::operator=(const Triangle& rhs){
|
||||
if(&rhs != this){
|
||||
this->color = rhs.color;
|
||||
delete coords;
|
||||
coords = new Matrix(4,3);
|
||||
for(int i = 0; i < 3; i++){
|
||||
for(int j = 0; j < 2; j++){
|
||||
this->coords[i][j] = rhs.coords[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Triangle::out(std::ostream& os) const{
|
||||
os << "Triangle" << endl;
|
||||
os << "Color: " << hex << setw(6) << setfill('0') << color << endl;
|
||||
os << "P1: " << (*coords)[0][0] << " " << (*coords)[0][1];
|
||||
os << " " << (*coords)[0][2] << endl;
|
||||
os << "P2: " << (*coords)[1][0] << " " << (*coords)[1][1];
|
||||
os << " " << (*coords)[1][2] << endl;
|
||||
os << "P3: " << (*coords)[2][0] << " " << (*coords)[2][1];
|
||||
os << " " << (*coords)[2][2] << endl;
|
||||
}
|
||||
|
||||
|
||||
Shape* Triangle::clone(){
|
||||
return new Triangle(*this);
|
||||
}
|
||||
|
||||
void Triangle::draw(GraphicsContext *gc, const ViewContext* vc){
|
||||
gc->setColor(color);
|
||||
gc->drawLine((*coords)[0][0], (*coords)[0][1],
|
||||
(*coords)[1][0], (*coords)[1][1]);
|
||||
gc->drawLine((*coords)[1][0], (*coords)[1][1],
|
||||
(*coords)[2][0], (*coords)[2][1]);
|
||||
gc->drawLine((*coords)[2][0], (*coords)[2][1],
|
||||
(*coords)[0][0], (*coords)[0][1]);
|
||||
}
|
||||
43
Lab6/triangle.h
Normal file
43
Lab6/triangle.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef triangle_h
|
||||
#define triangle_h
|
||||
/**
|
||||
* @file triangle.h
|
||||
* @author Trevor Barnes (barnestr@msoe.edu)
|
||||
* @brief
|
||||
* @version 1.0
|
||||
* @date 2022-04-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shape.h"
|
||||
|
||||
class ViewContext;
|
||||
|
||||
class Triangle: public Shape{
|
||||
public:
|
||||
// Triangle constructor
|
||||
Triangle(int x0, int y0, int x1, int y1, int x2, int y2,
|
||||
uint32_t color);
|
||||
|
||||
// Triangle copy constructor
|
||||
Triangle(const Triangle& from);
|
||||
|
||||
// Triangle destructor
|
||||
~Triangle();
|
||||
|
||||
// Triangle assignment operator
|
||||
Triangle& operator=(const Triangle& rhs);
|
||||
|
||||
// Draw function
|
||||
void draw(GraphicsContext *gc, const ViewContext* vc);
|
||||
|
||||
// Outputs line data to os
|
||||
void out(std::ostream& os) const;
|
||||
|
||||
// Clones a triangle
|
||||
Shape* clone();
|
||||
|
||||
};
|
||||
#endif
|
||||
11
Lab6/viewcontext.cpp
Normal file
11
Lab6/viewcontext.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
// - ViewContext Class -
|
||||
|
||||
#include "viewcontext.h"
|
||||
|
||||
ViewContext::ViewContext(){
|
||||
compMatrix = new Matrix(3,3);
|
||||
}
|
||||
|
||||
void ViewContext::model_to_device(){
|
||||
|
||||
}
|
||||
19
Lab6/viewcontext.h
Normal file
19
Lab6/viewcontext.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef viewcontext_h
|
||||
#define viewcontext_h
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
|
||||
class ViewContext{
|
||||
ViewContext();
|
||||
void model_to_device();
|
||||
|
||||
// Rotation - Around center of screen
|
||||
// Scaling - Around center of screen
|
||||
// Translation
|
||||
// Reset
|
||||
// Invert Colors
|
||||
Matrix* compMatrix;
|
||||
};
|
||||
|
||||
#endif
|
||||
286
Lab6/x11context.cpp
Normal file
286
Lab6/x11context.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/* Provides a simple drawing context for X11/XWindows
|
||||
* You must have the X11 dev libraries installed. If missing,
|
||||
* 'sudo apt-get install libx11-dev' should help.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h> // Every Xlib program must include this
|
||||
#include <X11/Xutil.h> // needed for XGetPixel
|
||||
#include <X11/XKBlib.h> // needed for keyboard setup
|
||||
#include "x11context.h"
|
||||
#include "drawbase.h"
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
/**
|
||||
* The only constructor provided. Allows size of window and background
|
||||
* color be specified.
|
||||
* */
|
||||
X11Context::X11Context(unsigned int sizex=400,unsigned int sizey=400,
|
||||
unsigned int bg_color=GraphicsContext::BLACK)
|
||||
{
|
||||
// Open the display
|
||||
display = XOpenDisplay(NULL);
|
||||
|
||||
// Holding a key in gives repeated key_press commands but only
|
||||
// one key_release
|
||||
int supported;
|
||||
|
||||
XkbSetDetectableAutoRepeat(display,true,&supported);
|
||||
|
||||
// Create a window - we will assume the color map is in RGB mode.
|
||||
window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0,
|
||||
sizex, sizey, 0, 0 , bg_color);
|
||||
|
||||
// Sign up for MapNotify events
|
||||
XSelectInput(display, window, StructureNotifyMask);
|
||||
|
||||
// Put the window on the screen
|
||||
XMapWindow(display, window);
|
||||
|
||||
// Create a "Graphics Context"
|
||||
graphics_context = XCreateGC(display, window, 0, NULL);
|
||||
|
||||
// Default color to white
|
||||
XSetForeground(display, graphics_context, GraphicsContext::WHITE);
|
||||
|
||||
// Wait for MapNotify event
|
||||
for(;;)
|
||||
{
|
||||
XEvent e;
|
||||
XNextEvent(display, &e);
|
||||
if (e.type == MapNotify)
|
||||
break;
|
||||
}
|
||||
|
||||
// We also want exposure, mouse, and keyboard events
|
||||
XSelectInput(display, window, ExposureMask|
|
||||
ButtonPressMask|
|
||||
ButtonReleaseMask|
|
||||
KeyPressMask|
|
||||
KeyReleaseMask|
|
||||
PointerMotionMask);
|
||||
|
||||
// We need this to get the WM_DELETE_WINDOW message from the
|
||||
// window manager in case user click the X icon
|
||||
Atom atomKill = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(display, window, &atomKill, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Destructor - shut down window and connection to server
|
||||
X11Context::~X11Context()
|
||||
{
|
||||
XFreeGC(display, graphics_context);
|
||||
XDestroyWindow(display,window);
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
// Set the drawing mode - argument is enumerated
|
||||
void X11Context::setMode(drawMode newMode)
|
||||
{
|
||||
if (newMode == GraphicsContext::MODE_NORMAL)
|
||||
{
|
||||
XSetFunction(display,graphics_context,GXcopy);
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetFunction(display,graphics_context,GXxor);
|
||||
}
|
||||
}
|
||||
|
||||
// Set drawing color - assume colormap is 24 bit RGB
|
||||
void X11Context::setColor(unsigned int color)
|
||||
{
|
||||
// Go ahead and set color here - better performance than setting
|
||||
// on every setPixel
|
||||
XSetForeground(display, graphics_context, color);
|
||||
}
|
||||
|
||||
// Set a pixel in the current color
|
||||
void X11Context::setPixel(int x, int y)
|
||||
{
|
||||
XDrawPoint(display, window, graphics_context, x, y);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
unsigned int X11Context::getPixel(int x, int y)
|
||||
{
|
||||
XImage *image;
|
||||
image = XGetImage (display, window, x, y, 1, 1, AllPlanes, XYPixmap);
|
||||
XColor color;
|
||||
color.pixel = XGetPixel (image, 0, 0);
|
||||
XFree (image);
|
||||
XQueryColor (display, DefaultColormap(display, DefaultScreen (display)),
|
||||
&color);
|
||||
// I now have RGB values, but, they are 16 bits each, I only want 8-bits
|
||||
// each since I want a 24-bit RGB color value
|
||||
unsigned int pixcolor = color.red & 0xff00;
|
||||
pixcolor |= (color.green >> 8);
|
||||
pixcolor <<= 8;
|
||||
pixcolor |= (color.blue >> 8);
|
||||
return pixcolor;
|
||||
}
|
||||
|
||||
void X11Context::clear()
|
||||
{
|
||||
XClearWindow(display, window);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Run event loop
|
||||
void X11Context::runLoop(DrawingBase* drawing)
|
||||
{
|
||||
run = true;
|
||||
|
||||
while(run)
|
||||
{
|
||||
XEvent e;
|
||||
XNextEvent(display, &e);
|
||||
|
||||
// Exposure event - lets not worry about region
|
||||
if (e.type == Expose)
|
||||
drawing->paint(this);
|
||||
|
||||
// Key Down
|
||||
else if (e.type == KeyPress)
|
||||
drawing->keyDown(this,XLookupKeysym((XKeyEvent*)&e,
|
||||
(((e.xkey.state&0x01)&&!(e.xkey.state&0x02))||
|
||||
(!(e.xkey.state&0x01)&&(e.xkey.state&0x02)))?1:0));
|
||||
|
||||
// Key Up
|
||||
else if (e.type == KeyRelease){
|
||||
drawing->keyUp(this,XLookupKeysym((XKeyEvent*)&e,
|
||||
(((e.xkey.state&0x01)&&!(e.xkey.state&0x02))||
|
||||
(!(e.xkey.state&0x01)&&(e.xkey.state&0x02)))?1:0));
|
||||
}
|
||||
|
||||
// Mouse Button Down
|
||||
else if (e.type == ButtonPress)
|
||||
drawing->mouseButtonDown(this,
|
||||
e.xbutton.button,
|
||||
e.xbutton.x,
|
||||
e.xbutton.y);
|
||||
|
||||
// Mouse Button Up
|
||||
else if (e.type == ButtonRelease)
|
||||
drawing->mouseButtonUp(this,
|
||||
e.xbutton.button,
|
||||
e.xbutton.x,
|
||||
e.xbutton.y);
|
||||
|
||||
// Mouse Move
|
||||
else if (e.type == MotionNotify)
|
||||
drawing->mouseMove(this,
|
||||
e.xmotion.x,
|
||||
e.xmotion.y);
|
||||
|
||||
// This will respond to the WM_DELETE_WINDOW from the
|
||||
// window manager.
|
||||
else if (e.type == ClientMessage)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int X11Context::getWindowWidth()
|
||||
{
|
||||
XWindowAttributes window_attributes;
|
||||
XGetWindowAttributes(display,window, &window_attributes);
|
||||
return window_attributes.width;
|
||||
}
|
||||
|
||||
int X11Context::getWindowHeight()
|
||||
{
|
||||
XWindowAttributes window_attributes;
|
||||
XGetWindowAttributes(display,window, &window_attributes);
|
||||
return window_attributes.height;
|
||||
}
|
||||
|
||||
// void X11Context::drawLine(int x1, int y1, int x2, int y2)
|
||||
// {
|
||||
// XDrawLine(display, window, graphics_context, x1, y1, x2, y2);
|
||||
// XFlush(display);
|
||||
// }
|
||||
|
||||
// Bresenham Implementation
|
||||
void X11Context::drawLine(int x1, int y1, int x2, int y2){
|
||||
bool steep;
|
||||
if(abs(y2-y1) < abs(x2-x1)){
|
||||
// Steep slope
|
||||
steep = true;
|
||||
if(x1 > x2){
|
||||
// Swap to change drawing direction
|
||||
int temp = x1;
|
||||
x1 = x2;
|
||||
x2 = temp;
|
||||
temp = y1;
|
||||
y1 = y2;
|
||||
y2 = temp;
|
||||
}
|
||||
} else {
|
||||
// Shallow slope
|
||||
steep = false;
|
||||
if(y1 > y2){
|
||||
// Swap to change drawing direction
|
||||
int temp = x1;
|
||||
x1 = x2;
|
||||
x2 = temp;
|
||||
temp = y1;
|
||||
y1 = y2;
|
||||
y2 = temp;
|
||||
}
|
||||
}
|
||||
// Initilize algorithm values
|
||||
int dx = x2-x1;
|
||||
int dy = y2-y1;
|
||||
int D = 2*dy-dx;
|
||||
// Will either be +1 or -1
|
||||
int c = 1;
|
||||
|
||||
if(steep){
|
||||
// When |dx| > |dy|
|
||||
if(dy<0){
|
||||
c = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
int D = 2*dy-dx;
|
||||
int y = y1;
|
||||
for(int i = x1; i < x2; i++){
|
||||
setPixel(i,y);
|
||||
if(D > 0){
|
||||
y += c;
|
||||
D += (2*(dy-dx));
|
||||
}else{
|
||||
D += 2*dy;
|
||||
}
|
||||
}
|
||||
} else if(!steep){
|
||||
// When |dx| < |dy|
|
||||
if(dx<0){
|
||||
c = -1;
|
||||
dx = -dx;
|
||||
}
|
||||
int D = 2*dx-dy;
|
||||
int x = x1;
|
||||
for(int j = y1; j < y2; j++){
|
||||
setPixel(x,j);
|
||||
if(D > 0){
|
||||
x += c;
|
||||
D += (2*(dx-dy));
|
||||
} else {
|
||||
D += 2*dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X11Context::drawCircle(int x, int y, unsigned int radius)
|
||||
{
|
||||
XDrawArc(display, window, graphics_context, x-radius,
|
||||
y-radius, radius*2, radius*2, 0, 360*64);
|
||||
XFlush(display);
|
||||
}
|
||||
48
Lab6/x11context.h
Normal file
48
Lab6/x11context.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef X11_CONTEXT
|
||||
#define X11_CONTEXT
|
||||
/**
|
||||
* This class is a sample implementation of the GraphicsContext class
|
||||
* for the X11 / XWindows system.
|
||||
* */
|
||||
|
||||
#include <X11/Xlib.h> // Every Xlib program must include this
|
||||
#include "gcontext.h" // base class
|
||||
|
||||
class X11Context : public GraphicsContext
|
||||
{
|
||||
public:
|
||||
// Default Constructor
|
||||
X11Context(unsigned int sizex,unsigned int sizey,unsigned int bg_color);
|
||||
|
||||
// Destructor
|
||||
virtual ~X11Context();
|
||||
|
||||
// Drawing Operations
|
||||
void setMode(drawMode newMode);
|
||||
void setColor(unsigned int color);
|
||||
void setPixel(int x, int y);
|
||||
unsigned int getPixel(int x, int y);
|
||||
void clear();
|
||||
void drawLine(int x1, int y1, int x2, int y2);
|
||||
void drawCircle(int x, int y, unsigned int radius);
|
||||
|
||||
|
||||
// Event looop functions
|
||||
void runLoop(DrawingBase* drawing);
|
||||
|
||||
// we will use endLoop provided by base class
|
||||
|
||||
// Utility functions
|
||||
int getWindowWidth();
|
||||
int getWindowHeight();
|
||||
|
||||
|
||||
private:
|
||||
// X11 stuff - specific to this context
|
||||
Display* display;
|
||||
Window window;
|
||||
GC graphics_context;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user