I am writing code to determine if a polyline is self-intersecting or not.
If at least two links of a polyline intersect (at their internal points), it is called self-intersecting.
To begin with, I write a function to determine the intersection of two intersect segments. There I use the school straight line formula y = kx + b.
And then the function f, where I check every 2 points of 2 segments for intersection. In principle, everything works, but the code breaks when some part of the polyline does not exactly intersect, but simply "touches" some other segment of this polyline. For example, as in the test:
Test:
4
0 0
2 2
2 1
1 1
Code:
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin("input.txt");
ofstream fout("output.txt");
class peresec{
public:
double x,y;
};
int intersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
double k1, k2, b1, b2, x, y, tmp;
if(x1>=x2) {tmp=x1; x1=x2; x2=tmp; tmp=y1; y1=y2; y2=tmp;}
if(x3>=x4) {tmp=x3; x3=x4; x4=tmp; tmp=y3; y3=y4; y4=tmp;}
if(y1==y2) k1=0; else k1 = ( y2 - y1 ) / ( x2 - x1 );
if(y3==y4) k2=0; else k2 = ( y4 - y3 ) / ( x4 - x3 );
if(k1 == k2) return 0;
b1=y1-k1*x1;
b2=y3-k2*x3;
x = (b2-b1)/(k1-k2);
y = k1*x + b1;
if(x1<=x && x3<=x && x2>=x && x4>=x && !((x==x1 && y==y1) || (x==x2 && y==y2) || (x==x3 && y==y3) || (x==x4 && y==y4)))
{return 1;}
else
return 0;
}
void f(peresec *a, int n)
{
int flag;
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
{
flag=intersect(a[i].x, a[i].y, a[(i + 1) % n].x, a[(i + 1) % n].y, a[j].x, a[j].y, a[(j + 1) % n].x, a[(j + 1) % n].y);
if(flag==1) {fout << 1; return;}
}
if(flag == 0){fout << 0; return;}
}
int main()
{
long long count;
peresec *a;
if( !(fin >> count)){fout<<0; return 0;}
fin.seekg(0);
fin >> count;
if(count == 0) {fout<<0; return 0;}
a = new peresec[count];
for(int i = 0; i < count; i++){ fin >> a[i].x; fin >> a[i].y;}
f(a,count);
return 0;
}
Then, having experienced a failure on this code, I decided to change the logic of the intersect function and did something like:
bool intersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
double v1, v2, v3, v4;
v1=(x4-x3)*(y1-y3)-(y4-y3)*(x1-x3);
v2=(x4-x3)*(y2-y3)-(y4-y3)*(x2-x3);
v3=(x2-x1)*(y3-y1)-(y2-y1)*(x3-x1);
v4=(x2-x1)*(y4-y1)-(y2-y1)*(x4-x1);
if((v1*v2<0) && (v3*v4<0)) return true;
else return false;
}
But even here the code breaks on this test. Should output 1 if there is a self-intersection, otherwise 0.
Most likely the problem is in the for loop in the function f. I've already tried everything.
I also tried this:
for (int i = 0; i < n - 1; i ++)
for (int j = i + 2; i < n; j ++)
Unfortunately, it did not help.
Can you explain why the code breaks???
I am afraid that you cannot always test this locally. In the example below, it is impossible to tell if there is a crossing or not without knowing the order of the links.
Another nasty case is when an endpoint falls "on" a link, and due to numerical inaccuracies, there could be zero or two intersections detected, or, even worse, only one. And adding tolerances does not help !
In order to resolve these difficult cases, you must first question the exact reason why you want to detect those self-intersections. Because the correct decisions are application-dependent.
Related
I have been trying to work on this problem for quite some time but I seem to be stuck and not getting the results that are needed.
Lets say I want to stack some cards in my hand.
I have to use an array of structs, because each card has a name as well.
struct Creature {
std::string name;
int x, y;
};
In my main.cpp, I make the variable
Creature c[MAX_CARDS]
I can only hold 100 cards so MAX_CARDS is 100.
The thing is, there are only 10 unique cards. Each has their own name and their own size. Sizes like 2x6, 3x1, 4x2, 1x10, 8x4, 1x5, 6x2, etc...
The rule is that no card is bigger than the card below it. Sorted in a way of 'smallest' to largest. For example if card1 is 4x8 and card2 is 2x9, then these cards are unstackable, so they would get sorted to the end of the array, as it is possible for the next card drawn to be a card that could satisfy one of those cards and then be shuffled to the correct location in the array, same with cards with identical sizes for x and y, so repeats to the back. However, if card1 is 1x2 and card2 is 1x3 this can work and is stackable.
I hope that explain the logic of stackable cards, because that is the part i think im having trouble with.
template <typename T>
void sortArray(T c[], const int size) {
int positionOfMin, x1, x2, y1, y2;
T minValue, temp;
bool swap = false;
for (int i = 0; i < size; i++) {
minValue = c[i];
positionOfMin = i;
for (int j = i+1; j < size; j++) {
x1 = minValue.x;
y1 = minValue.y;
x2 = c[j].x;
y2 = c[j].y;
if(x1 < x2 && y1 < y2) {
swap = false;
}else if (((x1 > x2 && x1 > y2) || (y2 > x2 && y1 > y2)) ) {
swap = true;
}else if (x1 == x2 && y1 == y2){
swap = false;
}else{
swap = true;
}
if (swap == true) {
minValue = c[j];
positionOfMin = j;
}
}
// Swap the values to the new or same minimum value
temp = c[i];
c[i] = minValue;
c[positionOfMin] = temp;
}
}
Any ideas or help would be greatly appreciated, the results im getting are not correct at all.
Sort by (decreasing) {x, y}, they create a different stack once you encounter an unstackable card.
std::vector<std::vector<Card>> reorganize(std::vector<Card> cards)
{
std::sort(cards.begin(), cards.end(),
[](const Card& lhs, const Card& rhs){
return std::tie(rhs.width, rhs.height) < std::tie(lhs.width, lhs.height);
});
std::vector<std::vector<Card>> res;
for (const auto& card : cards) {
auto it = std::find_if(res.begin(), res.end(),
[&](const auto& stack) {
return card.height <= stack.back().height;
});
if (it == res.end()) {
res.push_back({card});
} else {
(*it).push_back(card);
}
}
return res;
}
Demo
Fairly strange thing that, I build a search tree and search it. In the search function, if I dynamically allocate memory and delete, memory limit will exceed(I am solving problem in an OJ). But if I just declare an ordinary variable, there is no out of memory issue. Code looks like this:(I recursively search a tree(similar to a 2DTree))
void Search(int x1, int x2, int y1, int y2, node* n, int* st, long long* tem) {
int nx, ny, nx1, nx2, ny1, ny2;
nx = n->x; ny = n->y;
nx1 = n->x1; nx2 = n->x2;
ny1 = n->y1; ny2 = n->y2;
node* l = n->lc;
node* r = n->rc;
if (x1 > nx2 || x2<nx1 || y1>ny2 || y2 < ny1) {
*st = 0;
*tem = 0;
return;
}
else if (x1 <= nx1 && x2 >= nx2 && y1 <= ny1 && y2 >= ny2) {
*st = n->childNum;
*tem = n->tSum;
return;
}
else {
//part with memory issue
long long* tl = new long long;
int* sl = new int;
*tl = 0; *sl = 0;
if (l) Search(x1, x2, y1, y2, l, sl, tl);
*st += (*sl );
*tem += (*tl);
delete tl, sl;
long long* tr = new long long;
int* sr = new int;
if (r) Search(x1, x2, y1, y2, r, sr, tr);
*st += (*sr);
*tem += (*tr);
delete tr, sr;
if (nx >= x1 && nx <= x2 && ny >= y1 && ny <= y2) {
*st += 1;
*tem += n->t;
}
//this goes OK
long long tl = 0;
int sl = 0;
if (l) Search(x1, x2, y1, y2, l, &sl, &tl);
*st += (sl);
*tem += (tl);
long long tr = 0;
int sr = 0;
if (r) Search(x1, x2, y1, y2, r, &sr, &tr);
*st += (sr);
*tem += (tr);
if (nx >= x1 && nx <= x2 && ny >= y1 && ny <= y2) {
*st += 1;
*tem += n->t;
}
}
return;
}
Thanks to #nwp, I realize that this is a trivial problem.
The reason that the original code didn't work is that delete has higher precedence than comma, so delete a, b, c; is the same as (delete a), b, c, so,
delete a,b,c; only deletes a.
Likewise, cin >> a,b; is the same as cin >> a;
check this
The function f(x) and the series need to end up with the same answer
This is my attempt on this task, but it gives me different results and I don't fully understand the concept of series in C++
#include <iostream>
#include <math.h>
#include <cstdlib>
using namespace std;
int main()
{
float x, y1, y2, a;
int n;
cout<<"Enter x: ";
cin>>x;
cout<<"Enter n: ";
cin>>n;
if (x == 0) x = 3.0;
y1 = 1.0/(2.0*x+5.0);
a = 1.0/11;
y2 = a;
cout<<"f(x) = "<<y1<<endl;
if(x > -5.0/2.0 && x < 17.0/2.0){
for (int k = 0; k <= n; k++){
a = (a*(-1)*pow(2.0/11.0,k))/pow(11.0,k);
y2 = y2 + a;
}
}
else{
return 1;
}
cout<<"Sum = "<<y2<<endl;
system("pause");
return 0;
}
I used any x from -2,5 to 8,5 and n up to 100
the results are always different...
the function and sum of the series are supposed to have very close, if not equal answers, but it's not in my case..
How am I supposed to do it? would be happy for an explanation)
You should probably just use the correct term for your sum:
a = pow(-2.0 / 11.0 * (x - 3), k) / 11.0;
Note that I combined the terms in the power. The division by 11 may also be moved to the end, saving some operations. But then you would need a different initialization. However, this would also allow you to calculate a incrementally. Something like this:
//Initialization
a = 1.0;
y2 = a;
double factor = -2.0 / 11.0 * (x - 3);
//...
for (int k = 1; k <= n; k++)
{
a *= factor;
y2 += a;
}
//Finally
cout << "Sum = " << y2 / 11.0f << endl;
I was wondering how would one record the previous value of a variable that changes. An example of this problem is this code down below:
int distanceFormula(int x1, int x2, int y1, int y2){
int distance;
distance = sqrt(pow((x1-x2), 2) + pow((y1-y2), 2));
return distance;
}
int main(){
for(int i = 0; i < 2; i++){
int x = rand() % 180;
int y = rand() % 180;
int x2 = rand() % 180;
int y2 = rand() % 180;
int distance = distanceFormula(x, x2, y, y2);
int priordistance = distanceFormula(x, x2, y, y2);
if(priordistance != distance){
cout<<"Yes! It worked!"<<endl;
}
}
return 0;
}
The code itself won't return "Yes! It worked!" How would one record the previous value of distance and then compare that previous value to the current value?
Edit:
Thanks for the fast comments! Really appreciate it.
To clarify the actual question, the code above is just a quick template/example. Since the value of distance will change upon the second loop around, how would one RECORD the first value of distance and set that value to priordistance and then compare the current value of distance to priordistance (whose value is really just the previous value of distance).
Simply redord the previous value in a variable.
#include <cmath>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
int distanceFormula(int x1, int x2, int y1, int y2){
int distance;
distance = sqrt(pow((x1-x2), 2) + pow((y1-y2), 2));
return distance;
}
int main(){
int priordistance = 0; // a variable used to record the value
for(int i = 0; i < 2; i++){
int x = rand() % 180;
int y = rand() % 180;
int x2 = rand() % 180;
int y2 = rand() % 180;
int distance = distanceFormula(x, x2, y, y2);
if(i > 0 && priordistance != distance){ // use i > 0 to avoid compareing with meaningless value
cout<<"Yes! It worked!"<<endl;
}
priordistance = distance; // record the value
}
return 0;
}
There is a few ways you could do this... you could define priordistance outside of your for loop, and be sure to only redefine it 1 time (since you are looping twice).
However this is not what I would do, I would simply create an array of integers that hold n number of 'distances' for your reference by index i
int[] or int *
You can do various things. You need the value to persist throughout your for loop. Note that there is no point in comparing until you have already got one prior value.
int main(){
int priordistance = 0; //lifetime outside for loop
for(int i = 0; i < 2; i++){
int x = rand() % 180;
int y = rand() % 180;
int x2 = rand() % 180;
int y2 = rand() % 180;
int distance = distanceFormula(x, x2, y, y2);
if(i && priordistance != distance){
//^---- have we got a prior value yet?
cout<<"Yes! It worked!"<<endl;
}
priordistance = distance;//remember for next time
}
return 0;
}
Do you mean something like the following?
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
int distanceFormula( int x1, int x2, int y1, int y2 )
{
int distance;
distance = std::sqrt( std::pow( x1 - x2, 2 ) + std::pow( y1 - y2, 2 ) );
return distance;
}
int main()
{
const size_t N = 2;
int distance[N];
std::srand( ( unsigned int )std::time( nullptr ) );
for ( size_t i = 0; i < N; i++ )
{
int x = rand() % 180;
int y = rand() % 180;
int x2 = rand() % 180;
int y2 = rand() % 180;
distance[i] = distanceFormula( x, x2, y, y2 );
}
if ( distance[0] != distance[1] ) std::cout << "Yes! It worked!" << std::endl;
return 0;
}
The program output is
Yes! It worked!
I am trying to write a code to solve the n-body problem and i run into trouble when using an array with all the bodies instead of using the different bodies seperately. I currently have no idea what's going wrong in my code but when i plot x in function of y for any body i get a straight line which obviously isn't right.
This is my current code:
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <fstream>
#define h 10000.0
#define N 3
#define G 6.67384*pow(10.0,-11)
using namespace std;
class particle{
public:
double kx1,kx2,kx3,kx4, kv1, kv2, kv3, kv4;
double ky1, ky2, ky3, ky4, kvy1, kvy2, kvy3, kvy4;
double x,y,vx,vy,m;
double dist(particle aap){
double dx = x - aap.x;
double dy = y - aap.y;
return sqrt(pow(dx,2.0)+pow(dy,2.0));
}
double g(double x1, double y1,particle aap){
return G*aap.m*(aap.x-x1)/pow(dist(aap),3.0);
}
double p(double x1, double y1, particle aap){
return G*aap.m*(aap.y-y1)/pow(dist(aap),3.0);
}
void update(){ //object advances 1 step
x = x + (1/6.0)*(kx1+2*kx2+2*kx3+kx4);
vx = vx + (1/6.0)*(kv1+2*kv2+2*kv3+kv4);
y = y + (1/6.0)*(ky1+2*ky2+2*ky3+ky4);
vy = vy + (1/6.0)*(kvy1+2*kvy2+2*kvy3+kvy4);
}
void create(double x1, double y1, double vx1, double vy1, double m1){
x = x1;
y = y1;
vx = vx1;
vy = vy1;
m =m1;
}
bool operator ==(particle &other){
if(x == other.x && y == other.y && vx == other.vx && vy == other.vy){
return true;
}
}
};
particle bodies[N];
void set(particle (&bodies)[N]){
bodies[0].create(1, 1, -2, 1, 2*pow(10.0,30));
bodies[1].create(2870671*pow(10.0,6), 0, 0, 6800, 8.6810*pow(10.0,25));
bodies[2].create(4498542*pow(10.0,6),0 ,0, 5430, 1.0243*pow(10.0,26));
}
double xforce(double x1, double y1, particle aap, particle bodies[N]){ //force in the x- direction
double fx = 0;
for (int i = 0; i <= N; i++){
if (bodies[i] == aap ){;}
else{
fx += aap.g(x1,y1,bodies[i]);
}
}
return fx;
}
double yforce(double x1, double y1, particle aap, particle bodies[N]){ //force in the y- direction
double fy = 0;
for (int i = 0; i <= N; i++){
if (bodies[i] == aap) {;}
else{
fy += aap.p(x1,y1,bodies[i]);
}
}
return fy;
}
void corr(double t, particle bodies[N]){ //runge kutta 4
for(int i =0; i <= N; i++){
bodies[i].kx1 = t*bodies[i].vx;
bodies[i].kv1 = t*xforce(bodies[i].x, bodies[i].y, bodies[i], bodies);
bodies[i].ky1 = t*bodies[i].vy;
bodies[i].kvy1 = t*yforce(bodies[i].x, bodies[i].y, bodies[i], bodies);
bodies[i].kx2 = t*(bodies[i].vx + 0.5*bodies[i].kv1);
bodies[i].kv2 = t*xforce(bodies[i].x + 0.5*bodies[i].kx1, bodies[i].y + 0.5*bodies[i].ky1, bodies[i], bodies);
bodies[i].ky2 = t*(bodies[i].vy + 0.5*bodies[i].kvy1);
bodies[i].kvy2 = t*yforce(bodies[i].x + 0.5*bodies[i].kx1, bodies[i].y + 0.5*bodies[i].ky1, bodies[i], bodies);
bodies[i].kx3 = t*(bodies[i].vx+ 0.5*bodies[i].kv2);
bodies[i].kv3 = t*xforce(bodies[i].x + 0.5*bodies[i].kx2, bodies[i].y + 0.5*bodies[i].ky2, bodies[i], bodies);
bodies[i].ky3 = t*(bodies[i].vy+ 0.5*bodies[i].kvy2);
bodies[i].kvy3 = t*yforce(bodies[i].x + 0.5*bodies[i].kx2, bodies[i].y + 0.5*bodies[i].ky2,bodies[i], bodies);
bodies[i].kx4 = t*(bodies[i].vx + bodies[i].kv3);
bodies[i].kv4 = t*xforce(bodies[i].x+ bodies[i].kx3, bodies[i].y + bodies[i].ky3, bodies[i], bodies);
bodies[i].ky4 = t*(bodies[i].vy + bodies[i].kvy3);
bodies[i].kvy4 = t*yforce(bodies[i].x + bodies[i].kx3, bodies[i].y + bodies[i].ky3, bodies[i], bodies);
}
}
void calculate(particle (&bodies)[N]){
set(bodies);
ofstream file;
file.open("tester.txt");
for(int i =0; i <=50000; i++){
corr(h, bodies);
for(int j = 0; j <= N; j++){
bodies[j].update();
}
if( i%1000 == 0){
file << i*h;
for(int j = 0; j <=N ; j++){
file <<" "<<bodies[j].x << " "<< bodies[j].y;
}
file <<" "<<"\n";
}
else{;}
}
file.close();
}
int main()
{
calculate(bodies);
system("pause");
return 0;
}
The problem probably lies outside of the class particle since the program worked before i started using the array bodies. Any suggestions for non essential improvements are ofcourse welcome. Another thing i'm trying to do is use std::vector instead of an array but i don't know how i could define a vector outside my functions like i defined the array bodies.
For a start, all of your i <= N are wrong, because your loop will execute 4 times (0, 1, 2, 3) instead of 3 for i < N.
You are likely experiencing energy drift, as RK4 is not symplectic, and the n-body problem is a Hamiltonian system. I had this same problem trying to use RK4 for a solar system n-body as well. So did this person. You should try another symplectic numerical method like Euler, Verlet, Ruth's 3rd, or Ruth's 4th order symplectic integrator.