Distance from a point to a line/segment - c++

I have to compute the distance from a point to a line (check if it is line or a line segment). I am not sure that the bool function IsSegment is working properly. Can i have some suggestions? Thank you.
double Distance_From_Line_to_Point(int *a, int *b, int *c, bool IsSegment) {
double distance;
int dot1;
int dot2;
distance = Cross_Product(a, b, c) / Distance(a, b);
if (IsSegment(a,b,c) == true) {
dot1 = Dot_Product(a, b, c);
if (dot1 > 0) {
return Distance(b, c);
}
dot2 = Dot_Product(b, a, c);
if (dot2 > 0) {
return Distance(a, c);
}
}
return fabs(distance);
}
bool IsSegment(int *a, int *b, int *c) {
double angle1;
double angle2;
angle1 = atan(double(b[1] - a[1]) / (b[0] - a[0]));
angle2 = atan(double(c[1] - b[1]) / (c[0] - b[0]));
if ((angle2 - angle1) * (180 / PI) > 90) {
return false;
}
return true;
}

Can't you just use the formula to get the distance?
So to find the line:
void getLine(double x1, double y1, double x2, double y2, double &a, double &b, double &c)
{
// (x- p1X) / (p2X - p1X) = (y - p1Y) / (p2Y - p1Y)
a = y1 - y2; // Note: this was incorrectly "y2 - y1" in the original answer
b = x2 - x1;
c = x1 * y2 - x2 * y1;
}
http://formule-matematica.tripod.com/distanta-de-dreapta.htm
double dist(double pct1X, double pct1Y, double pct2X, double pct2Y, double pct3X, double pct3Y)
{
double a, b, c;
getLine(pct2X, pct2Y, pct3X, pct3Y, a, b, c);
return abs(a * pct1X + b * pct1Y + c) / sqrt(a * a + b * b);
}
Example on how to use the code:
#include <CMATH>
void getLine(double x1, double y1, double x2, double y2, double &a, double &b, double &c)
{
// (x- p1X) / (p2X - p1X) = (y - p1Y) / (p2Y - p1Y)
a = y1 - y2; // Note: this was incorrectly "y2 - y1" in the original answer
b = x2 - x1;
c = x1 * y2 - x2 * y1;
}
double dist(double pct1X, double pct1Y, double pct2X, double pct2Y, double pct3X, double pct3Y)
{
double a, b, c;
getLine(pct2X, pct2Y, pct3X, pct3Y, a, b, c);
return abs(a * pct1X + b * pct1Y + c) / sqrt(a * a + b * b);
}
int main(int argc, char* argv[])
{
double d = dist(1,2,3,4,5,6);
return 0;
}

Distance from a point to a line
You need 2 formulas:
Line formula: source this answer.
private Vector2 m_point1;
private Vector2 m_point1;
private float m_A;
private float m_B;
private float m_C;
public void CalculateLine()
{
m_A = m_point1.y - m_point2.y;
m_B = m_point2.x - m_point1.x;
m_C = m_point1.x * m_point2.y - m_point2.x * m_point1.y;
if(m_A == 0 && m_B == 0)
{
Debug.LogError("Line error: A & B = 0");
}
}
Distance from point to line: source Wikipedia
public float Distance2DPointToLine(Vector2 point)
{
return Mathf.Abs(m_A * point.x + m_B * point.y + m_C) /
Mathf.Sqrt(m_A * m_A + m_B * m_B);
}
Distance from a point to a line segment
It depends what you define "Distance from a point to a line segment"
Maybe distance from a point to a line segment is the distance from a point to the segment's middle point:
Maybe the distance is available if the point can be projected on the line segment
Maybe you didn't imagine what's result when you ask about segment, so I can't answer the segment part for you.

Related

Problem with ellipse (rotated): incorrect position of any point is detected

When the ellipse is not rotated with this formula 1. If value = 1 - point on the ellipse, if value > 1 - outside, if value < 1 - inside. The program works correctly.
Code:
int checkPointNoAngle(int x0, int y0, int x, int y, int a, int b)
{
int value = (pow((x - x0), 2) / pow(a, 2)) + (pow((y - y0), 2) / pow(b, 2));
return value;
}
I need to work with a rotated ellipse, so I used formula 2.
Now the program incorrectly determines the position of the point.
int checkPoint(int x0, int y0, int x, int y, int a, int b)
{
int angle = 90;
int value = (pow(cos(angle * M_PI / 180)*((x - x0)+sin(angle * M_PI / 180)*(y-y0)), 2) / pow(a, 2)) + (pow(sin(angle * M_PI / 180) * ((x - x0) - cos(angle * M_PI / 180) * (y - y0)), 2) / pow(b, 2));
return value;
}
I drawing an ellipse using this code:
for (int t = 0; t < 360; t++)
{
int x = a * cos(t);
int y = b * sin(t);
int x1 = x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180);
int y1 = -x * sin(angle * M_PI / 180) + y * cos(angle * M_PI / 180);
SDL_RenderDrawPoint(ren, x1 + centerX, y1 + centerY);
}
The program draws the ellipse correctly, but determines the position of the point incorrectly.
Examples of work:
3,4,5,6.
Example 4 and 5 works correctly with the checkPointNoAngle method.
I need to rotate the ellipse, so I created checkPoint method.
Example 6 indicates a bug.
The code was confusing a little bit. I tried to simplify the code corresponding to rotation and inverse rotation. The following code seems to work.
#include <iostream>
#include <vector>
#include <cmath>
struct Pt {int x, y;};
double checkPoint(int x0, int y0, int x, int y, int a, int b, int angle) {
double ang = (angle * M_PI)/180;
x = x - x0;
y = y - y0;
double xp = cos(ang)*x + sin(ang)*y;
double yp = -sin(ang)*x + cos(ang)*y;
double value = (xp*xp) / (a*a) + (yp*yp) / (b*b);
return value;
}
std::vector<Pt> gene_ellipse (int centerX, int centerY, int angle, int a, int b) {
std::vector<Pt> v;
double c = cos (angle * M_PI/180);
double s = sin (angle * M_PI/180);
for (int t = 0; t < 360; t++) {
double tt = M_PI * t / 180.0;
double x = a * cos(tt);
double y = b * sin(tt);
int x1 = x * c - y * s;
int y1 = x * s + y * c;
v.push_back (Pt{x1 + centerX, y1 + centerY});
}
return v;
}
int main () {
int centerX = 320;
int centerY = 240;
int angle = 120; // in degrees
int a = 200;
int b = 100;
int index = 25;
auto v = gene_ellipse (centerX, centerY, angle, a, b);
double check = checkPoint (centerX, centerY, v[index].x, v[index].y, a, b, angle);
std::cout << "check = " << check << "\n";
}

Unable to set private values from constructor

So I have code like this:
#include <iostream>
#include <string>
using namespace std;
#pragma region Class Definitions
struct Vector3
{
double x;
double y;
double z;
};
class Plane {
Vector3 point, normal, p_p1, p_p2, p_p3;
public:
Plane(Vector3 p1,
Vector3 p2, Vector3 p3);
const Vector3& get_point() const;
const Vector3& get_normal() const;
double get_hnf_d() const;
Vector3 closest_point(const Vector3& p);
double distance_to(const Vector3& p);
Vector3 intersect_line(const Line &l);
};
int main()
{
a.x = 1;
a.y = 2;
a.z = 3;
b.x = -1;
b.y = 2;
b.z = -2;
s = -2;
o.x = 0;
o.y = 0;
o.z = 0;
p1.x = sqrt(1 / 8);
p1.y = sqrt(1 / 8);
p1.z = sqrt(3 / 4);
p2.x = 0;
p2.y = 2 * sqrt(1 / 8);
p2.z = 0;
p3.x = sqrt(1 / 8) + sqrt(3 / 8);
p3.y = sqrt(1 / 8) + sqrt(3 / 8);
p3.z = sqrt(3 / 4) - sqrt(1 / 4);
q1.x = 1;
q1.y = 1;
q1.z = 1;
q2.x = -1;
q2.y = -1;
q2.z = -1;
switch (choice)
{
...
Plane _plane(p1, p2, p3);
cout << "Distance to p1, p2, p3 respectievly is : " << _plane.distance_to(p1) << endl;
}
return 0;
}
Plane::Plane(Vector3 p1, Vector3 p2, Vector3 p3)
{
p_p1 = p1;
p_p2 = p2;
p_p3 = p3;
}
const Vector3 & Plane::get_point() const
{
return p_p1;
}
const Vector3 & Plane::get_normal() const
{
return normalize(p_p2);
}
double Plane::get_hnf_d() const
{
Vector3 n, numerator;
double denominator;
numerator = cross_product(substract(p_p1, p_p3), substract(p_p2, p_p3));
denominator = sqrt(pow(numerator.x, 2) + pow(numerator.y, 2) + pow(numerator.z, 2));
cout <<"read" << numerator.y << numerator.x << denominator;
n.x = numerator.x / denominator;
n.y = numerator.y / denominator;
n.z = numerator.z / denominator;
//distance from origin
return -1 * dot_product(p_p1, n);
}
Vector3 Plane::closest_point(const Vector3 & p)
{
return Vector3();
}
double Plane::distance_to(const Vector3 & p)
{
return get_hnf_d() + dot_product(p, get_normal()) ;
}
And I am setting the values as such:
Plane::Plane(Vector3 p1, Vector3 p2, Vector3 p3)
{
p_p1 = p1;
p_p2 = p2;
p_p3 = p3;
}
However I always get 0s returned for values whenever I try to say print p_p1.x, thereby failing my computation. where am I wrong? I am really a C++ beginner.
Thanks.
You are doing integer divisions in the line:
p1.x = sqrt(1 / 8);
1/8 is 0 in C++
This is true in all other initialization.
Try writing
p1.x = sqrt(1.0 / 8.0);
at first you must declare in main p1 and p2 and p3 and initialize them then pass them to plane's constructor:
#include <iostream>
using namespace std;
#include <cmath>
struct Vector3
{
double x;
double y;
double z;
};
class Plane
{
Vector3 point, normal, p_p1, p_p2, p_p3;
public:
Plane(Vector3 p1,
Vector3 p2, Vector3 p3) : p_p1(p1), p_p2(p2), p_p3(p3){}
double distance_to(const Vector3& p)const;
};
double Plane:: distance_to(const Vector3& p)const
{
return get_hnf_d() + dot_product(p, get_normal()) ;
}
int main()
{
Vector3 p1 = {sqrt(1.0 / 8.0), sqrt(1.0 / 8.0), sqrt(3.0 / 4.0)};
// do the same thing as above
Vector3 p2, p3;
Plane _plane(p1, p2, p3);
cout << "Distance to p1 is : " << _plane.distance_to(p1) << endl;
return 0;
}
this is just a sample not full code

Why are points being generated outside of a my triangle in C++?

So I've read this formula generates a uniform random point inside of a triangle, from this article... http://www.cs.princeton.edu/~funk/tog02.pdf
P = (1 - sqrt(R1)) * A + (sqrt(R1) * (1 - R2)) * B + (sqrt(R1) * R2) * C
Where...
R1 & R2 are random floats in between 0 and 1.
A, B, & C are the points that create our triangle.
I've implemented this formula in my code with MANY test conditions, expecting each condition to have a point generated in the triangle... However, there always seems to be a few cases of it outside the triangle.
Here is my code (in C++)...
#include "stdafx.h"
#include <random>
#include <time.h>
class Location
{
public:
Location(
int x,
int y)
{
m_x = x;
m_y = y;
}
int m_x;
int m_y;
private:
};
double RandomValueBetweenZeroAndOne()
{
return ((double)rand() / (RAND_MAX));
}
float GetArea(
float x1, float y1,
float x2, float y2,
float x3, float y3)
{
return abs((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) / 2.0f);
}
bool InsideTriangle(
float Ax, float Ay,
float Bx, float By,
float Cx, float Cy,
float Px, float Py)
{
/* Calculate area of triangle ABC */
float A = GetArea(Ax, Ay, Bx, By, Cx, Cy);
/* Calculate area of triangle PBC */
float A1 = GetArea(Px, Py, Bx, By, Cx, Cy);
/* Calculate area of triangle PAC */
float A2 = GetArea(Ax, Ay, Px, Py, Cx, Cy);
/* Calculate area of triangle PAB */
float A3 = GetArea(Ax, Ay, Bx, By, Px, Py);
/* Check if sum of A1, A2 and A3 is same as A */
if ((A == (A1 + A2 + A3)))
{
return true;
}
return false;
};
int main()
{
srand(time(0));
Location* A = new Location(-54900, 933200);
Location* B = new Location(-62800, 934300);
Location* C = new Location(-70000, 932100);
bool in_triangle = true;
int i = 0;
do
{
float R1 = static_cast<float>(RandomValueBetweenZeroAndOne());
float R2 = static_cast<float>(RandomValueBetweenZeroAndOne());
float random_x = (1.0f - sqrt(R1)) * static_cast<float>(A->m_x) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_x) + (sqrt(R1) * R2) * static_cast<float>(C->m_x);
float random_y = (1.0f - sqrt(R1)) * static_cast<float>(A->m_y) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_y) + (sqrt(R1) * R2) * static_cast<float>(C->m_y);
in_triangle = InsideTriangle(
static_cast<float>(A->m_x), static_cast<float>(A->m_y),
static_cast<float>(B->m_x), static_cast<float>(B->m_y),
static_cast<float>(C->m_x), static_cast<float>(C->m_y),
random_x, random_y);
if (!in_triangle)
{
printf("Point located outside of Triangle on %i iteration", i);
}
i++;
} while (in_triangle);
system("pause");
}
In one example... The equation assigned the random coordinates as follows:
random_x = -66886;
random_y = 932326;
I even made a C# program to verify if the point was truley outside of the triangle (visually). Here's the results, everything above the line that is visible is INSIDE of the triangle... Everything Below the line that is visible is OUTSIDE of the triangle...
https://puu.sh/rJtSJ/7a7a88c346.png
For reference, I know that I can just wrap the number generating in a do while loop until a value inside the triangle is generated... I just wanted to know why it's generating outside when it's not supposed to be, and where the bug is...
Floating point arithmetic isn't perfect.That means when you do an artihmetic operation with floating points it may not give exact expected result.In that cases generally you should correct your code with wisely using a small number.
In that case part that should be corrected should be
float random_x = (1.0f - sqrt(R1)) * static_cast<float>(A->m_x) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_x) + (sqrt(R1) * R2) * static_cast<float>(C->m_x);
float random_y = (1.0f - sqrt(R1)) * static_cast<float>(A->m_y) + (sqrt(R1) * (1.0f - R2)) * static_cast<float>(B->m_y) + (sqrt(R1) * R2) * static_cast<float>(C->m_y);
Since I didn't understand the formula I can't fix it.But if you were use that formula:
if(R1+R2>1)
{
R1=1-R1;
R2=1-R2;
}
float random_x = A->m_x+(B->m_x-A->m_x)*R1+(C->m_x-A->m_x)*R2;
float random_y = A->m_y+(B->m_y-A->m_y)*R1+(C->m_y-A->m_y)*R2;
You could correct it as:
if(R1+R2>1)
{
R1=1-R1;
R2=1-R2;
}
float error=0.01;
float D=1-error;
float random_x = D*A->m_x+D*(B->m_x-A->m_x)*R1+D*(C->m_x-A->m_x)*R2+error*(A->m_x+B->m_x+C->m_x)/3;
float random_y = D*A->m_y+D*(B->m_y-A->m_y)*R1+D*(C->m_y-A->m_y)*R2+error*(A->m_x+B->m_x+C->m_x)/3;
That will ensure points will be inside the triangle.
You have a rounding problem, this needs to round down to smaller precision. Also using double instead of float will give better result.
Instead of comparing two double (or float) values to see if they are the same, take their difference and see if it is within a margin of error. The function below has arbitrary margin of 0.00001
bool InsideTriangle(double Ax, double Ay, double Bx, double By,
double Cx, double Cy, double Px, double Py)
{
double A = GetArea(Ax, Ay, Bx, By, Cx, Cy);
double A1 = GetArea(Px, Py, Bx, By, Cx, Cy);
double A2 = GetArea(Ax, Ay, Px, Py, Cx, Cy);
double A3 = GetArea(Ax, Ay, Bx, By, Px, Py);
double diff = A1 + A2 + A3 - A;
if (abs(diff) < 0.00001) return true;
std::cout << diff << "\n";
return false;
};
To compare the values directly, use the example below:
double getround(double f)
{
return floor(f * 1000.0f + 0.5f) / 1000.0f;
}
bool InsideTriangle(double Ax, double Ay, double Bx, double By,
double Cx, double Cy, double Px, double Py)
{
double A = GetArea(Ax, Ay, Bx, By, Cx, Cy);
double A1 = GetArea(Px, Py, Bx, By, Cx, Cy);
double A2 = GetArea(Ax, Ay, Px, Py, Cx, Cy);
double A3 = GetArea(Ax, Ay, Bx, By, Px, Py);
if ((A == (A1 + A2 + A3)))
{
return true;
}
double t1 = getround(A1 + A2 + A3);
double t2 = getround(A);
if (t1 == t2)
return true;
std::cout << t1 << ", " << t2 << "\n";
return false;
};
Note that you should not use cast unless the compiler complains. For example the following cast is not needed
float foo(){return 0.1f;}
...
float R1 = static_cast<float>(foo());
Because foo is already float. If you automatically put cast everywhere then it can hide potential problems.
Avoid using memory allocation when it's not need. For example, use Location A(-54900, 933200); instead of new operator. If you use new then be sure to free the memory with delete when it is no longer needed.

Adding unused formal parameters to C++ method results in different behavior

When I add some extra formal parameters double tmin=0.0, double tmax=0.0 to the constructor of the Ray in the code below, I always obtain a wrong image with a white top border. These formal parameters currently contribute in no way (i.e. are unused) to the code. So how is it possible to obtain a different image?
System specifications:
OS: Windows 8.1
Compiler: MSVC 2015
Code:
#include "stdafx.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <random>
std::default_random_engine generator(606418532);
std::uniform_real_distribution<double> distribution = std::uniform_real_distribution<double>(0.0, 1.0);
double erand48(unsigned short *x) {
return distribution(generator);
}
#define M_PI 3.14159265358979323846
struct Vector3 {
double x, y, z;
Vector3(double x_ = 0, double y_ = 0, double z_ = 0) { x = x_; y = y_; z = z_; }
Vector3 operator+(const Vector3 &b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
Vector3 operator-(const Vector3 &b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
Vector3 operator*(double b) const { return Vector3(x*b, y*b, z*b); }
Vector3 mult(const Vector3 &b) const { return Vector3(x*b.x, y*b.y, z*b.z); }
Vector3& norm() { return *this = *this * (1 / sqrt(x*x + y*y + z*z)); }
double Dot(const Vector3 &b) const { return x*b.x + y*b.y + z*b.z; } // cross:
Vector3 operator%(Vector3&b) { return Vector3(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x); }
};
//struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_, double tmin=0.0, double tmax=0.0) : o(o_), d(d_) {} };
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_) : o(o_), d(d_) {} };
enum Reflection_t { DIFFUSE, SPECULAR, REFRACTIVE };
struct Sphere {
double rad; // radius
Vector3 p, e, f; // position, emission, color
Reflection_t reflection_t; // reflection type (DIFFuse, SPECular, REFRactive)
Sphere(double rad_, Vector3 p_, Vector3 e_, Vector3 f_, Reflection_t reflection_t) :
rad(rad_), p(p_), e(e_), f(f_), reflection_t(reflection_t) {}
double intersect(const Ray &r) const {
Vector3 op = p - r.o;
double t, eps = 1e-4, b = op.Dot(r.d), det = b*b - op.Dot(op) + rad*rad;
if (det<0) return 0; else det = sqrt(det);
return (t = b - det)>eps ? t : ((t = b + det)>eps ? t : 0);
}
};
Sphere spheres[] = {
Sphere(1e5, Vector3(1e5 + 1,40.8,81.6), Vector3(),Vector3(.75,.25,.25),DIFFUSE),//Left
Sphere(1e5, Vector3(-1e5 + 99,40.8,81.6),Vector3(),Vector3(.25,.25,.75),DIFFUSE),//Rght
Sphere(1e5, Vector3(50,40.8, 1e5), Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Back
Sphere(1e5, Vector3(50,40.8,-1e5 + 170), Vector3(),Vector3(), DIFFUSE),//Frnt
Sphere(1e5, Vector3(50, 1e5, 81.6), Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Botm
Sphere(1e5, Vector3(50,-1e5 + 81.6,81.6),Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Top
Sphere(16.5,Vector3(27,16.5,47), Vector3(),Vector3(1,1,1)*.999, SPECULAR),//Mirr
Sphere(16.5,Vector3(73,16.5,78), Vector3(),Vector3(1,1,1)*.999, REFRACTIVE),//Glas
Sphere(600, Vector3(50,681.6 - .27,81.6),Vector3(12,12,12), Vector3(), DIFFUSE) //Lite
};
inline double clamp(double x) { return x<0 ? 0 : x>1 ? 1 : x; }
inline int toInt(double x) { return int(pow(clamp(x), 1 / 2.2) * 255 + .5); }
inline bool intersect(const Ray &r, double &t, int &id) {
double n = sizeof(spheres) / sizeof(Sphere), d, inf = t = 1e20;
for (int i = int(n); i--;) if ((d = spheres[i].intersect(r)) && d<t) { t = d; id = i; }
return t<inf;
}
Vector3 radiance(const Ray &r_, int depth_, unsigned short *Xi) {
double t; // distance to intersection
int id = 0; // id of intersected object
Ray r = r_;
int depth = depth_;
Vector3 cl(0, 0, 0); // accumulated color
Vector3 cf(1, 1, 1); // accumulated reflectance
while (1) {
if (!intersect(r, t, id)) return cl; // if miss, return black
const Sphere &obj = spheres[id]; // the hit object
Vector3 x = r.o + r.d*t, n = (x - obj.p).norm(), nl = n.Dot(r.d)<0 ? n : n*-1, f = obj.f;
double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl
cl = cl + cf.mult(obj.e);
if (++depth>5) if (erand48(Xi)<p) f = f*(1 / p); else return cl; //R.R.
cf = cf.mult(f);
if (obj.reflection_t == DIFFUSE) { // Ideal DIFFUSE reflection
double r1 = 2 * M_PI*erand48(Xi), r2 = erand48(Xi), r2s = sqrt(r2);
Vector3 w = nl, u = ((fabs(w.x)>.1 ? Vector3(0, 1) : Vector3(1)) % w).norm(), v = w%u;
Vector3 d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1 - r2)).norm();
r = Ray(x, d);
continue;
}
else if (obj.reflection_t == SPECULAR) {
r = Ray(x, r.d - n * 2 * n.Dot(r.d));
continue;
}
Ray reflRay(x, r.d - n * 2 * n.Dot(r.d));
bool into = n.Dot(nl)>0;
double nc = 1, nt = 1.5, nnt = into ? nc / nt : nt / nc, ddn = r.d.Dot(nl), cos2t;
if ((cos2t = 1 - nnt*nnt*(1 - ddn*ddn))<0) {
r = reflRay;
continue;
}
Vector3 tdir = (r.d*nnt - n*((into ? 1 : -1)*(ddn*nnt + sqrt(cos2t)))).norm();
double a = nt - nc, b = nt + nc, R0 = a*a / (b*b), c = 1 - (into ? -ddn : tdir.Dot(n));
double Re = R0 + (1 - R0)*c*c*c*c*c, Tr = 1 - Re, P = .25 + .5*Re, RP = Re / P, TP = Tr / (1 - P);
if (erand48(Xi)<P) {
cf = cf*RP;
r = reflRay;
}
else {
cf = cf*TP;
r = Ray(x, tdir);
}
continue;
}
}
int main(int argc, char *argv[]) {
int w = 512, h = 384, samps = argc == 2 ? atoi(argv[1]) / 4 : 1; // # samples
Ray cam(Vector3(50, 52, 295.6), Vector3(0, -0.042612, -1).norm()); // cam pos, dir
Vector3 cx = Vector3(w*.5135 / h), cy = (cx%cam.d).norm()*.5135, r, *c = new Vector3[w*h];
#pragma omp parallel for schedule(dynamic, 1) private(r) // OpenMP
for (int y = 0; y<h; y++) { // Loop over image rows
fprintf(stderr, "\rRendering (%d spp) %5.2f%%", samps * 4, 100.*y / (h - 1));
for (unsigned short x = 0, Xi[3] = { 0,0,y*y*y }; x<w; x++) // Loop cols
for (int sy = 0, i = (h - y - 1)*w + x; sy<2; sy++) // 2x2 subpixel rows
for (int sx = 0; sx<2; sx++, r = Vector3()) { // 2x2 subpixel cols
for (int s = 0; s<samps; s++) {
double r1 = 2 * erand48(Xi), dx = r1<1 ? sqrt(r1) - 1 : 1 - sqrt(2 - r1);
double r2 = 2 * erand48(Xi), dy = r2<1 ? sqrt(r2) - 1 : 1 - sqrt(2 - r2);
Vector3 d = cx*(((sx + .5 + dx) / 2 + x) / w - .5) +
cy*(((sy + .5 + dy) / 2 + y) / h - .5) + cam.d;
r = r + radiance(Ray(cam.o + d * 140, d.norm()), 0, Xi)*(1. / samps);
} // Camera rays are pushed ^^^^^ forward to start in interior
c[i] = c[i] + Vector3(clamp(r.x), clamp(r.y), clamp(r.z))*.25;
}
}
FILE *fp;
fopen_s(&fp, "image.ppm", "w"); // Write image to PPM file.
fprintf(fp, "P3\n%d %d\n%d\n", w, h, 255);
for (int i = 0; i<w*h; i++)
fprintf(fp, "%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z));
}
First Ray structure:
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_) : o(o_), d(d_) {} };
Results in:
Second Ray structure:
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_, double tmin=0.0, double tmax=0.0) : o(o_), d(d_) {} };
Results in:
The last image has a noticeable white top border which is not present in the first image.
Edit:
I used
size_t n = sizeof(spheres) / sizeof(Sphere);
Now I obtain the same images, but I also checked if the original int(n) could differ from 9 which is never the case.
Ok this is from the Debug build, which is different from the Release build.
Sounds like a memory error, looking quickly at your code I'm sceptical of this line:
for (int i = int(n); i--;) if ((d = spheres[i].intersect(r)) && d<t)
I suspect accessing sphere[i] is out of bounds, perhaps you should try sphere[i-1]. You could also try compiling your code with a compiler that adds extra code for debugging/sanitising/checking memory addresses.

Drawing thick line has holes

I've made simple method to draw line with fixed thickness.
Here's my function:
void ColoringScene::drawThickLine(int x1, int y1, int x2, int y2, int r, int g, int b, int a, float wd, bool began, unsigned char* data, unsigned char* areasData){
if(began){
//if just began draw "dot" with filled circle
drawFilledCircle(x1, y1, 1, wd, r, g, b, a, data, areasData);
return;
}
//otherwise calculate angle between two points
int angle = (int)(atan2(-y2 + y1, x2 - x1) * 180 / M_PI);
int a1 = angle - 90;
int a2 = angle + 90;
//calculate a distance between two points
float diff = sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
if(diff > wd) diff = wd;
//find all points in arc from angle - 90 to angle + 90
for(float _r = a1; _r < a2; _r+=1.0f){
float _x1 = cos(CC_DEGREES_TO_RADIANS(_r)) * wd + x1;
float _y1 = -sin(CC_DEGREES_TO_RADIANS(_r)) * wd + y1;
float _x2 = cos(CC_DEGREES_TO_RADIANS(_r)) * wd + x2;
float _y2 = -sin(CC_DEGREES_TO_RADIANS(_r)) * wd + y2;
//connect point from 2 arcs with line
drawLine(floor(_x1), floor(_y1), floor(_x2), floor(_y2), r, g, b, a, data, areasData);
}
}
it should draw line from (x1, y1) to (x2, y2) with color (r, g, b, a) and thickness wd. I use this method on drawing while moving finger on screen so I've also added extra parameter "began", which says if it's touch began or touch move. data is an array of pixels. areasData does not matter.
But it's not working as expected, here's an example result:
There could be a bit of compression, but you can see 2 dots, which were drawn fine and a curve build from many "thick" lines with holes.
If "wd" is not big enough the problem is not present. I'm almost sure it's some sort of problem with precision.
I tried:
- changing for loop from 0 to 360 (not angle-90, angle+90).
- using round instead of floor
- using sin instead of -sin (y is inverted anyway in my case)
- using _r lower than 1.0 like: 0.05.
And by given fixed thickness (in this example's 60 pixels) there's no way to set parameters like _r increment or angles to not draw without holes.
I decided to write my own function to do this, because other methods I found on web just didn't work as expected (especially with anti-aliasing, which will be perfect solution for me).
Here's drawLine function taken from website: http://willperone.net/Code/codeline.php
void ColoringScene::drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int a, unsigned char* data, unsigned char* areasData){
int dy = y2 - y1;
int dx = x2 - x1;
int stepx, stepy;
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
dy <<= 1; // dy is now 2*dy
dx <<= 1; // dx is now 2*dx
setPixelWithCheckingArea(x1, y1, r, g, b, a, data, areasData);
if (dx > dy)
{
int fraction = dy - (dx >> 1); // same as 2*dy - dx
while (x1 != x2)
{
if (fraction >= 0)
{
y1 += stepy;
fraction -= dx; // same as fraction -= 2*dx
}
x1 += stepx;
fraction += dy; // same as fraction -= 2*dy
setPixelWithCheckingArea(x1, y1, r, g, b, a, data, areasData);
}
} else {
int fraction = dx - (dy >> 1);
while (y1 != y2) {
if (fraction >= 0) {
x1 += stepx;
fraction -= dy;
}
y1 += stepy;
fraction += dx;
setPixelWithCheckingArea(x1, y1, r, g, b, a, data, areasData);
}
}
}