Browse Source

Triangles with fill instead of stroke

master
Joshua Moerman 6 years ago
parent
commit
12ef45abfa
  1. 79
      main.cpp

79
main.cpp

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

Loading…
Cancel
Save