Torna indietro   Hardware Upgrade Forum > Software > Programmazione

iPhone 17 Pro: più di uno smartphone. È uno studio di produzione in formato tascabile
iPhone 17 Pro: più di uno smartphone. È uno studio di produzione in formato tascabile
C'è tanta sostanza nel nuovo smartphone della Mela dedicato ai creator digitali. Nuovo telaio in alluminio, sistema di raffreddamento vapor chamber e tre fotocamere da 48 megapixel: non è un semplice smartphone, ma uno studio di produzione digitale on-the-go
Intel Panther Lake: i processori per i notebook del 2026
Intel Panther Lake: i processori per i notebook del 2026
Panther Lake è il nome in codice della prossima generazione di processori Intel Core Ultra, che vedremo al debutto da inizio 2026 nei notebook e nei sistemi desktop più compatti. Nuovi core, nuove GPU e soprattutto una struttura a tile che vede per la prima volta l'utilizzo della tecnologia produttiva Intel 18A: tanta potenza in più, ma senza perdere in efficienza
Intel Xeon 6+: è tempo di Clearwater Forest
Intel Xeon 6+: è tempo di Clearwater Forest
Intel ha annunciato la prossima generazione di processori Xeon dotati di E-Core, quelli per la massima efficienza energetica e densità di elaborazione. Grazie al processo produttivo Intel 18A, i core passano a un massimo di 288 per ogni socket, con aumento della potenza di calcolo e dell'efficienza complessiva.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 01-05-2008, 15:06   #1
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
[JAVA] Java2D/Graphics2D/AffineTransform: mapping coordinate mouse in "user space"

Lo scenario:
Ho un insieme di figure a contorno chiuso che rappresentano ognuna una sagoma reale da tagliare con una macchina CN.
Queste figure vengono dispososte su una lastra di materiale di forma rettangolare e dimensione nota.
Devo renderizzare queste figure, disposte sul pannello, per visualizzarle all'utente e permettergli di interfacciarsi con il mouse per riposizionarle dove meglio crede nella lastra (quindi trascinamento della sagoma, sua rotazione attorno al proprio centro).

L'immagine della lastra e delle sagome che contiene viene renderizzata sull'oggetto Graphics (Graphics2D) di un JPanel contenuto in una JDialog; per una visualizzazione opportuna, il rendering viene scalato e l'immagine della lastra centrata nel JPanel.

Il problema:
Ad ogni evento MouseMoved si vogliono stampare a video (in una zona apposita del Graphics) le coordinate correnti del puntatore del mouse.
Si recuperano le coordinate correnti del mouse all'interno del metodo public void mouseMoved(MouseEvent e) del Listener e tramite i metodi e.getX() ed e.getY().
Le coordinate così ottenute però non sono le coordinate "user space" (infatti il disegno della lastra è stato scalato e traslato) ma le coordinate screen/device space (cioè i valori X e Y correnti del mouse rispetto le origini del sistema cartesiano "nativo" del componente: l'origine è l'angolo in alto a sinistra, l'asse delle X si estende con verso positivo a destra, l'asse delle Y con verso positivo in basso).

Si devono quindi mappare le coordinate così ricavate rispetto alle trasformazioni inizialmente applicate al Graphics2D: ho visto in giro che normalmente basta prendere dal Graphics2D la sua trasformazione affine modificata dai vari translate(), rotate() ecc... e utilizzare quella per calcolare l'inversa da applicare alle coordinate del mouse in "device space" per ottenere le corrispettive coordinate in "user space".

Ho provato con questo approccio ma ottengo un risultato "strano" che temo dipenda da come utilizzo il Graphics2D e le AffineTransform

Ho realizzato un piccolo test per verificare la cosa, e di questo ora parlo: ho un JFrame che contiene 2 JPanel: in quello superiore ci sono delle label, una checkbox e dei textField; quello inferiore a sua volta contiene un altro JPanel, dove avviene il rendering (ho fatto così perchè il JPanel esterno l'ho inserito tramite Matisse e non lo posso estendere, mentre il JPanel interno è una mia classe che estende JPanel).

Quello che succede nel test è il semplice disegno degli assi cartesiani centrati sull'origine (X0Y0) del sistema di riferimento del Graphics2D su cui vengono poi disegnati un Rectangle2D e un Arc2D (stile "PIE").

Con i primi due textField in alto a sinistra si possono impostare dei valori in X e Y per eseguire una traslazione dell'origine in quelle coordinate.

C'è un MouseListener che on MouseMoved stampa continuamente i valori delle coordinate mappate in "device" e in "user" space.

Infine a destra c'è la stampa dei valori attualmente contenuti nella AffineTransform associata al Graphics2D su cui si renderizza. Questi valori vengono aggiornati solo all'evento MouseEntered nel JPanel di rendering.

Il problema è che mentre i valori delle coordinate "device space" del mouse combaciano sempre (provare prima e dopo eventuali traslazioni) i relativi valori rimappati in "user space" non sono esatti, perchè sembra (e si evince anche esaminando i valori stampati della AffineTransform) che sia sempre presente una certa quantità di offset sia nelle coordinate X (molto poco) che nelle Y (molto di più).

Guardando bene il valore di questo offset, ho quasi l'impressione che rappresenti la distanza (aka traslazione) del punto x0y0 del JPanel su cui disegno rispetto al punto x0y0 del JFrame che lo contiene.

Per chiarezza allego codice (due classi) e jar file eseguibile del applicativo di test.
Il jar è il file TransformTests.zip, basta rinominarlo cambiandogli l'estensione in .jar

Più tardi mi riconnetto per postare delle immagini di esempio che ho catturato, ora devo volare che ho la cresima di un cuginetto

Se qualcuno si è già imbattuto in un problema analogo o ha semplicemente già affrontato in un modo diverso la questione o ancora meglio sa esattamente cosa succede e mi da consigli gliene sarò davvero molto grato.

Ciao a tutti
Allegati
File Type: zip TransformTests.zip (22.5 KB, 18 visite)
File Type: zip code.zip (7.2 KB, 21 visite)

Ultima modifica di banryu79 : 02-05-2008 alle 14:14.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 02-05-2008, 00:38   #2
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
l'esempio con le immagini

Ecco il problema:

Avvio l'applicativo/test e posiziono il puntatore del mouse esattamente nel primo pixel in alto a sinistra del JPanel su cui avviene il rendering: in pratica sto puntando alle ccordinate x0y0 del sistema di riferimento in "device space".

Nei primi due JTextField sopra a sinistra leggo che non viene applicata nessuna traslazione al sistema di riferimento: sarebbe dunque lecito attendersi che le coordinate in "device space" di valore x0y0 convertite in "user space" valessero sempre x0y0 (in quanto non abbiamo applicato trasformazioni al Graphics2D).

[vedi: image01.jpg]


Invece si nota come le coordinate "user space" siano rimappate a x-13y-117 (internamente il remapping viene effettuato prendendo la reference alla AffineTransform del Graphics2D usandola per produrre un'altra AffineTransform equivalente all'inversa di se stessa da usare per trasformare le coordinate del punto del mouse) invece che corrispondere a x0y0, appunto.

Come dicevo nel post precedente, è verosimile che quel x-13y-117 applicato come traslazione al punto x0y0 del JPanel me lo porti a combaciare col punto x0y0 del JFrame che lo contiene? A me sembra di sì...

Cmq, continuando l'esempio: ora inserisco una traslazione di 100 per le X
[vedi: image02.jpg]

e una traslazione di 100 per le Y
[vedi: image04.jpg]


Esaminando le utlime voci a destra, sotto la stringa "Transform propertyes", vediamo stampati i valori della AffineTransform del Graphics2D aggiornati ai valori attuali e la traslazione è come ci aspettiamo: vale 100 per entrambe le coordinate e quindi in caso di trasformazione inversa dovrebbe andare tutto bene ma...

ho inserito un repaint(e quindi un refetch) di quei valori anche quando il mouse scatena l'evento MouseEntered nel JPanel e qui "casca l'asino"
[vedi: image05.jpg]


Come si vede ora i valori di traslazione si sono riaggiornati ma invece di presentarci l'atteso x100y100 è compraso un bel x113y217 che pare proprio tenenre conto dell'offset visto prima (x-13y-117) e che si nota come "errore" nella conversione della posizione del mouse: nel JPanel sono sopra l'origine traslata, il che significa che se come "screen/device space" le coordinate del mouse sono x100y100 (corretto perchè abbiamno applicato al Graphics2D una traslazione di x100y100) continuano però a essere rimappate in "user space" come x-13y-117, invece che come mi aspettavo legittimamente, cioè x0y0.

Ricordo che metre le coordinate stampate in "screen space" sono ricavate dal MouseEvent.getX()/.getY() le coordinate stampate in "user space" sono quelle del mouse rimappate da una AffineTransform che è l'inversa della AffineTransform del Graphics2D.

La mia domanda è: sono un nubbione da chilo e ho commesso qualche fesseria palese nel codice (il link nel post precedente, la classe rilevante è quella custom che estende JPanel per fare il rendering) o c'è sotto dell'altro?

Qualcuno ha idea da cosa sia dovuto il problema o in alternativa conosce delle "best practice" in materia che magari vede chiaramente non applicate qui, o ancora ci sono parti di codice nell'uso delle AffineTransform che gli "puzzano"?

Vi prego: ho davvero bisogno di capire perchè si comporta così e come rimediare dato che al click del mouse io devo neccessariamente risalire alle coordinate esatte del mio modello dati per selezionare/manovrare correttamente le figure da riposizionare nella lastra: le loro coordinate finali e i relativi percorsi devono combaciare a video rispetto a come verrano poi tagliati nell'effettivo dal CN sulla lastra, non posso permettermi errori di posizionamento.

Grazie mille a chiunque ha una anche minima idea della cosa e me la comunica.
A proposito: buonanotte
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 02-05-2008, 08:26   #3
dupa
Senior Member
 
L'Avatar di dupa
 
Iscritto dal: Jan 2002
Città: Napoli
Messaggi: 1727
non entro nei dettagli della progrmamazione swing.
in ogni a caso a mio parere stai sbagliando approccio.
devi definire un modello dati delle tue forme.. e poi una funziona che disegna su un "foglio bianco" a partire dal modello.

ciao
__________________
Se buttassimo in un cestino tutto ciò che in Italia non funziona cosa rimarrebbe? Il cestino.
dupa è offline   Rispondi citando il messaggio o parte di esso
Old 02-05-2008, 14:11   #4
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da dupa Guarda i messaggi
non entro nei dettagli della progrmamazione swing.
in ogni a caso a mio parere stai sbagliando approccio.
devi definire un modello dati delle tue forme.. e poi una funziona che disegna su un "foglio bianco" a partire dal modello.

ciao
Ciao Dupa,
grazie per l'intervento, purtroppo mi è di poco aiuto in quanto un modello dati per le mie "facce" da tagliare già esiste e funziona benissimo; partendo da quello generiamo le Shapes che rappresentano i PathIterator delle "facce" nella lastra corrente [non mi addentro nei dettagli, c'è dietro un algoritmo di nesting bidimensionale che ha già scelto su che lastra e in che posizione mettere ogni faccia passata] e quelli vengono manipolati in memoria fino a che l'utente non salva la situazione che ha definito: solo a quel punto viene applicata la modifica alla faccia originaria (e tra l'altro la faccia originaria non viene mai modificata ma resta com'è, in database viene solo salvato il set di valori di trasformazione da applicarle per ricostruire esattamente il suo percorso spiazzato sulla lastra).

A me serve capire solo il fenomeno che ho sottolineato qui: avviene perchè sbaglio io qualcosa di maddornale (probabilmente) o è un'anomalia (meno probabile)?

Il codice linkato e il jar sono relativi solamente al test su cui sto studiando questo specifico "problema".

Grazie dell'intervento cmq (almeno non mi fa sentire abbandonato )

Ciao

P.S.:
sono utili oltre che interventi, anche eventuali link a risorse online relative al campo specifico (utilizzo Java2D/Graphics2D/AffineTrasform & mapping mouse "device space" <-> "user space"). Lo chiedo perchè ho trovato tanto materiale al rigurado che sto spulciando con calma, ma magari salta fuori che qualcuno di voi ha un link a qualche risorsa succosa che non conosco.
Grazie a tutti

Ultima modifica di banryu79 : 02-05-2008 alle 14:18.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 03-05-2008, 13:33   #5
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
come ho risolto...

Ciao,

dato che con ulteriori indagini non sono riuscito a capire perchè la AffineTransform associata al Graphics2D del componente contenuto nel parent di massimo livello (nel mio caso la trasformazione affine del graphics di un JPanel contenuto in un JFrame) non sia corretta nei valori di traslazione di default (dovrebbero essere, o almeno così io mi aspettavo, X0Y0 in coordinate relative) ma sembri mantenere lo stesso valore di offset/posizionamento del componente rispetto al container in cui è inserito ho trovato due modi di aggirare il problema:

1) Posizionare l'oggetto su cui si renderizza in un certo modo
Posizionare sempre il componente su cui si disegna con l'angolo in alto a sinistra appoggiato all'angolo in alto a sinistra del container in cui lo si inserisce.
Nel caso del test qui sopra, non ho dovuto fare altro che prendere e trascinare (nell'editor visuale di NetBeans, Matisse) il pannello inferiore verso l'alto, in modo da averlo come primo componente, mentre il pannello con gli altri componenti viene posizionato sotto.

Il risultato è visibile qui, e nel file del .jar che allego per completezza: in questo modo i valori della matrice di AffineTransform associati al Graphics risultano corretti (attenzione: bisogna anche che il JPanel su cui si disegna non abbia un bordo, dato che altrimenti anche questo concorre a formare una certa quantità di offset, pari allo spessore del bordo).

[vedi immagine:]



2) Usare getLocation() o getBounds() per tenere conto dell'offset del Component
Usando getLocation() oppure getBounds() è possibile ottenere, in coordinate relative, la posizione del component: a quel punto basta utilizzare il valore di traslazione in X e Y nei calcoli.
Ci si fa dare dal component la sua trasformazione affine: da quella se ne produce una nuova identica computandole però i valori di traslazione X e Y nella quantità specificata dal getLocation() del Component, quindi da questa AffineTransform così composta si ottiene l'inversa e infine la si usa per trasformare le coordinate X e Y del mouse da "screen space" a "user space".

Nell'applicazione che sto scrivendo penso userò il primo sistema dato che non ho nessuna controindicazione nel piazzare il pannello con l'interfaccia sotto al pannello dove invece avviene il rendering.

Ciao


P.S.:
Quote:
Originariamente inviato da banryu79
A me serve capire solo il fenomeno che ho sottolineato qui: avviene perchè sbaglio io qualcosa di maddornale (probabilmente) o è un'anomalia (meno probabile)?
Dunque è un'anomalia?
(Chiamarlo bug ancora non mi sembra il caso). Però è strano che se chiedo le coordinate del mouse sopra il Graphics i valori prodotti di X e Y e inseriti nel MouseEvent da cui poi li posso leggere, queste siano corrette (tengono conto del posizionamento relativo del componente all'interno del massimo parent) e se invece le rimappo in "user space" queste non lo siano perchè la AffineTransform associata al Graphics del container computa esplicitamente la traslazione dal punto origine del parent contenitore... mha.
Allegati
File Type: zip TransformTests.zip (22.2 KB, 7 visite)

Ultima modifica di banryu79 : 03-05-2008 alle 13:59.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


iPhone 17 Pro: più di uno smartphone. È uno studio di produzione in formato tascabile iPhone 17 Pro: più di uno smartphone. &Eg...
Intel Panther Lake: i processori per i notebook del 2026 Intel Panther Lake: i processori per i notebook ...
Intel Xeon 6+: è tempo di Clearwater Forest Intel Xeon 6+: è tempo di Clearwater Fore...
4K a 160Hz o Full HD a 320Hz? Titan Army P2712V, a un prezzo molto basso 4K a 160Hz o Full HD a 320Hz? Titan Army P2712V,...
Recensione Google Pixel Watch 4: basta sollevarlo e si ha Gemini sempre al polso Recensione Google Pixel Watch 4: basta sollevarl...
iPad mini con chip A17 Pro: potenza da M...
Samsung cresce oltre le attese grazie al...
Microsoft presenta MAI-Image-1, il suo p...
AirPods Pro 3 contro AirPods Pro 2: Appl...
NVIDIA e l'era degli 800 VDC: come cambi...
Anche Duracell entra nel settore della r...
4 Macbook Pro 2024 con chip M4, M4 Pro ...
Recensione HONOR 400 Smart: autonomia da...
Il nuovo Snapdragon 8 Elite Gen 5 'for G...
2 Smart TV 4K in super offerta su Amazon...
AMD e Intel celebrano un anno di collabo...
NVIDIA consegna il suo mini supercompute...
La concorrenza cinese si fa sentire: il ...
4 accessori auto da non perdere su Amazo...
Era finito, eccolo ancora: torna il supe...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 09:44.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v