谷歌天空地图开源 - 如何将点击动作映射到对象?

时间:2012-01-23 11:51:11

标签: android

谷歌天空地图几天前开源,我正试图玩它。不幸的是,我无法将用户的点击动作映射到对象(行星等等)。

我认为这是GestureInterceptor.onDown(MotionEvent e)的切入点。

但是如何将MotionEvent映射到对象?我完全迷失在这里。

您可以在此处找到源代码:http://code.google.com/p/stardroid/source/browse/#svn%2Ftrunk%2Fapp

到目前为止提出了什么:

 AstronomerModel model = StardroidApplication.getModel();
 Pointing pointing = model.getPointing();

所以我有模型,我可以获得视线。但是,需要做的是将点击坐标转换为地心坐标(如何?),然后找到位于这些坐标处的对象(如何?)。

1 个答案:

答案 0 :(得分:1)

好的,所以这就是我所做的。

我捕获了标签Geocentric Positions并将它们全部存储在ApplicationConstants类中。您可以在ProtobufAstronomicalSource.getLabels()中获取它们,除了行星,您可以使用PlanetSource.initialize()。

然后,当用户点击时,会在com.google.android.stardroid.touch.GouchureInterpreter类中调用onSingleTapConfirmed方法。在这个方法中,我获得所有标签,使用以下代码将地心位置转换为屏幕位置:

    @Override
      public boolean onSingleTapConfirmed(MotionEvent e) {
        Log.d(TAG, "Confirmed single tap");

        Point screen = ApplicationConstants.getSizeOfScreen();
        int screenHeight = screen.y;
        int screenWidth = screen.x;
        float yClicked = screenHeight - e.getRawY(); //e.y is inverted, this normalizes it
        float xClicked = e.getRawX();
        ArrayList<Label> labelArray = ApplicationConstants.getLabels();
        Log.d("LabelClicked", "label count: " + labelArray.size());
        ArrayList<LabelScreen> labelsOnScreen = new ArrayList<LabelScreen>();
        for (Label label : labelArray) {
            //calculets current screen position of all labels, most of this code comes from LabelObjectManager.drawLabel()
            Vector3 lookDir = ApplicationConstants.getLookDir();
            if (lookDir.x * label.x + lookDir.y * label.y + lookDir.z * label.z < ApplicationConstants.getmDotProductThreshold()) {
              //return;
            }

            Vector3 mLabelOffset = ApplicationConstants.getmLabelOffset();

            // Offset the label to be underneath the given position (so a label will 
            // always appear underneath a star no matter how the phone is rotated) 
            Vector3 v = new Vector3(
                label.x - mLabelOffset.x * label.offset,
                label.y - mLabelOffset.y * label.offset,
                label.z - mLabelOffset.z * label.offset);

            Vector3 screenPos = Matrix4x4.transformVector(
                ApplicationConstants.setTransformToScreenMatrix(),
                v);

            // We want this to align consistently with the pixels on the screen, so we
            // snap to the nearest x/y coordinate, and add a magic offset of less than
            // half a pixel.  Without this, rounding error can cause the bottom and
            // top of a label to be one pixel off, which results in a noticeable
            // distortion in the text.
            final float MAGIC_OFFSET = 0.25f;
            screenPos.x = (int)screenPos.x + MAGIC_OFFSET;
            screenPos.y = (int)screenPos.y + MAGIC_OFFSET;

            //by Marcio Granzotto Rodrigues
            if ((screenPos.x < 0.0f) | (screenPos.y < 0.0f)) {
                //not on screen
            }else if ((screenPos.x > screenWidth) | (screenPos.y > screenHeight)) {
                //not on screen
            }else if (screenPos.z < 0) {
                //not on screen
            }else {
                //on screen
                Log.d("LabelClicked", "on screen: " + label.getText() + " - " + screenPos.x + " " + screenPos.y + " " + screenPos.z);
                LabelScreen labelScreen = new LabelScreen(label, screenPos);
                labelsOnScreen.add(labelScreen);
            }//end else
        }//end for

        Log.i("LabelClicked", "Labels on Screen: " + labelsOnScreen.size());
        LabelScreen theLabel = null;
        for (LabelScreen labelScreen : labelsOnScreen) {
            if (true) { //TODO check if label is on the clickable list
                if (theLabel == null) {
                    //defines first label
                    theLabel = labelScreen;
                    Log.i("LabelClicked", "theLabel null -> " + theLabel.getLabel().getText());
                }else {
                    //check if this label is closer to the click area than theLabel
                    float theLabelRelativeX = theLabel.getScreenPos().x - xClicked; 
                    float theLabelRelativeY = theLabel.getScreenPos().y - yClicked;
                    float myLabelRealativeX = labelScreen.getScreenPos().x - xClicked;
                    float myLabelRealativeY = labelScreen.getScreenPos().y - yClicked;

                    if ((Math.abs(myLabelRealativeX) < Math.abs(theLabelRelativeX)) 
                            && (Math.abs(myLabelRealativeY) < Math.abs(theLabelRelativeY))) {
                        Log.i("LabelClicked", "theLabel " + theLabel.getLabel().getText() + " -> " + labelScreen.getLabel().getText());
                        theLabel = labelScreen;
                    }
                }
            }
        }

        float theLabelRelativeX = theLabel.getScreenPos().x - xClicked; 
        float theLabelRelativeY = theLabel.getScreenPos().y - yClicked;
        if ((theLabelRelativeX < screenWidth*0.1f) && (theLabelRelativeY < screenHeight*0.1f)) {
            //clicked
            if (theLabel.getLabel().getText().equals(ApplicationConstants.myContext.getString(com.google.android.stardroid.R.string.moon))) {
                //ìf the clicked label is the moon, checks phase (in portuguese)
                String moonPhase = "";
                switch (ApplicationConstants.getMoonPhase()) {
                case ApplicationConstants.MOON_FULL:
                    moonPhase = " cheia";
                    break;
                case ApplicationConstants.MOON_CRESCENT:
                    moonPhase = " crescente";
                    break;
                case ApplicationConstants.MOON_NEW:
                    moonPhase = " nova";
                    break;
                case ApplicationConstants.MOON_GIBBOUS:
                    moonPhase = " minguante";
                    break;
                default:
                    break;
                }
                Toast.makeText(ApplicationConstants.myContext, theLabel.getLabel().getText() + moonPhase, Toast.LENGTH_SHORT).show();
                Log.i("LabelClicked", "You clicked: " + theLabel.getLabel().getText() + moonPhase);
            }else {
                Toast.makeText(ApplicationConstants.myContext, theLabel.getLabel().getText(), Toast.LENGTH_SHORT).show();
                Log.i("LabelClicked", "You clicked: " + theLabel.getLabel().getText());
            }
        }
        return false;
      }

我希望这会有所帮助。