This is from Bjarne Stroustrup's C++ Programming: Principles and Practice, Chapter 13 Exercise 2:
Draw a box with rounded corners. Define a class
Box
, consisting of four lines and four arcs.
I've already defined class Arc
and using existing facilities (class Lines
) for drawing the lines.
Here is the code that draws a rounded box of random size:
roundedBox.h
//#include "GUI.h"
//#include "Simple_window.h"
//#include <iostream>
namespace Graph_lib{
// Class Arc
bool validInput(int w, int h);
class Arc: public Ellipse{
public:
Arc(Point p, int w, int h, double s, double e)
: Ellipse(Point(p.x, p.y), w, h), start(s), end(e)
{ if (!validInput(w,h)) error("Invalid input Arc"); }
void draw_lines() const;
// starting and ending angle of the arc: start from 3'oclock counterclockwise
double start;
double end;
};
// Member function
void Arc::draw_lines() const{
if(color().visibility()) fl_arc(point(0).x, point(0).y, major() , minor() , start, end);
}
//------------------------------------------------------------------------------------------------
// Class RoundedBox
class Box: public Lines{
public:
Box(Point p, int w, int h);
Box(Point ul, Point dr);
private:
Point upperLeft;
Point downRight;
int width;
int height;
// 1/4th of width and height, respectively
int roundWidth;
int roundHeight;
};
//--------------------------------------------------------------------------------------------------
// Function Implementation
// Helper function
bool validInput(int w, int h){
if (w < 0 || h < 0) return false;
else return true;
}
bool validInput(Point ul, Point dr){
if(ul.x - dr.x < 0 || ul.y - dr.y < 0) return false;
return true;
}
// Class Constructors
Box::Box(Point p, int w, int h)
: upperLeft(p), downRight(p.x + w, p.y + h), roundWidth(w / 4), roundHeight(h / 4)
{
if (!validInput(w,h)) error("Invalid input Box");
Lines::add(Point(p.x + roundWidth, p.y), Point(p.x + w - roundWidth, p.y));
Lines::add(Point(p.x + w, p.y + roundHeight), Point(p.x + w, p.y + h - roundHeight));
Lines::add(Point(p.x + w - roundWidth, p.y + h), Point(p.x + roundWidth, p.y + h));
Lines::add(Point(p.x, p.y + h - roundHeight), Point(p.x, p.y + roundHeight));
}
Box::Box(Point ul,Point dr)
: upperLeft(ul), downRight(dr), roundWidth((dr.x - ul.x) / 10.), roundHeight((dr.y - ul.y) / 10.)
{
if(!validInput(ul, dr)) error ("Invalid input Box");
Lines::add(Point(ul.x + roundWidth, ul.y), Point(dr.x - roundWidth, ul.y));
Lines::add(Point(dr.x, ul.y + roundHeight), Point(dr.x, dr.y - roundHeight));
Lines::add(Point(dr.x - roundWidth, dr.y), Point(ul.x + roundWidth, dr.y));
Lines::add(Point(ul.x, dr.y - roundHeight), Point(ul.x, ul.y + roundHeight));
}
} // end of Graph_lib namespace
roundedBox.cpp
#include "GUI.h"
#include "Simple_window.h"
#include <iostream>
#include "roundedBox.h"
//-----------------------------------------------------------------------------------------------------------------------
int main(){
// window parameters
int winWidth = 800;
int winHeight = 600;
Point center((x_max() - winWidth) / 2., (y_max() - winHeight) / 2.);
Simple_window* sw = new Simple_window(center, winWidth, winHeight, "Chapter 13 Exercise 2");
// rounded box parameters
int width = 500;
int height = 400;
int xCoord = (sw->x_max() - width) / 2;
int yCoord = (sw->y_max() - height) / 2;
try{
// draw the 4 conrer arcs clockwise, starting from the top left corner
// each center of an arc is shiftet away from the center of the rounded box by multiples of its width and height
Graph_lib::Arc ulArc(Point(xCoord + width/2, yCoord + height/2), width/2, height/2, 90, 180);
ulArc.draw_lines();
sw->attach(ulArc);
Graph_lib::Arc urArc(Point(xCoord + width, yCoord + height/2), width/2, height/2, 0, 90);
urArc.draw_lines();
sw->attach(urArc);
Graph_lib::Arc drArc(Point(xCoord + width, yCoord + height), width/2, height/2, 270, 0);
drArc.draw_lines();
sw->attach(drArc);
Graph_lib::Arc dlArc(Point(xCoord + width/2, yCoord + height), width/2, height/2, 180, 270);
dlArc.draw_lines();
sw->attach(dlArc);
// create a box with rounded corners by creating four non-intersecting lines that will match the arcs
// both arcs and roundedbox are parametrized in function of the width and height
Graph_lib::Box rb(Point(xCoord, yCoord), width, height);
sw->attach(rb);
sw->wait_for_button();
delete sw;
}catch(exception& e){
cerr << e.what() << endl;
getchar();
}catch(...){
cerr <<"Default exception!"<< endl;
getchar();
}
return 0;
}
Output:
Suggestion:
Could I alter the definition of class Box
such that includes both arcs and lines?
Note:
Until now:
- I've (unsuccessfully) tried including an override of the function
void draw_lines()
: as a result I get nothing on the screen. In addition, if classArc
is included as base class and its constructor initialized via the classBox
constructor list, I get ambiguities in thevoid draw_lines()
function. - I've (unsuccessfully) tried passing a
Simple_window w*
object to the classBox
and then use it toattach()
Arc
objects within the functionvoid draw_lines()
. - Another idea is to define class
Arcs
that holds multipleArc
objects and to add them either in the body of the classBox
constructor or invoid draw_line()
.
Additional dependencies are here. The FLTK could be found here.
class Arc: public Ellipse, public Arc{...};
, and it is not working. I'm probably not taking into consideration some inheritance properties from the already existing facilities. \$\endgroup\$ – Ziezi Sep 15 '15 at 13:20