I am attempting to write a function that will tell me if an angle lies within 2 other angles. When say 'if an angle lies within 2 other angles' I mean for example, if I have the 2 angles 0 and 90 then 45 would lie between those angles but -20(or 99) would not.
My Problem: My function doesn't seem to be detecting when 2 angles lie within 2 angles when it should. I'm not sure if my function works for negative angles aswell?
What do I need to change to get my function working correctly?
bool is_angle_between(int target, int angle1, int angle2)
{
// Post: Return true if target lies between the 2 angles
int iTarget = (360 + (target % 360)) % 360;
int iAngle1 = (3600000 + angle1) % 360;
int iAngle2 = (3600000 + angle2) % 360;
if (iAngle1 < iAngle2)
if (iAngle1 <= iTarget && iTarget <= iAngle2)
return true;
else if (iAngle1 <= iTarget || iTarget <= iAngle2)
return true;
return false;
}
This question only has to do with testing whether an integer lies between within the range of two other integers. Since we do not know whether angle1 or angle2 is the larger value, I would do something like this:
bool is_angle_between(int target, int angle1, int angle2)
{
return (target > angle1 && target < angle2) ||
(target > angle2 && target < angle1);
}
A good way to do this is to rotate the interval so that all numbers you compare are positive:
int rTarget = ((target - angle1) % 360 + 360) % 360;
int rAngle2 = ((angle2 - angle1) % 360 + 360) % 360;
return 0 <= rAngle1 && rAngle1 <= rAngle2;
Otherwise you will get into trouble near 0 = 360 degrees.
BTW, you should avoid unnecessary if statements, as branching can be expensive.
Seems like this should work:
if (iAngle1 < iAngle2) {
if (iAngle1 <= iTarget && iTarget <= iAngle2) {
return true;
}
}
else {
if (iAngle2 <= iTarget && iTarget <= iAngle1) {
return true;
}
}
return false;
Note that the braces here help ensure that the else matches the if you intend it to. Your original code is indented as you want it to match, but that isn't how it's parsed.
Related
Given the following code pattern, wherein I am trying to state a vector direction in increments of 45 degrees over the integers int x and int y, inside of a circle positioned at the origin
// x == 0 && y == 0 case is already taken cared of
if(x > 1) {
if(y == 0) {
// horizontal right
m_rotation = 0;
}else if(y < 1) {
// diagonal down right
m_rotation = 315;
} else if(y > 1) {
// diagonal up right
m_rotation = 45;
}
} else if(x == 0) {
if(y < 1) {
// vertical down
m_rotation = 270;
} else if(y > 1) {
// vertical up
m_rotation = 90;
}
} else if(x < 1){
if(y == 0) {
// horizontal left
m_rotation = 180;
}else if(y < 1) {
// diagonal down left
m_rotation = 225;
} else if(y > 1) {
// diagonal up left
m_rotation = 135;
}
}
I am looking for an elegant way to make this compact. I know there's the spaceship operator <=>, but I need to restrict myself to C++17.
Things I have tried
Nesting ternary operators with m_rotation = x > 1? (y < 1? (y == 0? 0: 315): 45): (x == 0? (y < 1? 270: 90): (y < 1? (y == 0? 180: 225): 135));, but this looks weird
I tried putting the x == 0 case inside x < 1 case and transform the later into else, but that does not simplify enough the code
Using absolute values to compare x and y, but I quickly get lost
Nothing else really, I don't know what else to try
Something like
constexpr int rotation[3][3] = {
{225, 180, 135},
{270, 0, 90},
{315, 0, 45},
};
if (x != 0 || y != 0) // if (!(x == 0 && y == 0))
m_rotation = rotation[1 + sign(x)][1 + sign(y)];
There is a closed form:
// standard sign functions
int xs = x < 0 ? -1 : x > 0;
int ys = y < 0 ? -1 : y > 0;
return 180 - 45 * (xs + 2) * ys + 90 * (xs * xs + xs) * (ys * ys - 1);
or shorter
return 180 * (x < 0 || y) - 45 * (xs + 2) * ys;
I was coding when i faced this problem and i would like to know if this is correct or it can be improved for performance reasons:
if (color == 0) {
if (c.val[0] >= 0 && c.val[0] <= 64) {
//Black
Paint(cursor.x + x, cursor.y + y);
}
}
else if (color == 1) {
if (c.val[0] >= 64 && c.val[0] <= 128) {
//Grey
Paint(cursor.x + x, cursor.y + y);
}
}
else if (color == 2) {
if (c.val[0] >= 128 && c.val[0] <= 192) {
//White Gray
Paint(cursor.x + x, cursor.y + y);
}
}
As you can see im doing the exact same thing inside all IF statements and it looks kind weird, the program works as i want but i really think im missing something..
Thanks!
Because of the structure,
if (color >= 0 && color <= 2) {
if (c.val[0] >= 64*color && c.val[0] <= 64*(color+1)) {
Paint(cursor.x + x, cursor.y + y);
}
}
A few logical operations make it more compact.
if ((color == 0 && c.val[0] >= 0 && c.val[0] <= 64) ||
(color == 1 && c.val[0] >= 64 && c.val[0] <= 128) ||
(color == 2 && c.val[0] >= 128 && c.val[0] <= 192)) {
Paint(cursor.x + x, cursor.y + y);
}
This isn't too terrible with such a short piece of code repeated, but in the interest of Don't Repeat Yourself, and in case more code is needed later, you could simply separate the testing for whether something will be done from the actual doing it, using a flag.
bool need_Paint = false;
if (color == 0) {
// Black?
need_Paint = (c.val[0] >= 0 && c.val[0] <= 64);
}
else if (color == 1) {
// Grey?
need_Paint = (c.val[0] >= 64 && c.val[0] <= 128);
}
else if (color == 2) {
// White Gray?
need_Paint = (c.val[0] >= 128 && c.val[0] <= 192);
}
if (need_Paint)
Paint(cursor.x + x, cursor.y + y);
(Note a compiler's optimizations can possibly handle this sort of thing without actually putting a bool in memory, just jumping to the function call statement if the appropriate condition is true.)
(This also looks like the sort of pattern often written as a switch. You could consider using that syntax instead of all the ifs.)
But in fact this particular code can get even simpler, because there's a straightforward mathematical pattern to the three different tests you're doing:
if (color >= 0 && color <= 2 && // (if these aren't already guaranteed)
c.val[0] >= 64*color && c.val[0] <= 64*(color+1)) {
Paint(cursor.x + x, cursor.y + y);
}
(Another thing to consider might be using enum ColorType { BLACK=0, GREY=1, WHITE_GRAY=2 }; instead of just writing the "magic numbers" 0, 1, and 2 directly. But if you use both an enum and the mathematical version of this code, I'd recommend you specify the exact values as shown, even though the default for an enum is always consecutive counting from zero, to make it clear you're counting on those values.)
I like your original post more than the selection.
Here is a another approach with about the same number of lines ... but I find more readable.
void yourSnippet() {
switch (color) {
case 0: { PaintIf( 0, 64); } break; // black
case 1: { PaintIf( 64, 128); } break; // Grey
case 2: { PaintIf(128, 192); } break; // White Gray
} // switch
}
void PaintIf(int min, int max) {
if ((c.val[0] >= min) && (c.val[0] <= max))
Paint(cursor.x + x, cursor.y + y);
}
Another solution that closely follows the lines of 2785528's answer but uses a lambda to avoid passing additional arguments to PaintIf:
const auto PaintIf = [&](int min, int max)
{
if (min <= c.val[0] && c.val[0] <= max)
Paint(cursor.x + x, cursor.y + y);
};
switch (color)
{
case 0: PaintIf( 0, 64); break;
case 1: PaintIf( 64, 128); break;
case 2: PaintIf(128, 192);
}
Lambdas are (as of c++17) guaranteed to be constexpr (i.e. zero cost abstractions) if possible.
They can sometimes allow more succinct and maintainable expressions of logic:
auto range = [](int color)
{
auto min = color * 64;
auto max = min + 64;
return std::make_tuple(min, max);
};
auto in_range = [](auto val, auto tuple)
{
auto [min, max] = tuple;
return val >= min && val <= max;
};
if (in_range(c.val[0], range(color)))
Paint(cursor.x + x, cursor.y + y);
I would like to recognize in what axis quarter is a given angle
In the Most efficient way
Quarter 1:
Alpha > 0 && Alpha <= 90 (degrees)
Quarter 2:
Alpha > 90 && Alpha <= 180 (degrees)
Quarter 3:
Alpha > 180 && Alpha <= 270 (degrees)
Quarter 4:
Alpha > 270 && Alpha <= 360 (degrees)
C++ Code
FORCEINLINE uint8 MapAngleToQuarter(float angle)
{
angle = (int)angle % 360;
float answer = 0;
if(angle > 0 && angle <= 90)
{
answer = 1;
}
else if(angle > 90 && angle <= 180)
{
answer = 2;
}
else if(angle > 180 && angle <= 270)
{
answer = 3;
}
else if(angle > 270 && angle <= 360)
{
answer = 4;
}
return answer;
}
My question: Is there a better (more efficient) way to do the above task ?
With the angle in the (0...360] range
FORCEINLINE uint8 MapAngleToQuarter(float angle) {
int a = (int) angle;
return (a - 1)/90 + 1;
}
I'm trying to implement a simple 2D convolution (mean filter in this case). But when I compare my results with an image generated by opencv's filter2D function I see a lot of differences. My current code is:
cv::Mat filter2D(cv::Mat& image, uint32_t kernelSize = 3)
{
float divider = kernelSize*kernelSize;
cv::Mat kernel = cv::Mat::ones(kernelSize,kernelSize,CV_32F) / divider;
int kHalf = kernelSize/2.f;
cv::Mat smoothedImage = cv::Mat::ones(image.rows,image.cols,image.type());
for (int32_t y = 0; y<image.rows; ++y) {
for (int32_t x = 0; x<image.cols; ++x) {
uint8_t sum = 0;
for (int m = -kHalf; m <= kHalf; ++m) {
for (int n = -kHalf; n <= kHalf; ++n) {
if (x+n >= 0 || x+n <= image.cols || y+m >= 0 || y <= image.rows) {
sum += kernel.at<float>(m+kHalf, n+kHalf)*image.at<uint8_t>(y-m+1, x-n+1);
} else {
// Zero padding - nothing to do
}
}
}
smoothedImage.at<uint8_t>(y,x) = sum;
}
}
return smoothedImage;
}
The results for a kernel size of five are (1. opencv, 2. my implementation):
I would appreciate if someone can explain me what I'm doing wrong.
For starter, your condition to account for edges should use && instead of || like so:
if (x+n >= 0 && x+n <= image.cols && y+m >= 0 && y <= image.rows)
This should help a little to remove artefacts around the edge.
Then, for the artefacts on the inner region, you should make sure the sum stays within the 0-255 range, and try to avoid loosing resolution every time you cast the partial result back to uint8_t as you assign to sum:
float sum = 0;
for (int m = -kHalf; m <= kHalf; ++m) {
for (int n = -kHalf; n <= kHalf; ++n) {
if (x+n >= 0 && x+n <= image.cols && y+m >= 0 && y <= image.rows) {
sum += kernel.at<float>(m+kHalf, n+kHalf)*image.at<uint8_t>(y-m+1, x-n+1);
} else {
// Zero padding - nothing to do
}
}
}
smoothedImage.at<uint8_t>(y,x) = std::min(std::max(0.0f, sum), 255.0f);
I have an algorithm that can find if a point is inside a polygon.
int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
{
int i, j, c = 0;
for (i = 0, j = npts-1; i < npts; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
c = !c;
}
return c;
}
My only issue with it is it assumes an odd winding rule. What I mean by this is that if the polygon is self intersecting, certain parts that it would considered to be 'empty' will return as false. What I'd need in even if it self intersects, anything inside the polygon will return true.
Thanks
Beware: this answer is wrong. I have no time to fix it right now, but see the comments.
This casts a ray from the point to infinity, and checks for intersections with each of the polygon's edges. Each time an intersection is found, the flag c is toggled:
c = !c;
So an even number of intersections means an even number of toggles, so c will be 0 at the end. An odd number of intersections means an odd number of toggles, so c will be 1.
What you want instead is to set the c flag if any intersection occurs:
c = 1;
And for good measure, you can then eliminate c entirely, and terminate early:
int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
{
int i, j;
for (i = 0, j = npts-1; i < npts; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
return 1;
}
return 0;
}
To translate your original algorithm to english: You're determining if the number of polygon segments to the right of your point are even or odd. If it's even (including zero) your point is outside, if it's odd your point is inside. This means if there are two segments to the right and also two segments to the left, the point is not considered inside the polygon.
What you need to do is change the algorithm so that it checks for segments on both sides; if there's a segment on both sides of the point, then the point is within the polygon.
int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
{
int i, j;
bool hasSegmentLeft = false;
bool hasSegmentRight = false;
for (i = 0, j = npts-1; i < npts; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))))
{
if (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])
{
hasSegmentRight = true;
if (hasSegmentLeft) // short circuit early return
return true;
}
else
{
hasSegmentLeft = true;
if (hasSegmentRight) // short circuit early return
return true;
}
}
return hasSegmentLeft && hasSegmentRight;
}
P.S. that for statement construct is a very clever way of dealing with a circular list that wraps around to the beginning; I'd never seen it before.