mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-29 19:40:35 +00:00
160 lines
3.8 KiB
C++
160 lines
3.8 KiB
C++
namespace rogueviz {
|
|
|
|
namespace graph {
|
|
vector<string> formula;
|
|
bool graph_on;
|
|
|
|
color_t graphcolor;
|
|
|
|
hyperpoint err = point3(500,0,0);
|
|
|
|
bool iserror(hyperpoint h) { return sqhypot_d(2, h) > 10000 || std::isnan(h[0]) || std::isnan(h[1]) || std::isnan(h[2]) || std::isinf(h[0]) || std::isinf(h[1]) || std::isinf(h[2]); }
|
|
|
|
hyperpoint xy_to_point(ld x, ld y) {
|
|
if(sphere && hypot(x, y) > 1)
|
|
return err;
|
|
return hpxy(x, y);
|
|
}
|
|
|
|
hyperpoint find_point(ld t) {
|
|
exp_parser ep;
|
|
auto &dict = ep.extra_params;
|
|
dict["t"] = t;
|
|
dict["phi"] = t * 2 * M_PI;
|
|
dict["x"] = tan(t * M_PI - M_PI/2);
|
|
for(auto& ff: formula) {
|
|
ep.s = ff;
|
|
string varname = "";
|
|
ep.at = 0;
|
|
while(!among(ep.next(), '=', -1)) varname += ep.next(), ep.at++;
|
|
ep.at++;
|
|
cld x = ep.parse();
|
|
if(!ep.ok()) return err;
|
|
dict[varname] = x;
|
|
}
|
|
if(!dict.count("y") && dict.count("r"))
|
|
return xspinpush0(real(dict["phi"]), real(dict["r"]));
|
|
if(dict.count("z") && dict.count("x"))
|
|
return hpxyz(real(dict["x"]), real(dict["y"]), real(dict["z"]));
|
|
if(dict.count("z")) {
|
|
return xy_to_point(real(dict["z"]), imag(dict["z"]));
|
|
}
|
|
return xy_to_point(real(dict["x"]), real(dict["y"]));
|
|
}
|
|
|
|
hyperpoint gcurvestart = err;
|
|
|
|
void xcurvepoint(hyperpoint h) {
|
|
curvepoint(cwtV * h);
|
|
if(iserror(gcurvestart))
|
|
gcurvestart = h;
|
|
else if(sphere && intval(gcurvestart, h) > .1) {
|
|
queuecurve(graphcolor, 0, PPR::LINE);
|
|
curvepoint(cwtV * h);
|
|
gcurvestart = h;
|
|
}
|
|
}
|
|
|
|
void finish() {
|
|
if(!iserror(gcurvestart)) {
|
|
queuecurve(graphcolor, 0, PPR::LINE);
|
|
gcurvestart = err;
|
|
}
|
|
}
|
|
|
|
int small_limit = 6, big_limit = 20;
|
|
|
|
void draw_to(ld t0, hyperpoint h0, ld t1, hyperpoint h1, int small = 0, int big = 0) {
|
|
if(iserror(h0) || iserror(h1) || intval(h0, h1) < .01) small++;
|
|
else small = 0;
|
|
if(small >= small_limit || big >= big_limit) {
|
|
xcurvepoint(h1);
|
|
return;
|
|
}
|
|
if(t1-t0 < 1e-6) {
|
|
finish();
|
|
return;
|
|
}
|
|
ld t2 = (t0 + t1) / 2;
|
|
hyperpoint h2 = find_point(t2);
|
|
draw_to(t0, h0, t2, h2, small, big+1);
|
|
draw_to(t2, h2, t1, h1, small, big+1);
|
|
}
|
|
|
|
int editwhich = -1;
|
|
|
|
void show_graph() {
|
|
cmode = sm::SIDE | sm::MAYDARK;
|
|
gamescreen(0);
|
|
dialog::init(XLAT("graph"));
|
|
for(int i=0; i<isize(formula); i++) {
|
|
if(editwhich == i) {
|
|
dialog::addItem(dialog::view_edited_string(), '1'+i);
|
|
}
|
|
else {
|
|
dialog::addItem(formula[i], editwhich == -1 ? '1'+i : 0);
|
|
dialog::add_action([i] () { editwhich = i; dialog::start_editing(formula[i]); });
|
|
}
|
|
}
|
|
|
|
dialog::addBack();
|
|
dialog::display();
|
|
|
|
keyhandler = [] (int sym, int uni) {
|
|
if(editwhich >= 0) {
|
|
if(dialog::handle_edit_string(sym, uni)) ;
|
|
else if(doexiton(sym, uni))
|
|
editwhich = -1;
|
|
}
|
|
else {
|
|
handlePanning(sym, uni);
|
|
dialog::handleNavigation(sym, uni);
|
|
// if(doexiton(sym, uni)) popScreen();
|
|
}
|
|
};
|
|
}
|
|
|
|
void frame() {
|
|
if(graphcolor) {
|
|
hyperpoint h0 = find_point(0);
|
|
hyperpoint h1 = find_point(1);
|
|
if(!iserror(h0)) xcurvepoint(h0);
|
|
draw_to(0, h0, 1, h1);
|
|
finish();
|
|
}
|
|
}
|
|
|
|
#if CAP_COMMANDLINE
|
|
int readArgs() {
|
|
using namespace arg;
|
|
|
|
if(0) ;
|
|
else if(argis("-dgraph")) {
|
|
PHASE(3);
|
|
showstartmenu = false;
|
|
pushScreen(show_graph);
|
|
shift();
|
|
while(args().find("=") != string::npos) {
|
|
formula.emplace_back(args());
|
|
shift();
|
|
}
|
|
graphcolor = arghex();
|
|
}
|
|
else if(argis("-dgs")) {
|
|
small_limit = argi();
|
|
}
|
|
else if(argis("-dgl")) {
|
|
big_limit = argi();
|
|
}
|
|
else return 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
auto xhook = addHook(hooks_args, 100, readArgs)
|
|
+ addHook(hooks_frame, 0, frame);
|
|
|
|
}
|
|
}
|