Skip to content

Instantly share code, notes, and snippets.

@zoecarver
Created April 8, 2020 15:55
Show Gist options
  • Save zoecarver/5b2b2abf633fd855c6fbad12621fa05e to your computer and use it in GitHub Desktop.
Save zoecarver/5b2b2abf633fd855c6fbad12621fa05e to your computer and use it in GitHub Desktop.
//
// main.cpp
// vector
//
// Created by Zoe Carver on 4/7/20.
//
#include <iostream>
#include <fstream>
#include <vector>
#include <optional>
#include <cassert>
using namespace std;
enum class Action
{
Move,
Line,
Path
};
static std::optional<Action>
classify_action( char c )
{
switch (c) {
case 'm':
case 'M':
return {Action::Move};
case 'l':
case 'L':
return {Action::Line};
case 'c':
case 'C':
return {Action::Path};
default:
return {};
}
}
struct Command
{
Action action;
double x1, y1, x2, y2, x, y;
Command( Action action,
double x = 0, double y = 0,
double x1 = 0, double y1 = 0,
double x2 = 0, double y2 = 0 )
: action( action ), x( x ), y( y ), x1( x1 ), y1( y1 ), x2( x2 ), y2( y2 )
{ }
Command( ) { }
};
static std::vector<Command>
read_commands( std::string file_name )
{
ifstream infile;
infile.open( file_name );
if ( !infile.is_open() )
{
std::cout << "ERROR: could not open file." << std::endl;
return {};
}
vector<Command> commands;
char action_c, dummy;
double x, y;
while( infile >> action_c >> x >> dummy >> y )
{
auto action = classify_action( action_c );
if ( !action )
{
std::cout << "ERROR: could not classify action '" << action_c << "'\n";
break;
}
if ( action == Action::Path )
{
double x1, y1, x2, y2;
infile >> x1 >> dummy >> y1 >> x2 >> dummy >> y2;
commands.emplace_back( action.value( ), x2, y2, x, y, x1, y1 );
continue;
}
commands.emplace_back( action.value( ), x, y );
}
return commands;
}
using Range = std::pair<double, double>;
static std::string
format_line( Range x, Range y, double m, double b )
{
std::string fmt = "y = %fx + %f \\\\{ %f < x < %f \\\\} \\\\{ %f < y < %f \\\\}";
size_t size = snprintf( nullptr, 0, fmt.c_str(),
m, b, x.first, x.second, y.first, y.second ) + 1;
std::unique_ptr<char[]> buff( new char[ size ] );
snprintf( buff.get(), size, fmt.c_str(),
m, b, x.first, x.second, y.first, y.second );
return std::string( buff.get(), buff.get() + size - 1 );
}
static auto empty_move = Command(Action::Move, 0, 0);
static std::string
emit_line( Command line, Command move )
{
auto delta_x = move.x - line.x;
auto delta_y = move.y - line.y;
auto m = delta_x == 0 && delta_y == 0 ? 0 : delta_y / delta_x;
auto range_x = make_pair( min( move.x, line.x ), max( move.x, line.x ) );
auto range_y = make_pair( min( move.y, line.y ), max( move.y, line.y ) );
auto b = - ( ( m * line.x ) - line.y );
return format_line( range_x, range_y, m, b );
}
static std::string
format_line( Range p1, Range p2, Range p3, Range p4 )
{
std::string fmt =
"("
"((1-t)^{3}%f + 3t(1-t)^{2}%f + 3t^{2}(1-t)%f + t^{3} %f),"
"((1-t)^{3}%f + 3t(1-t)^{2}%f + 3t^{2}(1-t)%f + t^{3} %f)"
")";
size_t size = snprintf( nullptr, 0, fmt.c_str(),
p1.first, p2.first, p3.first, p4.first,
p1.second, p2.second, p3.second, p4.second ) + 1;
std::unique_ptr<char[]> buff( new char[ size ] );
snprintf( buff.get(), size, fmt.c_str(),
p1.first, p2.first, p3.first, p4.first,
p1.second, p2.second, p3.second, p4.second );
return std::string( buff.get(), buff.get() + size - 1 );
}
static std::string
emit_path( Command path, Command move )
{
return format_line( make_pair(move.x, move.y),
make_pair(path.x1, path.y1),
make_pair(path.x2, path.y2),
make_pair(path.x, path.y) );
}
static std::string
format_calc( std::string eq, int index )
{
std::string fmt = " calculator.setExpression({ id: 'graph%d', latex: '%s' });";
size_t size = snprintf( nullptr, 0, fmt.c_str(), index, eq.c_str() ) + 1;
std::unique_ptr<char[]> buff( new char[ size ] );
snprintf( buff.get(), size, fmt.c_str(), index, eq.c_str() );
return std::string( buff.get(), buff.get() + size - 1 );
}
int
main( int, const char * argv[] )
{
std::optional<Command> last;
std::vector<Command> commands = read_commands( argv[1] );
std::vector<std::string> eqs;
for ( Command c : commands )
{
if ( c.action == Action::Move )
{
last = c;
continue;
}
if ( c.action == Action::Line )
{
eqs.push_back( emit_line( c, last ? last.value() : empty_move ) );
last = c;
}
if ( c.action == Action::Path )
{
eqs.push_back( emit_path( c, last ? last.value() : empty_move ) );
last = c;
}
}
int index = 0;
for ( auto &s : eqs )
std::cout << format_calc(s, index++) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment