/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.util;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.globes.FlatGlobe;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import javax.media.opengl.GL2;
/**
* Uses the OpenGL clipping planes to clip the geometry around a given sector.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class SectorClipPlanes
{
private Sector sector = null;
private boolean dirty = false;
private double[] planes;
/**
* Setup the clipping planes to clip around the given sector.
*
* @param sector
*/
public void clipSector(Sector sector)
{
this.sector = sector;
dirty = true;
}
/**
* Clear the sector clipping planes so that no geometry is clipped.
*/
public void clear()
{
this.sector = null;
dirty = true;
}
/**
* Enable the clipping planes.
*
* @param dc
*/
public void enableClipping(DrawContext dc)
{
if (dirty)
{
if (sector == null)
{
planes = null;
}
else
{
planes = computeSectorClippingPlanes(dc.getGlobe(), sector);
}
dirty = false;
}
if (planes != null)
{
GL2 gl = dc.getGL().getGL2();
gl.glClipPlane(GL2.GL_CLIP_PLANE0, planes, 0);
gl.glClipPlane(GL2.GL_CLIP_PLANE1, planes, 4);
gl.glClipPlane(GL2.GL_CLIP_PLANE2, planes, 8);
gl.glClipPlane(GL2.GL_CLIP_PLANE3, planes, 12);
gl.glEnable(GL2.GL_CLIP_PLANE0);
gl.glEnable(GL2.GL_CLIP_PLANE1);
gl.glEnable(GL2.GL_CLIP_PLANE2);
gl.glEnable(GL2.GL_CLIP_PLANE3);
}
}
/**
* Disable the clipping planes.
*
* @param dc
*/
public void disableClipping(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2();
gl.glDisable(GL2.GL_CLIP_PLANE0);
gl.glDisable(GL2.GL_CLIP_PLANE1);
gl.glDisable(GL2.GL_CLIP_PLANE2);
gl.glDisable(GL2.GL_CLIP_PLANE3);
}
/**
* Calculate 4 clipping planes which clip the geomtry around the provided
* sector.
*
* @param globe
* Current globe
* @param sector
* Sector to clip around
* @return An array of length 16, containing 4x 4-value vectors representing
* 4 clipping planes
*/
protected static double[] computeSectorClippingPlanes(Globe globe, Sector sector)
{
if (globe instanceof FlatGlobe)
{
//TODO implement:
//Clipping on flat earth: instead of all planes going through (0,0,0) (D = 0), calculate
//distance of min/max lat/lon from 0,0,0, and use that for the plane's D value (plane
//normals will be (1,0,0),(-1,0,0),(0,1,0),(0,-1,0) for left,right,top,bottom respectively).
throw new UnsupportedOperationException("Sector clipping does not support FlatGlobe's");
}
else
{
double[] planes = new double[16];
LatLon[] corners = sector.getCorners(); //SW, SE, NE, NW
LatLon centroid = sector.getCentroid();
LatLon west = LatLon.interpolateGreatCircle(0.5, corners[0], corners[3]); //SW, NW
LatLon east = LatLon.interpolateGreatCircle(0.5, corners[1], corners[2]); //SE, NE
LatLon south = LatLon.interpolateGreatCircle(0.5, corners[0], corners[1]); //SW, SE
LatLon north = LatLon.interpolateGreatCircle(0.5, corners[3], corners[2]); //NW, NE
Vec4 center = globe.computePointFromLocation(centroid).normalize3();
Vec4 minX = globe.computePointFromLocation(west).normalize3();
Vec4 maxX = globe.computePointFromLocation(east).normalize3();
Vec4 minY = globe.computePointFromLocation(south).normalize3();
Vec4 maxY = globe.computePointFromLocation(north).normalize3();
Vec4 up = Vec4.UNIT_Y;
Vec4 left = center.cross3(up);
Vec4 leftPlaneNormal = up.cross3(minX);
Vec4 rightPlaneNormal = maxX.cross3(up);
Vec4 topPlaneNormal = left.cross3(minY);
Vec4 bottomPlaneNormal = maxY.cross3(left);
planes[0] = leftPlaneNormal.x;
planes[1] = leftPlaneNormal.y;
planes[2] = leftPlaneNormal.z;
planes[3] = 0;
planes[4] = rightPlaneNormal.x;
planes[5] = rightPlaneNormal.y;
planes[6] = rightPlaneNormal.z;
planes[7] = 0;
planes[8] = topPlaneNormal.x;
planes[9] = topPlaneNormal.y;
planes[10] = topPlaneNormal.z;
planes[11] = 0;
planes[12] = bottomPlaneNormal.x;
planes[13] = bottomPlaneNormal.y;
planes[14] = bottomPlaneNormal.z;
planes[15] = 0;
return planes;
}
}
}