What I'm doing is testing to see what the level of intersection between a circle and rectangle. I would like to find whether the rectangle is completely inside the circle, partially intersecting it, or if there is no intersection at all.
I've attached the code that I've come up with today, it simply checks the distances from the center of the circle to the corners of the rectangle to determine the level of intersection.
What I'm wondering is there a more efficient way of doing this?
EDIT:
Here is my updated, working code. fullIntersect is my own, I found the partialIntersect snippet on Circle-Rectangle collision detection (intersection). I'm going to leave this open, as I'm still curious as to whether there is a better way of doing this.
public boolean fullIntersect(float circleX, float circleY, float radius)
{
float radsq = radius * radius;
double xsq = Math.pow(circleX - xPosition, 2);
double xpwsq = Math.pow(circleX - (xPosition + width), 2);
double ysq = Math.pow(circleY - yPosition, 2);
double yphsq = Math.pow(circleY - (yPosition + height), 2);
if(xsq + ysq > radsq || xsq + yphsq > radsq || xpwsq + yphsq > radsq || xpwsq + ysq > radsq)
return false;
return true;
/* this is what the one if statement does
double disBotLeft = xsq + ysq;
double disTopLeft = xsq + yphsq;
double disTopRight = xpwsq + yphsq;
double disBotRight = xpwsq + ysq;
if(disBotRight > radsq) return false;
if(disBotLeft > radsq) return false;
if(disTopLeft > radsq) return false;
if(disTopRight > radsq) return false;
return true;
*/
}
public int intersects(float circleX, float circleY, float radius)
{
if(!enabled) return 0;
double wo2 = width / 2.0d;
double ho2 = height / 2.0d;
double circleDistanceX = Math.abs(circleX - xPosition - wo2);
double circleDistanceY = Math.abs(circleY - yPosition - ho2);
if (circleDistanceX > (wo2 + radius)) { return 0; }
if (circleDistanceY > (ho2 + radius)) { return 0; }
if(fullIntersect(circleX, circleY, radius)) { return 2; }
if (circleDistanceX <= (wo2)) { return 1; }
if (circleDistanceY <= (ho2)) { return 1; }
double cornerDistance_sq = Math.pow(circleDistanceX - wo2,2) +
Math.pow(circleDistanceY - ho2,2);
return cornerDistance_sq <= (radius*radius) ? 1 : 0;
}
I think your code does not consider these intersections:
I'll delete this answer as soon as you enhance your code/question.
Related
my result , but the shadow is so hard.
for (SceneLight* light : scene->lights)
{
Vector3D dir_to_light;
float dist_to_light;
float pdf;
int num_light_samples = light->is_delta_light() ? 1 : ns_area_light;
double scale = 1.0 / num_light_samples;
for (int i = 0; i < num_light_samples; i++) {
Spectrum light_L = light->sample_L(hit_p, &dir_to_light, &dist_to_light, &pdf);
Vector3D w_in = w2o * dir_to_light;
double cos_theta = std::max(0.0, w_in[2]);
Spectrum f = isect.bsdf->f(w_out, w_in);
Ray shadow_ray(hit_p + EPS_D * dir_to_light, dir_to_light, dist_to_light - (EPS_D * dir_to_light).norm(), 0);
if (!bvh->intersect(shadow_ray))
{
L_out += (f * light_L * (cos_theta * scale / pdf));
}
}
}
**
abolve is my some code and render result. The shadow looks so hard.If i want to make the shadow softer, What can I do? I am writing path tracing.
Thanks.**
I have made an implementation of the Reaction-Diffusion algorithm on Processing 3.1.1, following a video tutorial. I have made some adaptations on my code, like implementing it on a torus space, instead of a bounded box, like the video.
However, I ran into this annoying issue, that the code runs really slow, proportional to the canvas size (larger, slower). With that, I tried optmizing the code, according to my (limited) knowledge. The main thing I did was to reduce the number of loops running.
Even then, my code still ran quite slow.
Since I have noticed that with a canvas of 50 x 50 in size, the algorithm ran at a good speed, I tried making it multithreaded, in such a way that the canvas would be divided between the threads, and each thread would run the algorithm for a small region of the canvas.
All threads read from the current state of the canvas, and all write to the future state of the canvas. The canvas is then updated using Processing's pixel array.
However, even with multithreading, I didn't see any performance improvement. By the contrary, I saw it getting worse. Now sometimes the canvas flicker between a rendered state and completely white, and in some cases, it doesn't even render.
I'm quite sure that I'm doing something wrong, or I may be taking the wrong approach to optimizing this algorithm. And now, I'm asking for help to understand what I'm doing wrong, and how I could fix or improve my code.
Edit: Implementing ahead of time calculation and rendering using a buffer of PImage objects has removed flickering, but the calculation step on the background doesn't run fast enough to fill the buffer.
My Processing Sketch is below, and thanks in advance.
ArrayList<PImage> buffer = new ArrayList<PImage>();
Thread t;
Buffer b;
PImage currentImage;
Point[][] grid; //current state
Point[][] next; //future state
//Reaction-Diffusion algorithm parameters
final float dA = 1.0;
final float dB = 0.5;
//default: f = 0.055; k = 0.062
//mitosis: f = 0.0367; k = 0.0649
float feed = 0.055;
float kill = 0.062;
float dt = 1.0;
//multi-threading parameters to divide canvas
int threadSizeX = 50;
int threadSizeY = 50;
//red shading colors
color red = color(255, 0, 0);
color white = color(255, 255, 255);
color black = color(0, 0, 0);
//if redShader is false, rendering will use a simple grayscale mode
boolean redShader = true;
//simple class to hold chemicals A and B amounts
class Point
{
float a;
float b;
Point(float a, float b)
{
this.a = a;
this.b = b;
}
}
void setup()
{
size(300, 300);
//initialize matrices with A = 1 and B = 0
grid = new Point[width][];
next = new Point[width][];
for (int x = 0; x < width; x++)
{
grid[x] = new Point[height];
next[x] = new Point[height];
for (int y = 0; y < height; y++)
{
grid[x][y] = new Point(1.0, 0.0);
next[x][y] = new Point(1.0, 0.0);
}
}
int a = (int) random(1, 20); //seed some areas with B = 1.0
for (int amount = 0; amount < a; amount++)
{
int siz = 2;
int x = (int)random(width);
int y = (int)random(height);
for (int i = x - siz/2; i < x + siz/2; i++)
{
for (int j = y - siz/2; j < y + siz/2; j++)
{
int i2 = i;
int j2 = j;
if (i < 0)
{
i2 = width + i;
} else if (i >= width)
{
i2 = i - width;
}
if (j < 0)
{
j2 = height + j;
} else if (j >= height)
{
j2 = j - height;
}
grid[i2][j2].b = 1.0;
}
}
}
initializeThreads();
}
/**
* Divide canvas between threads
*/
void initializeThreads()
{
ArrayList<Reaction> reactions = new ArrayList<Reaction>();
for (int x1 = 0; x1 < width; x1 += threadSizeX)
{
for (int y1 = 0; y1 < height; y1 += threadSizeY)
{
int x2 = x1 + threadSizeX;
int y2 = y1 + threadSizeY;
if (x2 > width - 1)
{
x2 = width - 1;
}
if (y2 > height - 1)
{
y2 = height - 1;
}
Reaction r = new Reaction(x1, y1, x2, y2);
reactions.add(r);
}
}
b = new Buffer(reactions);
t = new Thread(b);
t.start();
}
void draw()
{
if (buffer.size() == 0)
{
return;
}
PImage i = buffer.get(0);
image(i, 0, 0);
buffer.remove(i);
//println(frameRate);
println(buffer.size());
//saveFrame("output/######.png");
}
/**
* Faster than calling built in pow() function
*/
float pow5(float x)
{
return x * x * x * x * x;
}
class Buffer implements Runnable
{
ArrayList<Reaction> reactions;
boolean calculating = false;
public Buffer(ArrayList<Reaction> reactions)
{
this.reactions = reactions;
}
public void run()
{
while (true)
{
if (buffer.size() < 1000)
{
calculate();
if (isDone())
{
buffer.add(currentImage);
Point[][] temp;
temp = grid;
grid = next;
next = temp;
calculating = false;
}
}
}
}
boolean isDone()
{
for (Reaction r : reactions)
{
if (!r.isDone())
{
return false;
}
}
return true;
}
void calculate()
{
if (calculating)
{
return;
}
currentImage = new PImage(width, height);
for (Reaction r : reactions)
{
r.calculate();
}
calculating = true;
}
}
class Reaction
{
int x1;
int x2;
int y1;
int y2;
Thread t;
public Reaction(int x1, int y1, int x2, int y2)
{
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
public void calculate()
{
Calculator c = new Calculator(x1, y1, x2, y2);
t = new Thread(c);
t.start();
}
public boolean isDone()
{
if (t.getState() == Thread.State.TERMINATED)
{
return true;
} else
{
return false;
}
}
}
class Calculator implements Runnable
{
int x1;
int x2;
int y1;
int y2;
//weights for calculating the Laplacian for A and B
final float[][] laplacianWeights = {{0.05, 0.2, 0.05},
{0.2, -1, 0.2},
{0.05, 0.2, 0.05}};
/**
* x1, x2, y1, y2 delimit a rectangle. The object will only work within it
*/
public Calculator(int x1, int y1, int x2, int y2)
{
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
//println("x1: " + x1 + ", y1: " + y1 + ", x2: " + x2 + ", y2: " + y2);
}
#Override
public void run()
{
reaction();
show();
}
public void reaction()
{
for (int x = x1; x <= x2; x++)
{
for (int y = y1; y <= y2; y++)
{
float a = grid[x][y].a;
float b = grid[x][y].b;
float[] l = laplaceAB(x, y);
float a2 = reactionDiffusionA(a, b, l[0]);
float b2 = reactionDiffusionB(a, b, l[1]);
next[x][y].a = a2;
next[x][y].b = b2;
}
}
}
float reactionDiffusionA(float a, float b, float lA)
{
return a + ((dA * lA) - (a * b * b) + (feed * (1 - a))) * dt;
}
float reactionDiffusionB(float a, float b, float lB)
{
return b + ((dB * lB) + (a * b * b) - ((kill + feed) * b)) * dt;
}
/**
* Calculates Laplacian for both A and B at same time, to reduce amount of loops executed
*/
float[] laplaceAB(int x, int y)
{
float[] l = {0.0, 0.0};
for (int i = x - 1; i < x + 2; i++)
{
for (int j = y - 1; j < y + 2; j++)
{
int i2 = i;
int j2 = j;
if (i < 0)
{
i2 = width + i;
} else if (i >= width)
{
i2 = i - width;
}
if (j < 0)
{
j2 = height + j;
} else if (j >= height)
{
j2 = j - height;
}
int weightX = (i - x) + 1;
int weightY = (j - y) + 1;
l[0] += laplacianWeights[weightX][weightY] * grid[i2][j2].a;
l[1] += laplacianWeights[weightX][weightY] * grid[i2][j2].b;
}
}
return l;
}
public void show()
{
currentImage.loadPixels();
//renders the canvas using the pixel array
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
float a = next[x][y].a;
float b = next[x][y].b;
int pix = x + y * width;
float diff = (a - b);
color c;
if (redShader) //aply red shading
{
float thresh = 0.5;
if (diff < thresh)
{
float diff2 = map(pow5(diff), 0, pow5(thresh), 0, 1);
c = lerpColor(black, red, diff2);
} else
{
float diff2 = map(1 - pow5(-diff + 1), 1 - pow5(-thresh + 1), 1, 0, 1);
c = lerpColor(red, white, diff2);
}
} else //apply gray scale shading
{
c = color(diff * 255, diff * 255, diff * 255);
}
currentImage.pixels[pix] = c;
}
}
currentImage.updatePixels();
}
}
A programmer had a problem. He thought “I know, I’ll solve it with threads!”. has Now problems. two he
Processing uses a single rendering thread.
It does this for good reason, and most other renderers do the same thing. In fact, I don't know of any multi-threaded renderers.
You should only change what's on the screen from Processing's main rendering thread. In other words, you should only change stuff from Processing's functions, not your own thread. This is what's causing the flickering you're seeing. You're changing stuff as it's being drawn to the screen, which is a horrible idea. (And it's why Processing uses a single rendering thread in the first place.)
You could try to use your multiple threads to do the processing, not the rendering. But I highly doubt that's going to be worth it, and like you saw, it might even make things worse.
If you want to speed up your sketch, you might also consider doing the processing ahead of time instead of in real time. Do all your calculations at the beginning of the sketch, and then just reference the results of the calculations when it's time to draw the frame. Or you could draw to a PImage ahead of time, and then just draw those.
For context: I am going to analyze the breathing movement of parents during kangaroo mother care and I wish to respect their privacy by not recording them, but only the movement of stickers I placed on their chest and stomach.
So far, I'm able to track 2 colours based on webcam input through the code below. However, I would like to record only the tracked colours instead of the webcam feed as to preserve the privacy of the parent.
Does anybody know how to add a background colour, whilst still being able to track colour?
import processing.video.*;
Capture video;
final int TOLERANCE = 20;
float XRc = 0;// XY coordinate of the center of the first target
float YRc = 0;
float XRh = 0;// XY coordinate of the center of the second target
float YRh = 0;
int ii=0; //Mouse click counter
color trackColor; //The first color is the center of the robot
color trackColor2; //The second color is the head of the robot
void setup() {
size(640,480);
video = new Capture(this,640,480);
video.start();
trackColor = color(255,0,0);
trackColor2 = color(255,0,0);
smooth();
}
void draw() {
background(0);
if (video.available()) {
video.read();
}
video.loadPixels();
image(video,0,0);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
float r3 = red(trackColor2);
float g3 = green(trackColor2);
float b3 = blue(trackColor2);
int somme_x = 0, somme_y = 0;
int compteur = 0;
int somme_x2 = 0, somme_y2 = 0;
int compteur2 = 0;
for(int x = 0; x < video.width; x++) {
for(int y = 0; y < video.height; y++) {
int currentLoc = x + y*video.width;
color currentColor = video.pixels[currentLoc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
if(dist(r1,g1,b1,r2,g2,b2) < TOLERANCE) {
somme_x += x;
somme_y += y;
compteur++;
}
else if(compteur > 0) {
XRc = somme_x / compteur;
YRc = somme_y / compteur;
}
if(dist(r1,g1,b1,r3,g3,b3) < TOLERANCE) {
somme_x2 += x;
somme_y2 += y;
compteur2++;
}
else if(compteur2 > 0) {
XRh = somme_x2 / compteur2;
YRh = somme_y2 / compteur2;
}
}
}
if(XRc != 0 || YRc != 0) { // Draw a circle at the first target
fill(trackColor);
strokeWeight(0.05);
stroke(0);
ellipse(XRc,YRc,20,20);
}
if(XRh != 0 || YRh != 0) {// Draw a circle at the second target
fill(trackColor2);
strokeWeight(0.05);
stroke(0);
ellipse(XRh,YRh,20,20);
}
}
void mousePressed() {
if (mousePressed && (mouseButton == RIGHT)) { // Save color where the mouse is clicked in trackColor variable
if(ii==0){
if (mouseY>480){mouseY=0;mouseX=0;}
int loc = mouseX + mouseY*video.width;
trackColor = video.pixels[loc];
ii=1;
}
else if(ii==1){
if (mouseY>480){mouseY=0;mouseX=0;}
int loc2 = mouseX + mouseY*video.width;
trackColor2 = video.pixels[loc2];
ii=2;
}
}
}
Try adding the background(0); right before you draw the first circle. It should cover the video and you can draw the circles on top of it.
Regards
Jose
I need a algorithm for detecting if a circle has hit a square, and I saw this post:
Circle-Rectangle collision detection (intersection)
It looks like I should go for ShreevatsaR's answer, but I am a math fool, and I have no idea how to finish the algorithm. Could anyone find the time to make a complete example for me please, I have searched the net for this, and have yet found no working example.
Thank you very much
Soeren
EDIT:
Ok here is my attempt. It is not working, it never detects any collisions.
typedef struct {
double x;
double y;
} point;
typedef struct {
point one;
point two;
} segment;
typedef struct {
point center;
double radius;
} circle;
typedef struct {
point p;
int width;
int height;
point a;
point b;
point c;
point d;
} rectangle;
double slope(point one, point two) {
return (double)(one.y-two.y)/(one.x-two.x);
}
double distance(point p, segment s) {
// Line one is the original line that was specified, and line two is
// the line we're constructing that runs through the specified point,
// at a right angle to line one.
//
// if it's a vertical line return the horizontal distance
if ( s.one.x == s.two.x)
return fabs(s.one.x - p.x);
// if it's a horizontal line return the vertical distance
if ( s.one.y == s.two.y )
return fabs(s.one.y - p.y);
// otherwise, find the slope of the line
double m_one = slope(s.one, s.two);
// the other slope is at a right angle.
double m_two = -1.0 / m_one;
// find the y-intercepts.
double b_one = s.one.y - s.one.x * m_one;
double b_two = p.y - p.x * m_two;
// find the point of intersection
double x = (b_two - b_one) / (m_one - m_two);
double y = m_one * x + b_one;
// find the x and y distances
double x_dist = x - p.x;
double y_dist = y - p.y;
// and return the total distance.
return sqrt(x_dist * x_dist + y_dist * y_dist);
}
bool intersectsCircle(segment s, circle c) {
return distance(c.center, s) <= c.radius;
}
bool pointInRectangle(point p, rectangle r)
{
float right = r.p.x + r.width;
float left = r.p.x - r.width;
float top = r.p.y + r.height;
float bottom = r.p.y - r.height;
return ((left <= p.x && p.x <= right) && (top <= p.y && p.y <= bottom));
}
bool intersect(circle c, rectangle r) {
segment ab;
ab.one = r.a;
ab.two = r.b;
segment bc;
ab.one = r.b;
ab.two = r.c;
segment cd;
ab.one = r.c;
ab.two = r.d;
segment da;
ab.one = r.d;
ab.two = r.a;
return pointInRectangle(c.center, r) ||
intersectsCircle(ab, c) ||
intersectsCircle(bc, c) ||
intersectsCircle(cd, c) ||
intersectsCircle(da, c);
}
The primary part he seems to have left is the InteresectsCircle(line, circle).
#include <math.h>
typedef struct {
double x;
double y;
} point;
typedef struct {
point one;
point two;
} segment;
typedef struct {
point center;
double radius;
} circle;
double slope(point &one, point &two) {
return (double)(one.y-two.y)/(one.x-two.x);
}
double distance(point &p, segment &s) {
// Line one is the original line that was specified, and line two is
// the line we're constructing that runs through the specified point,
// at a right angle to line one.
//
// if it's a vertical line return the horizontal distance
if ( s.one.x == s.two.x)
return fabs(s.one.x - p.x);
// if it's a horizontal line return the vertical distance
if ( s.one.y == s.two.y )
return fabs(s.one.y - p.y);
// otherwise, find the slope of the line
double m_one = slope(s.one, s.two);
// the other slope is at a right angle.
double m_two = -1.0 / m_one;
// find the y-intercepts.
double b_one = s.one.y - s.one.x * m_one;
double b_two = p.y - p.x * m_two;
// find the point of intersection
double x = (b_two - b_one) / (m_one - m_two);
double y = m_one * x + b_one;
// find the x and y distances
double x_dist = x - p.x;
double y_dist = y - p.y;
// and return the total distance.
return sqrt(x_dist * x_dist + y_dist * y_dist);
}
bool IntersectsCircle(segment s, circle c) {
return distance(circle.center, s) <= circle.radius;
}
I have some code in C++ (lightly templated) that should do these intersection tests, but I haven't had time to test them yet. In particular, I have the segment-circle intersection test as well as parallelogram-circle intersection, which is supposed to compute the intersection area and intersection points. Again, this is completely untested as of the writing of this comment, so you will need to test/adapt them to your needs.
I need a good source for reading up on how to create a algorithm to take two polylines (a path comprised of many lines) and performing a union, subtraction, or intersection between them. This is tied to a custom API so I need to understand the underlying algorithm.
Plus any sources in a VB dialect would be doubly helpful.
This catalogue of implementations of intersection algorithms from the Stony Brook Algorithm Repository might be useful. The repository is managed by Steven Skiena,
author of a very well respected book on algorithms: The Algorithm Design Manual.
That's his own Amazon exec link by the way :)
Several routines for you here. Hope you find them useful :-)
// routine to calculate the square of either the shortest distance or largest distance
// from the CPoint to the intersection point of a ray fired at an angle flAngle
// radians at an array of line segments
// this routine returns TRUE if an intersection has been found in which case flD
// is valid and holds the square of the distance.
// and returns FALSE if no valid intersection was found
// If an intersection was found, then intersectionPoint is set to the point found
bool CalcIntersection(const CPoint &cPoint,
const float flAngle,
const int nVertexTotal,
const CPoint *pVertexList,
const BOOL bMin,
float &flD,
CPoint &intersectionPoint)
{
float d, dsx, dsy, dx, dy, lambda, mu, px, py;
int p0x, p0y, p1x, p1y;
// get source position
const float flSx = (float)cPoint.x;
const float flSy = -(float)cPoint.y;
// calc trig functions
const float flTan = tanf(flAngle);
const float flSin = sinf(flAngle);
const float flCos = cosf(flAngle);
const bool bUseSin = fabsf(flSin) > fabsf(flCos);
// initialise distance
flD = (bMin ? FLT_MAX : 0.0f);
// for each line segment in protective feature
for(int i = 0; i < nVertexTotal; i++)
{
// get coordinates of line (negate the y value so the y-axis is upwards)
p0x = pVertexList[i].x;
p0y = -pVertexList[i].y;
p1x = pVertexList[i + 1].x;
p1y = -pVertexList[i + 1].y;
// calc. deltas
dsx = (float)(cPoint.x - p0x);
dsy = (float)(-cPoint.y - p0y);
dx = (float)(p1x - p0x);
dy = (float)(p1y - p0y);
// calc. denominator
d = dy * flTan - dx;
// if line & ray are parallel
if(fabsf(d) < 1.0e-7f)
continue;
// calc. intersection point parameter
lambda = (dsy * flTan - dsx) / d;
// if intersection is not valid
if((lambda <= 0.0f) || (lambda > 1.0f))
continue;
// if sine is bigger than cosine
if(bUseSin){
mu = ((float)p0x + lambda * dx - flSx) / flSin;
} else {
mu = ((float)p0y + lambda * dy - flSy) / flCos;
}
// if intersection is valid
if(mu >= 0.0f){
// calc. intersection point
px = (float)p0x + lambda * dx;
py = (float)p0y + lambda * dy;
// calc. distance between intersection point & source point
dx = px - flSx;
dy = py - flSy;
d = dx * dx + dy * dy;
// compare with relevant value
if(bMin){
if(d < flD)
{
flD = d;
intersectionPoint.x = RoundValue(px);
intersectionPoint.y = -RoundValue(py);
}
} else {
if(d > flD)
{
flD = d;
intersectionPoint.x = RoundValue(px);
intersectionPoint.y = -RoundValue(py);
}
}
}
}
// return
return(bMin ? (flD != FLT_MAX) : (flD != 0.0f));
}
// Routine to calculate the square of the distance from the CPoint to the
// intersection point of a ray fired at an angle flAngle radians at a line.
// This routine returns TRUE if an intersection has been found in which case flD
// is valid and holds the square of the distance.
// Returns FALSE if no valid intersection was found.
// If an intersection was found, then intersectionPoint is set to the point found.
bool CalcIntersection(const CPoint &cPoint,
const float flAngle,
const CPoint &PointA,
const CPoint &PointB,
const bool bExtendLine,
float &flD,
CPoint &intersectionPoint)
{
// get source position
const float flSx = (float)cPoint.x;
const float flSy = -(float)cPoint.y;
// calc trig functions
float flTan = tanf(flAngle);
float flSin = sinf(flAngle);
float flCos = cosf(flAngle);
const bool bUseSin = fabsf(flSin) > fabsf(flCos);
// get coordinates of line (negate the y value so the y-axis is upwards)
const int p0x = PointA.x;
const int p0y = -PointA.y;
const int p1x = PointB.x;
const int p1y = -PointB.y;
// calc. deltas
const float dsx = (float)(cPoint.x - p0x);
const float dsy = (float)(-cPoint.y - p0y);
float dx = (float)(p1x - p0x);
float dy = (float)(p1y - p0y);
// Calc. denominator
const float d = dy * flTan - dx;
// If line & ray are parallel
if(fabsf(d) < 1.0e-7f)
return false;
// calc. intersection point parameter
const float lambda = (dsy * flTan - dsx) / d;
// If extending line to meet point, don't check for ray missing line
if(!bExtendLine)
{
// If intersection is not valid
if((lambda <= 0.0f) || (lambda > 1.0f))
return false; // Ray missed line
}
// If sine is bigger than cosine
float mu;
if(bUseSin){
mu = ((float)p0x + lambda * dx - flSx) / flSin;
} else {
mu = ((float)p0y + lambda * dy - flSy) / flCos;
}
// if intersection is valid
if(mu >= 0.0f)
{
// calc. intersection point
const float px = (float)p0x + lambda * dx;
const float py = (float)p0y + lambda * dy;
// calc. distance between intersection point & source point
dx = px - flSx;
dy = py - flSy;
flD = (dx * dx) + (dy * dy);
intersectionPoint.x = RoundValue(px);
intersectionPoint.y = -RoundValue(py);
return true;
}
return false;
}
// Fillet (with a radius of 0) two lines. From point source fired at angle (radians) to line Line1A, Line1B.
// Modifies line end point Line1B. If the ray does not intersect line, then it is rotates every 90 degrees
// and tried again until fillet is complete.
void Fillet(const CPoint &source, const float fThetaRadians, const CPoint &Line1A, CPoint &Line1B)
{
if(Line1A == Line1B)
return; // No line
float dist;
if(CalcIntersection(source, fThetaRadians, Line1A, Line1B, true, dist, Line1B))
return;
if(CalcIntersection(source, CalcBaseFloat(TWO_PI, fThetaRadians + PI * 0.5f), Line1A, Line1B, true, dist, Line1B))
return;
if(CalcIntersection(source, CalcBaseFloat(TWO_PI, fThetaRadians + PI), Line1A, Line1B, true, dist, Line1B))
return;
if(!CalcIntersection(source, CalcBaseFloat(TWO_PI, fThetaRadians + PI * 1.5f), Line1A, Line1B, true, dist, Line1B))
ASSERT(FALSE); // Could not find intersection?
}
// routine to determine if an array of line segments cross gridSquare
// x and y give the float coordinates of the corners
BOOL CrossGridSquare(int nV, const CPoint *pV,
const CRect &extent, const CRect &gridSquare)
{
// test extents
if( (extent.right < gridSquare.left) ||
(extent.left > gridSquare.right) ||
(extent.top > gridSquare.bottom) ||
(extent.bottom < gridSquare.top))
{
return FALSE;
}
float a, b, c, dx, dy, s, x[4], y[4];
int max_x, max_y, min_x, min_y, p0x, p0y, p1x, p1y, sign, sign_old;
// construct array of vertices for grid square
x[0] = (float)gridSquare.left;
y[0] = (float)gridSquare.top;
x[1] = (float)(gridSquare.right);
y[1] = y[0];
x[2] = x[1];
y[2] = (float)(gridSquare.bottom);
x[3] = x[0];
y[3] = y[2];
// for each line segment
for(int i = 0; i < nV; i++)
{
// get end-points
p0x = pV[i].x;
p0y = pV[i].y;
p1x = pV[i + 1].x;
p1y = pV[i + 1].y;
// determine line extent
if(p0x > p1x){
min_x = p1x;
max_x = p0x;
} else {
min_x = p0x;
max_x = p1x;
}
if(p0y > p1y){
min_y = p1y;
max_y = p0y;
} else {
min_y = p0y;
max_y = p1y;
}
// test to see if grid square is outside of line segment extent
if( (max_x < gridSquare.left) ||
(min_x > gridSquare.right) ||
(max_y < gridSquare.top) ||
(min_y > gridSquare.bottom))
{
continue;
}
// calc. line equation
dx = (float)(p1x - p0x);
dy = (float)(p1y - p0y);
a = dy;
b = -dx;
c = -dy * (float)p0x + dx * (float)p0y;
// evaluate line eqn. at first grid square vertex
s = a * x[0] + b * y[0] + c;
if(s < 0.0f){
sign_old = -1;
} else if(s > 1.0f){
sign_old = 1;
} else {
sign_old = 0;
}
// evaluate line eqn. at other grid square vertices
for (int j = 1; j < 4; j++)
{
s = a * x[j] + b * y[j] + c;
if(s < 0.0f){
sign = -1;
} else if(s > 1.0f){
sign = 1;
} else {
sign = 0;
}
// if there has been a chnage in sign
if(sign != sign_old)
return TRUE;
}
}
return FALSE;
}
// calculate the square of the shortest distance from point s
// and the line segment between p0 and p1
// t is the point on the line from which the minimum distance
// is measured
float CalcShortestDistanceSqr(const CPoint &s,
const CPoint &p0,
const CPoint &p1,
CPoint &t)
{
// if point is at a vertex
if((s == p0) || (s == p1))
return(0.0F);
// calc. deltas
int dx = p1.x - p0.x;
int dy = p1.y - p0.y;
int dsx = s.x - p0.x;
int dsy = s.y - p0.y;
// if both deltas are zero
if((dx == 0) && (dy == 0))
{
// shortest distance is distance is to either vertex
float l = (float)(dsx * dsx + dsy * dsy);
t = p0;
return(l);
}
// calc. point, p, on line that is closest to sourcePosition
// p = p0 + l * (p1 - p0)
float l = (float)(dsx * dx + dsy * dy) / (float)(dx * dx + dy * dy);
// if intersection is beyond p0
if(l <= 0.0F){
// shortest distance is to p0
l = (float)(dsx * dsx + dsy * dsy);
t = p0;
// else if intersection is beyond p1
} else if(l >= 1.0F){
// shortest distance is to p1
dsx = s.x - p1.x;
dsy = s.y - p1.y;
l = (float)(dsx * dsx + dsy * dsy);
t = p1;
// if intersection is between line end points
} else {
// calc. perpendicular distance
float ldx = (float)dsx - l * (float)dx;
float ldy = (float)dsy - l * (float)dy;
t.x = p0.x + RoundValue(l * (float)dx);
t.y = p0.y + RoundValue(l * (float)dy);
l = ldx * ldx + ldy * ldy;
}
return(l);
}
// Calculates the bounding rectangle around a set of points
// Returns TRUE if the rectangle is not empty (has area), FALSE otherwise
// Opposite of CreateRectPoints()
BOOL CalcBoundingRectangle(const CPoint *pVertexList, const int nVertexTotal, CRect &rect)
{
rect.SetRectEmpty();
if(nVertexTotal < 2)
{
ASSERT(FALSE); // Must have at least 2 points
return FALSE;
}
// First point, set rectangle (no area at this point)
rect.left = rect.right = pVertexList[0].x;
rect.top = rect.bottom = pVertexList[0].y;
// Increst rectangle by looking at other points
for(int n = 1; n < nVertexTotal; n++)
{
if(rect.left > pVertexList[n].x) // Take minimum
rect.left = pVertexList[n].x;
if(rect.right < pVertexList[n].x) // Take maximum
rect.right = pVertexList[n].x;
if(rect.top > pVertexList[n].y) // Take minimum
rect.top = pVertexList[n].y;
if(rect.bottom < pVertexList[n].y) // Take maximum
rect.bottom = pVertexList[n].y;
}
rect.NormalizeRect(); // Normalise rectangle
return !(rect.IsRectEmpty());
}