PPP2 Chapter 14 Exercise 5

Pages: 12
Exercise specifications:

Define a Striped_rectangle where instead of fill, the rectangle is “filled”
by drawing one-pixel-wide horizontal lines across the inside of the rectangle (say, draw every second line like that). You may have to play with the
width of lines and the line spacing to get a pattern you like.


Here's my code (main() isn't filled in yet).

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Osman Zakir
// 6 / 4 / 2017
// Bjarne Stroutrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 14 Exercise 5
// chapter14ex5.vcxproj -> main.cpp
// Exercise Specifications:
/**
 * Define a Striped_rectangle where instead of fill, the rectangle is “filled”
 * by drawing one-pixel-wide horizontal lines across the inside of the rectangle
 * (say, draw every second line like that). You may have to play with the
 * width of lines and the line spacing to get a pattern you like.
 */

#include <iostream>
#include <vector>
#include "../../Graph.h"
#include "../../Simple_window.h"

class Striped_rectangle : public Graph_lib::Shape
{
public:
	Striped_rectangle::Striped_rectangle(const Graph_lib::Point &xy,
		const Graph_lib::Color &stripe_color, const int stripe_width, const int width, const int height);
	void draw_lines();
	void set_fill(const Graph_lib::Color& color, const int stripe_width);
	void set_stripe_color(const Graph_lib::Color &color) { m_stripe_color = color; }
	void set_stipe_width(int width) { m_stripe_width = width; }
	const Graph_lib::Color stripe_color() const { return m_stripe_color; }
	std::size_t number_of_points() const { return m_points.size(); }
	int stripe_width() const { return m_stripe_width; }
	std::vector<Graph_lib::Point> fill_points_v();
private:
	Graph_lib::Color m_stripe_color;
	std::vector<Graph_lib::Point> m_points;
	int m_stripe_width;
	int m_width;
	int m_height;
};

int main()
{

}

Striped_rectangle::Striped_rectangle(const Graph_lib::Point &xy,
	const Graph_lib::Color &stripe_color, const int stripe_width, const int width, const int height)
:m_stripe_color{ stripe_color },
m_stripe_width{ stripe_width }, m_width{ width }, m_height{ height }
{
	if (m_height <= 0 || m_width <= 0)
	{
		error("Bad rectangle: non-positive side");
	}
	if (m_stripe_width <= 0)
	{
		error("Invalid stripe width");
	}
	add(xy);
}

std::vector<Graph_lib::Point> Striped_rectangle::fill_points_v()
{
	using namespace std;
	for (size_t i = 0; i < m_height; i += 2)
	{
		
	}
}

void Striped_rectangle::draw_lines()
{
	set_fill(m_stripe_color, m_stripe_width);
	
	if (fill_color().visibility()) {	// fill
		fl_color(fill_color().as_int());
		fl_rectf(point(0).x, point(0).y, m_width, m_height);
		fl_color(color().as_int());	// reset color
	}

	if (color().visibility()) {	// edge on top of fill
		fl_color(color().as_int());
		fl_rect(point(0).x, point(0).y, m_width, m_height);
	}
}

void Striped_rectangle::set_fill(const Graph_lib::Color& color, const int stripe_width)
{
	Lines striped_lines;
	
	striped_lines.set_color(color);
}



I need help with Striped_rectangle::fill_points_v() (for filling the vector with the points I need to add to the striped_lines object I have in Striped_rectangle::set_fill()), as well as with Striped_rectangle::set_fill() itself. Though right now I can just fill the vector and go over it in a loop within Striped_rectangle::set_fill() to add the points to striped_lines. I'm iterating until m_height in the loop in Striped_rectangle::fill_pionts_v() because the stripes have to go into the rectangle over the height of the rectangle, and I thought to increment in intervals of 2 because the stripes have to skip one line each.
As far as I see you have to add a Lines member to your Striped_rectangle class. This member must be initialized in your Striped_rectangle constructor. Therefore you must calculate the points and pass them to the Lines() constructor.

At last you must ensure that in your Stripped_rectangle::draw_lines() method the draw_lines() method of your Lines-object will be invoked.
So I take out set_fill() and also call Lines' draw_lines() in Striped_rectangle::draw_lines()? And is everything else fine, or is there something I need to change or fix?

Edit: Copy constructors and assignment operators for all Shapes are deleted functions, so I can't initialize Lines in the constructor or create getters or setters for it.
Last edited on
So I take out set_fill() and also call Lines' draw_lines() in Striped_rectangle::draw_lines()?
If I not had not something important part overlooked, that's the way how I would approach.
And is everything else fine, or is there something I need to change or fix?
The suggestions I made I have considered after a roughly look over your code ( and the Graph.h file which lies fortuitously besides the other Graph_lib bundle still on my disk). Maybe I have something overlooked. Sure can you only be by testing your code. Good hunting!
Last edited on
I'll say this again here just in case it was missed earlier:
Copy constructors and assignment operators for all Shapes are deleted functions, so I can't initialize Lines in the constructor or create getters or setters for it.


So I need another way to initialize Lines. Please suggest a good "clone" function (as one alternative to copy constructors and assignment operators).

You don't need a copy constructor nor a assignment operator. You can use the standard constructor.
I'm trying to do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Striped_rectangle::Striped_rectangle(const Point &xy, const Lines &striped_lines,
	const Color &stripe_color, const int stripe_width, const int width, const int height)
	:m_stripe_color{ stripe_color }, m_striped_lines{striped_lines}, 
	m_stripe_width{ stripe_width }, m_width{ width }, m_height{ height }
{
	if (m_height <= 0 || m_width <= 0)
	{
		error("Bad rectangle: non-positive side");
	}
	if (m_stripe_width <= 0)
	{
		error("Invalid stripe width");
	}
	add(xy);
}


But the m_striped_lines{striped_lines} part is giving me trouble; {striped_lines} is flagged as an error and the reason the compiler is giving me is as you see here (warning: it's long):

1>c:\users\osman\programming\visual studio 2017\projects\programming_principles_practice_using_c++\chapter14ex5\chapter14ex5\main.cpp(51): error C2280: 'Graph_lib::Lines::Lines(const Graph_lib::Lines &)': attempting to reference a deleted function
1>c:\users\osman\programming\visual studio 2017\projects\programming_principles_practice_using_c++\graph.h(239): note: compiler has generated 'Graph_lib::Lines::Lines' here
1>c:\users\osman\programming\visual studio 2017\projects\programming_principles_practice_using_c++\graph.h(239): note: 'Graph_lib::Lines::Lines(const Graph_lib::Lines &)': function was implicitly deleted because a base class invokes a deleted or inaccessible function 'Graph_lib::Shape::Shape(const Graph_lib::Shape &)'
1>c:\users\osman\programming\visual studio 2017\projects\programming_principles_practice_using_c++\graph.h(153): note: 'Graph_lib::Shape::Shape(const Graph_lib::Shape &)': function was explicitly deleted


So yeah, the function I'm referencing when I try to do this is deleted. So I need a "clone" function.
I mean it such:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Striped_rectangle : ...
{
    ...
    Lines striped_lines;  // The Lines object should be a member of Striped_rectangle. 
                                         //Should be unset at at begin.
   ...
};

Striped_rectangle::Striped_rectangle( ... )
{
    ...
    // calculate the Points for stripped_lines
    ...
    striped_lines = Lines{ /* here the calculated points list */ };  // Here will stripped_lines be initialized.
}

Striped_rectangle::draw_lines()
{
    ...
    striped_lines.draw_lines();
    ...
}

This should work because stripped_lines is still unset at the Shaped_rectangle() call. But I'm not sure.
I'll try. But I need some clarification first: doing it this way doesn't require m_striped_lines{striped_lines}? I'm pretty sure I'll need it inside the function definition, though, which will cause the compile to yell at me. The only way is to either do striped_lines.Lines::Lines{/* Points list here */} or to use Lines::add() to add points to Lines. Using the assignment operator will flag an error because the assignment operator is a deleted function (and it also calls a copy constructor, which is again a deleted function).

But I also need help actually calculating the points to make the stripes.

Edit: This is what I have now:
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Osman Zakir
// 6 / 4 / 2017
// Bjarne Stroutrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 14 Exercise 5
// chapter14ex5.vcxproj -> main.cpp
// Exercise Specifications:
/**
 * Define a Striped_rectangle where instead of fill, the rectangle is “filled”
 * by drawing one-pixel-wide horizontal lines across the inside of the rectangle
 * (say, draw every second line like that). You may have to play with the
 * width of lines and the line spacing to get a pattern you like.
 */

#include <iostream>
#include <vector>
#include "../../Graph.h"
#include "../../Simple_window.h"

namespace Graph_lib
{
	class Striped_rectangle : public Shape
	{
	public:
		Striped_rectangle::Striped_rectangle(const Point &xy, const Lines &striped_lines, 
			const Color &stripe_color, const int stripe_width, const int width, const int height);
		void draw_lines();
		void set_stripe_color(const Color &color) { m_stripe_color = color; }
		void set_stipe_width(int width) { m_stripe_width = width; }
		const Color stripe_color() const { return m_stripe_color; }
		std::size_t number_of_points() const { return m_points.size(); }
		int stripe_width() const { return m_stripe_width; }
	private:
		Color m_stripe_color;
		std::vector<Point> m_points;
		Lines m_striped_lines;
		int m_stripe_width;
		int m_width;
		int m_height;
	};
}

int main()
{

}

Striped_rectangle::Striped_rectangle(const Point &xy, const Lines &striped_lines,
	const Color &stripe_color, const int stripe_width, const int width, const int height)
	:m_stripe_color{ stripe_color },  
	m_stripe_width{ stripe_width }, m_width{ width }, m_height{ height }
{
	if (m_height <= 0 || m_width <= 0)
	{
		error("Bad rectangle: non-positive side");
	}
	if (m_stripe_width <= 0)
	{
		error("Invalid stripe width");
	}
	
	for (int i = 0; i < m_height; ++i)
	{
		m_striped_lines.add(Point{ xy.x * i, xy.y * i }, Point{xy.x * i + i, xy.y * i + i});
	}
	add(xy);
}

void Striped_rectangle::draw_lines()
{	
	if (fill_color().visibility()) {	// fill
		fl_color(fill_color().as_int());
		fl_rectf(point(0).x, point(0).y, m_width, m_height);
		fl_color(color().as_int());	// reset color
	}

	if (color().visibility()) {	// edge on top of fill
		fl_color(color().as_int());
		fl_rect(point(0).x, point(0).y, m_width, m_height);
	}

	m_striped_lines.draw_lines();
}
Last edited on
doing it this way doesn't require m_striped_lines{striped_lines}?
No, that's not needed.
The only way is to either do striped_lines.Lines::Lines{/* Points list here */}
This doesn't work.
or to use Lines::add() to add points to Lines
This seems a good way.
But I also need help actually calculating the points to make the stripes.
Calculate the stripes relatively to the rectangle's size and then add the rectangle's position to all these.
Help me from here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Striped_rectangle::Striped_rectangle(const Point &xy, const Lines &striped_lines,
	const Color &stripe_color, const int stripe_width, const int width, const int height)
	:m_stripe_color{ stripe_color },  
	m_stripe_width{ stripe_width }, m_width{ width }, m_height{ height }
{
	if (m_height <= 0 || m_width <= 0)
	{
		error("Bad rectangle: non-positive side");
	}
	if (m_stripe_width <= 0)
	{
		error("Invalid stripe width");
	}
	
	for (int i = 0; i < m_height; ++i)
	{
		m_striped_lines.add(Point{ xy.x * i, xy.y * i }, Point{xy.x * i + i, xy.y * i + i});
	}
	add(xy);
}


Note: Rest of the code is in my previous post.

And thanks.
Last edited on
I haven't been following this thread too closely, but the problem you are having with striped_lines is that the data member of the class should be a const&, not an object. Then you don't need to copy the data passed in--no constructor needed. So, make line 35 (from the post three above):

const Lines& m_striped_lines;
Striped_rectangle::Striped_rectangle(const Point &xy, const Lines &striped_linesTry to instantiate the Lines-object within the constructor.
1
2
3
4
for (int i = 0; i < m_height / m_stripe_width; ++i)
	{
		m_striped_lines.add(Point{ xy.x, xy.y + m_stripe_width }, Point{xy.x + m_width, xy.y + m_stripe_width});
	}
Last edited on
@nuderobmonkey: Thanks for that, but that only gives me the first two points, doesn't it? Where do I get the rest? And how should I fill up the vector and use that to populate the Lines constructor's std::initialization_list?

@doug4: If I make it a const&, I can't add points to it. That's not what I want, though.
Try this:
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
Striped_rectangle::Striped_rectangle(
          const Point &xy
        , const Color &stripe_color
        , const int stripe_width
        , const int width
        , const int height
)
:  m_stripe_color{ stripe_color }
 , m_stripe_width{ stripe_width }
 , m_width{ width }
 , m_height{ height }
{
    if (m_height <= 0 || m_width <= 0)
    {
        error("Bad rectangle: non-positive side");
    }
    if (m_stripe_width <= 0)
    {
        error("Invalid stripe width");
    }
    
    add(xy);
    
    m_striped_lines = Lines;  // the default constructor is available
    
    // calculates the stripes
    for (int i = 1; i < m_height / stripe_width; ++i)
    {
        m_striped_lines.add(
              Point{ xy.x,           xy.y + i * stripe_width }
            , Point{ xy.x + m_width, xy.y + i * stripe_width }
        );
    }
}

So, I have now tested the Initialization of a member now. And it seems that the striped_lines object will be automatically initialized when a Striped_rectangle gets constructed. So we simply need to do nothing for initializing the striped_lines object. Bang! :-)
*edited*
Last edited on
But the loop needs more points, doesn't it? Right now it seems like there's only two points. Or did it create the whole Striped_rectangle object correctly when you tested it out? When I tested mine out earlier, I had nothing showing up on my window.

Edit: I tried it with those changes and I still get nothing drawn on my window.

Here's the code for references:
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Osman Zakir
// 6 / 4 / 2017
// Bjarne Stroutrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 14 Exercise 5
// chapter14ex5.vcxproj -> main.cpp
// Exercise Specifications:
/**
 * Define a Striped_rectangle where instead of fill, the rectangle is “filled”
 * by drawing one-pixel-wide horizontal lines across the inside of the rectangle
 * (say, draw every second line like that). You may have to play with the
 * width of lines and the line spacing to get a pattern you like.
 */

#include <iostream>
#include <vector>
#include "../../Graph.h"
#include "../../Simple_window.h"

namespace Graph_lib
{
	class Striped_rectangle : public Shape
	{
	public:
		Striped_rectangle(const Point &xy, 
			const Color &stripe_color, const int stripe_width, 
			const int width, const int height);
		void draw_lines();
		void set_stripe_color(const Color &color) { m_stripe_color = color; }
		void set_stipe_width(int width) { m_stripe_width = width; }
		const Color stripe_color() const { return m_stripe_color; }
		int stripe_width() const { return m_stripe_width; }
	private:
		Color m_stripe_color;
		Lines m_striped_lines;
		int m_stripe_width;
		int m_width;
		int m_height;
	};
}

int main()
{
	using namespace Graph_lib;

	constexpr int win_x{ 100 }, win_y{ 100 };
	const Point win_tl{ win_x, win_y };
	constexpr int win_width{ 600 }, win_height{ 400 };
	Simple_window win{ win_tl, win_width, win_height, "Striped Rectangle Class" };

	constexpr int rect_x{ win_width / 2 - 100 }, rect_y{ win_height / 2};
	const Point rect_tl{ rect_x, rect_y };
	constexpr int rect_width{ 200 }, rect_height{ 100 };
	Striped_rectangle striped_rect{ rect_tl, Color::blue, 2, rect_width, rect_height };
	striped_rect.set_color(Color::black);

	win.attach(striped_rect);
	win.wait_for_button();
}

Striped_rectangle::Striped_rectangle(const Point &xy,
	const Color &stripe_color, const int stripe_width, 
	const int width, const int height)
	:m_stripe_color{ stripe_color }, m_stripe_width{ stripe_width }, 
	m_width{ width }, m_height{ height }
{
	if (m_height <= 0 || m_width <= 0)
	{
		error("Bad rectangle: non-positive side");
	}
	if (m_stripe_width <= 0)
	{
		error("Invalid stripe width");
	}
	
	add(xy);
	for (int i = 0; i < m_height / m_stripe_width; ++i)
	{
		m_striped_lines.add(Point{ xy.x, xy.y + i * m_stripe_width },
			Point{ xy.x + m_width, xy.y + i * m_stripe_width });
	}
}

void Striped_rectangle::draw_lines()
{	
	m_striped_lines.draw_lines();
	
	if (fill_color().visibility()) {	// fill
		fl_color(fill_color().as_int());
		fl_rectf(point(0).x, point(0).y, m_width, m_height);
		fl_color(color().as_int());	// reset color
	}

	if (color().visibility()) {	// edge on top of fill
		fl_color(color().as_int());
		fl_rect(point(0).x, point(0).y, m_width, m_height);
	}
}
Last edited on
Okay, I derived Striped_rectangle from Rectangle and used Rectangle's constructor, and with that I managed to at least draw a rectangle on the window. But I still can't draw the stripes. So I need help on that now.

Here's the 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
60
61
62
63
64
65
66
67
68
69
70
71
72
// Osman Zakir
// 6 / 4 / 2017
// Bjarne Stroutrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 14 Exercise 5
// chapter14ex5.vcxproj -> main.cpp
// Exercise Specifications:
/**
 * Define a Striped_rectangle where instead of fill, the rectangle is “filled”
 * by drawing one-pixel-wide horizontal lines across the inside of the rectangle
 * (say, draw every second line like that). You may have to play with the
 * width of lines and the line spacing to get a pattern you like.
 */

#include <iostream>
#include <vector>
#include "../../Graph.h"
#include "../../Simple_window.h"

namespace Graph_lib
{
	class Striped_rectangle : public Graph_lib::Rectangle
	{
	public:
		using Rectangle::Rectangle;
		void draw_lines();
		void set_stripe_color(const Color &color) { m_stripe_color = color; }
		void set_stripe_width(int width) { m_stripe_width = width; }
		const Color stripe_color() const { return m_stripe_color; }
		int stripe_width() const { return m_stripe_width; }
	private:
		Color m_stripe_color = Color::invisible;
		Lines m_striped_lines;
		int m_stripe_width;
		int m_width;
		int m_height;
	};
}

int main()
{
	using namespace Graph_lib;

	constexpr int win_x{ 100 }, win_y{ 100 };
	const Point win_tl{ win_x, win_y };
	constexpr int win_width{ 600 }, win_height{ 400 };
	Simple_window win{ win_tl, win_width, win_height, "Striped Rectangle Class" };

	constexpr int rect_x{ (win_width / 2) - 100 }, rect_y{ (win_height / 2) - 45 };
	const Point rect_tl{ rect_x, rect_y };
	constexpr int rect_width{ 200 }, rect_height{ 100 };
	Striped_rectangle striped_rect{ rect_tl, rect_width, rect_height };
	striped_rect.set_color(Color::black);
	striped_rect.set_stripe_width(2);
	striped_rect.set_stripe_color(Color::blue);

	win.attach(striped_rect);
	win.wait_for_button();
}

void Striped_rectangle::draw_lines()
{	
	set_fill_color(Color::invisible);
	Rectangle::draw_lines();
	
	for (int i = 0; i < m_height / m_stripe_width; ++i)
	{
		m_striped_lines.add(Point{ point(0).x, point(0).y + i * m_stripe_width },
			Point{ point(0).x + m_width, point(0).y + i * m_stripe_width });
	}

	m_striped_lines.draw_lines();
}


And sorry for the double post.
Last edited on
Consider that void draw() is different to void draw() const . If you want to override a method its best if you declare it with the keyword override. Then you will get an error if your method doesn't overrides a base class method.

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include <vector>
#include "../../Graph.h"
#include "../../Simple_window.h"

namespace Graph_lib
{
class Striped_rectangle : public Shape
{
public:
    Striped_rectangle(const Point xy,  
    const int width, const int height, 
    const int stripe_width = 3, const Color stripe_color = Color::black);
    void draw_lines() const override;
    void set_stripe_color(const Color &color) { m_stripe_color = color; }
    void set_stipe_width(int width) { m_stripe_width = width; }
    const Color stripe_color() const { return m_stripe_color; }
    int stripe_width() const { return m_stripe_width; }
private:
    Color m_stripe_color;
    Lines m_striped_lines;
    int m_stripe_width;
    int m_width;
    int m_height;
};

Striped_rectangle::Striped_rectangle(
        const Point xy,
        const int width, const int height,
        const int stripe_width,
        const Color stripe_color
)
:m_stripe_color{ stripe_color }
  , m_stripe_width{ stripe_width }
  , m_width{ width }, m_height{ height }
{
    if (m_height <= 0 || m_width <= 0)
    {
         error("Bad rectangle: non-positive side");
    }
    if (m_stripe_width <= 0)
    {
        error("Invalid stripe width");
    }
    
    add(xy);
    
    // initialize m_striped_lines
    m_striped_lines.set_color( stripe_color);
    for (int i = 1; i < m_height / m_stripe_width; ++i)
    {
        m_striped_lines.add(
            Point{ point(0).x+1,             point(0).y + i * m_stripe_width },
            Point{ point(0).x + m_width - 2, point(0).y + i * m_stripe_width }
        );
    }
}

void Striped_rectangle::draw_lines() const
{	
    if (fill_color().visibility()) {	// fill
        fl_color(fill_color().as_uint());
        fl_rectf(point(0).x, point(0).y, m_width, m_height);
        fl_color(color().as_uint());	// reset color
    }

    if (color().visibility()) {	// edge on top of fill
        fl_color(color().as_uint());
        fl_rect(point(0).x, point(0).y, m_width, m_height);
    }
    
    m_striped_lines.draw();
 
}
} // namespace

int main()
{
    using namespace Graph_lib;


    Striped_rectangle rect(Point(100,100), 100, 100, 5, Color::red);

    Simple_window win( Point(50,50) , 600, 400, "Canvas" );
    win.attach(rect);
    win.wait_for_button();
}

This should definitively work (I have it tested).
Last edited on
I did it like this after looking at yours (I just didn't add those default values in the constructor):

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Osman Zakir
// 6 / 4 / 2017
// Bjarne Stroutrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 14 Exercise 5
// chapter14ex5.vcxproj -> main.cpp
// Exercise Specifications:
/**
 * Define a Striped_rectangle where instead of fill, the rectangle is “filled”
 * by drawing one-pixel-wide horizontal lines across the inside of the rectangle
 * (say, draw every second line like that). You may have to play with the
 * width of lines and the line spacing to get a pattern you like.
 */

#include <iostream>
#include <vector>
#include "../../Graph.h"
#include "../../Simple_window.h"

namespace Graph_lib
{
	class Striped_rectangle : public Shape
	{
	public:
		Striped_rectangle(const Point xy, const int width, const int height,
			const int stripe_width, const Color &stripe_color);
		void draw_lines() const override;
		void set_stripe_color(const Color &color) { m_stripe_color = color; }
		void set_stripe_width(int width) { m_stripe_width = width; }
		const Color stripe_color() const { return m_stripe_color; }
		int stripe_width() const { return m_stripe_width; }
	private:
		Color m_stripe_color = Color::invisible;
		Lines m_striped_lines;
		int m_stripe_width;
		int m_width;
		int m_height;
	};
}

int main()
{
	using namespace Graph_lib;

	constexpr int win_x{ 100 }, win_y{ 100 };
	const Point win_tl{ win_x, win_y };
	constexpr int win_width{ 600 }, win_height{ 400 };
	Simple_window win{ win_tl, win_width, win_height, "Striped Rectangle Class" };

	constexpr int rect_x{ (win_width / 2) - 100 }, rect_y{ (win_height / 2) - 45 };
	const Point rect_tl{ rect_x, rect_y };
	constexpr int rect_width{ 200 }, rect_height{ 100 };
	Striped_rectangle striped_rect{ rect_tl, rect_width, rect_height, 2, Color::blue };
	striped_rect.set_color(Color::black);

	win.attach(striped_rect);
	win.wait_for_button();
}

Striped_rectangle::Striped_rectangle(const Graph_lib::Point xy, 
	const int width, const int height, const int stripe_width, const Color &stripe_color)
	: m_width{width}, m_height{height}, 
	m_stripe_width{stripe_width}, m_stripe_color{stripe_color}
{
	if (m_width <= 0 || m_height <= 0)
	{
		error("Bad rectangle: non-positive side");
	}
	if (m_stripe_width <= 0)
	{
		error("Invalid stripe width");
	}

	add(xy);

	m_striped_lines.set_color(stripe_color);
	for (int i = 1; i < m_height / m_stripe_width; ++i)
	{
		m_striped_lines.add(Point{ point(0).x + 1, point(0).y + i * m_stripe_width },
			Point{ point(0).x + m_width - 2, point(0).y + i * m_stripe_width });
	}
}

void Striped_rectangle::draw_lines() const
{	
	if (fill_color().visibility()) 
	{	// fill
		fl_color(fill_color().as_int());
		fl_rectf(point(0).x, point(0).y, m_width, m_height);
		fl_color(color().as_int());	// reset color
	}

	if (color().visibility()) 
	{	// edge on top of fill
		fl_color(color().as_int());
		fl_rect(point(0).x, point(0).y, m_width, m_height);
	}

	m_striped_lines.draw_lines();
}


I don't know how to set the width of a Stripes object. And for some reason, the color of the stripes is always the same as that of the rectangle's edges (in this black).
Because the color:
You must take m_striped_lines.draw(), not m_striped_lines.draw_lines() within Striped_rectangle::draw_lines(). That's because fl_color() changes the color globally.

Because setting a new stripe width:
If you want to reset the stripe width, you have to clear all all the Line points in m_striped_lines and must calculate them with the new m_stripe_with value.

Also I suggest that you derive Striped_rectangle from Rectangle, not directly from Shape.
Pages: 12