Skip to content

Instantly share code, notes, and snippets.

@alf-p-steinbach
Last active April 24, 2020 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alf-p-steinbach/9d7df5abd60d144c0a8bac5f18851f9a to your computer and use it in GitHub Desktop.
Save alf-p-steinbach/9d7df5abd60d144c0a8bac5f18851f9a to your computer and use it in GitHub Desktop.
SVG graphics via cout (the C curve)
#include "draw_c_curve_on.hpp" // draw_c_curve_on
namespace g = graphics;
#include "util-string_from.hpp"
using util::string_from;
#include <iostream>
#include <string>
using std::cout, std::endl, std::ostream,
std::string;
class Attribute
{
string m_name;
string m_value;
public:
template< class Value >
Attribute( const string& name, const Value& value ):
m_name( name ),
m_value( string_from( value ) )
{}
friend auto operator<<( ostream& stream, const Attribute& Attribute )
-> ostream&
{ return stream << Attribute.m_name << "=\"" << Attribute.m_value << "\""; }
};
class Svg_canvas:
public g::Canvas
{
string m_stroke_color = "black";
public:
Svg_canvas( const g::Point& a_size ):
g::Canvas( a_size )
{}
void line( const g::Point& from, const g::Point& to ) override
{
cout << "<line "
<< Attribute( "x1", from.x ) << " " << Attribute( "y1", from.y ) << " "
<< Attribute( "x2", to.x ) << " " << Attribute( "y2", to.y ) << " "
<< Attribute( "stroke", m_stroke_color ) << " "
<< "/>" << endl;
}
};
auto main()
-> int
{
const int w = 600;
const int h = 400;
cout << R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?>)" << endl;
cout << "<svg "
<< Attribute( "width", w ) << " " << Attribute( "height", h ) << " "
<< Attribute( "xmlns", "http://www.w3.org/2000/svg" ) << " "
<< ">" << endl;
Svg_canvas canvas( {w, h} );
draw_c_curve_on( canvas );
cout << "</svg>" << endl;
}
#pragma once
#include "graphics.hpp"
namespace impl
{
namespace g = graphics;
void c_curve( g::Canvas& canvas, const g::Point& top, const g::Point& bottom )
{
if( g::squared_distance( top, bottom ) <= 4 ) {
canvas.line( top, bottom );
} else {
const g::Point vector_up = (top - bottom)/2;
const g::Point vector_left = { vector_up.y, -vector_up.x };
const g::Point left_middle = bottom + vector_up + vector_left;
c_curve( canvas, top, left_middle );
c_curve( canvas, left_middle, bottom );
}
}
} // impl
inline void draw_c_curve_on( graphics::Canvas& canvas )
{
const auto size = canvas.size();
impl::c_curve( canvas, {3*size.x/4, size.y/4}, {3*size.x/4, size.y - size.y/4} );
}
#pragma once
namespace graphics
{
struct Point
{
int x;
int y;
};
inline auto squared_distance( const Point& a, const Point& b )
-> int
{
constexpr auto squared = []( int x ) -> int { return x*x; };
return squared( b.x - a.x ) + squared( b.y - a.y );
}
inline auto operator+( const Point& a, const Point& b )
-> Point
{ return { a.x + b.x, a.y + b.y }; }
inline auto operator-( const Point& a, const Point& b )
-> Point
{ return { a.x - b.x, a.y - b.y }; }
inline auto operator/( const Point& a, const int c )
-> Point
{ return { a.x/c, a.y/c }; }
class Canvas
{
Point m_size;
public:
auto size() const -> Point { return m_size; }
virtual void line( const Point& from, const Point& to ) = 0;
Canvas( const Point& a_size ):
m_size( a_size )
{}
};
} // namespace graphics
#pragma once
#include <string>
#include <string_view>
namespace util
{
using std::string, std::to_string,
std::string_view;
inline auto string_from( const string_view& s )
-> const string_view
{ return s; }
template<
class Value,
bool enable_this_template = !!sizeof( to_string( Value() ) )
>
inline auto string_from( const Value& value )
-> string
{ return to_string( value ); }
} // namespace util
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment