Triangle


General

  • All submissions must include a work history to be worth credit.
  • Submit all files to elearn. 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.

Requirements

Submit file: assign2.zip

Make sure to compress your entire folder, not just your code file.

Provide doxygen comments for all public members in your Triangle.h file.

If I place all your code in one folder along with doctest.h and my Point.h and Point.cpp, I should be able to do this to build your code:

g++ -g -std=c++17 Point.cpp Triangle.cpp tests.cpp -o tests.exe

Overview

You will create a class Triangle that represents a triangle on a Cartesian plane. You are not writing any particular program that uses triangles, but the 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.

Setup/Starting Tips

Make a Unit Test project. You should replace the starter code in tests.cpp with your own unit tests that demonstrate the functions of your class work correctly.

Download Point.h and Point.cpp into that folder.

Make new Triangle.h and Triangle.cpp files.

Add the two new .h and .cpp files to HEADERS and TEST_FILES sections of the Makefile.

# list .h files here
HEADERS = Triangle.h Point.h

# list .cpp files here
TEST_FILES = tests.cpp Triangle.cpp Point.cpp

Triangle Details

Here is a UML diagram of what you are building.

A UML diagram of the Triangle and Point classes

Below are descriptions of expected behavior. Descriptions are written in UML format, not C++. You need to translate parameters/return types. UML also does not specify things like const qualifiers and passing by reference; it is up to you to use them where it is appropriate.

For each function, provide one or more TEST_CASES in the tests.cpp file that show the function works. See the Testing Guidelines below.

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 vertices

  • getPoint(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 just check if your angle is == Approx(30.1). Approx requires your answer to be accurate to about 6 significant digits. So to write a test, you must calculate the answer out (either with a calculator or code) so that you know it to at least 6 digits of precision. For the number listed above, that would be 30.1234 (2 digits to left of decimal, plus 4 digits to right is 6 total digits). So your test would have to check == Approx(30.1234) to work.

    Remember that the acos function will return angles in radians. To turn into degrees you must multiply by 180 and then divide by π.

    For π (PI), you will likely want to make your own constant. Since doubles provide 15-16 digits of accuracy, you will want to use that many digits in your const (something like 3.141592653589793). Putting this const in your .h file (outside of the class) means it will be available in any files that include the .h.

  • 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.)

    • 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.

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) ) );
}