/* Copyright (C) 2001, 2006 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. */ package gov.nasa.worldwind.render; import gov.nasa.worldwind.geom.Vec4; import gov.nasa.worldwind.globes.SectorGeometryList; import gov.nasa.worldwind.tracks.TrackPoint; import gov.nasa.worldwind.util.Logging; import javax.media.opengl.GL; import java.util.*; /** * @author tag * @version $Id: PipeRenderer.java 2984 2007-09-22 02:20:10Z tgaskins $ */ public class PipeRenderer extends LocationRenderer { private Material junctionMaterial = Material.RED; private Material pipeMaterial = Material.WHITE; private double pipeRadius = 1000; private double junctionShapeRadius = 1.8 * this.pipeRadius; private LocationRenderer.Shape junctionShape = SPHERE; private PipeRenderer.Pipe pipeShape = new PipeRenderer.Pipe(); public PipeRenderer() { } public Material getPipeMaterial() { return pipeMaterial; } public void setPipeMaterial(Material material) { if (material == null) { String msg = Logging.getMessage("nullValue.MaterialIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // don't validate material's colors - material does that. this.pipeMaterial = material; } public Material getJunctionMaterial() { return junctionMaterial; } public void setJunctionMaterial(Material material) { if (material == null) { String msg = Logging.getMessage("nullValue.MaterialIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // don't validate material's colors - material does that. this.junctionMaterial = material; } public void setJunctionShape(String shapeName) { if (shapeName.equalsIgnoreCase("Cone")) this.junctionShape = CONE; else if (shapeName.equalsIgnoreCase("Cylinder")) this.junctionShape = CYLINDER; else this.junctionShape = SPHERE; } public String getJunctionShape() { return this.junctionShape.name; } protected Vec4 draw(DrawContext dc, Iterator<TrackPoint> trackPositions) { if (dc.getVisibleSector() == null) return null; SectorGeometryList geos = dc.getSurfaceGeometry(); if (geos == null) return null; if (!this.pipeShape.isInitialized) { this.pipeShape.initialize(dc); } if (!this.junctionShape.isInitialized) this.junctionShape.initialize(dc); int index = 0; List<Vec4> points = new ArrayList<Vec4>(); while (trackPositions.hasNext()) { TrackPoint tp = trackPositions.next(); if (index >= this.lowerLimit && index <= this.upperLimit) { Vec4 point = this.computeSurfacePoint(dc, tp); if (point != null) { points.add(point); } } if (++index >= this.upperLimit) break; } if (points.size() < 1) return null; this.begin(dc); { this.pipeMaterial.apply(dc.getGL(), GL.GL_FRONT); Vec4 p1 = points.get(0); for (int i = 1; i < points.size(); i++) { Vec4 p2 = points.get(i); this.pipeShape.render(dc, p1, p2, this.pipeRadius); p1 = p2; } this.junctionMaterial.apply(dc.getGL(), GL.GL_FRONT); for (Vec4 point : points) { this.junctionShape.render(dc, point, this.junctionShapeRadius); } } this.end(dc); return null; // TODO: return the last-drawn location } private static class Pipe extends Cylinder { protected void initialize(DrawContext dc) { super.initialize(dc); this.name = "Pipe"; } private static final double TO_DEGREES = 180d / Math.PI; protected void render(DrawContext dc, Vec4 p1, Vec4 p2, double radius) { // To compute the rotation of the cylinder axis to the orientation of the vector between the two points, // this method performs the same operation as Vec4.axisAngle() but with a "v2" of <0, 0, 1>. // Compute rotation angle double length = p1.distanceTo3(p2); Vec4 u1 = new Vec4((p2.x - p1.x) / length, (p2.y - p1.y) / length, (p2.z - p1.z) / length); double angle = Math.acos(u1.z); // Compute the direction cosine factors that define the rotation axis double A = -u1.y; double B = u1.x; double L = Math.sqrt(A * A + B * B); GL gl = dc.getGL(); // pushReferenceCenter performs the translation of the pipe's origin to point p1 and the necessary // push/pop of the modelview stack. Otherwise we'd need to include a glPushMatrix and // gl.glTranslated(p1.x, p1.y, p1.z) above the rotation, and a corresponding glPopMatrix after the // call to glCallIst. dc.getView().pushReferenceCenter(dc, p1); gl.glRotated(angle * TO_DEGREES, A / L, B / L, 0); gl.glScaled(radius, radius, length / 2); // length / 2 because cylinder is created with length 2 dc.getGL().glCallList(this.glListId); dc.getView().popReferenceCenter(dc); } } }