2016-05-18 2 views
0

Я был сбит с толку, узнав, что метод closePath Java Path2D.Float фактически не закрывает путь правильно. Следующий код:Java Path2D.closePath работает неправильно?

Path2D.Float p = new Path2D.Float(); 
p.moveTo(3, 3); 
p.lineTo(10, 3); 
p.lineTo(8, 5); 
p.closePath(); 

PathIterator it = p.getPathIterator(null); 

float lastx = 0; 
float lasty = 0; 
boolean first = true; 
while (it.isDone() == false) { 
    float[] coordinates = new float[2]; 
    int type = it.currentSegment(coordinates); 
    if (first) { 
     first = false; 
    } else { 
     System.out.println("Segment from "+lastx+", "+lasty+" to "+coordinates[0]+", "+coordinates[1]); 
    } 
    lastx = coordinates[0]; 
    lasty = coordinates[1]; 
    it.next(); 
} 

производит этот выход:

Segment from 3.0, 3.0 to 10.0, 3.0 
Segment from 10.0, 3.0 to 8.0, 5.0 
Segment from 8.0, 5.0 to 0.0, 0.0 

Однако, можно было бы ожидать closePath, чтобы закрыть путь к координатам 3, 3, как говорится в документации:

Закрывает текущий подпуть, вычерчивая прямую линию обратно в координаты последнего перемещения.. Если путь уже закрыт, этот метод не действует. (https://docs.oracle.com/javase/8/docs/api/java/awt/geom/Path2D.html#closePath--)

Замена closePath от lineTo к исходным координатам производят желаемые сегменты, однако типа сегмента последнего сегмента таким образом, не равно SEG_CLOSE: (https://docs.oracle.com/javase/8/docs/api/java/awt/geom/PathIterator.html)

Type: 0 // SEG_MOVETO 
Type: 1 // SEG_LINETO 
Segment from 3.0, 3.0 to 10.0, 3.0 
Type: 1 
Segment from 10.0, 3.0 to 8.0, 5.0 
Type: 1 
Segment from 8.0, 5.0 to 3.0, 3.0 

добавляющих другой closePath звонок снова дает неправильные результаты:

Type: 0 
Type: 1 
Segment from 3.0, 3.0 to 10.0, 3.0 
Type: 1 
Segment from 10.0, 3.0 to 8.0, 5.0 
Type: 1 
Segment from 8.0, 5.0 to 3.0, 3.0 
Type: 4 // SEG_CLOSE 
Segment from 3.0, 3.0 to 0.0, 0.0 // <- not the correct coordinates! 

Может ли кто-нибудь воспроизвести это или объяснить другим, что мне не хватает, если это не ошибка?

Дополнительная информация: ОС: Mac OS X 10.10.5 JDK: jdk1.8.0_92

Сердечные приветы

+0

Я полагаю, что это также неправильно рисуется? – Ironcache

+0

Посмотрите на Javadoc 'PathIterator', и у вас будет ваш ответ.Подводя итог, если возвращаемый int равен SEG_CLOSE, в массив не помещаются точки (следовательно, [0.0, 0.0], значения поплавков по умолчанию возвращаются, как вы заметили и как ожидается). Поэтому, чтобы устранить проблему, проверьте тип возвращаемого типа 'currentSegment()' https://docs.oracle.com/javase/8/docs/api/java/awt/geom/PathIterator.html – Ironcache

+0

. Я не знаю о чертеже (но @Boann предлагает, что все будет хорошо), потому что я не использую путь для рисования. Я просто использую его для проверки наличия или отсутствия точек в области с контуром как формой. – Warkst

ответ

1

При определении Path2D он хранит, по существу, в необработанном список вызовов методов которые были использованы для определения пути в первую очередь, поэтому closePath() не выполняет никакой геометрической логики. Он записывает, что closePath() был вызван, но не хранит никаких дополнительных точек в массиве внутренних точек пути, потому что это необязательно; код, который выполняет итерации сегментов пути, сможет запомнить, где был запущен путь.

Аналогичным образом, PathIterator.currentSegment говорит: «SEG_CLOSE не возвращает никаких баллов» (поскольку closePath() не вызывался ни с одной точкой). Поскольку он не возвращает никаких точек, вы печатаете нулевые значения по умолчанию, с которыми инициализируется массив coordinates.

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

float moveX = 0, moveY = 0; 
for (PathIterator it = path.getPathIterator(null); !it.isDone(); it.next()) { 
    float[] c = new float[6]; 
    int type = it.currentSegment(c); 
    switch (type) { 
    case PathIterator.SEG_MOVETO: 
     System.out.println("moveTo(" + c[0] + ", " + c[1] + ")"); 
     moveX = c[0]; moveY = c[1]; 
     break; 
    case PathIterator.SEG_LINETO: 
     System.out.println("lineTo(" + c[0] + ", " + c[1] + ")"); 
     break; 
    case PathIterator.SEG_QUADTO: 
     System.out.println("quadTo(" + c[0] + ", " + c[1] + ", " + c[2] + ", " + c[3] + ")"); 
     break; 
    case PathIterator.SEG_CUBICTO: 
     System.out.println("cubicTo(" + c[0] + ", " + c[1] + ", " + c[2] + ", " + c[3] + ", " + c[4] + ", " + c[5] + ")"); 
     break; 
    case PathIterator.SEG_CLOSE: 
     System.out.println("closePath() (back to " + moveX + ", " + moveY + ")"); 
     break; 
    } 
} 

Если вы отправляете путь быть запряженной в Graphics2D вам не нужно беспокоиться об этом; рендерер обработает его правильно. Точно так же все методы тестирования ударов по пути работают нормально, так как they iterate the path тот же самый базовый способ, что вы видите выше.

+0

Я вижу. Я понял, что 'closePath' просто добавил' lineTo' в координаты последнего 'moveTo' и пометил его специальным типом сегмента, чтобы указать другим библиотекам геометрии, что путь закрыт (и, следовательно, является формой с поверхностью сорта). Из того, что я понимаю, это то, что он делает при рендеринге, но не при повторении по сегментам. Поэтому, чтобы решить мою проблему, я могу либо проверить тип сегмента, либо вручную перевести SEG_CLOSE на строку с первой координатой или просто «закрыть» мой путь с помощью строкиTo вместо closePath, правильно? Благодарю. – Warkst

+0

@Warkst Если вы используете собственные методы 'contains' пути для тестирования hit, нет никаких проблем. Он уже справляется с этим правильно. – Boann

+0

Помимо тестирования на удар, меня также интересует расстояние между любой точкой и формой пути. Для этого я думал, что буду перебирать сегменты, преобразовывать их в экземпляры line2d и использовать метод ptLineDist для нахождения ближайшего расстояния до любой точки (как минимум всех расстояний до каждого из сегментов). В этом случае необходимо, чтобы последний сегмент возвращал правильные координаты, чтобы правильно преобразовать его в строку2d. – Warkst

Смежные вопросы