diff --git a/archimedean.cpp b/archimedean.cpp index ac1baa56..252830c8 100644 --- a/archimedean.cpp +++ b/archimedean.cpp @@ -152,6 +152,29 @@ void archimedean_tiling::make_match(int a, int i, int b, int j) { /** mostly to protect the user from entering too large numbers */ const int MAX_EDGE_ARCM = FULL_EDGE; +/** compute the edge length of an Archimedean tiling. Each element of facemul is (face sides, multiplicity) */ +EX ld compute_edgelength(vector> facemul, ld halftotal IS(M_PI)) { + ld elmin = 0, elmax = hyperbolic ? 10 : sphere ? M_PI : 2 * euclidean_edge_length; + ld edgelength; + for(int p=0; p<100; p++) { + edgelength = (elmin + elmax) / 2; + ld alpha_total = 0; + for(auto fm: facemul) { + ld gamma = M_PI / fm.first; + auto c = asin_auto(sin_auto(edgelength/2) / sin(gamma)); + hyperpoint h = xpush(c) * spin(M_PI - 2*gamma) * xpush0(c); + ld a = atan2(h); + cyclefix(a, 0); + if(a < 0) a = -a; + alpha_total += a * fm.second; + } + if(isnan(alpha_total)) elmax = edgelength; + else if(sphere ^ (alpha_total > halftotal)) elmin = edgelength; + else elmax = edgelength; + } + return edgelength; + } + void archimedean_tiling::compute_sum() { N = isize(faces); euclidean_angle_sum = 0; @@ -436,6 +459,7 @@ void archimedean_tiling::compute_geometry() { inradius[i] = 0; } else for(int p=0; p<100; p++) { + /* unfortunately we cannot just use compute_edgelength because we need to set other values */ edgelength = (elmin + elmax) / 2; ld alpha_total = 0; diff --git a/util.cpp b/util.cpp index 27317165..5d930838 100644 --- a/util.cpp +++ b/util.cpp @@ -240,19 +240,21 @@ cld exp_parser::parse(int prio) { } #if CAP_ARCM else if(eat("arcmedge(")) { - vector vals; - vals.push_back(iparse(0)); + if(!hyperbolic && !sphere) throw hr_parse_exception("arcmedge works only in hyperbolic and spherical geometry"); + vector> vals; + vals.emplace_back(rparse(0), 1); while(true) { skip_white(); - if(eat(",")) vals.push_back(iparse(0)); + if(eat(":^")) { + ld rep = rparse(0); + vals.back().second *= rep; + } + if(eat(",")) vals.emplace_back(rparse(0), 1); else break; } force_eat(")"); - arcm::archimedean_tiling test; - test.faces = vals; - test.compute_sum(); - test.compute_geometry(); - res = test.edgelength; + res = arcm::compute_edgelength(vals); + if(real(res) < 1e-10) throw hr_parse_exception("wrong geometry for this arcmedge"); if (auto *distunit = hr::at_or_null(extra_params, "distunit")) res /= *distunit; }