How to draw a textured torus in OpenGL without using GLUT? - c#

I need to render a torus in OpenGL, without using GLUT. I'm using C# and Tao Framework bindings. I have the following code, which I got from here.
private void DrawTorus() {
int numc = 100, numt = 100;
double TWOPI = 2 * Math.PI;
for (int i = 0; i < numc; i++) {
Gl.glBegin(Gl.GL_QUAD_STRIP);
for (int j = 0; j <= numt; j++) {
for (int k = 1; k >= 0; k--) {
double s = (i + k) % numc + 0.5;
double t = j % numt;
double x = (1 + 0.1 * Math.Cos(s * TWOPI / numc)) * Math.Cos(t * TWOPI / numt);
double y = (1 + 0.1 * Math.Cos(s * TWOPI / numc)) * Math.Sin(t * TWOPI / numt);
double z = 0.1 * Math.Sin(s * TWOPI / numc);
Gl.glVertex3d(2 * x, 2 * y, 2 * z);
}
}
Gl.glEnd();
}
}
This code draws a torus, but now I need to put a texture on it. I'm trying to use these formulas for the texture coordinates, but I can't figure out what to use for R and r (inner and outer radius respectively).
v = arccos (Y/R)/2pi
u = [arccos ((X/(R + r*cos(2pi * v))] * 2pi
Having some trouble understanding that code, I would appreciate an explanation of it or perhaps an alternative, more intuitive code with comments. Any help will be much appreciated.

If we compare the formula
X = (R + r cos (2 pv)) cos (2 pu)
Y = r sin (2 pv)
Z = (R + r cos (2 pv)) sin (2 pu)
with the code
double x = (1 + 0.1 * Math.Cos(s * TWOPI / numc)) * Math.Cos(t * TWOPI / numt);
double y = (1 + 0.1 * Math.Cos(s * TWOPI / numc)) * Math.Sin(t * TWOPI / numt);
double z = 0.1 * Math.Sin(s * TWOPI / numc);
Clearly, X = x, Y = z, Z = y, R = 1, r = 0.1, 2 pv = s * TWOPI / numc and 2 pu = t * TWOPI / numt. Then
v = arccos (Y/R)/2p
u = [arccos ((X/(R + r*cos(2 pv))]2p
gives
v = arcos (z/1)/TWOPI
u = [arcos ((x/(1 + 0.1*cos(s * TWOPI / numc)]/TWOPI
EDIT: To be honest, I didn't try hard to understand the formula... Reading your code, I think this should do the trick:
u = (i + k) / (float)numc;
v = t / (float)numt;
(You may have to swap u and v.)

Related

Bicubic Interpolation - Correct Separation

I am trying to implement Bicubic image interpolation using cubic splines and the generalized formula for interpolation.
I was able to implement this by using all 16 surrounding pixels and calculate the interpolation coefficients from these 16 function values. But as interpolation is separable by definition, I tried to implement a version which uses two 1-D interpolations in order to achieve bicubic interpolation.
For the generalized interpolation formula I use e.g. http://bigwww.epfl.ch/publications/thevenaz9901.pdf chapter 3 and for the 1-D interpolation I use the idea behind this: http://www.vision-systems.com/articles/print/volume-12/issue-10/departments/wilsons-websites/understanding-image-interpolation-techniques.html
My coefficients are calculated by invertind the 4x4 matrix like in https://en.wikipedia.org/wiki/Spline_interpolation#Example
The interpolation consists of three functions.
The interpolation function itself (phi):
private float interpolate(float p_fValue)
{
p_fValue = Math.Abs(p_fValue);
if (p_fValue >= 1 && p_fValue < 2)
{
return 1.0f / 6.0f * (2.0f - p_fValue) * (2.0f - p_fValue) * (2.0f - p_fValue);//-(p_fValue * p_fValue * p_fValue) / 6.0f + p_fValue * p_fValue - 2.0f * p_fValue + 4.0f / 3.0f;
}
else if (p_fValue < 1)
{
return 2.0f / 3.0f - p_fValue * p_fValue + 0.5f * (p_fValue * p_fValue * p_fValue);
}
else
{
return 0.0f;
}
}
Calculating 4 coefficients from 4 function values:
private void calculateCoefficients(float p_f1, float p_f2, float p_f3, float p_f4, out float p_c1, out float p_c2, out float p_c3, out float p_c4)
{
p_c1 = 6.0f / 209.0f * (56.0f * p_f1 - 15.0f * p_f2 + 4.0f * p_f3 - p_f4);
p_c2 = 6.0f / 209.0f * (-15.0f * p_f1 + 60.0f * p_f2 - 16.0f * p_f3 + 4.0f * p_f4);
p_c3 = 6.0f / 209.0f * (4.0f * p_f1 - 16.0f * p_f2 + 60.0f * p_f3 - 15.0f * p_f4);
p_c4 = 6.0f / 209.0f * (-p_f1 + 4.0f * p_f2 - 15.0f * p_f3 + 56.0f * p_f4);
}
And the interpolation of a whole image from a smaller source image:
// p_siImage = original (smaller) image
// p_iImageWidth, p_iImageHeight = Image size (pixel count) of the new image
// Interpolation with standard formula u(x) = sum_{k to N} c_k * phi(x-k); For N function values
public SampledImage InterpolateImage(SampledImage p_siImage, int p_iImageWidth, int p_iImageHeight)
{
// Create interpolated image
SampledImage resultImage = new SampledImage((int)p_siImage.GetWidth(), (int)p_siImage.GetHeight(), p_iImageWidth, p_iImageHeight, p_siImage.GetPixelWidth(), p_siImage.GetPixelHeight());
for (int iX = 0; iX < p_iImageWidth; iX++)
{
for (int iY = 0; iY < p_iImageHeight; iY++)
{
// Calculate pixel position "in space"
float[] pixelSpace = resultImage.GetPixelInSpace(iX, iY);
// Calculate the index in smaller image, as real number (pixel index between pixels)
float[] pixelRealIndex = p_siImage.GetPixelRealFromSpace(pixelSpace[0], pixelSpace[1]);
// Calculate X values of surrounding pixels
int x_2 = (int)Math.Floor(pixelRealIndex[0]) - 1;
int x_1 = (int)Math.Floor(pixelRealIndex[0]);
int x1 = (int)Math.Floor(pixelRealIndex[0]) + 1;
int x2 = (int)Math.Floor(pixelRealIndex[0]) + 2;
// Calculate Y value of nearest pixel
int y = (int)Math.Floor(pixelRealIndex[1]);
// Arrays for "function values" (= color values)
float[] red = new float[4];
float[] green = new float[4];
float[] blue = new float[4];
// Create polynom for each column
for (int iiX = -1; iiX < 3; iiX++)
{
// Get column X-index
int x = (int)Math.Floor(pixelRealIndex[0]) + iiX;
// Used Y-Indices for polynom
int y_2 = (int)Math.Floor(pixelRealIndex[1]) - 1;
int y_1 = (int)Math.Floor(pixelRealIndex[1]);
int y1 = (int)Math.Floor(pixelRealIndex[1]) + 1;
int y2 = (int)Math.Floor(pixelRealIndex[1]) + 2;
// Get "function values" for each pixel in the column
Color fxy_2 = p_siImage.GetValueMirrored(x, y_2);
Color fxy_1 = p_siImage.GetValueMirrored(x, y_1);
Color fxy1 = p_siImage.GetValueMirrored(x, y1);
Color fxy2 = p_siImage.GetValueMirrored(x, y2);
// Coefficients c_k
float redC_2, redC_1, redC1, redC2;
float greenC_2, greenC_1, greenC1, greenC2;
float blueC_2, blueC_1, blueC1, blueC2;
// Calculate the coefficients for the column polynom
calculateCoefficients(fxy_2.R, fxy_1.R, fxy1.R, fxy2.R, out redC_2, out redC_1, out redC1, out redC2);
calculateCoefficients(fxy_2.G, fxy_1.G, fxy1.G, fxy2.G, out greenC_2, out greenC_1, out greenC1, out greenC2);
calculateCoefficients(fxy_2.B, fxy_1.B, fxy1.B, fxy2.B, out blueC_2, out blueC_1, out blueC1, out blueC2);
// Interpolate in each column at the same Y-Index as the actual interpolation position
red[iiX+1] = redC_2 * interpolate(pixelRealIndex[1] - (float)y_2) + redC_1 * interpolate(pixelRealIndex[1] - (float)y_1) +
redC1 * interpolate(pixelRealIndex[1] - (float)y1) + redC2 * interpolate(pixelRealIndex[1] - (float)y2);
green[iiX+1] = greenC_2 * interpolate(pixelRealIndex[1] - (float)y_2) + greenC_1 * interpolate(pixelRealIndex[1] - (float)y_1) +
greenC1 * interpolate(pixelRealIndex[1] - (float)y1) + greenC2 * interpolate(pixelRealIndex[1] - (float)y2);
blue[iiX+1] = blueC_2 * interpolate(pixelRealIndex[1] - (float)y_2) + blueC_1 * interpolate(pixelRealIndex[1] - (float)y_1) +
blueC1 * interpolate(pixelRealIndex[1] - (float)y1) + blueC2 * interpolate(pixelRealIndex[1] - (float)y2);
}
//Now: interpolate the actual value
// Get "function values" for each pixel in the row
Color fx_2y = p_siImage.GetValueMirrored(x_2, y);
Color fx_1y = p_siImage.GetValueMirrored(x_1, y);
Color fx1y = p_siImage.GetValueMirrored(x1, y);
Color fx2y = p_siImage.GetValueMirrored(x2, y);
// Coefficients c_k
float redCX_2, redCX_1, redCX1, redCX2;
float greenCX_2, greenCX_1, greenCX1, greenCX2;
float blueCX_2, blueCX_1, blueCX1, blueCX2;
// Calculate coefficients by using the interpolated values of each column
calculateCoefficients(red[0], red[1], red[2], red[3], out redCX_2, out redCX_1, out redCX1, out redCX2);
calculateCoefficients(green[0], green[1], green[2], green[3], out greenCX_2, out greenCX_1, out greenCX1, out greenCX2);
calculateCoefficients(blue[0], blue[1], blue[2], blue[3], out blueCX_2, out blueCX_1, out blueCX1, out blueCX2);
// Interpolate finally for the actual value
float redResult = redCX_2 * interpolate(pixelRealIndex[0] - (float)x_2) + redCX_1 * interpolate(pixelRealIndex[0] - (float)x_1) +
redCX1 * interpolate(pixelRealIndex[0] - (float)x1) + redCX2 * interpolate(pixelRealIndex[0] - (float)x2);
float greenResult = greenCX_2 * interpolate(pixelRealIndex[0] - (float)x_2) + greenCX_1 * interpolate(pixelRealIndex[0] - (float)x_1) +
greenCX1 * interpolate(pixelRealIndex[0] - (float)x1) + greenCX2 * interpolate(pixelRealIndex[0] - (float)x2);
float blueResult = blueCX_2 * interpolate(pixelRealIndex[0] - (float)x_2) + blueCX_1 * interpolate(pixelRealIndex[0] - (float)x_1) +
blueCX1 * interpolate(pixelRealIndex[0] - (float)x1) + blueCX2 * interpolate(pixelRealIndex[0] - (float)x2);
// Make sure to care for under/overshoots
redResult = Math.Max(0, Math.Min(redResult, 255));
greenResult = Math.Max(0, Math.Min(greenResult, 255));
blueResult = Math.Max(0, Math.Min(blueResult, 255));
// Set the pixel to the calculated value
Color resultColor = Color.FromArgb((int)redResult, (int)greenResult, (int)blueResult);
resultImage.SetValue(iX, iY, resultColor);
}
}
return resultImage;
}
For an image like this (15x15px):
The result looks like this (scaled to 80x80px):
In contrast, this is how the result looks if I calculate all 16 coefficients at once(80x80px):
My question is now:
How is the separation done correctly? Or am I missing something completely and I only can separate the interpolation function (phi) but not the calculation of the coefficients?

Is there a way to get a more precise circle in GDI+ than with DrawCircle?

I am struggling with a situation, where I want to draw a circle with GDI+ and some points on it (drawn as smaller circles), but the circle seems to be noncircular. By implementing scaling and zero point shifting, I zoom into the points and the circle, and find the points not lying exactly on the circle.
When I add a 'discrete' circle drawn with line segments, this circle does fit the points very well, if enough segments are used. Since the math is the same, I think that roundoff errors in my code can not be the cause of the circle deviations (although probably in the implementation of DrawEllipse).
In fact the deviations are biggest on 45/135/225/315 degrees.
I made a small project reproducing the effect with a slightly different setup: I draw multiple circles with their origins lying on an other circle with its center on the center of the form with the same radius. If everything goes well all circles shoud touch the center of the form. But with big radii like 100'000, they dont pass throug the center anymore, but miss it by a screendistance of maybe 15 pixel.
To reproduce the situation make a new c# project, put on form1 button1, and call the function Draw() from it:
private void Draw()
{
Graphics g = this.CreateGraphics();
g.Clear(this.BackColor );
double hw = this.Width / 2;
double hh = this.Height / 2;
double scale = 100000;
double R = 1;
for (int i = 0; i < 12; i++)
{
double angle = i * 30;
double cx = R * Math.Cos(angle * Math.PI / 180);
double cy = R * Math.Sin(angle * Math.PI / 180);
g.DrawEllipse(new Pen(Color.Blue, 1f), (float)(hw - scale * (cx + R)), (float)(hh + scale * (cy - R)), (float)(2 * R * scale), (float)(2 * R * scale));
g.DrawLine(Pens.Black, new Point(0, (int)hh), new Point(this.Width, (int)hh));
g.DrawLine(Pens.Black, new Point((int)hw, 0), new Point((int)hw, this.Height));
double r = 3;
g.DrawEllipse(new Pen(Color.Green, 1f), (float)(hw - r), (float)(hh - r), (float)(2 * r), (float)(2 * r));
//Pen magpen = new Pen(Color.Magenta, 1);
//double n = 360d / 1000;
//for (double j = 0; j < 360; j += n)
//{
// double p1x = R * Math.Cos(j * Math.PI / 180) + cx;
// double p1y = R * Math.Sin(j * Math.PI / 180) + cy;
// double p2x = R * Math.Cos((j + n) * Math.PI / 180) + cx;
// double p2y = R * Math.Sin((j + n) * Math.PI / 180) + cy;
// g.DrawLine(magpen, (float)(hw - scale * p1x), (float)(hh + scale * p1y), (float)(hw - scale * p2x), (float)(hh + scale * p2y));
//}
}
}
use the variable scale from 100 to 100'000 to see the effect: The circles don't touch the origin anymore, but wobble around it. If you uncomment the commented lines you can see, that the magenta 'discrete' circle performs much better.
Since using 'discrete' circles and arcs is a performance killer, I am looking for a way to draw better circles with GDI+.
Any ideas, suggestions?
GDI+ (at least in its native version) doesn't draw ellipses: it uses the cubic Bezier approximation, as described here and here.
That is, instead of
c = cos(angle);
s = sin(angle);
x = c * radius;
y = s * radius;
or, for an ellipse (a & b as semi major and semi minor axes in some order)
x = c * a;
y = s * b;
it uses
K = (sqrt(2) - 1) * 4.0 / 3;
t = angle * 0.5 / pi;
u = 1 - t;
c = (u * u * u) * 1 + (3 * u * u * t) * 1 + (3 * u * t * t) * K + (t * t * t) * 0;
s = (u * u * u) * 0 + (3 * u * u * t) * K + (3 * u * t * t) * 1 + (t * t * t) * 1;
(for angle in the range [0, pi/2]: other quadrants can be calculated by symmetry).
g.DrawArc(new Pen(Color.Blue, 1f), (float)((hw) - R * scale), -(float)((2 * R * scale) - hh), (float)(2 * R * scale), (float)(2 * R * scale), 0, 360);
Well I got somewhat precise results with this method.However this is only a sample.

how to Color map to dense optical flow

I'm trying to give certain colors to image based on their movement (like vector direction) in Emgu Cv. I have managed to calculate the dense optical flow to my video stream. I have used this
OpticalFlow.Farneback(prev,NextFrame,velx,vely,0.5,1,1,2,5,1.1,Emgu.CV.CvEnum.OPTICALFLOW_FARNEBACK_FLAG.FARNEBACK_GAUSSIAN);
The variable vely and velx contains the velocity of vertical and horizontal directions.Does anyone know how to map colors to these. There are many algorithms that calculates the dense flow. HS also can be used, but I'm not sure what to use.
Any solution would be really appreciated.
EDIT:
Optical Flow Color Map in OpenCV
This is the same thing that i wanted, since I'm using Emgu cv I tried to convert this code to c# but I cannot understand how to pass the dense flow to function "colorflow".
public void colorflow(MCvMat imgColor)
{
MCvMat imgHsv = new MCvMat();
double max_s = 0;
double[] hsv_ptr = new double[3000];
IntPtr[] color_ptr = new IntPtr[3000];
int r = 0, g = 0, b = 0;
double angle = 0;
double h = 0, s = 0, v = 0;
double deltaX = 0, deltaY = 0;
int x = 0, y = 0;
for (y = 0; y < imgColor.rows; y++)
{
for (x = 0; x < imgColor.cols; x++)
{
PointF fxy = new PointF(y, x);
deltaX = fxy.X;
deltaY = fxy.Y;
angle = Math.Atan2(deltaX, deltaY);
if (angle < 0)
angle += 2 * Math.PI;
hsv_ptr[3 * x] = angle * 180 / Math.PI;
hsv_ptr[3 * x + 1] = Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
hsv_ptr[3 * x + 2] = 0.9;
if (hsv_ptr[3 * x + 1] > max_s)
max_s = hsv_ptr[3 * x + 1];
}
}
for (y = 0; y < imgColor.rows; y++)
{
//hsv_ptr=imgHsv.ptr<float>(y);
//color_ptr=imgColor.ptr<unsigned char>(y);
for (x = 0; x < imgColor.cols; x++)
{
h = hsv_ptr[3 * x];
s = hsv_ptr[3 * x + 1] / max_s;
v = hsv_ptr[3 * x + 2];
//hsv2rgb(h,s,v,r,g,b);
Color c = ColorFromHSV(h, s, v);
color_ptr[3 * x] = (IntPtr)c.B;
color_ptr[3 * x + 1] = (IntPtr)c.G;
color_ptr[3 * x + 2] = (IntPtr)c.R;
}
}
drawLegendHSV(imgColor, 15, 25, 15);
}
I having trouble how to covert the two commented lines in the code. Can anyone Help me with this.?
Another thing that the Farneback algorithm gives two images velx and vely. It does not gives the flow( MCvMat). The colorFlow algorithms it takes the MCvMat type parameters.Did i done any wrong with the code. thanks

Rotate bunch of points thourgh an origin [duplicate]

This question already has answers here:
Rotating a point about another point (2D)
(6 answers)
Closed 9 years ago.
I have list of points containing x and y locations of a page. I want to apply rotation on all these points relative to any pivot point of page (currently lets assume its center).
var points = new List<Point>();
points.Add(1,1);
points.Add(15,18);
points.Add(25,2);
points.Add(160,175);
points.Add(150,97);
const int pageHeight = 300;
const int pageWidth = 400;
var pivotPoint = new Point(200, 150); //Center
var angle = 45; // its in degree.
// Apply rotation.
Do I need some formula here?
public static Point Rotate(Point point, Point pivot, double angleDegree)
{
double angle = angleDegree * Math.PI / 180;
double cos = Math.Cos(angle);
double sin = Math.Sin(angle);
int dx = point.X - pivot.X;
int dy = point.Y - pivot.Y;
double x = cos * dx - sin * dy + pivot.X;
double y = sin * dx + cos * dy + pivot.X;
Point rotated = new Point((int)Math.Round(x), (int)Math.Round(y));
return rotated;
}
static void Main(string[] args)
{
Console.WriteLine(Rotate(new Point(1, 1), new Point(0, 0), 45));
}
If you have a large number of points to rotate, you might want to precompute the rotation matrix…
[C -S U]
[S C V]
[0 0 1]
…where…
C = cos(θ)
S = sin(θ)
U = (1 - C) * pivot.x + S * pivot.y
V = (1 - C) * pivot.y - S * pivot.x
You then rotate each point as follows:
rotated.x = C * original.x - S * original.y + U;
rotated.x = S * original.x + C * original.y + V;
The above formula is the result of combining three transforms…
rotated = translate(pivot) * rotate(θ) * translate(-pivot) * original
…where…
translate([x y]) = [1 0 x]
[0 1 y]
[0 0 1]
rotate(θ) = [cos(θ) -sin(θ) 0]
[sin(θ) cos(θ) 0]
[ 0 0 1]
if u rotate a point(x,y) around point (x1,y1) by an angle some a then you need a formula...
x2 = cos(a) * (x-x1) - sin(a) * (y-y1) + x1
y2 = sin(a) * (x-x1) + cos(a) * (y-y1) + y1
Point newRotatedPoint = new Point(x2,y2)

lat lng of a point , knowing x distance and y degrees of a given point

I work on a C# project where i have a point of a given lattitude and longitude.
I need to find the lattitude and longitude of a second point that is x degrees angled and y meteres away from the given point.
thank you,
Agisilaos
See this page for Destination point given distance and bearing from start point
Here's a WGS-84 (non-spherical earth) version adapted from http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html:
private const double wgs84_major = 6378.137;
private const double wgs84_minor = 6356.7523142;
private const double wgs84_flattening = 1D / 298.257223563;
public static bool PointFromDistance(double latitude, double longitude, double angleRadians, double distanceMetres, out double newLatitude, out double newLongitude)
{
double a = wgs84_major * 1000;
double b = wgs84_minor * 1000;
double f = wgs84_flattening;
double s = distanceMetres;
double sinAlpha1 = Math.Sin(angleRadians), cosAlpha1 = Math.Cos(angleRadians);
double tanU1 = (1 - f) * Math.Tan(latitude * Math.PI / 180D);
double cosU1 = 1 / Math.Sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;
double sigma1 = Math.Atan2(tanU1, cosAlpha1);
double sinAlpha = cosU1 * sinAlpha1;
double cosSqAlpha = 1 - sinAlpha * sinAlpha;
double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
double sigma = s / (b * A), sigmaP = 2 * Math.PI;
double cos2SigmaM = 0;
double sinSigma = 0;
double cosSigma = 0;
double deltaSigma = 0;
while (Math.Abs(sigma - sigmaP) > 1e-12)
{
cos2SigmaM = Math.Cos(2 * sigma1 + sigma);
sinSigma = Math.Sin(sigma);
cosSigma = Math.Cos(sigma);
deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
sigmaP = sigma;
sigma = s / (b * A) + deltaSigma;
}
double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
double lat2 = Math.Atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - f) * Math.Sqrt(sinAlpha * sinAlpha + tmp * tmp));
double lambda = Math.Atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
double L = lambda - (1 - C) * f * sinAlpha *
(sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
double revAz = Math.Atan2(sinAlpha, -tmp); // final bearing
newLatitude = lat2 * 180D / Math.PI;
newLongitude = longitude + L * 180D / Math.PI;
return true;
}

Categories

Resources