Place the canvas circle at the closest point of the canvas

I am currently developing a tree-shaped structure using Canvas Circles and I almost led to layouts with Canvas but ran into a problem while implementing Drag and Drop in Canvas. For a better understanding, the code looks like this:

private HashSet<CircleArea> mCircles = new HashSet<CircleArea>(CIRCLES_LIMIT);
    private SparseArray<CircleArea> mCirclePointer = new SparseArray<CircleArea>(CIRCLES_LIMIT);
     private static class CircleArea {
            int radius;
            int centerX;
            int centerY;

            CircleArea(int centerX, int centerY, int radius) {
                this.radius = radius;
                this.centerX = centerX;
                this.centerY = centerY;
            }

            public int getCenterX()
            {
                return centerX;
            }
            public int getCenterY()
            {
                return centerY;
            }

            public int getRadius()
            {
                return radius;
            }


            @Override
            public String toString() {
                return "Circle[" + centerX + ", " + centerY + ", " + radius + "]";
            }
        }

    private void init(final Context ct) {

            Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            int width = size.x;
            int height = size.y;
            System.out.println("Width is " + width + "Height is " + height);
            scrWidth = width;
            scrHeight = height;

        }
 @Override
    public void onDraw(final Canvas canv) {

       // setWillNotDraw(false);

            for (int i = 0; i < name.length; i++) {

                if (i == 0) {
                    for (int j = 0; j < latitude_0.length; j++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_0[j]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_0[j]));
                        mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));

                    }

                } else if (i == 1) {
                    for (int k = 0; k < latitude_1.length; k++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_1[k]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_1[k]));
                        mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));



                    }
                } else if (i == 2) {
                    for (int l = 0; l < latitude_2.length; l++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_2[l]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_2[l]));
                        mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));


                    }
                } else if (i == 3) {
                    for (int l = 0; l < latitude_3.length; l++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_3[l]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_3[l]));
                        mCircles.add(new CircleArea(x, y, RADIUS_LIMIT));

                    }
                } else if (i == 4) {
                    for (int l = 0; l < latitude_4.length; l++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_4[l]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_4[l]));
                        mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));


                    }
                }else if (i == 5) {
                    for (int l = 0; l < latitude_5.length; l++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_5[l]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_5[l]));
                        mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));


                    }
                }else if (i == 6) {
                    for (int l = 0; l < latitude_6.length; l++) {
                        x = (int) ((scrWidth / 360.0) * (90 + longitude_6[l]));
                        y = (int) ((scrHeight / 180.0) * (90 - latitude_6[l]));
                        mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));


                    }
                }

            }


                for (CircleArea circle : mCircles) {

                    canv.drawCircle(circle.getCenterX(),circle.getCenterY(),RADIUS_LIMIT, mCirclePaint);
                }




      //  invalidate();;
    }
   @Override
    public boolean onTouchEvent(final MotionEvent event) {
        boolean handled = false;

        CircleArea touchedCircle;
        int xTouch;
        int yTouch;
        int pointerId;
        int actionIndex = event.getActionIndex();

        // get touch event coordinates and make transparent circle from it
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:

                xTouch = (int) event.getX(0);
                yTouch = (int) event.getY(0);

                        touchedCircle = obtainTouchedCircle(xTouch, yTouch);
                        touchedCircle.centerX = xTouch;
                        touchedCircle.centerY = yTouch;
                        mCirclePointer.put(event.getPointerId(0), touchedCircle);


                invalidate();
                handled = true;
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                Log.w(TAG, "Pointer down");
                // It secondary pointers, so obtain their ids and check circles
                pointerId = event.getPointerId(actionIndex);

                xTouch = (int) event.getX(actionIndex);
                yTouch = (int) event.getY(actionIndex);

                // check if we've touched inside some circle
                for(CircleArea circle: mCircles)
                {
                    touchedCircle = obtainTouchedCircle(circle.getCenterX(), circle.getCenterY());
                    mCirclePointer.put(pointerId, touchedCircle);
                    touchedCircle.centerX = circle.getCenterX();
                    touchedCircle.centerY = circle.getCenterY();

                }

                invalidate();
                handled = true;
                break;

            case MotionEvent.ACTION_MOVE:
                final int pointerCount = event.getPointerCount();

                Log.w(TAG, "Move");

                for (actionIndex = 0; actionIndex < pointerCount; actionIndex++) {
                    // Some pointer has moved, search it by pointer id
                    pointerId = event.getPointerId(actionIndex);

                    for(CircleArea circle: mCircles)
                    {
                        xTouch = (int) event.getX(actionIndex);
                        yTouch = (int) event.getY(actionIndex);
                        float dx = xTouch - circle.getCenterX();
                        float dy = yTouch - circle.getCenterY();

                        float r = FloatMath.sqrt((dx * dx) + (dy * dy));

                        touchedCircle = mCirclePointer.get(pointerId);

                        if (null != touchedCircle) {
                            touchedCircle.centerX = xTouch;
                            touchedCircle.centerY = yTouch;
                        }
                    }

                }
                invalidate();
                handled = true;
                break;

            case MotionEvent.ACTION_UP:
                //clearCirclePointer();
                invalidate();
                handled = true;
                break;

            case MotionEvent.ACTION_POINTER_UP:
                // not general pointer was up
                pointerId = event.getPointerId(actionIndex);

                mCirclePointer.remove(pointerId);
                // invalidate();
                handled = true;
                break;

            case MotionEvent.ACTION_CANCEL:
                handled = true;
                break;

            default:
                // do nothing
                break;
        }

        return super.onTouchEvent(event) || handled;
    }
   private CircleArea obtainTouchedCircle(final int xTouch, final int yTouch) {
        CircleArea touchedCircle = getTouchedCircle(xTouch, yTouch);

        if (null == touchedCircle) {

            touchedCircle = new CircleArea(xTouch, yTouch, RADIUS_LIMIT);



        }

        return touchedCircle;
    }

    private CircleArea getTouchedCircle(final int xTouch, final int yTouch) {
        CircleArea touched = null;

        for (CircleArea circle : mCircles) {
            if ((circle.centerX - xTouch) * (circle.centerX - xTouch) + (circle.centerY - yTouch) * (circle.centerY - yTouch) <= circle.radius * circle.radius) {
                touched = circle;
                break;
            }
        }

        return touched;
    }

      

I am well aware that I wrote bad code, but very helpless, to create a mathematical calculation of how to place the dragged circle on the closest available circle of the canvas. Below is a screenshot that helps in a deeper understanding.

Points to note: Function obtainTouchedCircle

and getTouchedCircle

vital. MotionEvent.ACTION_MOVE

helps me move the circle, but what it does is that it generates a new circle with the same dimensions every time that is absolutely normal, but when the user drags and falls somewhere, it should be placed in the closest available circle ...

Consider the image below, where the yellow circles need to be moved and placed in the blue circles according to the user's wishes. It is my goal.

If anyone can help me with calculations on how I should figure out the closest available circle, and dragging would be very helpful !!!! Thanks in advance.

enter image description here

+3


source to share





All Articles