Add your own alternative version
Stats
116.2K views 2.2K downloads 87 bookmarked
Posted
23 Jul 2007

Comments and Discussions



Hi,
I was looking at the code presented and was wondering how you avoid clashes with remapping of pixels. There would be occasions when two pixels in the original source image map to the same point in the output, which isn't so bad because the second would simply overwrite the first. However, there would also be occasions when no pixels in the source map to a given destination in the output resulting in unfilled locations  which I assume will appear as black spots.
Is this the case or have I missed something?
Regards,
John W.





I can not find the complete source code.
Where is the source code for Quote: Algebra class?
can you please help me to find the complete source code for this article?






Hi, I'm new here. Still in the learning process.
After i download the this project, it's work fine. What i found is it run a bit slow at bitmap.getpixel() there. Any ideas can make it faster? Thanks....





Hi there,
yes there is, you can get the raw bytes from the image and access the pixel colors directly from the array:
BitmapData oData = oBitmap.LockBits(
new Rectangle(0, 0, original.Width, oBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
int pixelSize = 3;
for (int y = 0; y < oBitmap.Height; y++)
{
byte* oRow = (byte*)oData.Scan0 + (y * oData.Stride);
byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);
for (int x = 0; x <; original.Width; x++)
{
// this is B nRow[x * pixelSize]
// this is G nRow[x * pixelSize + 1]
// this is R nRow[x * pixelSize + 2]
}
}
oBitmap.UnlockBits(oData);
Kind Regards
A
Anderson J. Almeida
Systems Analyst
TIHunter
http://www.tihunter.com





Hi,
Thanks for helping!
I had try it by using 2 it. May I know that is it need to assigned a set of point position first to become sphere then only pass to your function?
How about I want to assign the point one by one ?
Thanks ...





Hi,
can you insert this into your original code?





Dear friend,
I really upset with the program because it used a Library name Algebra which is not exists in my computer. Can you give me the link to download??
Eg: Algebra.RotX(Math.PI / 2, ref rty, ref rtz);
this line showns an error
www.socbay.com  Best data center  search engine in Vietnam





From the article...
The Rotation Functions [almost forgot]
Actually I made a 3D Math class, but here you will need only these
functions
public static void RotX(double angle, ref double y, ref double z)
{
double y1 = y * System.Math.Cos(angle)  z * System.Math.Sin(angle);
double z1 = y * System.Math.Sin(angle) + z * System.Math.Cos(angle);
y = y1;
z = z1;
}
public static void RotY(double angle, ref double x, ref double z)
{
double x1 = x * System.Math.Cos(angle)  z * System.Math.Sin(angle);
double z1 = x * System.Math.Sin(angle) + z * System.Math.Cos(angle);
x = x1;
z = z1;
}
public static void RotZ(double angle, ref double x, ref double y)
{
double x1 = x * System.Math.Cos(angle)  y * System.Math.Sin(angle);
double y1 = x * System.Math.Sin(angle) + y * System.Math.Cos(angle);
x = x1;
y = y1;
}
Anderson J. Almeida
Systems Analyst
SimSysBr
www.simsysbr.com





My point is that why don't you wrap all the classes up into a solution?
www.socbay.com  Best data center  search engine in Vietnam





Dear,
I got a feedback for you, when the image is large and the size of the output picture is larger than 600x600. there's many black dots in the output.
Yours sincerely,
Xuan Tai
www.socbay.com  Best data center  search engine in Vietnam





Any way to rotate the globe along polar axis  simulate normal globe rotation?
Thanks
Would look cool.





Already worked it out
Modified code
/// <summary>
/// The process is very simple where the x axis of the image will be mapped on sphere longitudes and the y axis of the image will be mapped on sphere latitudes.
/// The process of mapping is similar to proportion equations xx0/yy0 = pxx0/pyy0
///
/// <param name="i1">
/// <param name="i2">
/// <param name="w1">
/// <param name="w2">
/// <param name="p">
/// <returns>
private double MapCoordinate(double i1, double i2, double w1, double w2, double p)
{
return ((p  i1) / (i2  i1)) * (w2  w1) + w1;
}
public Bitmap Create(Bitmap imgBitmap)
{
return Create(imgBitmap, 0, 0);
}
public Bitmap Create(Bitmap imgBitmap, double rotateX, Double rotateY)
{
return Create(imgBitmap, rotateX, rotateY, 0);
}
public Bitmap Create(Bitmap imgBitmap, double rotateX,Double rotateY, double rotateLongitude)
{
double radius = imgBitmap.Height / 2;
int width = imgBitmap.Width;
int height = imgBitmap.Height;
int xcentre = width / 2;
int ycentre = height / 2;
Bitmap newBitmap = new Bitmap(imgBitmap.Width, imgBitmap.Height , PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(newBitmap);
for (int i = 0; i < imgBitmap.Width; i++)
{
for (int j = 0; j < imgBitmap.Height; j++)
{
// map the angles from image coordinates longitude
double theta = MapCoordinate(0.0, width  1,
theta1, theta0, i);
if (rotateLongitude != 0)
{
theta+= rotateLongitude;
}
// latitude
double phi = MapCoordinate(0.0, height  1, phi0,
phi1, j);
// find the cartesian coordinates
double x = radius * Math.Sin(phi) * Math.Cos(theta);
double y = radius * Math.Sin(phi) * Math.Sin(theta);
double z = radius * Math.Cos(phi);
// apply rotation around X and Y axis to reposition the sphere
if (rotateX != 0)
{
RotateAxis(rotateX, ref x, ref z);
}
if (rotateY != 0)
{
RotateAxis(rotateY, ref y, ref z);
}
// plot only positive points
if (z >= 0)
{
Color color = imgBitmap.GetPixel(i, j);
Brush brs = new SolidBrush(color);
//newBitmap.SetPixel((int)x + xcentre, (int)y + ycentre, color);
int ix = (int)x + xcentre;
int iy = (int)y + ycentre;
g.FillRectangle(brs, ix, iy, 3, 3);
brs.Dispose();
}
}
}
return newBitmap;
}
private void RotateAxis(double angle, ref double y, ref double z)
{
double y1 = y * System.Math.Cos(angle)  z * System.Math.Sin(angle);
double z1 = y * System.Math.Sin(angle) + z * System.Math.Cos(angle);
y = y1;
z = z1;
}





cool
Anderson J. Almeida
Systems Analyst
SimSysBr





It is a great article and I have a lot of fun playing the code. Do you have a similiar thing to map to a cylindrical surface? Thanks.





Sure, it is just you replace spherical coordinates to cylindrical coordinates:
...
for (int j = 0; j < imgBitmap.Height; j++)
{
double theta = Algebra.MapCoordinate(imgBitmap.Width  1, 0.0, theta0, theta1, i);
double x = radius * Math.Cos(theta);
double y = radius * Math.Sin(theta);
double z = 100j; // just to fit
Algebra.RotX(1.5, ref y, ref z);
if (z > 0)
{
...
Anderson J. Almeida
Systems Analyst
SimSysBr





Thank you very much! I'll try it later during weekend. Have a nice weekend!





A good series of articles! You've obviously got a good handle on the maths that underpins this sort of operation, and I hope you might be able to point me in the right for something I have been playing with. I've written some basic mapping functions to take geospatial data and draw a relatively simple 2D map. Drawing the roads/rivers/lakes etc is pretty straight forward, it's the labels (eg road names) that have proven hard. There are a number of issues here (such as collisions), but the one that I thought you might have a suggestion for is an algorithm/implementation for a text label that follows a curve. At the moment I simply take the end points of the curve (an array of points at present) and place a label on the resultant line. It works OK, but has got me curious as to how one makes the text follow the curve. Any ideas? I'm sure I'm not the first person to want to this.






Thx. I guess the trick is now to convert this so that it works using the .NET framework. That will keep me busy for a while.





The codes!
<br />
Color color = imgBitmap.GetPixel(i, j);<br />
Brush brs = new SolidBrush(color);<br />
Pen pen = new Pen(color);<br />
int ix = (int)x + 100;<br />
int iy = (int)y + 100;<br />
graphics.FillRectangle(brs, ix, iy, 1, 1);<br />
you are creating a pen several times without even using it, and a brush several times without even disposing any. Please, you only need to create the brush once and do brush.Color = imgBitmap.GetPixel(i, j); , since it a solidbrush.
BTW, it is a cool idea, similar to image reprojection algorithm in GIS.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.





Hmm thanks a lot, i will review my code and provide the changes
Anderson J. Almeida
Systems Analyst
SimSysBr





About disposing, i thought it was released by garbage collection after loosing scope?!?
Thanks again
Anderson J. Almeida
Systems Analyst
SimSysBr





Well, I always prefer simple experiment to test my *thought*....
Please run this console test and see the results.
using System;
namespace Experiment
{
public class TextA : IDisposable
{
private int _i;
public TextA(int i)
{
_i = i;
}
~TextA()
{
Dispose(false);
}
public void Print()
{
Console.WriteLine("Print: {0}", _i);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
Console.WriteLine("Test A: {0}", _i);
}
}
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
TextA text = new TextA(j);
text.Print();
}
}
Console.WriteLine("The Print is complete...");
System.Threading.Thread.Sleep(5000);
}
}
}
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.





It is, but if you call dispose the memory/resources are freed immediately, instead of "when it gets around to it."
I wrote a photo album/thumbmail generator a few years back using GDI+ to generate thumbnails of the jpegs on the fly. I immediately started having memory problems  my webserver only had 256mb ram, and after a few page loads asp.net would restart the process because it exceeded memory limits. Apparently the GDI objects were being created faster than the GC would clean them up.
I added in .dispose calls for all my GDI paint and bitmap objects and the memory problems completely dissapeared.





andalmeida wrote: About disposing, i thought it was released by garbage collection after loosing scope?!?
GDI objects are not  they have to be disposed directly. Answering 'why' would require alot more knowledge about Win32 and GDI than I know, but it has something to do with using unmanaged resources to draw to device contexts which never actually go away.
In other words, the references to drawing objects lay around once they're created, because they're attached to objects in the operating system. So, the GC can't dispose them.





Wow,thanks a lot for all this info, i have never released them...
Is it well documented ? I really didnt know...
Thanks a lot!
Anderson J. Almeida
Systems Analyst
SimSysBr





andalmeida wrote: Is it well documented ? I really didnt know...
Hmmm.. yes, depending on where you look. The MSDN documentation is spotty in their recommendation to dispose the objects.
It's a common thing for people not to know, it's not immediately obvious that THOSE particular objects won't be disposed.
It's something I didn't discover until I was doing some stuff with icons and was getting random crashes and couldn't figure out why, until someone told me to dispose all of my GDI objects.





yes, you'd run into problems if you "new" a lot of GDI resources without disposing them.
Best approach is to use "using", then even if you get exception in your code, your resoures will be disposed.
using (Brush brush = new SolidBrush(...))
{
use brush
}
also, since you'r drawing onto bitmap, it would be faster to juse use bitmap.SetPixel() instead of FillRect with 1 pixel rectangle.





That math made absolutely no sense to me...but the end result is cool! lol
Thanks,
Ben





Thanks
Anderson J. Almeida
Systems Analyst
SimSysBr





Good job on a clear sample of math for a sphere.
How about the code/math for an ellipse or a link for finding it?
Neil
nlneilson





Hey, i have never seen, but i can try from scratch if i figure out will post here
Anderson J. Almeida
Systems Analyst
SimSysBr





you can extend the algorithm using the ellipse math... http://mathworld.wolfram.com/Ellipsoid.html
now it is only calculate the line x ellipse intersection please let me know if you need help on this
Anderson J. Almeida
Systems Analyst
SimSysBr





That is an interesting link, it has been many years since I took calculus.
I have tinkered with the Vincenty Formula considerably for the geodesic distance and bearings.
I have not tried 2D pictures on a sphere, that is why your post was interesting.
NASA WorldWind 1.4 in .net C# and WWJ in Java is using a sphereoid rather than an ellipsoid. If the math could be worked out it would be a real improvement.
nlneilson





done,
just change the radius to a, b and c from the ellipse formula
double x = a * Math.Sin(phi) * Math.Cos(theta);
double y = b * Math.Sin(phi) * Math.Sin(theta);
double z = c * Math.Cos(phi);
http://www.simsysbr.com/articles/mapping/mappingapp2.aspx[^]
Anderson J. Almeida
Systems Analyst
SimSysBr





Yes, this will draw an ellipsoid, or a close approximation.
The distance using Math.Cos(theta) is close enough for most purposes. For an actual drawing of the Earth, as a spheroid or an ellipsoid per WGS84, it is visually indistinguishable.
The problem comes into play when when a distance over the drawing is measured from two points, where an icon or other image is placed, tracking, etc.
The GIS, WMS images are quite accurate. To get the data FROM a pixel on the screen and working backwards to get the latlon the error is compounded.
In the Vincenty Formula, and others, getting the accurate "cos" which is found by iteration until the desired accuracy is obtained.
The latitude measured for a point on the Earth and the GIS data is normal to the surface of the ellipsoid, it is not the same as on a sphere except at the poles and the equator.
You answered my original question on placing a 2D image on an ellipse.
The link given in your first reply may be able to modify the approx. to a more accurate placement. Trimble's GPS Survey software will do this as others will (I think from the data read) but of course it is not open source.
nlneilson







General News Suggestion Question Bug Answer Joke Praise Rant Admin Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

