2017-01-29 3 views
0

Для одного из моих текущих проектов javafx я работаю с Venn Diagrams. Я бы хотел использовать Shape.intersect, чтобы облегчить количество математических вычислений, которые мне пришлось бы лично выполнять (и избегать работы с объектами Path). Shape.intersect производит идеальную форму, но она переведена/перемещена немного, и я не могу понять, сколько ее вернуть. В идеале, я бы хотел, чтобы область пересечения происходила точно там, где пересекаются две исходные формы, т. Е. Новое пересечение будет легко сочетаться с исходными фигурами.Почему результирующая фигура из Shape.intersect появляется в неправильном положении?

В настоящий момент мой код создает трехмерную диаграмму Венна, которая масштабируется с окном. У меня есть доступ к 3 центральным точкам кругов, а также к грубым приближениям других важных точек пересечения. Эти другие точки аппроксимируются, потому что они полагаются на значения sin и cos, чтобы убедиться, что все три круга одинакового размера и симметричны.

я издевался до следующего изображения (точки/буквы были добавлены извне в краске, но основное изображение, что мое приложение производит сейчас): enter image description here

Как вы можете видеть, пересечение окружностей А и В (показано синим цветом) не соответствует значению.

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

// Constructor creates 3 circles and adds to canvas 
Circle a = new Circle(); 
canvas.getChildren().add(a); 
// etc. for the other two circles 

// And also makes a Shape object to hold the intersection 
Shape ab = Shape.intersect(a,b); // initially empty 
canvas.getChildren().add(ab); 

Позже на ...

// Resizing the window calls an update function 
// which recalculates the circles' centers and 
// radii and then updates them. Since circles are 
// drawn from upper left corner, the relocate call 
// makes sure to subtract the radius to center it 
a.setRadius(radius); 
a.relocate(acx-radius,acy-radius); 

И логика пересечения (также в функции обновления):

canvas.getChildren().remove(ab); 
ab = Shape.intersect(a,b); 

// Can relocate to point c, but this doesn't do the job either (see below) 
ab.relocate(pcx,pcy); 

// Add the new intersection back to the canvas 
canvas.getChildren().add(ab); 

Я попытался сделать перемещение по полученной форме пересечения в точку C, но я не уверен, что мое приближение к этой точке слишком сильно округлено, потому что оно все еще не выровнено правильно:

enter image description here

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

В идеале, я бы хотел избежать вычисления точки C вручную, так как сами круги создаются с помощью аппроксимации/округления, что делает C практически невозможным. Я надеюсь, что кто-то может указать мне на решение, которое может использовать только исходные круги, но я возьму все, что делает пересечение отображаемым в нужном месте, независимо от размера текущего холста.

В целом: как я могу сделать форму, возвращенную Shape.intersect, появляться в центре двух фигур, из которых она создана? Спасибо за ваше время.

+1

Я попытался воссоздать вашу проблему, но [это сработало отлично] (http://imgur.com/a/42vf9) со мной. Я вижу, что у вас есть панель меню и строка состояния, может быть, потому, что ваше пересечение связывается с набором координат, который не включает один из этих двух элементов? Может быть, если вы разделите код, который связывает или изменяет размеры ваших фигур, было бы легче исправить? – MikaelF

+0

Спасибо за ответ. Я посмотрю, смогу ли я сделать очень краткий пример моей проблемы, так как мой код настолько длинный и беспорядочный, что было бы контрпродуктивно загружать его, как есть. Я обновлюсь через пару часов после того, как закончу работу сегодня. Я подозреваю, что проблема связана с изменением размера объекта canvas, который я использую, поэтому да, я согласен, что определенно будет важно поделиться. – Prester

ответ

0

Мне удалось выяснить проблему. Я работал с объективом с автоматическим изменением размера, вдохновленным this post. Я нашел здесь, на StackOverflow. В случае, если ссылка когда-либо изменения, ключевой бит кода, который я позаимствовал оттуда выглядел следующим образом:

// Update function when the window is resized 
@Override 
protected void layoutChildren() { 
    final double top = snappedTopInset(); 
    final double right = snappedRightInset(); 
    final double bottom = snappedBottomInset(); 
    final double left = snappedLeftInset(); 

    width = getWidth() - left - right; 
    height = getHeight() - top - bottom; 

    // Update the layout 
    canvas.setLayoutX(left); 
    canvas.setLayoutY(top); 

    if (width != canvas.getWidth() || height != canvas.getHeight()) { 
     // Resize 
     canvas.setWidth(width); 
     canvas.setHeight(height); 

     // Determine center 
     cx = width/2; 
     cy = height/2; 

     // Determine radius of circles 
     radius = 0.25 * Math.min(width, height); 

     // Clear and redraw circles 
     clear(); 
     redraw(); 
    } 
} 

где «холст» был частный случай объекта Canvas, и вся эта функция была внутри класса под названием CanvasPane, которая расширила область.

То, что я узнал выше код имеет проблемы, когда у вас также есть объекты, такие как круги, добавленных к детям() в CanvasPane. Мой метод redraw() только перемещал центры круга и корректировал радиусы. Я никогда не обновлял функции .setLayoutX() и .setLayoutY(), как я сделал для фактического объекта canvas для реальных кругов. Таким образом, изменение размера CanvasPane будет обновлять информацию о макете непоследовательно, и все позиции макета, расположенные в кругах, будут не синхронизированы.

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

// Update the layout 
for (Node n : getChildren()) { 
    n.setLayoutX(left); 
    n.setLayoutY(top); 
} 

Это обновляет позицию макета окружностей и любой другой объект, добавленный к CanvasPane (а не только холст, как я первоначально), в результате чего результирующая часть пересечения фактически находится в правильном положении.

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

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