Triangles with fill instead of stroke
This commit is contained in:
parent
4ceb2dbc70
commit
12ef45abfa
1 changed files with 31 additions and 48 deletions
79
main.cpp
79
main.cpp
|
@ -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;
|
||||||
|
|
Reference in a new issue