Intereting Posts
Как настроить диалоговое окно виджета PlaceAutocomplete для списка мест "Android.util.AndroidRuntimeException: requestFeature () необходимо вызвать перед добавлением содержимого" в showDialog (dialogId) Как я могу использовать несколько компонентов GLSurfaceView в одном макете? Элемент списка с CheckBox не доступен для кликов Как заменить запятую пробелом, когда я использую «MultiAutoCompleteTextView», Как расширить зону касания вида Что делает DetailedState.VERIFYING_POOR_LINK для Программная клавиатура Android скрывает поля ввода в мобильном веб-приложении HTML5. Ошибка! Используя CDATA в файле strings.xml Android Индикатор мобильной активности jQuery не отображается в android Погрузчики в Android Honeycomb Вы можете отслеживать, когда андроидное приложение было прекращено? Android: можно установить высоту SlidingDrawer с помощью wrap_content? Последний незавершенный блок с CipherInputStream / CipherOutputStream, даже с дополнением AES / CBC / PKCS5Padding Как определить тип файла MIME в android?

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

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

Path.contains (int x, int y)

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

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

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

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

Класс 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<paths.size();i++) { paint.setColor(i<<24); // use only alpha value for color 0xXX000000 canvas.drawPath(paths.get(i), paint); } 

Затем посмотрите точки,

 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<int>(floorf(point.x() / scale)); int y = static_cast<int>(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, существует операция пересечения для Paths. Вы можете создать очень маленький квадратный путь вокруг своей тестовой точки, пересечь ее с помощью Path и посмотреть, пуст ли результат или нет.

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

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

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

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

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