Triangle
General
- All submissions must include a work history to be worth credit.
- Submit all files to Canvas. Make sure to name file(s) EXACTLY as specified - including capitalization.
- Make sure your program accepts input in EXACTLY the order and format given.
Do not ask for extra input or change the order of inputs.
If you want to make an expanded version of a program that and get feedback on it, email it to me or show me in class. - Slight variations in output wording/formatting are usually fine
(as long as formatting isn't part of the assignment).
If you do not get the right final output, print out some evidence of the work your program did to demonstrate your progress. - Readability and maintainability of your code counts. Poor formatting, confusing variable names, unnecessarily complex code, etc… will all result in deductions to your score.
Overview
You will create a class Triangle that represents a simple triangle on a Cartesian
plane. You are not writing any particular program that uses triangles,
but a tool that could be used by someone who wanted to write a program
and use your Triangle class to do it. The way you will demonstrate your
code works is by providing unit tests in tests.cpp.
Your Triangle class will use a provided Point class to help represent the triangle.
For the purposes of this problem, a triangle can be described by the locations of its three vertices, which we will call p0, p1, and p2. Each vertex is a Point with an x and y coordinate. Those points could be three variables or a vector of three points.
Your task is to build a class Triangle that provides the public interface described below:
Remember that UML does not show things like const qualifiers or passing by reference.
Assignment Instructions
Setup
You should use the Unit Test Project Template (or combo project and just use the unit test program in it) in either a codespace or a local development environment to do this assignment.
While working on this assignment, MAKE sure that you are generating a worklog with time stamped entries.
Then add these four files to your project:
Triangle.h: This will have the declarations for the functions you write.Triangle.cpp: This will have the definitions for the functions you write.Point.h: This will have the declarations for the provided Point class. Start it with code in this copy of Point.h.Point.cpp: This will have the definitions for the provided Point class. Start it with code in this copy of Point.cpp.
In your Makefile, add Triangle.cpp and Point.cpp to the SHARED_FILES variable and Triangle.h and Point.h to the HEADERS variable. It should end up looking something like this:
...existing content...
HEADERS = Triangle.h Point.h
...existing content...
SHARED_FILES = Triangle.cpp Point.cpp
...existing content...
In your tests.cpp, add #include "Triangle.h" and #include "Point.h" at the top of the file
(after the #include "doctest.h" line). You can remove the sample tests that were in the file
(or comment them out to use as reference).
Process
You should focus on building and testing one function at a time. The recommended process is:
- Get the Triangle class declared in Triangle.h. Initially, just declare the class, its member variables, one constructor (your choice which one), and one getter function.
- Implement that constructor and getter in Triangle.cpp.
- Write unit tests for that constructor that uses the getter to verify it works.
- Once that is working, move on to the next function. Implement it, then write tests to verify it works.
Testing Guidelines
Your Unit tests in tests.cpp should test each public member. Each TEST_CASE should focus on testing one function. It is not okay to wrap a bunch of unrelated tests into one test function (e.g. one TEST_CASE that tests both getPerimeter and getArea). It is okay, in fact necessary, to use other functions as part of your tests—for example, it would be impossible to test the constructors without using getPoint function.
You may need multiple tests for any given function (a bool function should be tested to make sure it answers both true and false at appropriate times).
My Assignment2CircleSample project in the class git repository has sample unit tests. You won’t be writing the same exact tests, but use them as a reference.
To figure out what your answers should be, you might want to use this calculator.
Here is a sample test, for your Triangle constructor and getPoint,
to get you going. The getPoint method will be tested in lots of other
places; you do not need to write a separate test for it.
//Helper function - feel free to use in your tests
Triangle makeT1() {
Point p0(0, 0);
Point p1(6, 0);
Point p2(3, 5);
return Triangle(p0, p1, p2);
}
TEST_CASE( "Triangle/Constructor" ) {
//Set up a triangle using helper - could just do work here
Triangle t = makeT1();
//Check the vertices
//Vertex A - wordy version
Point tempA = t.getPoint(0);
Point tempAGoal(0, 0);
REQUIRE( tempA.isSameAs(tempAGoal) );
//Vertex B - check vs anonymous point
Point tempB = t.getPoint(1);
REQUIRE( tempB.isSameAs( Point(6, 0) ) );
//Vertex C - super terse - harder to debug...
REQUIRE( t.getPoint(2).isSameAs( Point(3, 5) ) );
}
Function Descriptions
Below are descriptions of expected behavior. Descriptions are written in UML format, not C++. You need to translate parameters/return types.
Remember that UML does not specify things like const qualifiers and passing by reference. It is up to you to decide where those are appropriate.
For each function, provide one or more TEST_CASES in the
tests.cpp file that show the function works. See the
Testing Guidelines.
When possible, use functions from Point to help you do work.
Triangle(p0 : Point, p1 : Point, p2 : Point)
Construct triangle using the three Points as the verticesgetPoint(number : int) : Point
Takes value expected to be 0, 1, 2 and returns corresponding vertex from triangle. (You don't have to handle bad indexes. This would be a good spot for an exception—which we learn about later. For now, just assume the argument is valid.)setPoint(number : int, p : Point)
Takes value expected to be 0, 1, 2 and a Point. Stores that point as the indicated vertex. (Again, you do not have to handle bad indexes.)getSideLength(oppositePoint : int) : double
Takes value expected to be 0, 1, 2. Calculate and return the length of the side that is opposite of the indicated point. For example, getSideLength(1) would return the length of the side opposite p1, which is the side that connects p0 and p2.getArea() : double
Calculate and return value. (Google Heron's formula)getPerimeter() : double
Calculate and return value.getAngle(number : int)
Return the measure of the given angle in degrees. (Angle 0 would be one with p0 as its vertex, Angle 1 would be one with p1 as vertex, …).Math hint: You can find the formula here (look for "Easier Version For Angles").
If the correct value of an angle to 16 significant digits is
30.12341234123456, you can't necessarily just check if your angle is== Approx(30). Approx requires your answer to be accurate within a certain percentage (0.000001 by default).So either use an approximation that goes to ~6 places, like
30.123412, or use== Approx(30.1).epsilon(0.01)to check that your answer is within 1% of the correct answer (which would be good enough to show you are calculating the angle correctly, but not good enough to show you are doing it with high precision).Remember that the
acosfunction will return angles in radians. To turn into degrees you must multiply by 180 and then divide by π.translate(xShift : double, yShift : double)
Translate is the fancy word for "move". Move the triangle by the given amount in x and y dimensions. Do so by moving all three vertices.contains(p : Point) : boolean
Return true if indicated Point is within the triangle.
Call three points of Triangle A, B, C. Two suggested strategies:Calculate area of triangles PAB, PAC, PBC. If the sum of those are approximately equal to area of ABC, P must be inside.
(This is the easier approach. Literally make 3 temporary triangles and calculate their areas.)Point P is inside a triangle if it is consistently to the right or left of segments AB, BC, and CA.
This code sample shows the math involved. You would need to adapt it to work as a member function. You can add a non-member sign function to your .cpp code as a helper to the member function.
Submission
Submit file: project.zip
See the codespace guide for instructions on how to create a .zip file of your project.