|
|
d2b2b5 |
|
|
|
d2b2b5 |
#ifndef TOOL_H
|
|
|
d2b2b5 |
#define TOOL_H
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
#include <cassert></cassert>
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
#include "raster.h"
|
|
|
e31ea0 |
#include "shape.h"
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
class Tool {
|
|
|
d2b2b5 |
public:
|
|
|
d2b2b5 |
virtual ~Tool() { }
|
|
|
d2b2b5 |
virtual Real get_radius() const = 0; // must be >= 0
|
|
|
d2b2b5 |
virtual Real get_height(Real offset) const = 0; // must be >= 0
|
|
|
8ee194 |
|
|
|
8ee194 |
virtual void calc_collision(
|
|
|
e31ea0 |
Real plane_k,
|
|
|
8ee194 |
Real &tool_height,
|
|
|
8ee194 |
Real &collision_height,
|
|
|
8ee194 |
Real &collision_offset ) const = 0;
|
|
|
8ee194 |
|
|
|
d2b2b5 |
virtual Real get_height_polar(Real distance, Real offset, Real angle) const { // must be >= distance
|
|
|
d2b2b5 |
// not exact solution, only for small angles
|
|
|
d2b2b5 |
if (distance < 1e-5) return 1e-5;
|
|
|
d2b2b5 |
Vector2 v(offset, tan(angle)*distance);
|
|
|
d2b2b5 |
return sqrt(distance*distance + v.y*v.y) + get_height(v.len());
|
|
|
d2b2b5 |
}
|
|
|
8ee194 |
|
|
|
e31ea0 |
virtual Shape* create_collision_shape(const Vector3 &pos, const Vector3 &dir) const = 0;
|
|
|
e31ea0 |
|
|
|
8ee194 |
virtual void draw(const Vector3 &pos, const Vector3 &dir) const = 0;
|
|
|
d2b2b5 |
};
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
class FlatTool: public Tool {
|
|
|
d2b2b5 |
public:
|
|
|
d2b2b5 |
Real radius;
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
explicit FlatTool(Real radius = 0.5):
|
|
|
d2b2b5 |
radius(radius) { }
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
Real get_radius() const override
|
|
|
d2b2b5 |
{ return radius; }
|
|
|
d2b2b5 |
Real get_height(Real offset) const override
|
|
|
d2b2b5 |
{ return fabs(offset) <= fabs(radius) ? 0 : INFINITY; }
|
|
|
8ee194 |
|
|
|
8ee194 |
void calc_collision(
|
|
|
e31ea0 |
Real plane_k,
|
|
|
8ee194 |
Real &tool_height,
|
|
|
8ee194 |
Real &collision_height,
|
|
|
8ee194 |
Real &collision_offset
|
|
|
8ee194 |
) const override
|
|
|
8ee194 |
{
|
|
|
8ee194 |
tool_height = 0;
|
|
|
8ee194 |
collision_height = 0;
|
|
|
8ee194 |
collision_offset = 0;
|
|
|
8ee194 |
|
|
|
e31ea0 |
if (plane_k <= 1e-5) return;
|
|
|
e31ea0 |
tool_height = collision_height = radius*plane_k;
|
|
|
8ee194 |
collision_offset = radius;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
|
|
|
d2b2b5 |
Real get_height_polar(Real distance, Real offset, Real angle) const override {
|
|
|
d2b2b5 |
if (distance < 1e-5) return 1e-5;
|
|
|
d2b2b5 |
if (!(fabs(offset) <= fabs(radius))) return INFINITY;
|
|
|
d2b2b5 |
Real t2 = tan(angle)*distance; t2 *= t2;
|
|
|
d2b2b5 |
Real r2 = radius*radius - offset*offset;
|
|
|
d2b2b5 |
return t2 <= r2 ? sqrt(distance*distance + t2) : INFINITY;
|
|
|
d2b2b5 |
}
|
|
|
8ee194 |
|
|
|
e31ea0 |
Shape* create_collision_shape(const Vector3 &pos, const Vector3 &dir) const override {
|
|
|
e31ea0 |
return new CilinderShape(radius, pos, dir);
|
|
|
e31ea0 |
}
|
|
|
e31ea0 |
|
|
|
8ee194 |
void draw(const Vector3 &pos, const Vector3 &dir) const override;
|
|
|
d2b2b5 |
};
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
class ToolPainter: public Painter {
|
|
|
d2b2b5 |
public:
|
|
|
d2b2b5 |
const Tool *tool;
|
|
|
d2b2b5 |
Vector2 scale;
|
|
|
d2b2b5 |
Real distance;
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
explicit ToolPainter(const Tool *tool = 0, const Vector2 scale = Vector2(1, 1)):
|
|
|
d2b2b5 |
tool(tool), scale(scale), distance() { }
|
|
|
d2b2b5 |
Real get_min_height() const override
|
|
|
d2b2b5 |
{ return distance; }
|
|
|
d2b2b5 |
Vector2 get_radius_xy() const override {
|
|
|
d2b2b5 |
if (!tool) return Vector2();
|
|
|
d2b2b5 |
Vector2 rxy = get_tool_radius_xy();
|
|
|
d2b2b5 |
return Vector2(rxy.x/scale.x, rxy.y/scale.y);
|
|
|
d2b2b5 |
}
|
|
|
d2b2b5 |
Real get_height_xy(const Vector2 &offset) const override {
|
|
|
d2b2b5 |
if (!tool) return INFINITY;
|
|
|
d2b2b5 |
return get_tool_height_xy(Vector2(offset.x*scale.x, offset.y*scale.y));
|
|
|
d2b2b5 |
}
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
virtual Vector2 get_tool_radius_xy() const = 0;
|
|
|
d2b2b5 |
virtual Real get_tool_height_xy(const Vector2 &offset) const = 0;
|
|
|
d2b2b5 |
};
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
class FlatToolPainter: public ToolPainter {
|
|
|
d2b2b5 |
using ToolPainter::ToolPainter; // parent constructors
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
Vector2 get_tool_radius_xy() const override {
|
|
|
d2b2b5 |
Real r = tool->get_radius();
|
|
|
d2b2b5 |
return Vector2(r, r);
|
|
|
d2b2b5 |
}
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
Real get_tool_height_xy(const Vector2 &offset) const override
|
|
|
d2b2b5 |
{ return distance + tool->get_height(offset.len()); }
|
|
|
d2b2b5 |
};
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
class PolarToolPainter: public ToolPainter {
|
|
|
d2b2b5 |
public:
|
|
|
d2b2b5 |
int coord;
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
explicit PolarToolPainter(const Tool *tool = 0, const Vector2 scale = Vector2(1, 1), int coord = 0):
|
|
|
d2b2b5 |
ToolPainter(tool, scale), coord(coord) { }
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
Vector2 get_tool_radius_xy() const override {
|
|
|
d2b2b5 |
assert(coord > 0 && coord < 2);
|
|
|
d2b2b5 |
Real r = tool->get_radius();
|
|
|
d2b2b5 |
Vector2 rxy(r, r);
|
|
|
d2b2b5 |
rxy.c[coord] = distance > 1e-5 ? rxy.c[coord]/distance : INFINITY;
|
|
|
d2b2b5 |
return rxy;
|
|
|
d2b2b5 |
}
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
Real get_tool_height_xy(const Vector2 &offset) const override {
|
|
|
d2b2b5 |
if (!tool) return INFINITY;
|
|
|
d2b2b5 |
assert(coord > 0 && coord < 2);
|
|
|
d2b2b5 |
return tool->get_height_polar(distance, offset.c[1-coord], offset.c[coord]);
|
|
|
d2b2b5 |
}
|
|
|
d2b2b5 |
};
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
|
|
|
d2b2b5 |
#endif
|