|
@ -10,6 +10,14 @@ struct pt { |
|
|
ld x = 0, y = 0; |
|
|
ld x = 0, y = 0; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
bool operator<(pt lhs, pt rhs) { |
|
|
|
|
|
return make_pair(lhs.x, lhs.y) < make_pair(rhs.x, rhs.y); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ostream& operator<<(ostream& out, pt p) { |
|
|
|
|
|
return out << p.x << ',' << p.y; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
constexpr pt zero = pt{0, 0}; |
|
|
constexpr pt zero = pt{0, 0}; |
|
|
|
|
|
|
|
|
pt operator+(pt a, pt b) { |
|
|
pt operator+(pt a, pt b) { |
|
@ -103,16 +111,11 @@ int main() { |
|
|
pt p31b = unit_triangle(p31a, {0, 0}, c1) * c1; |
|
|
pt p31b = unit_triangle(p31a, {0, 0}, c1) * c1; |
|
|
cone c31{p31a, c3, p31b, c1}; |
|
|
cone c31{p31a, c3, p31b, c1}; |
|
|
|
|
|
|
|
|
// we keep track of all lines in the construction
|
|
|
// we keep track of all triangles in the construction
|
|
|
vector<pair<pt, pt>> rays; |
|
|
vector<tuple<pt, pt, pt>> triangles; |
|
|
rays.emplace_back(zero, c1); |
|
|
triangles.emplace_back(p12a, p12b, zero); |
|
|
rays.emplace_back(zero, c2); |
|
|
triangles.emplace_back(p23a, p23b, zero); |
|
|
rays.emplace_back(zero, c3); |
|
|
triangles.emplace_back(p31a, p31b, zero); |
|
|
|
|
|
|
|
|
vector<pair<pt, pt>> lines; |
|
|
|
|
|
lines.emplace_back(p12a, p12b); |
|
|
|
|
|
lines.emplace_back(p23a, p23b); |
|
|
|
|
|
lines.emplace_back(p31a, p31b); |
|
|
|
|
|
|
|
|
|
|
|
// I use a priority queue to pick the closest cone
|
|
|
// I use a priority queue to pick the closest cone
|
|
|
priority_queue<cone_d> work; |
|
|
priority_queue<cone_d> work; |
|
@ -121,7 +124,7 @@ int main() { |
|
|
work.push(c31); |
|
|
work.push(c31); |
|
|
|
|
|
|
|
|
// we pick the closest cone to expand
|
|
|
// we pick the closest cone to expand
|
|
|
while(!work.empty() && lines.size() < 2000) { |
|
|
while(!work.empty() && triangles.size() < 2000) { |
|
|
auto c = work.top().c; |
|
|
auto c = work.top().c; |
|
|
work.pop(); |
|
|
work.pop(); |
|
|
|
|
|
|
|
@ -139,15 +142,13 @@ int main() { |
|
|
const auto l = sqrt(lensqr(c.p1, c.p2)); |
|
|
const auto l = sqrt(lensqr(c.p1, c.p2)); |
|
|
const auto wiggle = l - 4; |
|
|
const auto wiggle = l - 4; |
|
|
const auto r0 = unif01(gen); |
|
|
const auto r0 = unif01(gen); |
|
|
const auto r = 2.0 / l + pow(r0, 1.5) * wiggle / l; |
|
|
const auto r = 2.0 / l + pow(r0, 1.1) * wiggle / l; |
|
|
const auto pm = (1.0 - r) * c.p1 + r * c.p2; |
|
|
const auto pm = (1.0 - r) * c.p1 + r * c.p2; |
|
|
|
|
|
|
|
|
const auto r20 = unif01(gen); |
|
|
const auto r20 = unif01(gen); |
|
|
const auto r2 = 0.001 + 0.998 * pow(r20, 1.2); |
|
|
const auto r2 = 0.001 + 0.998 * pow(r20, 1.1); |
|
|
const auto dm = r2 * c.d1 + (1.0 - r2) * c.d2; |
|
|
const auto dm = r2 * c.d1 + (1.0 - r2) * c.d2; |
|
|
|
|
|
|
|
|
rays.emplace_back(pm, dm); |
|
|
|
|
|
|
|
|
|
|
|
cone c1{c.p1, c.d1, pm, dm}; |
|
|
cone c1{c.p1, c.d1, pm, dm}; |
|
|
cone c2{pm, dm, c.p2, c.d2}; |
|
|
cone c2{pm, dm, c.p2, c.d2}; |
|
|
work.push(c1); |
|
|
work.push(c1); |
|
@ -165,49 +166,31 @@ int main() { |
|
|
// the one with a shorter edge, sounds fine to me. I reintroduce
|
|
|
// the one with a shorter edge, sounds fine to me. I reintroduce
|
|
|
// some randomness for artistic reasons. Increase 20 for wild
|
|
|
// some randomness for artistic reasons. Increase 20 for wild
|
|
|
// results.
|
|
|
// results.
|
|
|
if (lensqr(c.p1, p2b) + 20*unif01(gen) < lensqr(p1b, c.p2) + 20*unif01(gen)) { |
|
|
if (lensqr(c.p1, p2b) + 34*unif01(gen) < lensqr(p1b, c.p2) + 34*unif01(gen)) { |
|
|
cone c2{c.p1, c.d1, p2b, c.d2}; |
|
|
cone c2{c.p1, c.d1, p2b, c.d2}; |
|
|
work.push(c2); |
|
|
work.push(c2); |
|
|
lines.emplace_back(c.p1, p2b); |
|
|
triangles.emplace_back(c.p1, p2b, c.p2); |
|
|
} else { |
|
|
} else { |
|
|
cone c2{p1b, c.d1, c.p2, c.d2}; |
|
|
cone c2{p1b, c.d1, c.p2, c.d2}; |
|
|
work.push(c2); |
|
|
work.push(c2); |
|
|
lines.emplace_back(p1b, c.p2); |
|
|
triangles.emplace_back(c.p1, p1b, c.p2); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// the print an svg attribute
|
|
|
|
|
|
const auto p = [](auto str, auto v) { |
|
|
|
|
|
cout << ' ' << str << "=\"" << v << "\""; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// I roughly estimate the maximal distance from zero
|
|
|
|
|
|
ld max_l = 0; |
|
|
|
|
|
|
|
|
|
|
|
shuffle(lines.begin(), lines.end(), gen); |
|
|
|
|
|
|
|
|
|
|
|
cout << "<svg>\n"; |
|
|
cout << "<svg>\n"; |
|
|
for(auto && l : lines) { |
|
|
for(auto && t : triangles) { |
|
|
max_l = 0.5 * max_l + 0.5 * max(max_l, max(norm(l.first), norm(l.second))); |
|
|
auto p1 = get<0>(t), p2 = get<1>(t), p3 = get<2>(t); |
|
|
cout << "<line"; |
|
|
vector<ld> lengths{{norm(p2 - p1), norm(p3 - p2), norm(p1 - p3)}}; |
|
|
p("x1", l.first.x); |
|
|
sort(lengths.begin(), lengths.end()); |
|
|
p("y1", l.first.y); |
|
|
auto r = max(0.0l, min(255.0l, 70 * lengths[2])); |
|
|
p("x2", l.second.x); |
|
|
auto g = max(0.0l, min(255.0l, 70 * lengths[1])); |
|
|
p("y2", l.second.y); |
|
|
auto b = max(0.0l, min(255.0l, 256 - 100 * lengths[0])); |
|
|
p("style", "stroke:#000;stroke-width:0.1"); |
|
|
cout << "<polygon"; |
|
|
cout << "/>\n"; |
|
|
cout << " points=\"" << get<0>(t) << ' ' << get<1>(t) << ' ' << get<2>(t) << "\""; |
|
|
} |
|
|
cout << " style=\"" << "stroke-width:0.01;" |
|
|
for(auto && l : rays) { |
|
|
<< "fill:rgb(" << r << ", " << g << ", " << b << ");" |
|
|
const auto p1 = l.first; |
|
|
<< "stroke:rgb(" << max(0.0l, r-100) << ", " << max(0.0l, g-100) << ", " << max(0.0l, b-100) << ");" << "\""; |
|
|
const auto l_left = max(ld(1.0), max_l - norm(p1)); |
|
|
|
|
|
const auto p2 = p1 + (l_left / norm(l.second)) * l.second; |
|
|
|
|
|
cout << "<line"; |
|
|
|
|
|
p("x1", p1.x); |
|
|
|
|
|
p("y1", p1.y); |
|
|
|
|
|
p("x2", p2.x); |
|
|
|
|
|
p("y2", p2.y); |
|
|
|
|
|
p("style", "stroke:#000;stroke-width:0.1"); |
|
|
|
|
|
cout << "/>\n"; |
|
|
cout << "/>\n"; |
|
|
} |
|
|
} |
|
|
cout << "</svg>" << endl; |
|
|
cout << "</svg>" << endl; |
|
|