#ifdef HAVE_CONFIG_H # include #endif #include "light.hh" #include "grafix.hh" #include "view.hh" #include Light::Light(Body *attachment, double angle1, double angle2, double strength, int stimulus) : _stimulus(stimulus), _attachment(attachment), _angle1(angle1), _angle_delta(angle2 - angle1), _strength(strength) { _gc = Grafix::line_gc(255, 255, 0); } Light::Light(const Point &p, double angle1, double angle2, double strength, int stimulus) : _stimulus(stimulus), _attachment(0), _angle1(angle1), _angle_delta(angle2 - angle1), _strength(strength) { _position = p; _gc = Grafix::line_gc(255, 255, 0); } Body * Light::clone() { return new Light(_position, _angle1, _angle1 + _angle_delta, _strength, stimulus()); } Body * Light::clone_attachment(Body *other) { return new Light(other, _angle1, _angle1 + _angle_delta, _strength, stimulus()); } void Light::place(const Point &p, double rotation) { _position = p; _angle1 = rotation - _angle_delta/2; } void Light::reset() { if (_attachment) _position = _attachment->position(); } int Light::move_phase() const { return 1; } void Light::move(double) { if (_attachment) _position = _attachment->position(); } bool Light::attached_to(const Body *b) const { return (_attachment == b); } double Light::angle1() const { if (_attachment) return _attachment->rotation() + _angle1; else return _angle1; } bool Light::has_stimulus(int stim) { return _stimulus == stim; } void Light::set_strength(double s) { _strength = s; } double Light::stimulus(int stim, Point sensor, Point &stimulus_out) { /* A light gives stimulus inversely proportional to distance from sensor. Light cannot stimulate more than strength(). */ if (stim != _stimulus) return 0; Point pos = stimulus_out = position(); double distance = Point::distance(sensor, pos); double s = strength(); double delta = angle_delta(); double fudge = (distance < s ? M_PI : M_PI * s / distance); if (delta >= 2*M_PI) return s * fudge / M_PI; /* Fuck me. This is annoying. Determine the angle overlap between the angle produced by the light and the angle read by the sensor. */ double ang1 = angle1(); while (ang1 < 0) ang1 += 2*M_PI; double beeline = (sensor - pos).angle() - fudge/2; while (beeline + fudge < ang1) beeline += 2*M_PI; double left = (beeline < ang1 ? ang1 : beeline); double right = (beeline+fudge < ang1+delta ? beeline+fudge : ang1+delta); if (left > right) return 0; else return s * (right - left) / M_PI; } void Light::draw(View *view) { Point pos = position(); double ang1 = angle1(); double ang2 = angle2(); double str = strength(); if (str) { view->fill_arc(_gc, pos, str, ang1, ang2); if (!_attachment) view->draw_arc(_gc, pos, str+5, ang1, ang2); } view->draw_arc(_gc, pos, str+2, ang1, ang2); } TimedLight::TimedLight(const Point &position, double angle1, double angle2, double strength, int stimulus, int ticks) : Light(position, angle1, angle2, strength, stimulus), _ticks(ticks), _ticks_left(0) { } TimedLight::TimedLight(Body *other, double angle1, double angle2, double strength, int stimulus, int ticks) : Light(other, angle1, angle2, strength, stimulus), _ticks(ticks), _ticks_left(0) { } Body * TimedLight::clone() { return new TimedLight(_position, _angle1, _angle1 + _angle_delta, _strength, _stimulus, _ticks); } Body * TimedLight::clone_attachment(Body *other) { return new TimedLight(other, _angle1, _angle1 + _angle_delta, _strength, _stimulus, _ticks); } void TimedLight::reset() { _ticks_left = _ticks; } void TimedLight::move(double) { if (_ticks_left) _ticks_left--; } double TimedLight::strength() const { if (_ticks_left == 0) return 0; else return _ticks_left * _strength / _ticks; } ThresholdLight::ThresholdLight(const Point &pos, double angle1, double angle2, double strength, int stim, double threshold) : Light(pos, angle1, angle2, strength, stim), _threshold(threshold), _on(false) { } ThresholdLight::ThresholdLight(Body *attachment, double angle1, double angle2, double strength, int stim, double threshold) : Light(attachment, angle1, angle2, strength, stim), _threshold(threshold), _on(false) { } Body * ThresholdLight::clone() { return new ThresholdLight(_position, _angle1, _angle1 + _angle_delta, _strength, stimulus(), _threshold); } Body * ThresholdLight::clone_attachment(Body *other) { return new ThresholdLight(other, _angle1, _angle1 + _angle_delta, _strength, stimulus(), _threshold); } void ThresholdLight::sensation(const Vector &sense) { double d = 0; for (int i = 0; i < sense.size(); i++) d += sense[i]; _on = d >= _threshold; }