/*
i have an object moving in 2d space. the space is restricted by the screen size defined with HEIGHT,
WIDTH.
the start location of the object is at start_x, start_y. the object moves on a straight line until
it hits the boundary of the screen. i know the moving direction (degrees) of the object, which lies
between 0 and 360 degrees.
Q: how can i generate a random point which is on the path the object will move until it reaches the
screen boundary?
figure: https://s...content-available-to-author-only...s.com/aww-imagedata/0353066c-5c8f-432f-88a5-9065c52adc07.png
*/
#include <iostream>
#include <cmath>
#include <cassert>
using namespace std;
// range : [min, max]
int random(int min, int max) {
static bool first = true;
if (first) {
srand(time(NULL)); //seeding for the first time only!
first = false;
}
return min + rand() % (max - min + 1);
}
bool approximately_equal(float a, float b, float epsilon) {
return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}
bool test_is_point_on_path(int start_x, int start_y, int max_x, int max_y, int heading_dir, float point_x, float point_y) {
float curr_x = start_x;
float curr_y = start_y;
float heading_rad = heading_dir * (M_PI / 180);
int inc_Len = 1;
float x_inc = cos(heading_rad) * inc_Len;
float y_inc = sin(heading_rad) * inc_Len;
while (curr_x > 0 && curr_x < max_x &&
curr_y > 0 && curr_y < max_y) {
if (approximately_equal(curr_x, point_x, 0.02) &&
approximately_equal(curr_y, point_y, 0.02)) {
return true;
}
curr_x += x_inc;
curr_y += y_inc;
}
return false;
}
std::pair<float,float> get_end_point(int start_x, int start_y, int max_x, int max_y, int heading_dir) {
int len = 0;
float end_x = 0;
float prev_end_x = 0;
float end_y = 0;
float prev_end_y = 0;
float heading_rad = heading_dir * (M_PI / 180);
while (true) {
end_x = start_x + len * cos(heading_rad);
end_y = start_y + len * sin(heading_rad);
if (end_x > max_x || end_x < 0 ||
end_y > max_y || end_y < 0) {
break;
}
prev_end_x = end_x;
prev_end_y = end_y;
len++;
}
return std::make_pair(prev_end_x, prev_end_y);
}
std::pair<float,float> rand_point_on_path(float start_x, float start_y, float end_x, float end_y, int heading_dir) {
float heading_rad = heading_dir * (M_PI / 180);
float delta_x = abs(end_x - start_x);
float delta_y = abs(end_y - start_y);
float max_len = sqrt(delta_x * delta_x + delta_y * delta_y);
int rand_len = random(0, max_len);
float calc_x = start_x + rand_len * cos(heading_rad);
float calc_y = start_y + rand_len * sin(heading_rad);
return std::make_pair(calc_x, calc_y);
}
int main() {
int start_x = 200;
int start_y = 100;
int WIDTH = 500;
int HEIGHT = 500;
int dir = 45;
cout << "start_point_x: " << start_x << ", start_point_y: " << start_y << endl;
auto end_point = get_end_point(start_x, start_y, WIDTH, HEIGHT, dir);
cout << "end_point_x: " << end_point.first << ", end_point_y: " << end_point.second << endl;
auto rand_point = rand_point_on_path(start_x, start_y, end_point.first, end_point.second, dir);
cout << "rand_point_x: " << rand_point.first << ", rand_point_y: " << rand_point.second << endl;
assert(test_is_point_on_path(start_x, start_y, WIDTH, HEIGHT, dir, rand_point.first, rand_point.second) == true);
return 0;
}
LyoKaSBoYXZlIGFuIG9iamVjdCBtb3ZpbmcgaW4gMmQgc3BhY2UuIHRoZSBzcGFjZSBpcyByZXN0cmljdGVkIGJ5IHRoZSBzY3JlZW4gc2l6ZSBkZWZpbmVkIHdpdGggSEVJR0hULCAKV0lEVEguCnRoZSBzdGFydCBsb2NhdGlvbiBvZiB0aGUgb2JqZWN0IGlzIGF0IHN0YXJ0X3gsIHN0YXJ0X3kuIHRoZSBvYmplY3QgbW92ZXMgb24gYSBzdHJhaWdodCBsaW5lIHVudGlsCml0IGhpdHMgdGhlIGJvdW5kYXJ5IG9mIHRoZSBzY3JlZW4uIGkga25vdyB0aGUgbW92aW5nIGRpcmVjdGlvbiAoZGVncmVlcykgb2YgdGhlIG9iamVjdCwgd2hpY2ggbGllcwpiZXR3ZWVuIDAgYW5kIDM2MCBkZWdyZWVzLgoKUTogaG93IGNhbiBpIGdlbmVyYXRlIGEgcmFuZG9tIHBvaW50IHdoaWNoIGlzIG9uIHRoZSBwYXRoIHRoZSBvYmplY3Qgd2lsbCBtb3ZlIHVudGlsIGl0IHJlYWNoZXMgdGhlIApzY3JlZW4gYm91bmRhcnk/CgpmaWd1cmU6IGh0dHBzOi8vcy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ucy5jb20vYXd3LWltYWdlZGF0YS8wMzUzMDY2Yy01YzhmLTQzMmYtODhhNS05MDY1YzUyYWRjMDcucG5nCiovCgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxjbWF0aD4KI2luY2x1ZGUgPGNhc3NlcnQ+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CiAKLy8gcmFuZ2UgOiBbbWluLCBtYXhdCmludCByYW5kb20oaW50IG1pbiwgaW50IG1heCkgewogICBzdGF0aWMgYm9vbCBmaXJzdCA9IHRydWU7CiAgIGlmIChmaXJzdCkgeyAgCiAgICAgIHNyYW5kKHRpbWUoTlVMTCkpOyAvL3NlZWRpbmcgZm9yIHRoZSBmaXJzdCB0aW1lIG9ubHkhCiAgICAgIGZpcnN0ID0gZmFsc2U7CiAgIH0KICAgcmV0dXJuIG1pbiArIHJhbmQoKSAlIChtYXggLSBtaW4gKyAxKTsKfQoKYm9vbCBhcHByb3hpbWF0ZWx5X2VxdWFsKGZsb2F0IGEsIGZsb2F0IGIsIGZsb2F0IGVwc2lsb24pIHsKICAgIHJldHVybiBmYWJzKGEgLSBiKSA8PSAoIChmYWJzKGEpIDwgZmFicyhiKSA/IGZhYnMoYikgOiBmYWJzKGEpKSAqIGVwc2lsb24pOwp9Cgpib29sIHRlc3RfaXNfcG9pbnRfb25fcGF0aChpbnQgc3RhcnRfeCwgaW50IHN0YXJ0X3ksIGludCBtYXhfeCwgaW50IG1heF95LCBpbnQgaGVhZGluZ19kaXIsIGZsb2F0IHBvaW50X3gsIGZsb2F0IHBvaW50X3kpIHsKCWZsb2F0IGN1cnJfeCA9IHN0YXJ0X3g7CglmbG9hdCBjdXJyX3kgPSBzdGFydF95OwoJZmxvYXQgaGVhZGluZ19yYWQgPSBoZWFkaW5nX2RpciAqIChNX1BJIC8gMTgwKTsKICAgIGludCBpbmNfTGVuID0gMTsKICAgIGZsb2F0IHhfaW5jID0gY29zKGhlYWRpbmdfcmFkKSAqIGluY19MZW47CiAgICBmbG9hdCB5X2luYyA9IHNpbihoZWFkaW5nX3JhZCkgKiBpbmNfTGVuOwogICAgICAKCXdoaWxlIChjdXJyX3ggPiAwICYmIGN1cnJfeCA8IG1heF94ICYmCgkgICAgICAgY3Vycl95ID4gMCAmJiBjdXJyX3kgPCBtYXhfeSkgewoJCQoJCWlmIChhcHByb3hpbWF0ZWx5X2VxdWFsKGN1cnJfeCwgcG9pbnRfeCwgMC4wMikgJiYKCQkgICAgYXBwcm94aW1hdGVseV9lcXVhbChjdXJyX3ksIHBvaW50X3ksIDAuMDIpKSB7CgkJCXJldHVybiB0cnVlOwoJCX0KCQkKCQljdXJyX3ggKz0geF9pbmM7CgkJY3Vycl95ICs9IHlfaW5jOwoJfQoJCglyZXR1cm4gZmFsc2U7Cn0KCnN0ZDo6cGFpcjxmbG9hdCxmbG9hdD4gZ2V0X2VuZF9wb2ludChpbnQgc3RhcnRfeCwgaW50IHN0YXJ0X3ksIGludCBtYXhfeCwgaW50IG1heF95LCBpbnQgaGVhZGluZ19kaXIpIHsKCWludCBsZW4gPSAwOwoJZmxvYXQgZW5kX3ggPSAwOwoJZmxvYXQgcHJldl9lbmRfeCA9IDA7CglmbG9hdCBlbmRfeSA9IDA7CglmbG9hdCBwcmV2X2VuZF95ID0gMDsKCWZsb2F0IGhlYWRpbmdfcmFkID0gaGVhZGluZ19kaXIgKiAoTV9QSSAvIDE4MCk7CgkKCXdoaWxlICh0cnVlKSB7CgkJZW5kX3ggPSBzdGFydF94ICsgbGVuICogY29zKGhlYWRpbmdfcmFkKTsKICAgIAllbmRfeSA9IHN0YXJ0X3kgKyBsZW4gKiBzaW4oaGVhZGluZ19yYWQpOwogICAgCQogICAgCWlmIChlbmRfeCA+IG1heF94IHx8IGVuZF94IDwgMCB8fAogICAgCSAgICBlbmRfeSA+IG1heF95IHx8IGVuZF95IDwgMCkgewogICAgCQlicmVhazsKICAgIAl9CiAgICAJCiAgICAJcHJldl9lbmRfeCA9IGVuZF94OwogICAgCXByZXZfZW5kX3kgPSBlbmRfeTsKICAgIAlsZW4rKzsKCX0KCQoJcmV0dXJuIHN0ZDo6bWFrZV9wYWlyKHByZXZfZW5kX3gsIHByZXZfZW5kX3kpOwp9CgpzdGQ6OnBhaXI8ZmxvYXQsZmxvYXQ+IHJhbmRfcG9pbnRfb25fcGF0aChmbG9hdCBzdGFydF94LCBmbG9hdCBzdGFydF95LCBmbG9hdCBlbmRfeCwgZmxvYXQgZW5kX3ksIGludCBoZWFkaW5nX2RpcikgewogICAgZmxvYXQgaGVhZGluZ19yYWQgPSBoZWFkaW5nX2RpciAqIChNX1BJIC8gMTgwKTsKICAgIGZsb2F0IGRlbHRhX3ggPSBhYnMoZW5kX3ggLSBzdGFydF94KTsKICAgIGZsb2F0IGRlbHRhX3kgPSBhYnMoZW5kX3kgLSBzdGFydF95KTsKICAgIGZsb2F0IG1heF9sZW4gPSBzcXJ0KGRlbHRhX3ggKiBkZWx0YV94ICsgZGVsdGFfeSAqIGRlbHRhX3kpOwogICAgaW50IHJhbmRfbGVuID0gcmFuZG9tKDAsIG1heF9sZW4pOwogICAgCiAgICBmbG9hdCBjYWxjX3ggPSBzdGFydF94ICsgcmFuZF9sZW4gKiBjb3MoaGVhZGluZ19yYWQpOwogICAgZmxvYXQgY2FsY195ID0gc3RhcnRfeSArIHJhbmRfbGVuICogc2luKGhlYWRpbmdfcmFkKTsKICAgIAogICAgcmV0dXJuIHN0ZDo6bWFrZV9wYWlyKGNhbGNfeCwgY2FsY195KTsKfQoJCmludCBtYWluKCkgewoJaW50IHN0YXJ0X3ggPSAyMDA7CglpbnQgc3RhcnRfeSA9IDEwMDsKCWludCBXSURUSCA9IDUwMDsKCWludCBIRUlHSFQgPSA1MDA7CglpbnQgZGlyID0gNDU7CgkKCWNvdXQgPDwgInN0YXJ0X3BvaW50X3g6ICIgPDwgc3RhcnRfeCA8PCAiLCBzdGFydF9wb2ludF95OiAiIDw8IHN0YXJ0X3kgPDwgZW5kbDsKCQoJYXV0byBlbmRfcG9pbnQgPSBnZXRfZW5kX3BvaW50KHN0YXJ0X3gsIHN0YXJ0X3ksIFdJRFRILCBIRUlHSFQsIGRpcik7Cgljb3V0IDw8ICJlbmRfcG9pbnRfeDogIiA8PCBlbmRfcG9pbnQuZmlyc3QgPDwgIiwgZW5kX3BvaW50X3k6ICIgPDwgZW5kX3BvaW50LnNlY29uZCA8PCBlbmRsOwoJCglhdXRvIHJhbmRfcG9pbnQgPSByYW5kX3BvaW50X29uX3BhdGgoc3RhcnRfeCwgc3RhcnRfeSwgZW5kX3BvaW50LmZpcnN0LCBlbmRfcG9pbnQuc2Vjb25kLCBkaXIpOwoJY291dCA8PCAicmFuZF9wb2ludF94OiAiIDw8IHJhbmRfcG9pbnQuZmlyc3QgPDwgIiwgcmFuZF9wb2ludF95OiAiIDw8IHJhbmRfcG9pbnQuc2Vjb25kIDw8IGVuZGw7CgkKCWFzc2VydCh0ZXN0X2lzX3BvaW50X29uX3BhdGgoc3RhcnRfeCwgc3RhcnRfeSwgV0lEVEgsIEhFSUdIVCwgZGlyLCByYW5kX3BvaW50LmZpcnN0LCByYW5kX3BvaW50LnNlY29uZCkgPT0gdHJ1ZSk7CgoJcmV0dXJuIDA7Cn0=