2017-01-29 1 views
0

Pour l'un de mes projets javafx actuels, je travaille avec Venn Diagrams. Je voudrais profiter de Shape.intersect pour faciliter la quantité de calculs mathématiques que je devrais travailler personnellement (et éviter de travailler avec des objets Path). Shape.intersect produit une forme parfaite, mais il est traduit/déplacé un peu et je n'arrive pas à comprendre combien il faut remettre. Idéalement, j'aimerais que la zone d'intersection se trouve exactement à l'endroit où les deux formes originales se croisent, c.-à-d. Que la nouvelle intersection s'adapte parfaitement aux formes originales. À l'heure actuelle, mon code produit un triple diagramme de Venn qui évolue avec la fenêtre. J'ai accès aux 3 points centraux des cercles ainsi qu'aux approximations approximatives d'autres points d'intersection importants. Ces autres points sont approximés parce qu'ils s'appuient sur les valeurs sin et cos pour s'assurer que les trois cercles ont la même taille et la même symétrie.Pourquoi la forme résultante de Shape.intersect apparaît-elle dans une position incorrecte?

Je moquaient l'image suivante (points/lettres ont été ajoutés à l'extérieur dans la peinture, mais l'image sous-jacente est ce que mon application produit maintenant): enter image description here

Comme vous pouvez le voir, l'intersection des cercles A et B (montré en bleu) est hors de la marque. Pour ce faire, mon code redimensionne le canevas sous-jacent à la taille de la fenêtre, calcule où placer les centres des cercles, puis dessine tous les 3 avec le même rayon. Découper toutes les peluches supplémentaires, mon code ressemble essentiellement à ceci:

// 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); 

Plus tard ...

// 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); 

Et la logique d'intersection (également dans la fonction de mise à jour):

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); 

J'ai essayé de faire un déplacement sur la forme d'intersection résultante au point C, mais je ne suis pas sûr si mon approximation de ce point est trop arrondie trop parce qu'elle n'est toujours pas correctement alignée:

enter image description here

Je devine que ce décalage pourrait avoir quelque chose à voir avec des bornes de mise en page/limites visuelles ou quelque chose qui est modifiée sur un redimensionnement et jamais correctement mis à jour, mais j'ai passé un long terme regardant la documentation et ne pouvait pas comprendre.

Idéalement, je voudrais éviter d'avoir à calculer le point C à la main puisque les cercles eux-mêmes sont générés par approximation/arrondi, ce qui rend pratiquement impossible l'obtention de C. J'espère que quelqu'un peut me diriger vers une solution qui ne peut utiliser que les cercles originaux, mais je prendrai tout ce qui fera apparaître l'intersection au bon endroit, quelle que soit la taille de la toile actuelle.

En résumé: comment faire pour que la forme renvoyée par Shape.intersect apparaisse au centre des deux formes à partir desquelles elle a été créée? Merci pour votre temps.

+1

J'ai essayé de recréer votre problème, mais [cela a bien fonctionné] (http://imgur.com/a/42vf9) avec moi. Je vois que vous avez une barre de menu et une barre d'état, est-ce parce que votre intersection se lie à un ensemble de coordonnées qui n'inclut pas l'un de ces deux éléments? Peut-être que si vous partagiez le code qui lie ou redimensionne vos formes, il serait plus facile de corriger? – MikaelF

+0

Merci pour la réponse. Je vais voir si je peux donner un exemple très concis de mon problème, car mon code est si long et désordonné qu'il serait contreproductif de le télécharger tel quel. Je vais mettre à jour dans quelques heures après avoir fini de travailler aujourd'hui. Je soupçonne que le problème est avec le redimensionnement de l'objet de toile que j'utilise, alors oui je suis d'accord que ce sera certainement important de partager. – Prester

Répondre

0

J'ai réussi à comprendre le problème. Je travaillais avec un objet canvas auto-redimensionnable inspiré par this post que j'ai trouvé ici sur StackOverflow. Dans le cas où un lien ne change jamais, le bit clé du code que j'emprunté à partir de là ressemblait les suivantes:

// 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(); 
    } 
} 

où « toile » est une instance privée d'un objet Canvas, et cette fonction entière était à l'intérieur d'une classe appelée CanvasPane qui a étendu le volet.

Ce que j'ai découvert Le code ci-dessus a un problème lorsque vous avez également des objets comme des cercles ajoutés aux enfants() du CanvasPane. Ma méthode redessiner() n'a déplacé que les centres du cercle et ajusté les rayons. Je n'ai jamais mis à jour les fonctions .setLayoutX() et .setLayoutY() comme je l'ai fait pour l'objet canvas réel pour les cercles réels. Ainsi, le redimensionnement de CanvasPane mettrait à jour les informations de mise en page de manière incohérente et les positions de mise en page sous-jacentes de tous les cercles seraient désynchronisées. Alors

, le correctif ici est de changer la section de mise en page de mise à jour sur les points suivants:

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

Cela met à jour les positions de mise en page des cercles et tout autre objet ajouté au CanvasPane (pas seulement la toile que je avait à l'origine), rendant la pièce d'intersection résultante réellement dans la bonne position.

En rétrospective, je devrais certainement avoir inclus plus de code dans ma question originale afin que d'autres puissent aider. Espérons que quelqu'un aura un jour les mêmes problèmes que moi et sera capable de trouver cette réponse.