Как я могу определить, содержит ли замкнутый путь заданную точку?

В Android у меня есть объект Path, который, как мне известно, определяет закрытый путь, и мне нужно выяснить, содержится ли данная точка в пути. То, на что я надеялся, было чем-то вроде

path.contains (int x, int y)

но это, похоже, не существует.

Конкретная причина, по которой я ищу это, состоит в том, что у меня есть набор фигур на экране, определенный как пути, и я хочу выяснить, на какой из них пользователь нажал. Если есть лучший способ приблизиться к этому, например, использовать разные элементы пользовательского интерфейса, а не делать это «трудным путем», я открыт для предложений.

Я открыт для написания алгоритма самостоятельно, если нужно, но это означает, что я предполагаю различные исследования.

    Класс android.graphics.Path не имеет такого метода. Класс Canvas имеет область отсечения, которая может быть установлена ​​в путь, и нет возможности протестировать ее против точки. Вы можете попробовать Canvas.quickReject, тестирование на один прямоугольник точки (или 1×1 Rect ). Я не знаю, действительно ли это будет проверять путь или только прямоугольник.

    Класс Region явно отслеживает только содержащий прямоугольник.

    Вы можете рассмотреть возможность рисования каждого из ваших регионов в 8-битном битовом слое альфа-слоя с каждым Path заполненным его собственным «цветным» значением (убедитесь, что сглаживание отключено в вашей Paint ). Это создает маску для каждого пути, заполненного индексом, на путь, который его заполняет. Затем вы можете просто использовать значение пикселя в качестве индекса в списке путей.

     Bitmap lookup = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8); //do this so that regions outside any path have a default //path index of 255 lookup.eraseColor(0xFF000000); Canvas canvas = new Canvas(lookup); Paint paint = new Paint(); //these are defaults, you only need them if reusing a Paint paint.setAntiAlias(false); paint.setStyle(Paint.Style.FILL); for(int i=0;i 

    Затем найдите точки,

     int pathIndex = lookup.getPixel(x, y); pathIndex >>>= 24; 

    Обязательно проверьте 255 (нет пути), если есть незаполненные точки.

    Вот что я сделал и, похоже, работает:

     RectF rectF = new RectF(); path.computeBounds(rectF, true); region = new Region(); region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom)); 

    Теперь вы можете использовать метод region.contains(x,y) .

     Point point = new Point(); mapView.getProjection().toPixels(geoPoint, point); if (region.contains(point.x, point.y)) { // Within the path. } 

    ** Обновление от 6/7/2010 ** Метод region.setPath приведет к сбою моего приложения (без предупреждения), если rectF слишком большой. Вот мое решение:

     // Get the screen rect. If this intersects with the path's rect // then lets display this zone. The rectF will become the // intersection of the two rects. This will decrease the size therefor no more crashes. Rect drawableRect = new Rect(); mapView.getDrawingRect(drawableRect); if (rectF.intersects(drawableRect.left, drawableRect.top, drawableRect.right, drawableRect.bottom)) { // ... Display Zone. } 

    У SkiaUtils от WebKit есть работа на C ++ для ошибки Randy Findley:

     bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; SkRect bounds = originalPath->getBounds(); // We can immediately return false if the point is outside the bounding rect if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) return false; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast(floorf(point.x() / scale)); int y = static_cast(floorf(point.y() / scale)); clip.setRect(x, y, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; } 

    Я знаю, что я немного опаздываю на вечеринку, но я бы решил эту проблему, подумав об этом, как определить, находится ли точка в полигоне.

    http://en.wikipedia.org/wiki/Point_in_polygon

    Математика вычисляется медленнее, когда вы смотрите на сплайны Безье вместо сегментов линии, но рисование луча от точки все еще работает.

    Для полноты я хочу сделать пару заметок здесь:

    Начиная с API 19, существует операция пересечения для путей. Вы можете создать очень маленький квадратный путь вокруг своей тестовой точки, пересечь ее с помощью Path и посмотреть, пуст ли результат или нет.

    Вы можете конвертировать маршруты в регионы и выполнять операцию contains () . Однако регионы работают в целых координатах, и я думаю, что они используют преобразованные (пиксельные) координаты, поэтому вам придется работать с этим. Я также подозреваю, что процесс преобразования является вычислительно интенсивным.

    Алгоритм кросс-пересечения, который Ханс опубликовал, хорош и быстр, но вы должны быть очень осторожны для определенных угловых случаев, например, когда луч проходит непосредственно через вершину или пересекает горизонтальный край, или когда ошибка округления является проблемой , что всегда есть.

    Метод числовой обмотки в значительной степени доказан дураком, но включает в себя множество триггеров и является дорогостоящим вычислительным.

    В этой статье Дэн Воскресенье приводится гибридный алгоритм, который столь же точен, как и число обмотки, но как вычислительно простой, как алгоритм лучевого каста. Меня отпугнул, насколько он утончен.

    См. https://stackoverflow.com/a/33974251/338479 для моего кода, который будет выполнять вычисление «точка-в-пути» для пути, состоящего из сегментов линии, дуг и кругов.

    Interesting Posts

    Рекомендации по использованию интерфейса Java. Неужели получатели и сеттеры в интерфейсе плохо?

    Использование инициализаторов и конструкторов в Java

    Как удалить мое имя из верхнего правого угла Chrome?

    java.net.URLEncoder.encode (String) устарел, что я должен использовать вместо этого?

    Как объединить два репозитория Git?

    Почему моя загрузочная папка так долго загружается?

    Как настроить сетевой менеджер Ubuntu / Linux для выборочного маршрутизации сетевого трафика через VPN?

    Насколько легко хакеру получить доступ к вашей веб-камере, когда вы просматриваете Интернет?

    Что означает подчеркивание в этом случае?

    Android – Ускорение вниз (разбить)

    Макрос для копирования отдельных значений из одного листа Excel в другой

    Действительно ли работает обфускация адресов электронной почты?

    Как определить, совместим ли SSD в моей Dell?

    Windows Update пробуждает машину из спящего режима

    Как включить «прокрутку для клика» в Windows XP?

    Давайте будем гением компьютера.