@jlb: By the vector<double> being external of the class, do you mean to make it a "helper" data object (variable equivalent of a helper function, I guess)? The exercise says to make the vector<double> a data member, though, which I assume means it should be a private member of the class. Am I wrong?
And yeah, I already knew that about vector.at() and the [] operator. I've tried using them interchangeably before, to try to experiment.
@dhayden: I'll try to see what I can do about the top-left corner. But I'm not good at this sort of math, so that's why I need help.
And I do still also need to know how to use the bar_spaces variable.
Edit: Updated code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
// Osman Zakir
// 7 / 4 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 15 Exercise 6
// chapter15ex6.cpp
// Exercise Specifications:
/**
* Design and implement a bar graph class. Its basic data is a vector<double>
* holding N values, and each value should be represented by a “bar” that is
* a rectangle where the height represents the value.
*/
#include <vector>
#include <iostream>
#include "../../Graph.h"
#include "../../Window.h"
namespace Graph_lib
{
struct Bar_graph : Shape
{
Bar_graph(const std::vector<double> &values);
void draw_lines() const;
const std::vector<double> &values_v() const { return m_values; }
const Vector_ref<Rectangle> &bars_v() const { return m_bars_v; }
private:
std::vector<double> m_values;
Vector_ref<Rectangle> m_bars_v;
};
}
int main()
{
}
Graph_lib::Bar_graph::Bar_graph::Bar_graph(const std::vector<double> &values)
:m_values{ values }
{
if (values.size() <= 0)
{
error("invalid number of values!");
}
constexpr int width = 100;
double bar_spaces = width * 1.0 / (2 * values.size() - 1);
for (std::size_t i = 0; i < values.size(); ++i)
{
int height = std::round(values[i]);
m_bars_v.push_back(new Rectangle{ Point{height / width, height}, width, height });
}
}
void Graph_lib::Bar_graph::draw_lines() const
{
for (std::size_t i = 0; i < m_bars_v.size(); ++i)
{
m_bars_v[i].draw();
}
}
|
I'm thinking of this pseudocode for the spaces:
1 2
|
if current rectangle and/or bar is the 0th bar/rectangle or greater and is not the last one
add value of bar_spaces to x-value of top_left Point of the next rectangle;
|
But how do I make the necessary if-condition for that? What do I put there? Also, would this work?
Edit2: Updated it again. I decided to not use an if-condition since it'd be doing that anyway. I just need to get top-left corner points of the "bars" right.
Anyway, here's the code (Note: I added the bars' width as an argument to the constructor and also made the width itself a private data member. Now the user can provide a width for the bars through the constructor while also being able to do so through the setter function provided by the class):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
// Osman Zakir
// 7 / 4 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 15 Exercise 6
// chapter15ex6.cpp
// Exercise Specifications:
/**
* Design and implement a bar graph class. Its basic data is a vector<double>
* holding N values, and each value should be represented by a “bar” that is
* a rectangle where the height represents the value.
*/
#include <vector>
#include <iostream>
#include "../../Graph.h"
#include "../../Window.h"
namespace Graph_lib
{
struct Bar_graph : Shape
{
Bar_graph(const int bar_width, const std::vector<double> &values);
void draw_lines() const;
int bar_width() const { return m_bar_width; }
const std::vector<double> &values_v() const { return m_values; }
const Vector_ref<Rectangle> &bars_v() const { return m_bars_v; }
void set_bar_width(const int value) { m_bar_width = value; }
private:
int m_bar_width; // width of "bars"
std::vector<double> m_values;
Vector_ref<Rectangle> m_bars_v;
};
}
int main()
{
}
Graph_lib::Bar_graph::Bar_graph(const int bar_width, const std::vector<double> &values)
:m_bar_width{ bar_width }, m_values { values }
{
const std::size_t N = values.size();
if (N == 0)
{
error("invalid number of values!");
}
double bar_spaces = bar_width * 1.0 / (2 * N - 1);
for (std::size_t i = 0; i < N; ++i)
{
int bar_height = std::round(values[i]);
m_bars_v.push_back(new Rectangle{
Point{ (bar_height / bar_width) + bar_spaces, bar_height }, bar_width, bar_height
});
}
}
void Graph_lib::Bar_graph::draw_lines() const
{
for (std::size_t i = 0; i < m_bars_v.size(); ++i)
{
m_bars_v[i].draw();
}
}
|