1515 */
1616package com .projecttango .experiments .augmentedrealitysample ;
1717
18- import java .util .ArrayList ;
19-
2018import android .app .Activity ;
2119import android .content .Intent ;
2220import android .os .Bundle ;
3129import com .google .atap .tangoservice .TangoConfig ;
3230import com .google .atap .tangoservice .TangoCoordinateFramePair ;
3331import com .google .atap .tangoservice .TangoEvent ;
32+ import com .google .atap .tangoservice .TangoException ;
33+ import com .google .atap .tangoservice .TangoOutOfDateException ;
3434import com .google .atap .tangoservice .TangoPoseData ;
3535import com .google .atap .tangoservice .TangoXyzIjData ;
3636import com .projecttango .rajawali .ar .TangoRajawaliView ;
3737import com .projecttango .tangosupport .TangoSupport ;
3838
39+ import java .util .ArrayList ;
40+
3941/**
4042 * An example showing how to build a very simple augmented reality application in Java.
4143 * It uses Rajawali to do the rendering through the utility classes
4446 * user clicks on the camera display, plane detection will be done on the surface closest to the
4547 * click location and a 3D object will be placed in the scene anchored in that location.
4648 * <p/>
47- * TangoRajawaliView is used in the same way as the TangoCamaraPreview: we first need initialize the
49+ * TangoRajawaliView is used in the same way as the TangoCameraPreview: We first need initialize the
4850 * TangoRajawaliView class with the activity's context and connect to the camera we want by using
4951 * connectToTangoCamera method. Once the connection is established we need to update
5052 * the view's texture by using the onFrameAvailable callbacks.
6062 * the RGB camera.
6163 */
6264public class AugmentedRealityActivity extends Activity implements View .OnTouchListener {
63- private static final String TAG = "AugmentedRealityActiv" ;
65+ private static final String TAG = AugmentedRealityActivity . class . getSimpleName () ;
6466 private TangoRajawaliView mGLView ;
6567 private AugmentedRealityRenderer mRenderer ;
6668 private PointCloudManager mPointCloudManager ;
6769 private Tango mTango ;
6870 private boolean mIsConnected ;
69- private boolean mIsPermissionGranted ;
7071
7172 @ Override
7273 protected void onCreate (Bundle savedInstanceState ) {
@@ -76,87 +77,66 @@ protected void onCreate(Bundle savedInstanceState) {
7677 mGLView .setSurfaceRenderer (mRenderer );
7778 mGLView .setOnTouchListener (this );
7879 mTango = new Tango (this );
79- startActivityForResult (
80- Tango .getRequestPermissionIntent (Tango .PERMISSIONTYPE_MOTION_TRACKING ),
81- Tango .TANGO_INTENT_ACTIVITYCODE );
8280 setContentView (mGLView );
8381 }
8482
85- @ Override
86- protected void onActivityResult (int requestCode , int resultCode , Intent data ) {
87- // Check which request we're responding to
88- if (requestCode == Tango .TANGO_INTENT_ACTIVITYCODE ) {
89- // Make sure the request was successful
90- if (resultCode == RESULT_CANCELED ) {
91- Toast .makeText (this , "Motion Tracking Permissions Required!" ,
92- Toast .LENGTH_SHORT ).show ();
93- finish ();
94- } else {
95- startAugmentedreality ();
96- mIsPermissionGranted = true ;
97- }
98- }
99- }
100-
10183 // Augmented reality view and renderer
10284 private void startAugmentedreality () {
10385 if (!mIsConnected ) {
104- mIsConnected = true ;
105- // Connect to color camera
106- mGLView .connectToTangoCamera (mTango , TangoCameraIntrinsics .TANGO_CAMERA_COLOR );
107-
108- // Use default configuration for Tango Service, plus low latency IMU integration.
109- TangoConfig config = mTango .getConfig (TangoConfig .CONFIG_TYPE_DEFAULT );
110- // NOTE: low latency integration is necessary to achieve a precise alignment of
111- // virtual objects with the RBG image and produce a good AR effect.
112- config .putBoolean (TangoConfig .KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION , true );
113- config .putBoolean (TangoConfig .KEY_BOOLEAN_DEPTH , true );
114- mTango .connect (config );
115-
116- // No need to add any coordinate frame pairs since we are not using
117- // pose data. So just initialize.
118- ArrayList <TangoCoordinateFramePair > framePairs = new ArrayList <TangoCoordinateFramePair >();
119- mTango .connectListener (framePairs , new OnTangoUpdateListener () {
120- @ Override
121- public void onPoseAvailable (TangoPoseData pose ) {
122- // We are not using OnPoseAvailable for this app
123- }
124-
125- @ Override
126- public void onFrameAvailable (int cameraId ) {
127- // Check if the frame available is for the camera we want and
128- // update its frame on the view.
129- if (cameraId == TangoCameraIntrinsics .TANGO_CAMERA_COLOR ) {
130- mGLView .onFrameAvailable ();
86+ try {
87+ mIsConnected = true ;
88+ // Connect to color camera.
89+ mGLView .connectToTangoCamera (mTango , TangoCameraIntrinsics .TANGO_CAMERA_COLOR );
90+
91+ // Use default configuration for Tango Service, plus low latency IMU integration.
92+ TangoConfig config = mTango .getConfig (TangoConfig .CONFIG_TYPE_DEFAULT );
93+ // NOTE: Low latency integration is necessary to achieve a precise alignment of
94+ // virtual objects with the RBG image and produce a good AR effect.
95+ config .putBoolean (TangoConfig .KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION , true );
96+ config .putBoolean (TangoConfig .KEY_BOOLEAN_DEPTH , true );
97+ mTango .connect (config );
98+
99+ // No need to add any coordinate frame pairs since we are not using
100+ // pose data. So just initialize.
101+ ArrayList <TangoCoordinateFramePair > framePairs = new ArrayList <TangoCoordinateFramePair >();
102+ mTango .connectListener (framePairs , new OnTangoUpdateListener () {
103+ @ Override
104+ public void onPoseAvailable (TangoPoseData pose ) {
105+ // We are not using OnPoseAvailable for this app.
106+ }
107+
108+ @ Override
109+ public void onFrameAvailable (int cameraId ) {
110+ // Check if the frame available is for the camera we want and
111+ // update its frame on the view.
112+ if (cameraId == TangoCameraIntrinsics .TANGO_CAMERA_COLOR ) {
113+ mGLView .onFrameAvailable ();
114+ }
131115 }
132- }
133-
134- @ Override
135- public void onXyzIjAvailable (TangoXyzIjData xyzIj ) {
136- // Get the device pose at the time the point cloud was acquired
137- TangoCoordinateFramePair framePair = new TangoCoordinateFramePair (
138- TangoPoseData .COORDINATE_FRAME_START_OF_SERVICE ,
139- TangoPoseData .COORDINATE_FRAME_DEVICE );
140- TangoPoseData cloudPose = mTango .getPoseAtTime (xyzIj .timestamp , framePair );
141-
142- // Save the cloud and point data for later use
143- mPointCloudManager .updateXyzIjData (xyzIj , cloudPose );
144- }
145-
146- @ Override
147- public void onTangoEvent (TangoEvent event ) {
148- // We are not using OnPoseAvailable for this app
149- }
150- });
151-
152- // Get extrinsics from device for use in transforms
153- // This needs to be done after connecting Tango and listeners
154- setupExtrinsics ();
155-
156- // Set-up point cloud plane fitting library helper class
157- mPointCloudManager = new PointCloudManager (mTango .getCameraIntrinsics (
158- TangoCameraIntrinsics .TANGO_CAMERA_COLOR ));
159116
117+ @ Override
118+ public void onXyzIjAvailable (TangoXyzIjData xyzIj ) {
119+ // Save the cloud and point data for later use.
120+ mPointCloudManager .updateXyzIjData (xyzIj );
121+ }
122+
123+ @ Override
124+ public void onTangoEvent (TangoEvent event ) {
125+ // We are not using OnPoseAvailable for this app.
126+ }
127+ });
128+
129+ // Get extrinsics from device for use in transforms. This needs to be done after
130+ // connecting Tango and listeners.
131+ setupExtrinsics ();
132+
133+ // Setup point cloud plane fitting library helper class.
134+ mPointCloudManager = new PointCloudManager (mTango .getCameraIntrinsics (
135+ TangoCameraIntrinsics .TANGO_CAMERA_COLOR ));
136+ } catch (TangoOutOfDateException e ) {
137+ Toast .makeText (getApplicationContext (), R .string .TangoOutOfDateException ,
138+ Toast .LENGTH_SHORT ).show ();
139+ }
160140 }
161141 }
162142
@@ -165,17 +145,17 @@ public void onTangoEvent(TangoEvent event) {
165145 * to be used later for transformations between frames.
166146 */
167147 private void setupExtrinsics () {
168- // Create Camera to IMU Transform
148+ // Create camera to IMU transform.
169149 TangoCoordinateFramePair framePair = new TangoCoordinateFramePair ();
170150 framePair .baseFrame = TangoPoseData .COORDINATE_FRAME_IMU ;
171151 framePair .targetFrame = TangoPoseData .COORDINATE_FRAME_CAMERA_COLOR ;
172152 TangoPoseData imuTrgbPose = mTango .getPoseAtTime (0.0 , framePair );
173153
174- // Create Device to IMU Transform
154+ // Create device to IMU transform.
175155 framePair .targetFrame = TangoPoseData .COORDINATE_FRAME_DEVICE ;
176156 TangoPoseData imuTdevicePose = mTango .getPoseAtTime (0.0 , framePair );
177157
178- // Create Depth camera to IMU Transform
158+ // Create depth camera to IMU transform.
179159 framePair .targetFrame = TangoPoseData .COORDINATE_FRAME_CAMERA_DEPTH ;
180160 TangoPoseData imuTdepthPose = mTango .getPoseAtTime (0.0 , framePair );
181161
@@ -196,22 +176,28 @@ protected void onPause() {
196176 @ Override
197177 protected void onResume () {
198178 super .onResume ();
199- if (!mIsConnected && mIsPermissionGranted ) {
179+ if (!mIsConnected ) {
200180 startAugmentedreality ();
201181 }
202182 }
203183
204184 @ Override
205185 public boolean onTouch (View view , MotionEvent motionEvent ) {
206186 if (motionEvent .getAction () == MotionEvent .ACTION_UP ) {
207- // Calculate click location in u,v (0;1) coordinates
187+ // Calculate click location in u,v (0;1) coordinates.
208188 float u = motionEvent .getX () / view .getWidth ();
209189 float v = motionEvent .getY () / view .getHeight ();
210190
211191 try {
212192 doFitPlane (u , v );
213- } catch (Throwable t ) {
214- Log .e (TAG , "Exception measuring nomral" , t );
193+ } catch (TangoException t ) {
194+ Toast .makeText (getApplicationContext (), R .string .failed_measurement ,
195+ Toast .LENGTH_SHORT ).show ();
196+ Log .e (TAG , getString (R .string .failed_measurement ), t );
197+ } catch (SecurityException t ) {
198+ Toast .makeText (getApplicationContext (), R .string .failed_permissions ,
199+ Toast .LENGTH_SHORT ).show ();
200+ Log .e (TAG , getString (R .string .failed_permissions ), t );
215201 }
216202 }
217203 return true ;
@@ -223,15 +209,24 @@ public boolean onTouch(View view, MotionEvent motionEvent) {
223209 * renderer to show a 3D object in that location.
224210 */
225211 private void doFitPlane (float u , float v ) {
226- // Get the current device pose
212+ // NOTE: We request measurement at the latest available time. If we wanted to be even more
213+ // precise, we should use the timestamp of the RGB image rendered at the time the user
214+ // clicked the screen
215+ double measurementTimestamp = 0.0 ;
216+
217+ // Perform plane fitting with the latest available point cloud data.
218+ PointCloudManager .FitPlaneResult planeModelAndTimestamp =
219+ mPointCloudManager .fitPlane (u , v , measurementTimestamp );
220+
221+ // Get the device pose at the time the plane data was acquired.
227222 TangoCoordinateFramePair framePair = new TangoCoordinateFramePair (
228223 TangoPoseData .COORDINATE_FRAME_START_OF_SERVICE ,
229224 TangoPoseData .COORDINATE_FRAME_DEVICE );
230- TangoPoseData devicePose = mTango .getPoseAtTime (0.0 , framePair );
225+ TangoPoseData devicePose =
226+ mTango .getPoseAtTime (planeModelAndTimestamp .cloudTimestamp , framePair );
231227
232- // Perform plane fitting with the latest available point cloud data
233- TangoSupport .IntersectionPointPlaneModelPair planeModel =
234- mPointCloudManager .fitPlane (u , v , devicePose , mRenderer .getPoseCalculator ());
235- mRenderer .updateObjectPose (planeModel .intersectionPoint , planeModel .planeModel , devicePose );
228+ // Update the AR object location
229+ mRenderer .updateObjectPose (planeModelAndTimestamp .planeModelPair .intersectionPoint ,
230+ planeModelAndTimestamp .planeModelPair .planeModel , devicePose );
236231 }
237232}
0 commit comments