Получение размера спокойного Объекта

Для графики я не предпочел бы целые числа. Много систем используют целые числа для рисования UI (пиксели являются ints, в конце концов), но macOS, например, использует плавание для всего. macOS только знает точки, и точка может перевести в один пиксель, но в зависимости от разрешения монитора, это могло бы перевести во что-то еще. На экранах сетчатки половина точки (0.5/0.5) является пикселем. Однако, я никогда не замечал, что macOS UIs значительно медленнее, чем другой UIs. После всех 3D API (OpenGL или Direct3D) также работает с плаваниями, и современные графические библиотеки очень часто используют в своих интересах ускорение GPU.

Теперь Вы сказали, что скорость является Вашим основным беспокойством, хорошо, давайте пойдем для скорости. Перед выполнением любого сложного алгоритма сначала сделайте простой тест. Создайте , ось выровняла ограничительную рамку вокруг Вашего полигона. Это очень легко, быстро и уже может безопасный Вы много вычислений. Как это работает? Выполните итерации по всем точкам полигона и найдите минимальные значения / макс. значения X и Y.

, Например, у Вас есть точки (9/1), (4/3), (2/7), (8/2), (3/6). Это означает, что Xmin равняется 2, Xmax равняется 9, Ymin равняется 1, и Ymax равняется 7. Точка за пределами прямоугольника с этими двумя краями (2/1) и (9/7) не может быть в полигоне.

// p is your point, p.x is the x coord, p.y is the y coord
if (p.x < Xmin || p.x > Xmax || p.y < Ymin || p.y > Ymax) {
    // Definitely not within the polygon!
}

Это - первый тест, который будет работать за любой точкой. Как Вы видите, этот тест крайний быстрый, но это также очень крупно. Для обработки точек, которые являются в ограничительном прямоугольнике нам нужен более сложный алгоритм. Существует несколько путей, как это может быть вычислено. Который работы метода также зависит от факта, если полигон может иметь дыры или всегда будет тверд. Вот примеры твердых (одно выпуклое, одна впадина):

Polygon without hole

И вот один с дырой:

Polygon with hole

зеленый имеет дыру в середине!

самый легкий алгоритм, который может обработать все три случая выше и все еще довольно быстр, называют луч, бросая . Идея алгоритма довольно проста: Потяните виртуальный луч отовсюду вне полигона к Вашей точке и количеству, как часто это поражает сторону полигона. Если количество хитов даже, это за пределами полигона, если это нечетно, это внутри.

Demonstrating how the ray cuts through a polygon

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

Вы все еще имеете ограничительную рамку вышеупомянутых, помните? Просто выберите точку вне ограничительной рамки и используйте ее в качестве начальной точки для Вашего луча. Например, точка (Xmin - e/p.y) вне полигона наверняка.

, Но что e? Ну, e (на самом деле эпсилон) дает ограничительную рамку приблизительно [1 120] дополнение . Как я сказал, сбои трассировки лучей, если мы запускаем слишком близкий к строке полигона. Так как ограничительная рамка могла бы равняться полигону (если полигон является выровненным прямоугольником оси, ограничительная рамка равна самому полигону!), нам нужно некоторое дополнение для создания этого сейфа, это - все. Как большой необходимо выбрать e? Не слишком большой. Это зависит от системы координат, масштабируют Вас использование для рисования. Если Ваша пиксельная ширина шага 1.0, то просто выбирают 1.0 (все же 0.1, работал бы также)

Теперь, когда у нас есть луч с его запуском и координатами конца, сдвиги задач от" точка в полигоне " к" , как часто делает луч, пересекает сторону полигона ". Поэтому мы не можем только работать с точками полигона как прежде, теперь нам нужны фактические стороны. Сторона всегда определяется двумя точками.

side 1: (X1/Y1)-(X2/Y2)
side 2: (X2/Y2)-(X3/Y3)
side 3: (X3/Y3)-(X4/Y4)
:

необходимо протестировать луч против всех сторон. Полагайте, что луч вектор и каждая сторона, чтобы быть вектором. Луч должен поразить каждую сторону точно однажды или никогда вообще. Это не может поразить ту же сторону дважды. Две строки в 2D пространстве будут всегда пересекаться точно однажды, если они не будут параллельны, в этом случае они никогда не пересекаются. Однако, так как векторы имеют ограниченную длину, два вектора не могли бы быть параллельными и все еще никогда не пересекаться, потому что они слишком коротки, чтобы когда-либо встретить друг друга.

// Test the ray against all sides
int intersections = 0;
for (side = 0; side < numberOfSides; side++) {
    // Test if current side intersects with ray.
    // If yes, intersections++;
}
if ((intersections & 1) == 1) {
    // Inside of polygon
} else {
    // Outside of polygon
}

До сих пор так хорошо, но как Вы тестируете, если два вектора пересекаются? Вот некоторый код C (не протестированный), который должен добиться цели:

#define NO 0
#define YES 1
#define COLLINEAR 2

int areIntersecting(
    float v1x1, float v1y1, float v1x2, float v1y2,
    float v2x1, float v2y1, float v2x2, float v2y2
) {
    float d1, d2;
    float a1, a2, b1, b2, c1, c2;

    // Convert vector 1 to a line (line 1) of infinite length.
    // We want the line in linear equation standard form: A*x + B*y + C = 0
    // See: http://en.wikipedia.org/wiki/Linear_equation
    a1 = v1y2 - v1y1;
    b1 = v1x1 - v1x2;
    c1 = (v1x2 * v1y1) - (v1x1 * v1y2);

    // Every point (x,y), that solves the equation above, is on the line,
    // every point that does not solve it, is not. The equation will have a
    // positive result if it is on one side of the line and a negative one 
    // if is on the other side of it. We insert (x1,y1) and (x2,y2) of vector
    // 2 into the equation above.
    d1 = (a1 * v2x1) + (b1 * v2y1) + c1;
    d2 = (a1 * v2x2) + (b1 * v2y2) + c1;

    // If d1 and d2 both have the same sign, they are both on the same side
    // of our line 1 and in that case no intersection is possible. Careful, 
    // 0 is a special case, that's why we don't test ">=" and "<=", 
    // but "<" and ">".
    if (d1 > 0 && d2 > 0) return NO;
    if (d1 < 0 && d2 < 0) return NO;

    // The fact that vector 2 intersected the infinite line 1 above doesn't 
    // mean it also intersects the vector 1. Vector 1 is only a subset of that
    // infinite line 1, so it may have intersected that line before the vector
    // started or after it ended. To know for sure, we have to repeat the
    // the same test the other way round. We start by calculating the 
    // infinite line 2 in linear equation standard form.
    a2 = v2y2 - v2y1;
    b2 = v2x1 - v2x2;
    c2 = (v2x2 * v2y1) - (v2x1 * v2y2);

    // Calculate d1 and d2 again, this time using points of vector 1.
    d1 = (a2 * v1x1) + (b2 * v1y1) + c2;
    d2 = (a2 * v1x2) + (b2 * v1y2) + c2;

    // Again, if both have the same sign (and neither one is 0),
    // no intersection is possible.
    if (d1 > 0 && d2 > 0) return NO;
    if (d1 < 0 && d2 < 0) return NO;

    // If we get here, only two possibilities are left. Either the two
    // vectors intersect in exactly one point or they are collinear, which
    // means they intersect in any number of points from zero to infinite.
    if ((a1 * b2) - (a2 * b1) == 0.0f) return COLLINEAR;

    // If they are not collinear, they must intersect in exactly one point.
    return YES;
}

входные значения две конечных точки из вектора 1 (v1x1/v1y1 и v1x2/v1y2) и вектора 2 (v2x1/v2y1 и v2x2/v2y2). Таким образом, у Вас есть 2 вектора, 4 точки, 8 координат. YES и NO ясны. YES пересечения увеличений, NO ничего не делает.

Что относительно КОЛЛИНЕАРНОГО? Это означает, что оба вектора лежат на той же бесконечной строке, в зависимости от положения и длины, они не пересекаются вообще, или они пересекаются в бесконечном числе очков. Я не абсолютно уверен, как обработать этот случай, я не считал бы его как пересечение так или иначе. Ну, этот случай довольно редок на практике так или иначе из-за погрешностей округления с плавающей точкой; лучший код, вероятно, не протестировал бы на [1 117], но вместо этого на что-то как [1 118], где эпсилон является довольно небольшим числом.

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

Наконец, что не менее важно: Если можно использовать 3D аппаратные средства для решения проблемы, существует интересная альтернатива. Просто позвольте GPU сделать всю работу для Вас. Создайте поверхность рисования, которая является от экрана. Заполните его полностью черным цветом. Теперь позвольте OpenGL, или Direct3D красят Ваш полигон (или даже все Ваши полигоны, если Вы просто хотите протестировать, если точка в каком-либо из них, но Вы не заботитесь, какой), и заполняют полигон (полигоны) другим цветом, например, белый. Чтобы проверить, ли точка в полигоне, получите цвет этой точки от поверхности рисунка. Это - просто O (1) выборка памяти.

, Конечно, этот метод только применим, если Ваша поверхность рисунка не должна быть огромной. Если это не может вписаться в память GPU, этот метод медленнее, чем выполнение его на ЦП. Если это должно было бы быть огромно, и Ваш GPU поддерживает современные программы построения теней, можно все еще использовать GPU путем реализации кастинга луча, показанного выше как программа построения теней GPU, которая абсолютно возможна. Для большего числа полигонов или большого числа очков для тестирования, это окупится, рассмотрит, некоторые GPU смогут протестировать 64 - 256 точек параллельно. Обратите внимание однако, что передача данных от ЦП до GPU и назад является всегда дорогой, таким образом, для того, чтобы просто протестировать несколько точек против нескольких простых полигонов, где или точки или полигоны являются динамичными и будут часто изменяться, подход GPU будет редко окупаться.

6
задан Diaa Sami 13 August 2009 в 19:16
поделиться

4 ответа

На этот вопрос нет точного ответа, поскольку объем памяти, выделенной для разных объектов одного типа, может даже не совпадать (например, QSomething A может повторно использовать некоторые данные из cache, тогда как QSomething B, возможно, придется выделить его отдельно и т. д.).

Что вы могли бы сделать, я полагаю, это написать тривиальную тестовую программу, которая запускается, выделяет N объектов, о которых идет речь, а затем переходит в sleep () для долгое время. Пока программа спит, используйте диспетчер задач (или любой другой инструмент, который вам больше нравится), чтобы узнать, сколько оперативной памяти использует процесс. Затем ctrl-C (или завершите процесс) и снова запустите его с большим значением N и повторите измерение. Повторите этот процесс, и в конечном итоге вы получите представление о том, как объем оперативной памяти процесса увеличивается с количеством выделенных элементов,

7
ответ дан 8 December 2019 в 04:30
поделиться

Нет способ сделать это в Стандартном C ++, и очень немногие фреймворки поддерживают что-либо подобное. Причина довольно проста - как вы заметили, объект может содержать указатели, и эти указатели могут указывать на другие объекты, содержащие указатели, и так далее. И даже когда вы дойдете до конца цепочки указателей, не существует общего способа узнать, на какой объем памяти указывает указатель.

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

10
ответ дан 8 December 2019 в 04:30
поделиться

На самом деле проблема не только в Qt. Подумайте, сколько места занимает std :: string . Это ни sizeof (std :: string) , ни std :: string :: size () .

В C ++ нет ответа на этот вопрос, потому что вопрос редко имеет смысл.

5
ответ дан 8 December 2019 в 04:30
поделиться

Я обнаружил, что в целом QObject довольно тяжелый для создания более нескольких тысяч экземпляров.

Как упоминали несколько других людей, часто лучший способ решить эту проблему - это попробуйте и посмотрите, что произойдет. Вы даже можете написать небольшое приложение, подобное этому:

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QObject objects[5000];
    return app.exec();
}

Затем измерьте использование памяти перед выходом из приложения.

3
ответ дан 8 December 2019 в 04:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: