I have a std::vector with 3 points (2D) with values x >= 0 and x <= 512.
With these 3 points I have to calculate a draw that passes all of these 3 points.
Here
you see the 3 Points and the corresponding circle. I need a function to interpolate the points based on a variable which defines the accuracy (eg the number of points inbetween).
If its not clear: I work in C++.
To solve your issue you need to calculate center of triangle's circumscribed circle and it radius. Then find min X and max X from triangle coordinates then calculate delta between maxX - minX and divide delta to numbers of input points. Then in loop you iterates from minX to maxX and calculate coordinates by using circle formula R^2 = (x - centerX)^2 + (y - centerY)^2.
Below a small example
#include <iostream>
#include <vector>
#include <math.h>
template <typename T>
class CPoint2D
{
public:
CPoint2D(T _x, T _y)
: x(_x)
, y(_y)
{}
~CPoint2D()
{}
const T& X() const { return x; }
const T& Y() const { return y; }
private:
T x;
T y;
};
typedef CPoint2D<float> CPoint2Df;
bool GetCenterCircumscribedCircle(float x0, float y0,
float x1, float y1,
float x2, float y2,
float& centerX, float& centerY, float& radius)
{
if ((x0 == x1 && x1 == x2) ||
(y0 == y1 && y1 == y2))
{
return false;
}
float D = 2.0f * (y0 * x2 + y1 * x0 - y1 * x2 - y0 * x1 - y2 * x0 + y2 * x1);
centerX = ( y1 * x0 * x0
- y2 * x0 * x0
- y1 * y1 * y0
+ y2 * y2 * y0
+ x1 * x1 * y2
+ y0 * y0 * y1
+ x2 * x2 * y0
- y2 * y2 * y1
- x2 * x2 * y1
- x1 * x1 * y0
+ y1 * y1 * y2
- y0 * y0 * y2) / D;
centerY = ( x0 * x0 * x2
+ y0 * y0 * x2
+ x1 * x1 * x0
- x1 * x1 * x2
+ y1 * y1 * x0
- y1 * y1 * x2
- x0 * x0 * x1
- y0 * y0 * x1
- x2 * x2 * x0
+ x2 * x2 * x1
- y2 * y2 * x0
+ y2 * y2 * x1) / D;
radius = sqrt((x0 - centerX) * (x0 - centerX) + (y0 - centerY) * (y0 - centerY));
return true;
}
void CalculatePointsOnCirle(const std::vector<CPoint2Df>& triVertexes, std::vector<CPoint2Df>& outPoints, float stride)
{
if (triVertexes.size() != 3)
{
return;
}
const CPoint2Df& v1 = triVertexes[0];
const CPoint2Df& v2 = triVertexes[1];
const CPoint2Df& v3 = triVertexes[2];
float minX = std::min(v1.X(), v2.X());
minX = std::min(minX, v3.X());
float maxX = std::max(v1.X(), v2.X());
maxX = std::max(maxX, v3.X());
float deltaX = (maxX - minX) / stride;
float centerX;
float centerY;
float radius;
if (GetCenterCircumscribedCircle(v1.X(), v1.Y(),
v2.X(), v2.Y(),
v3.X(), v3.Y(),
centerX, centerY, radius))
{
for (float x = minX; x < maxX; x += deltaX)
{
float y = sqrt(radius * radius - (x - centerX) * (x - centerX));
outPoints.push_back(CPoint2Df(x, y));
}
}
}
int main(int argc, const char * argv[])
{
std::vector<CPoint2Df> triVertex = {CPoint2Df(0.0f, 0.0f),
CPoint2Df(256.0f, 256.0f),
CPoint2Df(512.0f, 0.0f)};
std::vector<CPoint2Df> outPoints;
CalculatePointsOnCirle(triVertex, outPoints, 4);
for (unsigned int i = 0; i < outPoints.size(); ++i)
{
printf("p[%d]: (%f, %f)\n", i, outPoints[i].X(), outPoints[i].Y());
}
return 0;
}
Related
Can I operate the elements of an array in a function(in the parameter)?
float f(i, u, v)
{
if (i == 1) {
return (u - v); //example of the returned value
}
if (i == 2) {
return (u + v);
}
}
int main()
{
int i;
float x[3],y1,y2,h;
x[1]=1;//value of the first element of x[m]
x[2]=1;
h=0.01;
for (i = 1; i <= 2; i++) {
y1=h * f(i, x[1], x[2]);
y2=h * f(i, x[1] + y1/2, x[2]+y1/2);
y3=h* f(i,x[1] + y2/2, x[2]+y2/2);
y4=h * f(i,x[1] + y3, x[2]+y3);
x[1]=x[1] + (y1+ 2 * y2 + 2 * y3+2 * y4)/ 6;
x[2]=x[2] + (y1+ 2 * y2 + 2 * y3+2 * y4)/ 6;
cout<<x[1]<<endl;
}
}
with:
x[1] and x[2] are the elements of the array x[m]
How can I operate elements of different arrays in parameter?
I would recommend you to try to compile your code, the compiler will give you some important hints as of what is wrong. Here is the code compiled online.
To make it compile i changed it to this:
#include <iostream>
using namespace std;
float f(int i, float u, float v) {
if (i == 1) {
return (u - v); // example of the returned value
}
// if (i == 2) { // This if-statement is not needed
return (u + v);
// }
}
int main() {
int i;
float x[3] = {0, 1, 1}; // x[0] is unused...?
float y1 = 0;
float y2 = 0;
float y3 = 0;
float y4 = 0;
const float h = 0.01;
for (int i = 1; i <= 2; i++) {
y1 = h * f(i, x[1], x[2]);
y2 = h * f(i, x[1] + y1 / 2, x[2] + y1 / 2);
y3 = h * f(i, x[1] + y2 / 2, x[2] + y2 / 2);
y4 = h * f(i, x[1] + y3, x[2] + y3);
x[1] = x[1] + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
x[2] = x[2] + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
cout << x[1] << endl;
}
}
Note the changes
You need to specify the types for the variables in the function f(...)
You need to define all variables before using them (a good rule is to specify everything right before you use it, and add const if not changed.
Remember to zero initialize variables that you are going to add to (y1, y2... etc)
Also I would recommend you to use x1 instead of x1, since you are mixing styles between x and y, and you are not using the zeroeth element. Like this
int main() {
int i;
float x1 = 1;
float x2 = 2;
float y1 = 0;
float y2 = 0;
float y3 = 0;
float y4 = 0;
const float h = 0.01;
for (int i = 1; i <= 2; i++) {
y1 = h * f(i, x1, x2);
y2 = h * f(i, x1 + y1 / 2, x2 + y1 / 2);
y3 = h * f(i, x1 + y2 / 2, x2 + y2 / 2);
y4 = h * f(i, x1 + y3, x2 + y3);
x1 = x1 + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
x2 = x2 + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
cout << x1 << endl;
}
}
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";
}
Apologies for the wall of code below... but I'm not 100% sure of where the exact issue is. I'm using the Sutherland Hodgman clipping algorithm to find the contact points in my collision detection system (physics engine for my undergrad thesis). The vertices it returns are MOSTLY correct however I often get a lot of false positives on the InsideEdge function or incorrect intersections. If anyone can help I'd be so grateful! I have tried with many different input vertices and the result varies, however the X-axis does seem to be the most consistently correct.
Example IO with visual:
Input: clipping vertices [ (2.0, 2.0), (2.0, -2.0), (-2.0, -2.0), (-2.0, 2.0) ], poly vertices [ (2.5, 3.0), (2.5, 1.0), (0.5, 1.0), (0.5, 3.0) ]
Output: (2.0, 1.0), (0.5, 1.0), (0.5, 3.0 (wrong))
bool SAT::InsideEdge(double px, double py, double edgeMaxX, double edgeMaxY, double edgeMinX, double edgeMinY)
{
double one = (edgeMaxX - edgeMinX) * (py - edgeMinY);
double two = (edgeMaxY - edgeMinY) * (px - edgeMinX);
return (one - two) < 0;
}
void SAT::SutherlandHodgman(std::vector<Vector3>& _clipped, const Vector3& normal, const Vector3* polyVertices, const Vector3* clippingVertices)
{
const unsigned maxPoints = 16;
Vector3 newPoints[maxPoints];
for (unsigned i = 0; i < numVertices; i++)
{
newPoints[i] = polyVertices[i];
}
unsigned newSize = 0;
for (unsigned edge = 0; edge < numEdges; edge++) //for each clipping edge
{
//NOTE: axes is a 2D array to define which two axes to consider out of x, y, z
Vector3 edgeMin = clippingVertices[edge];
Vector3 edgeMax = clippingVertices[(edge + 1) % numEdges];
for (unsigned v = 0; v < numVertices; v++) //for each input vertex
{
Vector3 v1 = newPoints[v];
Vector3 v2 = newPoints[(v + 1) % numVertices];
bool insideEdge1 = InsideEdge(v1[axes[0]], v1[axes[1]], edgeMax[axes[0]], edgeMax[axes[1]], edgeMin[axes[0]], edgeMin[axes[1]]);
bool insideEdge2 = InsideEdge(v2[axes[0]], v2[axes[1]], edgeMax[axes[0]], edgeMax[axes[1]], edgeMin[axes[0]], edgeMin[axes[1]]);
if (insideEdge1 && insideEdge2)
{
newPoints[newSize] = v2;
newSize++;
}
else if (!insideEdge1 && insideEdge2)
{
newPoints[newSize] = CalculateIntersection(v1, v2, axes, edgeMin, edgeMax);
newSize++;
newPoints[newSize] = v2;
newSize++;
}
else if (insideEdge1 && !insideEdge2)
{
newPoints[newSize] = CalculateIntersection(v1, v2, axes, edgeMin, edgeMax);
newSize++;
}
}
numVertices = newSize;
if (numVertices >= maxPoints)
break;
}
for (unsigned i = 0; i < numVertices; i++)
{
//Removes duplicates before adding to the final list
VerifyVertex(_clipped, newPoints[i]);
}
}
And the calculate intersection code...
//x intersect
double num = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
double den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
double X = num / den;
//y intersect
num = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
double Y = num / den;
Vector3 intersection;
intersection[axes[0]] = X;
intersection[axes[1]] = Y;
//Get the value of the remaining axis
double percAcrossLine = 1;
if (x2 != 0)
percAcrossLine = (x1 + X) / x2;
else if (y2 != 0)
percAcrossLine = (y1 + Y) / y2;
unsigned i = 0;
if (axes[0] == 0)
{
if (axes[1] == 1)
i = 2;
else if (axes[1] == 2)
i = 1;
}
intersection[i] = v1[i] + (v2[i] - v1[i]) * percAcrossLine;
return intersection;
I'm trying to draw a flat bottom triangle, but its drawn as flat top triangle.
I would like to know what I'm doing wrong, in terms of math
here is my code
void Rasterizer::DrawBottomTriangle(int x0, int y0, int x1, int y1, int x2, int y2, Color color)
{
int temp_x;
// test order of x1 and x2
if (x2 < x1)
{
temp_x = x1;
x1 = x2;
x2 = temp_x;
} //
float dxy_left = (float)(x2 - x0) / (y2 - y0);
float dxy_right = (float)(x1 - x0) / (y1 - y0);
// set starting and ending points for edge trace
float xs = x0;
float xe = x0;
// draw each scanline
for (int y = y0; y >= y1; y--)
{
// draw a line from xs to xe at y in color c
DrawLine(color, (int)xs, y, color, (int)xe, (int)y);
// move down one scanline
xs += dxy_left;
xe += dxy_right;
} // end for y
}
I have two image buffers in YV12 format that I need to combine into a single side-by-side image.
(1920x1080) + (1920x1080) = (3840*1080)
YV12 is split into 3 seperate planes.
YYYYYYYY VV UU
The pixel format is 12 bits-per-pixel.
I have created a method that memcpys one buffer (1920x1080) into a larger buffer (3840x1080), but it isn't working.
Here is my c++.
BYTE* source = buffer;
BYTE* destination = convertBuffer3D;
// copy over the Y
for (int x = 0; x < height; x++)
{
memcpy(destination, source, width);
destination += width * 2;
source += width;
}
// copy over the V
for (int x = 0; x < (height / 2); x++)
{
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
}
// copy over the U
for (int x = 0; x < (height / 2); x++)
{
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
}
I expected this:
Instead, I get this result:
What am I missing?
What you wanted is this:
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
U1 U1 U2 U2 V1 V1 V2 V2
U1 U1 U2 U2 V1 V1 V2 V2
but your code is actually doing this:
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
U1 U1 V1 V1 U2 U2 V2 V2
U1 U1 V1 V1 U2 U2 V2 V2
Here's the corrected code (untested)
BYTE* source = buffer;
BYTE* destination = convertBuffer3D;
// copy over the Y
for (int x = 0; x < height; x++)
{
memcpy(destination, source, width);
destination += width * 2;
source += width;
}
for (int x = 0; x < (height / 2); x++)
{
// copy over the V
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
// copy over the U
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
}