[Java] Arc angle berekenen, misschien met cos etc.

Pagina: 1
Acties:
  • 231 views sinds 30-01-2008
  • Reageer

  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Ik ben bezig geweest om netwerk verkeer om te zetten in een real-time grafiek.

De bedoeling is dat hij er op de volgende manier uit komt te zien (gewoon omdat dit een stuk netter is).

Afbeeldingslocatie: http://members.home.nl/bvprooijen/1.jpg


Ik ben nu tot de volgende oplossing gekomen:

Afbeeldingslocatie: http://members.home.nl/bvprooijen/2.jpg

Deze heb ik gemaakt door een zwarte cirkel te tekenen.
Hier overheen heb ik 3 arc's getekend (groen voor overloaded, geel voor severely overloaded en het rode stuk voor de maximal load).
Hier overheen weer een kleinere zwarte cirkel om alleen de rand van de arc's maar te laten zien.

Nu komt het.
De pijl van de current load teken ik nu door vanuit het middenpunt van de cirkel een arc van 5 breed naar de buitenkant te tekenen.

Java:
1
2
3
4
5
6
7
8
9
//Deze bepaal ik in een hoek van 270 omdat ik de onderkant van de cirkel niet gebruik
private float oneTransaction = 270.0f / extractedData.getMaxLoad();

//De waarde van de current, waar de pijl heen moet.
current = Math.round(-(extractedData.getTotalTransactions()*oneTransaction)-oneTransaction);

//Het tekenen van de pijl en het kleine rondje in het midden.
graphics.fillArc(10, 10, width-20, height-20, 225+current, 5);
graphics.fillOval((width/2)-4, (height/2)-4, 8, 8);


De bedoeling is nu dat deze pijl dynamisch precies de andere kant op komt te staan zodat hij in het midden dik begint en dun eindigt.

Ik heb het al met een gewone lijn geprobeerd, en ook met cos, sin en tan maar mijn wiskunde kennis is niet echt om naar huis te schrijven :o
Is er misschien een makkelijke/mooie manier om dit op te lossen?

Alvast bedankt!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23-04 22:57

Janoz

Moderator Devschuur®

!litemod

Een arc is een taartpunt. Deze is per definitie smal in het middelpunt en breed bij het uiteinde. Je kunt je wijzer beter als polygoon renderen. Daarnaast lijkt het me handiger wanneer je gewoon in een tekenprogramma een wijzerplaat tekend en deze als bmp of png inlaad. Zeker omdat je er al een hebt die er ook nog een stuk leuker uitziet. Je hoeft dan alleen nog de wijzer te tekenen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
Wat Janoz zegt, of... De arc niet vanaf het midden naar rand tekenen, maar vanaf de rand naar het midden.

  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Janoz schreef op dinsdag 15 november 2005 @ 10:00:
Een arc is een taartpunt. Deze is per definitie smal in het middelpunt en breed bij het uiteinde. Je kunt je wijzer beter als polygoon renderen. Daarnaast lijkt het me handiger wanneer je gewoon in een tekenprogramma een wijzerplaat tekend en deze als bmp of png inlaad. Zeker omdat je er al een hebt die er ook nog een stuk leuker uitziet. Je hoeft dan alleen nog de wijzer te tekenen.
Tja dat heeft niet zo heel veel zin omdat dan de grootte van de kleuren voor de verschillende levels vast staan.
De overloaded, severely overloaded en max load is voor elke service via database in te stellen.
Bijv. voor service1 is de:
maximale load: 100
severely overloaded: 60
overloaded: 40

Dit geeft een ander plaatje dan:
Service 2
maximale load: 100
severely overloaded: 30
overloaded: 10

Bij service2 zal de rode rand dus veel groter zijn dan bij service1 etc. etc. Ik hoop dat ik het zo duidelijk uit heb gelegd ;)
Als polygoon heb ik idd ook al geprobeerd, maar daar kwam ik op deze manier echt niet uit

En kopjethee, ik weet dat ik vanuit buiten naar binnen dan de arc moet tekenen, maar dat was juist mijn vraag.
Hoe draai ik deze hoek met een berekening precies om zodat de arc de andere kant op "wijst".

  • OnTracK
  • Registratie: Oktober 2002
  • Laatst online: 18:30
Ik had zo'n idee, geen idee of het makkelijk te gebruiken is? (quick paint)

Afbeeldingslocatie: http://img399.imageshack.us/img399/2227/cirkels7de.png

Je hebt de donkere cirkel, dat is wat je nu hebt. Op het punt waar het uiteinde van je wijzer moet zijn heb je nog een tweede (niet bestaande) cirkel, even groot als de eerste.
Op de tweede cirkel teken je vanaf het middelpunt een taartpunt naar het midden van je eerste cirkel (hoek is precies omgekeerd)

Het middelpunt van de lichte cirkel beweegt dus over de rand van de donkere cirkel, en het brede gedeelte van de taartpunt blijft altijd in het midden van de donkere cirkel

[ Voor 6% gewijzigd door OnTracK op 15-11-2005 10:41 ]

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
OK, nu begrijp ik het. API van fillArc:
public abstract void fillArc(int x_oud, int y_oud, int width_oud, int height_oud, int startAngle_oud, int arcAngle_oud)

Jij hebt andere namen gebruikt, maar ik zal deze namen gebruiken en proberen (ongetest) de arc "omdraaien".

arcAngle_new = arcAngle_oud;
startAngle_new = startAngle_oud + 180;
height_new = height_oud;
width_new = width_oud;

Ik neem aan dat width en height gelijk zijn, aangezien je een cirkel tekent en geen ovaal.
De width en height zijn de straal van de cirkel als ik de documentatie goed interpreteer.

y_new = y_oud - width_new*sin(startAngle_oud);
x_new = x_oud + width_new*cos(startAngle_oud);

Dan gebruik je:
fillArc(int x_new, int y_new, int width_new, int height_new, int startAngle_new, int arcAngle_new)

[ Voor 10% gewijzigd door KopjeThee op 15-11-2005 11:01 ]


  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Thnx OnTrack, erg slim bedacht en wilde er al meteen mee aan de slag gaan. :9
Toen bedacht ik me daarna dat dit juist precies is wat ik nodig heb. Het maakt namelijk niet uit of je die 2e cirkel eromheen tekent of niet (onzichtbaar). Het gaat uiteindelijk juist toch om de arc (taartpunt) en de hoek ervan.

Dus de vraag is met wat voor formule draai ik de taartpunt precies om voor elke willekeurige hoek:

Java:
1
graphics.fillArc(10, 10, 205, 205, 225+current, 5); 

  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
kopjethee schreef op dinsdag 15 november 2005 @ 10:59:
OK, nu begrijp ik het. API van fillArc:
public abstract void fillArc(int x_oud, int y_oud, int width_oud, int height_oud, int startAngle_oud, int arcAngle_oud)

Jij hebt andere namen gebruikt, maar ik zal deze namen gebruiken en proberen (ongetest) de arc "omdraaien".

arcAngle_new = arcAngle_oud;
startAngle_new = startAngle_oud + 180;
height_new = height_oud;
width_new = width_oud;

Ik neem aan dat width en height gelijk zijn, aangezien je een cirkel tekent en geen ovaal.
De width en height zijn de straal van de cirkel als ik de documentatie goed interpreteer.

y_new = y_oud - width_new*sin(startAngle_oud);
x_new = x_oud + width_new*cos(startAngle_oud);

Dan gebruik je:
fillArc(int x_new, int y_new, int width_new, int height_new, int startAngle_new, int arcAngle_new)
Ok thnx! ga het ff proberen te implementeren, laat zo weten of ie werkt! :P


edit:
helaas werkt niet, de arc komt dan buiten de cirkel uit.
Heb er nog wat langer mee zitten klooien en kwam op en gegeven moment wel mooi uit voor de hoek tot 90 graden maar voor de rest van de hoeken dan weer niet.

[ Voor 11% gewijzigd door bvp op 15-11-2005 12:00 ]


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23-04 22:57

Janoz

Moderator Devschuur®

!litemod

Ik snap nog steeds niet waarom je zo moeilijk doet met een arc. Je kunt heel simpel ene polygoon tekenen. Hoekpunten van dit polygoon bereken je op dezelfde manier als het middelpunt van de arc van kopjethee, maar het is nog veel makkelijker wanneer je gewoon gebruik maakt van een transformatie matrix (Zit gewoon standaard in java2d)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
Janoz schreef op dinsdag 15 november 2005 @ 11:08:
Ik snap nog steeds niet waarom je zo moeilijk doet met een arc. Je kunt heel simpel ene polygoon tekenen. Hoekpunten van dit polygoon bereken je op dezelfde manier als het middelpunt van de arc van kopjethee, maar het is nog veel makkelijker wanneer je gewoon gebruik maakt van een transformatie matrix (Zit gewoon standaard in java2d)
Dat zou idd makkelijker zijn. Off topic: Ik ken 'm niet, omdat ik heel weinig Java gebruik (Waarom reageer ik dan op een Java vraag? Goede vraag, geen idee :-) ).

  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Je kan natuurlijk ook gewoon een Image inladen en deze met de Java2D api roteren naar de juiste stand. Is denk ik een stuk sneller en simpeler (en w.s. mooier)

  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Janoz schreef op dinsdag 15 november 2005 @ 11:08:
Ik snap nog steeds niet waarom je zo moeilijk doet met een arc. Je kunt heel simpel ene polygoon tekenen. Hoekpunten van dit polygoon bereken je op dezelfde manier als het middelpunt van de arc van kopjethee, maar het is nog veel makkelijker wanneer je gewoon gebruik maakt van een transformatie matrix (Zit gewoon standaard in java2d)
Denk dat ik het dan toch maar anders op moet gaan lossen dan.
Wilde nu ff gaan kijken naar de transformatie matrix maar waar moet ik dan zoeken in de API?

Zat nu gewoon op: http://java.sun.com/j2se/1.4.2/docs/api/ => Graphics2D
Of zit ik dan helemaal verkeerd te zoeken?
edit:
Of is er een aparte API voor Java2D?

Ook met image trouwens al eerder geprobeerd maar die is ook erg moeilijk te draaien omdat ook een image uiteraard vierkant is....

[ Voor 3% gewijzigd door bvp op 15-11-2005 12:04 ]


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23-04 22:57

Janoz

Moderator Devschuur®

!litemod

Jij hebt AffineTransform niet kunnen vinden? Daarnaast zie ik niet in wat het vierkant zijn van een plaatje voor invloed heeft op het makkelijk kunnen draaien

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Janoz schreef op dinsdag 15 november 2005 @ 13:02:
Jij hebt AffineTransform niet kunnen vinden? Daarnaast zie ik niet in wat het vierkant zijn van een plaatje voor invloed heeft op het makkelijk kunnen draaien
Ok thnx, zat hier inmiddels al te kijken ;)
Omdat als je een plaatje hebt, je hem alleen maar met hoeken van 90gr kan draaien elke keer. Als daar dus de naald in staat kun je dus alleen maar hoeken van 90gr gaan maken :? 8)7

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23-04 22:57

Janoz

Moderator Devschuur®

!litemod

Hoe kom je daar bij? Je kunt een plaatje draaien over elke mogelijke hoek. Als je vervolgens ook zorgt voor een goede smoothing strategie (antialias) zal het er ook goed uit blijven zien.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Janoz schreef op dinsdag 15 november 2005 @ 13:21:
Hoe kom je daar bij? Je kunt een plaatje draaien over elke mogelijke hoek. Als je vervolgens ook zorgt voor een goede smoothing strategie (antialias) zal het er ook goed uit blijven zien.
Heb toch echt veel te weinig dingen gedaan met GUI-achtige zaken, zo blijkt wel weer :o
Normaal gesproken ben ik alleen maar met webservices bezig, ben nu deze applet er tussendoor aan het doen. Wel weer es wat anders, en erg leuk!
Kom er helaas ook niet echt uit met de AffineTransform. Maar ik verzin er wel weer wat op hoop ik :+

  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
bvp schreef op dinsdag 15 november 2005 @ 11:03:
[...]


Ok thnx! ga het ff proberen te implementeren, laat zo weten of ie werkt! :P


edit:
helaas werkt niet, de arc komt dan buiten de cirkel uit.
Heb er nog wat langer mee zitten klooien en kwam op en gegeven moment wel mooi uit voor de hoek tot 90 graden maar voor de rest van de hoeken dan weer niet.
O, dat verbaast me een beetje. Houdt je er wel rekening mee dat de sin en cos functie in Java met radialen werkt ipv graden? Dus cos(hoekInGraden) geeft niet het gewenste resultaat. Als je de hoek in graden hebt, moet je dus cos((hoekInGraden*pi)/180) gebruiken datzelfde geldt voor sin. Ik was er vanuit gegaan dat de java functies met graden zouden werken.

Dus je vervangt de oude aanroep van fillArc door fillArcOmgekeerd:
code:
1
2
3
4
5
6
7
8
9
10
11
void fillArcOmgekeerd(Graphics g, int x_oud, int y_oud, int width_oud, int height_oud, int startAngle_oud, int arcAngle_oud)
{
  int x_new = x_oud + (int)(width_oud/2.0*Math.cos(startAngle_oud*Math.PI/180.0));
  int y_new = y_oud - (int)(width_oud/2.0*Math.sin(startAngle_oud*Math.PI/180.0));
  int width_new = width_oud;
  int height_new = height_oud;
  int startAngle_new = startAngle_oud + 180;
  int arcAngle_new = arcAngle_oud;

  g.fillArc(x_new, y_new, width_new, height_new, startAngle_new, arcAngle_new);
}


Nu helemaal... (ik heb het maar even ingetikt en zelfs getest)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    void fillArcOmgekeerd(Graphics g, int x_oud, int y_oud, int width_oud, int height_oud, int startAngle_oud, int arcAngle_oud)    
    {
        int x_new = (int)(width_oud/2.0*Math.cos(startAngle_oud*Math.PI/180.0));
        x_new += (int)(width_oud/2.0*Math.cos((startAngle_oud+arcAngle_oud)*Math.PI/180.0));
        x_new /= 2;
        x_new += x_oud;
        
        int y_new = (int)(width_oud/2.0*Math.sin(startAngle_oud*Math.PI/180.0));
        y_new += (int)(width_oud/2.0*Math.sin((startAngle_oud+arcAngle_oud)*Math.PI/180.0));
        y_new /= 2;
        y_new = y_oud - y_new;

        int width_new = width_oud;
        int height_new = height_oud;
        int startAngle_new = startAngle_oud + 180;
        int arcAngle_new = arcAngle_oud;

        g.fillArc(x_new, y_new, width_new, height_new, startAngle_new, arcAngle_new);
    }

[ Voor 56% gewijzigd door KopjeThee op 15-11-2005 14:48 . Reden: width is geen straal, maar diameter. Edit 2: x_new en y_new even verschoven om te zorgen dat de arc echt precies goed terecht komt. ]


  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Thnx, kopjethee maar werkt toch niet helemaal zo.
Op die code van vanmiddag heb ik ook geprobeerd verder te gaan maar zoals ik eerder al aan heb gegeven is mijn wiskunde op het gebied van tan, cos etc. echt gewoon niet goed.
Dat is (denk ik) ook de reden waarom het op alle andere aangedragen oplossingen niet lukt.
Omdat ik de hoek niet goed berekent krijg, lukt het uiteraard ook niet met plaatjes etc. etc.

Heb nu het volgende van jou (ff simpel in testapplet geplakt):

[code: java]
public void paint (Graphics g) {
g.drawOval(0, 0, 200, 200);
g.fillArc(0, 0, 200, 200, 240, 5);
fillArcOmgekeerd(g, 0, 0, 200, 200, 240, 5);
}

void fillArcOmgekeerd(
Graphics g, int x_oud, int y_oud, int width_oud, int height_oud,
int startAngle_oud, int arcAngle_oud) {

double x_new = x_oud + width_oud*Math.cos(startAngle_oud*Math.PI/180.0);
double y_new = y_oud - height_oud*Math.sin(startAngle_oud*Math.PI/180.0);
int width_new = width_oud;
int height_new = height_oud;
int startAngle_new = startAngle_oud + 180;
int arcAngle_new = arcAngle_oud;

g.fillArc(new Double(x_new).intValue(), new Double(y_new).intValue(), width_new, height_new, startAngle_new, arcAngle_new);
}
[/code]

Dit levert het volgende resultaat:

Afbeeldingslocatie: http://members.home.nl/bvprooijen/3.jpg

Er blijft dus toch nog steeds iets fout zitten in de x_new en y_new.
Ben hier dus al mee verder aan het klooien maar ik blijf verkeerde waardes terugkrijgen.

edit:
Ok bedankt kopjethee! _/-\o_
Hier was ik denk ik nog lang mee aan het prutsen geweest voordat ik dit voor elkaar zou hebben!

[ Voor 5% gewijzigd door bvp op 15-11-2005 14:53 ]


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
bvp schreef op dinsdag 15 november 2005 @ 14:50:
Thnx, kopjethee maar werkt toch niet helemaal zo.
Ja, dit kwam dus doordat ik dacht dat de width en height de straal waren van de cirkel, maar het was de diameter. Zie vorige post. Nu werkt het :-) Ik heb ook het startpunt een beetje verschoven, omdat je eigenlijk in het midden van de oude boog wilt beginnen ipv het uiteinde van de boog..

[ Voor 19% gewijzigd door KopjeThee op 15-11-2005 14:54 ]


  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Een oplossing met heel veel Math.cos en Math.sin kan erg duur worden qua resources.
Ik weet niet hoevaak je je meter hertekend? Anders zou ik overwegen een opzoektabel te maken.

Overigens blijf ik erbij dat een oplossing met affineTransfrom sneller,flexiber en mooier is :)

  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
wasigh schreef op dinsdag 15 november 2005 @ 15:04:
Een oplossing met heel veel Math.cos en Math.sin kan erg duur worden qua resources.
Ik weet niet hoevaak je je meter hertekend? Anders zou ik overwegen een opzoektabel te maken.

Overigens blijf ik erbij dat een oplossing met affineTransfrom sneller,flexiber en mooier is :)
Daar was ik idd ook wel bang voor, dat het wat meer resources zou kosten.
De reload wordt bepaald aan de hand van een database configuratie, hoe vaak er in Zweden een nieuwe timestamp wordt weggeschreven. Op het moment is dit elke 15 sec. maar dit zou kunnen veranderen.

Maar ook met andere oplossingen, zoals affineTransform, kom je vervolgens er niet omheen om eerst de hoeken te moeten gaan berekenen met cos. etc. :'(

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23-04 22:57

Janoz

Moderator Devschuur®

!litemod

Mwah, niet helemaal waar. Bij een affine transform wordt de berekening slechts 1x gedaan. Deze berekening vind ook nog intern plaats. Jijzelf hoeft enkel een rotatie matrix op te vragen. Met een beetje mazzel is dit vervolgens ook nog met een beetje hardware versnelling geimplementeerd (alhoewel ik er niet zeker van ben dat dat standaard aanstaat)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
bvp schreef op dinsdag 15 november 2005 @ 15:21:
[...]


Daar was ik idd ook wel bang voor, dat het wat meer resources zou kosten.
De reload wordt bepaald aan de hand van een database configuratie, hoe vaak er in Zweden een nieuwe timestamp wordt weggeschreven. Op het moment is dit elke 15 sec. maar dit zou kunnen veranderen.

Maar ook met andere oplossingen, zoals affineTransform, kom je vervolgens er niet omheen om eerst de hoeken te moeten gaan berekenen met cos. etc. :'(
Ik denk dat dit beter en duidelijker is, en je weer 2 cos/sin operaties scheelt. Een opzoek tabel voor cos/sin kan handig zijn. Verder zou ik er niet te snel vanuit gaan dat die affineTransform veel efficienter is (om maar te zwijgen van fillArc).

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
void fillArcOmgekeerd(Graphics g, int x_oud, int y_oud, int width, int height, int startAngle_oud, int arcAngle)
{
  double middenHoek = startAngle_oud + arcAngle/2.0; // in graden
  middenHoek *= Math.PI/180.0; // in radialen

  double straal = width/2.0;

  int x_new = x_oud + (int)(straal*Math.cos(middenHoek));
  int y_new = y_oud - (int)(straal*Math.sin(middenHoek));
  int startAngle_new = startAngle_oud + 180;

  g.fillArc(x_new, y_new, width, height, startAngle_new, arcAngle);
}

[ Voor 4% gewijzigd door KopjeThee op 16-11-2005 08:17 ]


  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03
Ok heb hem ff in de testapplet geplakt en werkt ook gewoon goed.
Mijn historyapplet (op basis van JFreeChart) werkte nu niet meer nu ik de omgekeerde naald gebruik. Misschien omdat de realTimeApplet nu meer rekenwerk vergt :?
Maar daar ga ik nu zo weer ff naar kijken.

Bedankt kopjethee voor die mooie oplossing en iedereen voor de reacties!
Pagina: 1