/* * This file is part of the Remote Sensor Actuator Interface (ReSAI). * * Copyright(c) Andreas Kipp, Frederic Siepmann * http://opensource.cit-ec.de/projects/resai * * This file may be licensed under the terms of of the * GNU Lesser General Public License Version 3 (the ``LGPL''), * or (at your option) any later version. * * Software distributed under the License is distributed * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either * express or implied. See the LGPL for the specific language * governing rights and limitations. * * You should have received a copy of the LGPL along with this * program. If not, go to http://www.gnu.org/licenses/lgpl.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The development of this software was supported by the * Excellence Cluster EXC 277 Cognitive Interaction Technology. * The Excellence Cluster EXC 277 is a grant of the Deutsche * Forschungsgemeinschaft (DFG) in the context of the German * Excellence Initiative. * */ /** * Tab showing information from SLAM sensor. * * @author akipp */ package de.unibi.airobots.resaidroid.tabactivities; import org.jivesoftware.smack.util.Base64; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PointF; import android.os.Bundle; import android.util.FloatMath; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; import de.unibi.airobots.resaidroid.R; import de.unibi.airobots.resaidroid.constants.Constants.Commands; import de.unibi.airobots.resaidroid.constants.Constants.Properties; import de.unibi.airobots.resaidroid.constants.ServerConfig; import de.unibi.airobots.resaidroid.helper.DataPacker; import de.unibi.airobots.resaidroid.helper.EasyDialog; import de.unibi.airobots.resaidroid.helper.WrapMotionEvent; import de.unibi.airobots.resaidroid.tabactivities.template.TabTemplate; public class TabSlamSensor extends TabTemplate implements OnTouchListener { private ImageView ivMap; private int roboX = 0, roboY = 0; // TOUCH VARAIBLES PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; float touchStartX = 0f, touchStartY = 0f, touchX = 0f, touchY = 0f; float targetX = 0f, targetY = 0f; int mode = NONE; private static Matrix matrix = new Matrix(); private static Matrix savedMatrix = new Matrix(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.slamsensor); ivMap = (ImageView) findViewById(R.id.ivMap); ivMap.setImageMatrix(matrix); ivMap.setOnTouchListener(this); registerForContextMenu(ivMap); } @Override protected void onPause() { super.onPause(); // Disconnect NavigationThread addProperty(Properties.CMD.name(), Commands.disconnectComponent.name()); addProperty(Properties.COMP.name(), "NavigationActuatorThread"); // TODO auslagern? propertiesToSend.put("TAG", "ComponentDispatcher"); sendMessage(ServerConfig.RECIPIENT_FULL); } @Override protected void onResume() { super.onResume(); // Connect to NavigationThread addProperty(Properties.CMD.name(), Commands.requestComponent.name()); addProperty(Properties.COMP.name(), "NavigationActuatorThread"); // TODO auslagern? propertiesToSend.put("TAG", "ComponentDispatcher"); sendMessage(ServerConfig.RECIPIENT_FULL); } @Override public void processProperties() { messageHandler.post(new Runnable() { public void run() { try { String _img = ""; synchronized (receivedProperties) { for (String prop : receivedProperties.keySet()) { if (prop.equals(cm.getComponent(TAG) + "_IMG")) { _img = receivedProperties.get(prop).toString(); } if (prop.equals(cm.getComponent(TAG) + "_POSX")) { roboX = Integer.parseInt(mIn.getProperty(prop) .toString()); } if (prop.equals(cm.getComponent(TAG) + "_POSY")) { roboY = Integer.parseInt(mIn.getProperty(prop) .toString()); } } } if (_img.length() > 0) { byte[] imageByte = DataPacker.decompressBytes(Base64 .decode(_img,Base64.GZIP)); Bitmap bitmap = BitmapFactory.decodeByteArray( imageByte, 0, imageByte.length); Bitmap b = bitmap.copy(Bitmap.Config.RGB_565, true); Canvas canvas = new Canvas(b); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.RED); canvas.drawCircle(targetX, targetY, 5, paint); paint.setColor(Color.BLUE); canvas.drawCircle(roboX, roboY, 5, paint); ivMap.setImageBitmap(b); } } catch (Exception e) { // TODO Log.i(TAG, "%%%%Exception: " + e.getMessage()); } } }); } @Override public boolean onTouch(View v, MotionEvent rawEvent) { WrapMotionEvent event = WrapMotionEvent.wrap(rawEvent); ImageView view = (ImageView) v; touchX = event.getX(); touchY = event.getY(); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG"); mode = DRAG; touchStartX = event.getX(); touchStartY = event.getY(); break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; Log.d(TAG, "mode=NONE"); break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); } else if (mode == ZOOM) { float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } Matrix invMatrix = new Matrix(); matrix.invert(invMatrix); float[] matrixValues = new float[9]; invMatrix.getValues(matrixValues); targetX = matrixValues[0] * touchX + matrixValues[1] * touchY + matrixValues[2]; targetY = matrixValues[3] * touchX + matrixValues[4] * touchY + matrixValues[5]; view.setImageMatrix(matrix); return false; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (Math.abs(touchStartX - touchX) < 10f && Math.abs(touchStartY - touchY) < 10f) { Log.i(TAG, "######Show Menu"); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.slamsensortouchmenu, menu); } else { Log.i(TAG, "###### Don't show Menu"); } } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.miResetView: EasyDialog.makeToast(getApplicationContext(), "Resetting View."); matrix = new Matrix(); ivMap.getImageMatrix().set(matrix); break; case R.id.miMoveTo: EasyDialog.makeToast(getApplicationContext(), "Sending Target."); sendTarget(); break; case R.id.miManualStop: EasyDialog .makeToast(getApplicationContext(), "Sending Manual Stop"); sendManualStop(); break; // case R.id.miCenterRobot: // EasyDialog.makeToast(getApplicationContext(), // "Centering View to Robot."); // matrix.setTranslate((-1) * roboX + ivMap.getWidth(), // (-1) * roboY + ivMap.getHeight()); // // ivMap.getImageMatrix().set(matrix); // break; case R.id.miCancel: EasyDialog.makeToast(getApplicationContext(), "Cancel by user"); default: EasyDialog.makeToast(getApplicationContext(), "Uknown ID selected: " + item.toString()); } // TODO return true; } private void sendTarget() { addProperty("TAG", "NavigationActuatorThread"); addProperty("NavigationActuatorThread", "True"); addProperty("NAVDATA", "true"); addProperty("X", String.valueOf(targetX)); addProperty("Y", String.valueOf(targetY)); sendMessage(ServerConfig.RECIPIENT_FULL); } private void sendManualStop() { addProperty("TAG", "NavigationActuatorThread"); addProperty("NavigationActuatorThread", "True"); addProperty("MANUALSTOP", "true"); sendMessage(ServerConfig.RECIPIENT_FULL); } // TODO BESCHREIBEN WOFUER ETC. /** Determine the space between the first two fingers */ private float spacing(WrapMotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } /** Calculate the mid point of the first two fingers */ private void midPoint(PointF point, WrapMotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } }