From 0a0ecd3141391b9c40f9f9c0f2e5e3cb1f4a4821 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Apr 29 2020 13:11:32 +0000 Subject: GeneratorRadialXYZ --- diff --git a/generator.cpp b/generator.cpp index 07d3346..26831df 100644 --- a/generator.cpp +++ b/generator.cpp @@ -66,15 +66,14 @@ void GeneratorRowsZAX::touch( Vector3 pos(x, 0, 0); Real z = collider.distance_to_model(pos, dir); - if (std::isinf(z)) { + if (std::isinf(z)) + z = std::max(Real(0), z0); + + z = std::max(-z, z0); + if (z > z1 || (skip_z0 && z == z0)) tool_up(track, safe_z); - } else { - z = std::max(-z, z0); - if (z > z1 || (skip_z0 && z == z0)) - tool_up(track, safe_z); - else - tool_feed(track, safe_z, z1, z, a, x); - } + else + tool_feed(track, safe_z, z1, z, a, x); } @@ -98,8 +97,8 @@ bool GeneratorRowsZAX::generate(const Collider &collider, Track &track) const { Real min_x = this->min_x; Real max_x = this->max_x; - Real min_z = 0; - Real max_z = 0; + Real min_z = this->min_z; + Real max_z = this->max_z; Real safe_z = this->safe_z; const TriangleList &triangles = collider.model.triangles; @@ -132,7 +131,7 @@ bool GeneratorRowsZAX::generate(const Collider &collider, Track &track) const { } if (max_x + precision <= min_x) return false; - min_z = std::max(min_z, Real(0)); + min_z = std::max(min_z, -max_z); max_z = std::max(max_z, bz1); safe_z = std::max(safe_z, max_z + 1); @@ -141,18 +140,18 @@ bool GeneratorRowsZAX::generate(const Collider &collider, Track &track) const { bool forward_a = true; bool forward_x = true; - Real z1 = bz1 + precision; + Real z1 = max_z + precision; for(int iz = 0; iz < count_z; ++iz) { - Real z0 = count_z <= 1 ? min_z : max_z - iz*(max_z - min_z)/(count_z - 1); + Real z0 = count_z <= 1 ? min_z : max_z - (iz+1)*(max_z - min_z)/count_z; int count_a = 3; - if (z1 > precision) - count_a = std::max(count_a, (int)ceil(2*M_PI*z1/step_a - precision)); + if (fabs(z1) > precision) + count_a = std::max(count_a, (int)ceil(2*M_PI*fabs(z1)/step_a - precision)); Real sa = 2*M_PI/count_a; int count_aa = 0; - if (z1 > precision) - count_aa = (int)ceil(sa*z1/step_x - precision); + if (fabs(z1) > precision) + count_aa = (int)ceil(sa*fabs(z1)/step_x - precision); for(int ia = 0; ia < count_a; ++ia) { int iia = forward_a ? ia : count_a - ia - 1; diff --git a/generatorradial.cpp b/generatorradial.cpp new file mode 100644 index 0000000..a657681 --- /dev/null +++ b/generatorradial.cpp @@ -0,0 +1,218 @@ + +#include + +#include "generatorradial.h" + + +void GeneratorRadialXYZ::tool_point(Track &track, const TrackPoint &p) const { + if (!track.points.empty()) { + TrackPoint &last = track.points.back(); + if ( (last.position - p.position).len() <= precision + && fabs(last.angle - p.angle) <= precision ) + { + last.speed = p.speed; + return; + } + } + + track.points.push_back(p); +} + + +void GeneratorRadialXYZ::tool_up(Track &track, Real safe_z) const { + if (track.points.empty()) return; + + const TrackPoint &prev = track.points.back(); + if (prev.position.z == safe_z) return; + + TrackPoint p; + p.position = prev.position; + p.position.z = safe_z; + p.speed = move_speed/60.0; + + tool_point(track, p); +} + + +void GeneratorRadialXYZ::tool_feed(Track &track, Real safe_z, Real z1, Real z, Real x, Real y) const { + TrackPoint p; + p.position = Vector3(x, y, safe_z); + + if (track.points.empty() || track.points.back().position.z == safe_z) { + p.speed = move_speed/60.0; + tool_point(track, p); + + if (safe_z > z1 && z1 > z) { + p.position.z = z1; + tool_point(track, p); + } + } + + p.position.z = z; + p.speed = feed_speed/60.0; + tool_point(track, p); +} + + +void GeneratorRadialXYZ::touch( + const Collider &collider, + Track &track, + Real safe_z, Real z1, Real z0, + Real x, Real y, + bool skip_z0 ) const +{ + Vector3 dir(0, 0, -1); + Vector3 pos(x, y, 0); + + Real z = collider.distance_to_model(pos, dir); + if (std::isinf(z)) + z = -z0; + + z = std::max(-z, z0); + if (z > z1 || (skip_z0 && z == z0)) + tool_up(track, safe_z); + else + tool_feed(track, safe_z, z1, z, x, y); +} + + +bool GeneratorRadialXYZ::generate(const Collider &collider, Track &track) const { + track.points.clear(); + + const Real precision = 1e-3; + + if (collider.model.triangles.empty()) return false; + + if (step_z != 0 && step_z <= precision) return false; + if (step_a <= precision) return false; + if (step_r <= precision) return false; + if (feed_speed <= precision) return false; + if (move_speed <= precision) return false; + + std::cout << "GeneratorRadialXYZ::generate" << std::endl; + + unsigned long long max_count = 100ull*1024*1024/sizeof(track.points.front()); + + Real min_r = this->min_r; + Real max_r = this->max_r; + Real min_z = this->min_z; + Real max_z = this->max_z; + Real safe_z = this->safe_z; + + const TriangleList &triangles = collider.model.triangles; + + // calc bounds + Real br1 = 0, bz0 = INFINITY, bz1 = -INFINITY; + for(TriangleList::const_iterator i = triangles.begin(); i != triangles.end(); ++i) { + for(int j = 0; j < 3; ++j) { + const Vector3 &v = i->vertices[j]; + const Real r = sqrt(v.x*v.x + v.y*v.y); + br1 = std::max(br1, r); + bz0 = std::min(bz0, v.z); + bz1 = std::max(bz1, v.z); + } + } + + if (br1 < step_a || bz1 + precision <= bz0) { + std::cout << "GeneratorRadialXYZ::generate: zero model size" << std::endl; + return false; + } + br1 += collider.tool.get_radius() + 0.5*step_r; + + if (max_r <= min_r) { min_r = 0; max_r = br1; } + if (max_z <= min_z) { min_z = bz0; max_z = bz1; } + max_z = std::max(max_z, bz1); + + if (max_r - precision <= min_r || max_z - precision <= min_z) { + std::cout << "GeneratorRadialXYZ::generate: zero bounds" << std::endl; + return false; + } + + min_r = std::max(min_r - collider.tool.get_radius(), step_a*0.5); + safe_z = std::max(safe_z, max_z + 1); + + int count_z = step_z ? std::max(1, (int)ceil((max_z - min_z)/step_z - precision)) : 1; + + int count_rl = full_radius ? 1 : std::max(1, (int)ceil(log2(max_r/min_r) - precision) + 1); + Real kr = pow(max_r/min_r, -1/Real(count_rl)); + + Real z1 = max_z + precision; + int forward_rl = true; + for(int iz = 0; iz < count_z; ++iz) { + Real z0 = iz == count_z-1 ? min_z : max_z - (iz+1)*(max_z - min_z)/count_z; + + for(int irl = 0; irl < count_rl; ++irl) { + int iirl = forward_rl ? irl : count_rl - irl - 1; + Real r1 = max_r*pow(kr, Real(iirl)); + Real r0 = r1*kr; + + int count_a = std::max(3, (int)ceil(2*M_PI/step_a*r1 - precision)); + if (count_a%2 == 0) ++count_a; + double sa = 2*M_PI/count_a; + + int count_aa0 = std::max(1, (int)ceil(sa*r0/step_r - precision)); + int count_aa1 = std::max(1, (int)ceil(sa*r1/step_r - precision)); + + int count_r = std::max(1, (int)ceil((r1-r0)/step_r - precision)); + + int forward_r = !forward_rl; + for(int ia = 0; ia < count_a; ++ia) { + Real a = ia*sa; + + if (ia > 0) { + int count_aa = forward_r ? count_aa0 : count_aa1; + Real r = forward_r ? r0 : r1; + for(int iaa = 1; iaa < count_aa; ++iaa) { + Real aa = a - (sa - sa*iaa/count_a); + Real x = cos(aa)*r; + Real y = sin(aa)*r; + touch(collider, track, safe_z, z1, z0, x, y, skip_middle_layers); + if (track.points.size() >= max_count) break; + } + } + + Real c = cos(a); + Real s = sin(a); + for(int ir = 0; ir < count_r; ++ir) { + int iir = forward_r ? ir : count_r - ir - 1; + Real r = r0 + iir*(r1 - r0)/(count_r - 1); + touch(collider, track, safe_z, z1, z0, c*r, s*r, skip_middle_layers); + if (track.points.size() >= max_count) break; + } + + if (track.points.size() >= max_count) break; + forward_r = !forward_r; + } + assert(forward_r == forward_rl); + + if (track.points.size() >= max_count) break; + std::cout << "." << std::flush; + r1 = r0; + } + + if (track.points.size() >= max_count) break; + std::cout << std::endl << std::flush; + forward_rl = !forward_rl; + z1 = z0; + } + + tool_up(track, safe_z); + + if (track.points.size() >= max_count) { + std::cout << "GeneratorRadialXYZ::generate: reached memory limit" << std::endl; + return false; + } + + if (track.points.size() <= 1) { + std::cout << "GeneratorRadialXYZ::generate: generated track is empty" << std::endl; + return false; + } + + track.calc_length(); + track.split(0, 0.1, 0); + + std::cout << "GeneratorRadialXYZ::generate: track duration " << (track.points.back().time/60) << std::endl; + std::cout << "GeneratorRadialXYZ::generate: done" << std::endl; + return true; +} + diff --git a/generatorradial.h b/generatorradial.h new file mode 100644 index 0000000..3427c71 --- /dev/null +++ b/generatorradial.h @@ -0,0 +1,50 @@ + +#ifndef GENERATORRADIAL_H +#define GENERATORRADIAL_H + +#include "generator.h" + +class GeneratorRadialXYZ: public Generator { +public: + Real step_z; + Real step_a; + Real step_r; + + Real min_r; + Real max_r; + Real min_z; + Real max_z; + Real safe_z; + + Real feed_speed; + Real move_speed; + + bool full_radius; + bool skip_middle_layers; + + explicit GeneratorRadialXYZ(): + step_z(1), + step_a(1), + step_r(0.1), + min_r(), + max_r(), + min_z(), + max_z(), + safe_z(), + feed_speed(600), + move_speed(1500), + full_radius(false), + skip_middle_layers(false) + { } + + void tool_point(Track &track, const TrackPoint &p) const; + void tool_up(Track &track, Real safe_z) const; + void tool_feed(Track &track, Real safe_z, Real z1, Real z, Real x, Real y) const; + void touch(const Collider &collider, Track &track, Real safe_z, Real z1, Real z0, Real x, Real y, bool skip_z0) const; + + bool generate(const Collider &collider, Track &track) const override; +}; + + +#endif + diff --git a/loader.cpp b/loader.cpp index ce41ebc..e74be47 100644 --- a/loader.cpp +++ b/loader.cpp @@ -229,7 +229,7 @@ public: std::cout << "skipped degenerated triangles: " << degenerated_count << std::endl; std::cout << "loaded triangles: " << model.triangles.size() << std::endl; model.normalize(); - model.transform(Matrix4::scaling(Vector3(1000, 1000, 1000))); + //model.transform(Matrix4::scaling(Vector3(1000, 1000, 1000))); std::cout << "loaded: " << filename << std::endl; return success; diff --git a/main.cpp b/main.cpp index c55b970..0b90d5e 100644 --- a/main.cpp +++ b/main.cpp @@ -12,6 +12,7 @@ #include "loader.h" #include "collider.h" #include "generator.h" +#include "generatorradial.h" class Main { @@ -194,8 +195,9 @@ int main(int argc, char **argv) Model model; SimulatorXYZA simulator_xyza(400, 360); - //FlatTool tool(1.5); - ConeTool tool(1.25, 10, 0.75); + SimulatorXYZ simulator_xyz(400, 400); + FlatTool tool(1.5);// + 0.5); + //ConeTool tool(1.25, 10, 0.75); Collider collider(model, tool); Vector3 dir(1, 3, -3); @@ -203,7 +205,8 @@ int main(int argc, char **argv) if (argc > 1 && std::string(argv[1]) != ".") { Loader::load(app.scene->track, argv[1]); - app.scene->simulator = &simulator_xyza; + //app.scene->simulator = &simulator_xyza; + app.scene->simulator = &simulator_xyz; app.scene->simulator->simulate(app.scene->track, tool); load_track = true; } @@ -217,22 +220,41 @@ int main(int argc, char **argv) if (argc > 3 && std::string(argv[3]) != ".") { if (!load_track && load_model) { - GeneratorRowsZAX generator; - //generator.step_z = 1.5; - generator.step_z = 0; - //generator.step_a = 2*tool.radius*0.5; - generator.step_a = 0.5*1.5; - generator.step_x = 0.5; - //generator.skip_middle_layers = true; - generator.feed_speed = 150; - generator.generate(collider, app.scene->track); - app.scene->simulator = &simulator_xyza; + if (0) { + GeneratorRowsZAX generator; + generator.max_z = 26; + generator.min_z = -10; + //generator.step_z = 2.0; + generator.step_z = 5.0; + //generator.step_z = 0; + //generator.step_a = 2*(tool.radius - 0.6); + generator.step_a = 0.75; + generator.step_x = 0.5; + generator.skip_middle_layers = true; + generator.feed_speed = 150; + generator.generate(collider, app.scene->track); + app.scene->simulator = &simulator_xyza; + } else { + GeneratorRadialXYZ generator; + generator.max_z = 26; + generator.min_z = 0; + //generator.min_r = 6.5 - tool.radius - 0.1; + generator.max_r = 17.45 + tool.radius - 0.1; + //generator.full_radius = true; + generator.step_z = 2.0; + generator.step_a = 2*tool.radius - 0.5; + generator.step_r = 0.1; + //generator.skip_middle_layers = true; + generator.feed_speed = 150; + generator.generate(collider, app.scene->track); + app.scene->simulator = &simulator_xyz; + } + app.scene->simulator->simulate(app.scene->track, tool); Loader::save(app.scene->track, argv[3]); } } - app.scene->tool = &tool; app.scene->tool_dir = dir; app.scene->collider = &collider; diff --git a/raster.cpp b/raster.cpp index 8c65cc9..00d89bb 100644 --- a/raster.cpp +++ b/raster.cpp @@ -39,6 +39,65 @@ void Raster::touch(const Painter &painter, const Vector2 &position, int index, T } +Vector4 FlatRaster::color_by_distance(Real d) const { + Real dv = max_value - min_value; + Real k = fabs(dv) < 1e-5 ? 0 : (d - min_value)/dv; + return Vector4( + 1 - k, + 1 - 2*fabs(0.5 - k), + k, + 0.5 ); +} + +void FlatRaster::draw() const +{ + int w = raster.get_width(); + int h = raster.get_height(); + if (w < 2 || h < 2) return; + + Vector3 v, v0, v1; + + Real kx = (x1 - x0)/w; + Real ky = (y1 - y0)/h; + + glEnable(GL_LIGHTING); + + glBegin(GL_TRIANGLE_STRIP); + for(int r = 1; r < h; ++r) { + v0.y = y0 + (r - 1)*ky; + v1.y = y0 + r*ky; + for(int c = 0; c < w; ++c) { + v0.x = v1.x = x0 + c*kx; + v0.z = raster[r-1][c]; + v1.z = raster[r][c]; + + if (r == 1 && c == 0) v = v0; + + Vector3 dv0(v0.x - v.x, v0.y - v.y, v0.z - v.z); + Vector3 dv1(v1.x - v.x, v1.y - v.y, v1.z - v.z); + Vector3 norm( + dv0.y*dv1.z - dv0.z*dv1.y, + dv0.z*dv1.x - dv0.x*dv1.z, + dv0.x*dv1.y - dv0.y*dv1.x ); + Real l = sqrt(norm.x*norm.x + norm.y*norm.y + norm.z*norm.z); + l = l > 1e-5 ? 1/l : 0; + glNormal3d(norm.x*l, norm.y*l, norm.z*l); + + if (!c) glVertex3dv(v0.c); + glColor4dv(color_by_distance(v0.z).c); + glVertex3dv(v0.c); + glColor4dv(color_by_distance(v1.z).c); + glVertex3dv(v1.c); + v = v1; + } + glVertex3dv(v.c); + } + glEnd(); + + glDisable(GL_LIGHTING); +} + + Vector4 PolarRaster::color_by_distance(Real d) const { Real dv = max_value - min_value; Real k = fabs(dv) < 1e-5 ? 0 : (d - min_value)/dv; diff --git a/raster.h b/raster.h index c4e39e0..1f87125 100644 --- a/raster.h +++ b/raster.h @@ -93,6 +93,40 @@ public: }; +class FlatRaster { +public: + Real x0; + Real x1; + Real y0; + Real y1; + Real min_value; + Real max_value; + Raster raster; + + explicit FlatRaster( + int xpixels = 0, + int ypixels = 0, + Real x0 = 0, + Real x1 = 1, + Real y0 = 0, + Real y1 = 1, + Real min_value = 0, + Real max_value = 1 + ): + x0(x0), + x1(x1), + y0(y0), + y1(y1), + min_value(min_value), + max_value(max_value), + raster(xpixels, ypixels, min_value) + { } + + Vector4 color_by_distance(Real d) const; + void draw() const; +}; + + class PolarRaster { public: Real x0; diff --git a/scene.cpp b/scene.cpp index b1b6c67..681e8b5 100644 --- a/scene.cpp +++ b/scene.cpp @@ -15,8 +15,8 @@ Scene::Scene(): stars_seed(rand()), time(), time_forward(0.0), - time_backward(20.0), - time_speed(1.0), + time_backward(100.0), + time_speed(10.0), model_angle(), model(), simulator(), diff --git a/simulator.cpp b/simulator.cpp index 3e88df9..f5ba178 100644 --- a/simulator.cpp +++ b/simulator.cpp @@ -4,6 +4,86 @@ #include "simulator.h" +void SimulatorXYZ::simulate(const Track &track, const Tool &tool) { + points.clear(); + simu_index = 0; + raster.x0 = raster.x1 = raster.y0 = raster.y1 = raster.min_value = raster.max_value = 0; + + if (!raster.raster.get_data() || track.points.empty()) return; + + std::cout << "SimulatorXYZ::simulate" << std::endl; + std::cout << "SimulatorXYZ::simulate: track points: " << track.points.size() << std::endl; + + const TrackPoint &first = track.points.front(); + raster.x0 = raster.x1 = first.position.x; + raster.y0 = raster.y1 = first.position.y; + raster.min_value = raster.max_value = first.position.z; + for(TrackPointList::const_iterator i = track.points.begin(); i != track.points.end(); ++i) { + if (raster.x0 > i->position.x) raster.x0 = i->position.x; + if (raster.x1 < i->position.x) raster.x1 = i->position.x; + if (raster.y0 > i->position.y) raster.y0 = i->position.y; + if (raster.y1 < i->position.y) raster.y1 = i->position.y; + if (raster.min_value > i->position.z) raster.min_value = i->position.z; + if (raster.max_value < i->position.z) raster.max_value = i->position.z; + } + + const Real precision = 1e-5; + if ( raster.x1 + precision < raster.x0 + || raster.y1 + precision < raster.y0 + || raster.max_value + precision < raster.min_value ) + { + std::cout << "SimulatorXYZ::simulate: zero bounds" << std::endl; + return; + } + + raster.raster.fill(raster.max_value); + + Real x0 = raster.x0; + Real y0 = raster.y0; + Real dx = raster.x1 - x0; + Real dy = raster.y1 - y0; + Real w = raster.raster.get_width(); + Real h = raster.raster.get_height(); + + Vector2 scale_to_raster(w/dx , h/dy); + Vector2 scale_to_tool (dx/w , dy/h); + FlatToolPainter painter(&tool, scale_to_tool); + + unsigned long long max_count = 2ull*1024*1024*1024/sizeof(points.front()); + + int index = 0; + for(TrackPointList::const_iterator i = track.points.begin(); i != track.points.end(); ++i, ++index) { + painter.distance = i->position.z; + + Vector2 position( + scale_to_raster.x * (i->position.x - x0), + scale_to_raster.y * (i->position.y - y0) ); + + raster.raster.touch(painter, position, index, points); + if (points.size() >= max_count) { + std::cerr << "SimulatorXYZ::simulate: reached memory limit at time " << i->time << std::endl; + break; + } + + if (index % 1000 == 0) + std::cout << "." << std::flush; + if (index % 100000 == 0) + std::cout << std::endl << std::flush; + } + simu_index = (int)points.size(); + + std::cout << std::endl; + std::cout << "SimulatorXYZ::simulate: done" << std::endl; +} + +void SimulatorXYZ::scroll_to(int index) { + while(simu_index < (int)points.size() && points[simu_index].index <= index) + points[simu_index++].apply_next(raster.raster); + while(simu_index > 0 && points[simu_index-1].index > index) + points[--simu_index].apply_prev(raster.raster); +} + + void SimulatorXYZA::simulate(const Track &track, const Tool &tool) { points.clear(); simu_index = 0; diff --git a/simulator.h b/simulator.h index ff9efa1..530f83a 100644 --- a/simulator.h +++ b/simulator.h @@ -19,6 +19,28 @@ public: }; +class SimulatorXYZ: public Simulator { +private: + TouchPointList points; + int simu_index; + +public: + FlatRaster raster; + + explicit SimulatorXYZ(int xpixels = 0, int ypixels = 0): + simu_index(), raster(xpixels, ypixels, 0, 0, 0, 0, 0, 0) { } + + const TouchPointList& get_points() const { return points; } + int get_simu_index() const { return simu_index; } + int get_index() const { return simu_index <= 0 ? -1 : points[simu_index-1].index; } + + void simulate(const Track &track, const Tool &tool) override; + void scroll_to(int index) override; + void draw() const override + { raster.draw(); } +}; + + class SimulatorXYZA: public Simulator { private: TouchPointList points;