| 
					
				 | 
			
			
				@@ -0,0 +1,137 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright (C) 2014 Google Inc. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 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 org.ros.android.view.visualization.layer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.google.common.base.Preconditions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.jboss.netty.buffer.ChannelBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.android.view.visualization.Color; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.android.view.visualization.Vertices; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.android.view.visualization.VisualizationView; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.message.MessageListener; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.namespace.GraphName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.node.ConnectedNode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.ros.node.topic.Subscriber; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.nio.ByteOrder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.nio.FloatBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import javax.microedition.khronos.opengles.GL10; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import sensor_msgs.PointCloud2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import sensor_msgs.PointField; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * A {@link org.ros.android.view.visualization.layer.SubscriberLayer} that visualizes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * sensor_msgs/PointCloud2 messages in 2D. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @author damonkohler@google.com (Damon Kohler) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class PointCloud2DLayer extends SubscriberLayer<PointCloud2> implements TfLayer { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private static final Color FREE_SPACE_COLOR = Color.fromHexAndAlpha("377dfa", 0.1f); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private static final Color OCCUPIED_SPACE_COLOR = Color.fromHexAndAlpha("377dfa", 0.3f); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private static final float POINT_SIZE = 10.f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private final Object mutex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private GraphName frame; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private FloatBuffer vertexFrontBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private FloatBuffer vertexBackBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public PointCloud2DLayer(String topicName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this(GraphName.of(topicName)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public PointCloud2DLayer(GraphName topicName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    super(topicName, PointCloud2._TYPE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mutex = new Object(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public void draw(VisualizationView view, GL10 gl) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (vertexFrontBuffer != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      synchronized (mutex) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Vertices.drawTriangleFan(gl, vertexFrontBuffer, FREE_SPACE_COLOR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Drop the first point which is required for the triangle fan but is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // not a range reading. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        FloatBuffer pointVertices = vertexFrontBuffer.duplicate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pointVertices.position(3); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Vertices.drawPoints(gl, pointVertices, OCCUPIED_SPACE_COLOR, POINT_SIZE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public void onStart(VisualizationView view, ConnectedNode connectedNode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    super.onStart(view, connectedNode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Subscriber<PointCloud2> subscriber = getSubscriber(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subscriber.addMessageListener(new MessageListener<PointCloud2>() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      public void onNewMessage(PointCloud2 pointCloud) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        frame = GraphName.of(pointCloud.getHeader().getFrameId()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        updateVertexBuffer(pointCloud); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private void updateVertexBuffer(final PointCloud2 pointCloud) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // We expect an unordered, XYZ point cloud of 32-bit floats (i.e. the result of 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // pcl::toROSMsg()). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // TODO(damonkohler): Make this more generic. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getHeight() == 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getIsDense()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getFields().size() == 3); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getFields().get(0).getDatatype() == PointField.FLOAT32); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getFields().get(1).getDatatype() == PointField.FLOAT32); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getFields().get(2).getDatatype() == PointField.FLOAT32); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getPointStep() == 16); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Preconditions.checkArgument(pointCloud.getData().order().equals(ByteOrder.LITTLE_ENDIAN)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    final int numVertices = (pointCloud.getRowStep() / pointCloud.getPointStep() + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        1 /* triangle fan origin */) * 3 /* x, y, z */; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (vertexBackBuffer == null || vertexBackBuffer.capacity() < numVertices) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      vertexBackBuffer = Vertices.allocateBuffer(numVertices); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    vertexBackBuffer.clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // We start with the origin of the triangle fan. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    vertexBackBuffer.put(0.f); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    vertexBackBuffer.put(0.f); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    vertexBackBuffer.put(0.f); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    final ChannelBuffer buffer = pointCloud.getData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    while (buffer.readable()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      vertexBackBuffer.put(buffer.readFloat()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      vertexBackBuffer.put(buffer.readFloat()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      vertexBackBuffer.put(0.f); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // Discard z data. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      buffer.readFloat(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // Discard intensity. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      buffer.readFloat(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    vertexBackBuffer.position(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    synchronized (mutex) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      FloatBuffer tmp = vertexFrontBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      vertexFrontBuffer = vertexBackBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      vertexBackBuffer = tmp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public GraphName getFrame() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return frame; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |