PDA

View Full Version : Equation of a plane at an altitude h from earth's surface



shariq
05-04-2015, 11:21 PM
Hi,

I need a plane at an altitude say h from earth's surface. I am going to use this to clip a sphere. In normal cartesian coordination system, I am able to visualize it. But when it comes to a globe, I have few doubts:
1.) The units that i follow is in meters, so I draw a plane that is at a height of (earth's radius + h) meters from earth's core(0,0,0). Is this correct? or some conversion is required.
2.) I fail to understand whether the axes of globe(x,y,z) are fixed or not, i mean if they are fixed then let say z axis is normal at longitude 0 degrees, then if I am standing at lat lon (32.5, 75.2) then how can the equation of the plane tangent to the surface at this location be z=radius of earth at (32.5, 75.2). It should be in terms of x,y,z and not z alone. isn't it?

To my help my api provides the conversion from latlon to cartesian coords(Vec4) as required by openGL.

Vec4 centerPoint = this.computePointFromPosition(dc,
this.location.getLatitude(), this.location.getLongitude(), altitudes[0], terrainConformant[0]);

I create a plane at this location:

DoubleBuffer eqn1 = BufferUtils.createDoubleBuffer(8).put(new double[] {centerPoint.getX(), centerPoint.getY(), centerPoint.getZ(), centerPoint.getW()}); //Some thing wrong with this Please check if this equation is correct
eqn1.flip();
gl.glClipPlane(GL.GL_CLIP_PLANE0, eqn1);
gl.glEnable(GL.GL_CLIP_PLANE0);

Here is the code, please check the equation of plane and let me know if some modification is required:

@Override
public void drawSphere(DrawContext dc)
{
double[] altitudes = this.getAltitudes(dc.getVerticalExaggeration());
boolean[] terrainConformant = this.isTerrainConforming();
int subdivisions = this.getSubdivisions();

if (this.isEnableLevelOfDetail())
{
DetailLevel level = this.computeDetailLevel(dc);

Object o = level.getValue(SUBDIVISIONS);
if (o != null && o instanceof Integer)
subdivisions = (Integer) o;
}

Vec4 centerPoint = this.computePointFromPosition(dc,
this.location.getLatitude(), this.location.getLongitude(), altitudes[0], terrainConformant[0]);

Matrix modelview = dc.getView().getModelviewMatrix();
modelview = modelview.multiply(Matrix.fromTranslation(centerPo int));
modelview = modelview.multiply(Matrix.fromScale(this.getRadius ()));
double[] matrixArray = new double[16];
modelview.toArray(matrixArray, 0, false);

this.setExpiryTime(-1L); // Sphere geometry never expires.


GL gl = dc.getGL(); // GL initialization checks for GL2 compatibility.
gl.glPushAttrib(GL.GL_POLYGON_BIT | GL.GL_TRANSFORM_BIT);
try
{

gl.glEnable(GL.GL_CULL_FACE);
gl.glFrontFace(GL.GL_CCW);

// Were applying a scale transform on the modelview matrix, so the normal vectors must be re-normalized
// before lighting is computed. In this case we're scaling by a constant factor, so GL_RESCALE_NORMAL
// is sufficient and potentially less expensive than GL_NORMALIZE (or computing unique normal vectors
// for each value of radius). GL_RESCALE_NORMAL was introduced in OpenGL version 1.2.
gl.glEnable(GL.GL_RESCALE_NORMAL);

gl.glMatrixMode(GL.GL_MODELVIEW);

//clipping
//double eRad = canvas.getModel().getGlobe().getRadiusAt(location) ;//added this to clipping height to come to earth's surface from core, please check this
DoubleBuffer eqn1 = BufferUtils.createDoubleBuffer(8).put(new double[] {centerPoint.getX(), centerPoint.getY(), centerPoint.getZ(), centerPoint.getW()}); //Some thing wrong with this Please check if this equation is correct
eqn1.flip();
gl.glClipPlane(GL.GL_CLIP_PLANE0, eqn1);
gl.glEnable(GL.GL_CLIP_PLANE0);

gl.glPushMatrix();


try
{
gl.glLoadMatrixd(matrixArray, 0);
this.drawUnitSphere(dc, subdivisions);
}
finally
{
gl.glPopMatrix();
}
}
finally
{
gl.glPopAttrib();
}
}

@Override
public void drawUnitSphere(DrawContext dc, int subdivisions)
{
Object cacheKey = new Geometry.CacheKey(this.getClass(), "Sphere", subdivisions);
Geometry geom = (Geometry) this.getGeometryCache().getObject(cacheKey);
if (geom == null || this.isExpired(dc, geom))
{
if (geom == null)
geom = new Geometry();
this.makeSphere(1.0, subdivisions, geom);
this.updateExpiryCriteria(dc, geom);
this.getGeometryCache().add(cacheKey, geom);
}

this.getRenderer().drawGeometry(dc, geom);
}

@Override
public void makeSphere(double radius, int subdivisions, Geometry dest)
{
GeometryBuilder gb = this.getGeometryBuilder();
gb.setOrientation(GeometryBuilder.OUTSIDE);

GeometryBuilder.IndexedTriangleArray ita = gb.tessellateSphere((float) radius, subdivisions);
float[] normalArray = new float[3 * ita.getVertexCount()];
gb.makeIndexedTriangleArrayNormals(ita, normalArray);

dest.setElementData(GL.GL_TRIANGLES, ita.getIndexCount(), ita.getIndices());
dest.setVertexData(ita.getVertexCount(), ita.getVertices());
dest.setNormalData(ita.getVertexCount(), normalArray);
}

Carmine
05-05-2015, 12:04 PM
The figure below demonstrates a 'clipped' versus a 'flattened' sphere.
Which is it that you want? Seems to me that you want a flattened sphere.
BTW - I'm not explicitly clipping the parts of the spheres beneath the earth's surface.
OpenGL is doing that automatically with the Z buffer.

1793

shariq
05-06-2015, 04:13 AM
Hi Carmine,

What have you used to to draw this figure? Please share your implementation, you can also check my implementation and let me know whats wrong.

Yes in your figure,the flattened sphere is close to my requirement.
But the rounded edges seem inappropriate to me, if I am cutting a sphere by a plane why should I get rounded edges?


I have made some progress in my code and hope I am very close.

The cartesian coordinate system I am following is at : http://www.colorado.edu/geography/gcraft/notes/coordsys/gif/ecefxyz.gif

I am able to translate to my location and draw a gluSphere(). Before this I rotate the axes and define a plane at (1,0,0,eRad + 1000). Here eRad is earth's radius and 1000 is height above surface, since radius of my sphere is 2000 meters).

It still does not clip my sphere.

Here is the code:

@Override
public void drawSphere(DrawContext dc)
{
double[] altitudes = this.getAltitudes(dc.getVerticalExaggeration());
boolean[] terrainConformant = this.isTerrainConforming();
int subdivisions = this.getSubdivisions();

if (this.isEnableLevelOfDetail())
{
DetailLevel level = this.computeDetailLevel(dc);

Object o = level.getValue(SUBDIVISIONS);
if (o != null && o instanceof Integer)
subdivisions = (Integer) o;
}

Vec4 centerPoint = this.computePointFromPosition(dc,
this.location.getLatitude(), this.location.getLongitude(), altitudes[0], terrainConformant[0]);

Matrix modelview = dc.getView().getModelviewMatrix();
modelview = modelview.multiply(Matrix.fromTranslation(centerPo int));
modelview = modelview.multiply(Matrix.fromScale(this.getRadius ()));
double[] matrixArray = new double[16];
modelview.toArray(matrixArray, 0, false);

this.setExpiryTime(-1L); // Sphere geometry never expires.


GL gl = dc.getGL();
gl.glPushAttrib(GL.GL_POLYGON_BIT | GL.GL_TRANSFORM_BIT);
try
{
gl.glEnable(GL.GL_CULL_FACE);
gl.glFrontFace(GL.GL_CCW);
gl.glEnable(GL.GL_RESCALE_NORMAL);
gl.glMatrixMode(GL.GL_MODELVIEW);

//clipping
gl.glRotated(location.getLongitude().getDegrees(), 1,0,0);
gl.glRotated(-location.getLatitude().getDegrees(),0,1,0);
double eRad = dc.getGlobe().getRadiusAt(location);
DoubleBuffer eqn1 = BufferUtils.createDoubleBuffer(8).put(new double[] {1,0,0,eRad+1000});
eqn1.flip();
gl.glClipPlane(GL.GL_CLIP_PLANE0, eqn1);
gl.glEnable(GL.GL_CLIP_PLANE0);

gl.glPushMatrix();
try
{
gl.glRotated(-location.getLongitude().getDegrees(),1,0,0);
gl.glRotated(location.getLatitude().getDegrees(),0 ,1,0);
gl.glTranslated(centrePoint.getX(), centrePoint.getY(), centrePoint.getZ());
gl.glColor3f(1.0f, 0.0f, 0.0f);
GLU glu = dc.getGLU();
GLUQuadric obj = glu.gluNewQuadric();
glu.gluSphere(obj,this.getRadius(),100,10);

}
finally
{
gl.glPopMatrix();
}
}
finally
{
gl.glPopAttrib();
}
}

Carmine
05-06-2015, 10:10 AM
... What have you used to to draw this figure? I used a geometric modeling/animation package called 'modo' to draw my spheres. You could think of it as using a CAD package. So that's not going to be of use to you since you are working in OpenGL.


... in your figure,the flattened sphere is close to my requirement. But the rounded edges seem inappropriate to me, if I am cutting a sphere by a plane why should I get rounded edges? I used rounded edges on the flattened sphere because it looked like that's what was used in the images you posted. It's actually easier to do it with sharp edges. Would be helpful if you posted a picture showing where you stand now. You realize that simply clipping a sphere will leave a hole as in shown in my figure. You're going to need to find a way to plug that hole.

Also, if you 'cap' a clipped sphere with a filled in circle, the cap will not be a surface of constant altitude. Ideally, the clipped sphere should be capped with a section of a sphere centered at the center of the earth.

shariq
05-07-2015, 02:33 AM
At the moment I am trying to at least clip my sphere in any manner, will correct it if it does not cap but it should at least clip or have any effect on my sphere.

For that I need to be sure about my plane if its defined correctly.

I am currently able to draw a hemisphere at the position I translated to. Don't have a picture as I am at client's location with restricted access.

Please verify if the rotation and plane equation in the code below is correct according to the requirement:


gl.glRotated(location.getLongitude().getDegrees(), 1,0,0);
gl.glRotated(-location.getLatitude().getDegrees(),0,1,0);
double eRad = dc.getGlobe().getRadiusAt(location);
DoubleBuffer eqn1 = BufferUtils.createDoubleBuffer(8).put(new double[] {1,0,0,eRad+1000});
eqn1.flip();
gl.glClipPlane(GL.GL_CLIP_PLANE0, eqn1);
gl.glEnable(GL.GL_CLIP_PLANE0);

gl.glPushMatrix();
try
{
gl.glRotated(-location.getLongitude().getDegrees(),1,0,0);
gl.glRotated(location.getLatitude().getDegrees(),0 ,1,0);
gl.glTranslated(centrePoint.getX(), centrePoint.getY(), centrePoint.getZ());
gl.glColor3f(1.0f, 0.0f, 0.0f);
GLU glu = dc.getGLU();
GLUQuadric obj = glu.gluNewQuadric();
glu.gluSphere(obj,this.getRadius(),100,10);

}

Carmine
05-07-2015, 09:50 AM
Will be a few days before I can look at your code.
Suggest trying to set up a simple scene with a sphere at the origin being clipped by a plane.
The idea being to make sure you can get clipping to work at all.
Good luck.

Carmine
05-09-2015, 11:34 AM
Had some time to fool around with clipping gluSpheres today. Had to play around with the commands to get any sort of handle on it. Reading the docs usually doesn't do it for me when I'm trying out something new. Have to code up simple examples, then change parameters to get a feel for the behavior. The figure shows a small, clipped, gluSphere sitting on the surface of the earth. The earth clips part of the green sphere, while a clipping plane clips the rest. It leaves an ugly hole in the green sphere that I would want to cap if it was my application. I suggest you do something like this in your app to make sure you can get a basic example of clipping to work. Set up a simple situation, for example with the small sphere at the north pole. Can you get that to clip by manually putting numbers into the clip plane routine? The OpenGL code I used to generate the picture is shown below.

1808



GLUquadricObj *oceans = gluNewQuadric();
GLUquadricObj *hemsfr = gluNewQuadric();

gluQuadricTexture (oceans, GL_TRUE );
gluQuadricNormals (oceans, GLU_SMOOTH);

gluQuadricTexture (hemsfr, GL_TRUE );
gluQuadricNormals (hemsfr, GLU_SMOOTH);

static double klip[4] = {-1.0, 0.0, 0.0, 18.0};

glClipPlane (GL_CLIP_PLANE3, klip);
glEnable (GL_CLIP_PLANE3);

glPushMatrix ();
glScalef (15.0, 15.0, 15.0);
glColor4f (0.30, 0.60, 0.80, opacity);
gluSphere (oceans, 1.0, 144, 72);
glPushAttrib (GL_ALL_ATTRIB_BITS);
glRotatef (180.0, 1,0,0);
glColor4f (0.90, 0.90, 0.50, opacity);
glDisable (GL_DEPTH_TEST);
Draw_Obj (59, FALSE);
glEnable (GL_DEPTH_TEST);
glPopAttrib ();
glColor4f (0.50, 0.90, 0.50, opacity);
glTranslatef (1.0, 0.0, 0.0);
gluSphere (hemsfr, 0.25, 36, 18);
glPopMatrix ();


First 3 values in the 'klip' vector are the x,y,z components of the clipping plane normal.
If you make this a unit vector, the 4th value is simply the distance from the origin to the plane.

Let V be the vector you calculated to be the position of your small sphere in cartesian coordinates.
Normalize V and reverse it - so it points from the clipping plane towards the center of the earth.
The 3 components of the resulting unit vector become the first 3 values of 'klip'.
The 4th value of 'klip' is the distance from the center of earth to the clipping plane (erad + h).

shariq
05-13-2015, 04:07 AM
From what I understand from your code, you are constructing the bigger sphere of radius 15 and defining a plane 3 units from surface so at x=18, why is the equation of your plane is :


static double klip[4] = {-1.0, 0.0, 0.0, 18.0};
instead of {1.0, 0.0, 0.0, -18.0}. is there any difference?
I am not sure what


glPushAttrib (GL_ALL_ATTRIB_BITS);
glRotatef (180.0, 1,0,0);
glColor4f (0.90, 0.90, 0.50, opacity);
glDisable (GL_DEPTH_TEST);
Draw_Obj (59, FALSE);
glEnable (GL_DEPTH_TEST);
glPopAttrib (); is doing.

I am concerned about
Normalize V and reverse it
what does this mean?
Because now I am able to clip my sphere but it clips in opposite direction, i.e. instead of removing the upper part it removes the lower part of the hemisphere.

I need something to change this direction of clipping.

I am providing my code herem please check:


Vec4 centerPoint = this.computePointFromPosition(dc,
this.location.getLatitude(), this.location.getLongitude(), altitudes[0], terrainConformant[0]);
this.setExpiryTime(-1L); // Sphere geometry never expires.


GL gl = dc.getGL();
gl.glPushAttrib(GL.GL_POLYGON_BIT | GL.GL_TRANSFORM_BIT);
try
{
gl.glEnable(GL.GL_CULL_FACE);
gl.glFrontFace(GL.GL_CCW);
gl.glEnable(GL.GL_RESCALE_NORMAL);
gl.glMatrixMode(GL.GL_MODELVIEW);

//clipping
double d= -(Math.pow(centerPoint.getX()+1000,2)+Math.pow(cent erPoint.getY()+1000,2)+Math.pow(centerPoint.getZ() +1000,2));
DoubleBuffer eqn1 = BufferUtils.createDoubleBuffer(8).put(new double[] {centerPoint.getX()+1000,centerPoint.getY()+1000,c enterPoint.getY()+1000,d});
eqn1.flip();
gl.glClipPlane(GL.GL_CLIP_PLANE0, eqn1);
gl.glEnable(GL.GL_CLIP_PLANE0);

gl.glPushMatrix();
try
{
gl.glTranslated(centrePoint.getX(), centrePoint.getY(), centrePoint.getZ());
gl.glColor3f(1.0f, 0.0f, 0.0f);
GLU glu = dc.getGLU();
GLUQuadric obj = glu.gluNewQuadric();
glu.gluSphere(obj,this.getRadius(),100,100);

}
finally
{
gl.glPopMatrix();
}
}
finally
{
gl.glPopAttrib();
}

shariq
05-13-2015, 05:48 AM
Hi Carmen,

Thanks a lot, after doing a little modification to my equation as you suggested by reversing the signs, i am able to clip it correctly.

I am now getting my sphere exactly same as yours.

I wonder why is this sphere hollow, can something be done to have a solid sphere. In that case we will not have to cap it.

One more thing i have to take care of is that this plane should not clip other object in space. Will check if call to gldisable() will do that.

Carmine
05-13-2015, 10:46 AM
I wonder why is this sphere hollow, can something be done to have a solid sphere.
In that case we will not have to cap it. The sphere is made up of lots of small polygons, i.e. it is a surface not a solid. By default, a GL polygon is a thin surface that can only be seen from one side, which is why when you look into the clipped sphere you can't see the inside walls. Using glPolygonMode, you can make GL render both sides of the polys which would allow you to see the inside walls. It would be better than what you have now, but not really what you want. You have to explicitly cap the clipped sphere. There are many ways to do this. If it were me, I'd write my own routine which generated all the polygons making up the sides and capped portion of the clipped sphere. I'm guessing that some advanced users could come up with a way to cap the sphere using stencil planes.

Some very basic kluges (i.e. brute force, inelegant) ways to cap the sphere would be to use scaled and positioned gluSpheres or gluDisks. In my figure a gluSphere has been flattened to look like a disc. With careful positioning and scaling it could be used to 'cap' the clipped sphere. gluDisk would be even better. You're going to have to do some trig to figure out what the radius of the cap disk should be. You already know where to position the cap (the aircraft's altitude).


One more thing i have to take care of is that this plane should not clip other object in space. Will check if call to gldisable() will do that. glDisable should work. It works for me.

1811

Once again, if the cap to your volume is supposed to represent a surface of constant altitude, it shouldn't be flat (which we are doing above). It should be a curved surface. Specifically, it should be a section of an earth-centered sphere with radius = to the radius of the earth + the aircraft's altitude.

BTW - the stuff we are talking about is very basic OpenGL. It should be in the beginner's forum.

Carmine
05-14-2015, 06:37 PM
Reading my own post made me realize there might be an easy way to solve this problem correctly and succinctly.
By 'correctly', I mean capping the small sphere with a larger sphere of radius = earth radius + aircraft altitude.
By 'succinctly', I mean with even less code than I used in my last solution.
Here it is. You tell me why it works. 'l' is the magic number.

1816

Some examples ....

1812 1813 1814

shariq
05-18-2015, 02:26 AM
Hi Carmine,

My use case isn't this. Its still in talks with the product team providing input for the required 3d shape that we have to draw. I started with clipping. But seems there is much more to it. From where I see it could involve clipping out a 3d portion from another 3d shape. Like a cone from this cut hemisphere that we have drawn. Till now what i had thought was this shape but seems there is more to it.

But then it would be more learning and some advanced things propably suitable for this thread as you suggested.


You are absolutely right when you say:

Once again, if the cap to your volume is supposed to represent a surface of constant altitude, it shouldn't be flat (which we are doing above). It should be a curved surface. Specifically, it should be a section of an earth-centered sphere with radius = to the radius of the earth + the aircraft's altitude.

This is true for capping the small sphere with a curved surface at an altitude of h from earth. I could understand your calculation where 'l', which is p(cos a) where from cosine rule you get the angle(a) from the triangle with sides p,q and r.

Will use your solution till further clarification.

Thanks again as I could learn many things about openGL programming practices from your solution.

Carmine
05-20-2015, 02:53 PM
I could understand your calculation where 'l', which is p(cos a) where from cosine rule you get the angle(a) from the triangle with sides p,q and r. Correct. Angle 'a' comes from the law of cosines.