[PHP] Krijg lijn niet goed getekend mbv imageline()

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik probeerde vandaag een script te schrijven om taartdiagrammen mee te kunnen tekenen. Na behoorlijk wat stoeiwerk is dit het resultaat:

Afbeeldingslocatie: http://www.danandan.luna.nl/piechart.gif

Zoals je ziet heb ik 1 probleem: de zwarte lijntjes moeten de scheidslijnen vormen tussen de verschillende taartpunten, zoals hieronder (met dank aan PhotoShop :))

Afbeeldingslocatie: http://www.danandan.luna.nl/piechart2.gif

De code die het bovenste plaatje genereert staat hier. De regels waar het fout gaat zijn
PHP:
1
2
3
4
$end_x = round($hoofd['Xas'] + ($hoofd['Xas'] * cos($input[$a][4] * pi() / 180)));  
$end_y = round($hoofd['Yas'] + ($hoofd['Yas'] * sin($input[$a][4] * pi() / 180))); 

imageline($img, $hoofd['Xas'], $hoofd['Yas'], $end_x, $end_y, $black);
Met andere woorden: ik krijg de coordinaten van deze lijntjes niet goed berekend. Wiskunde B (goniometrie :?) was op de middelbare school altijd mijn slechtste vak. Had ik nu maar bijles genomen!

In ieder geval - wie kan mij uitleggen wat ik fout doe en mij op de goede weg helpen?

[ Voor 12% gewijzigd door Reveller op 30-10-2005 22:06 . Reden: Typo's ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Ultra
  • Registratie: Maart 2000
  • Niet online
Bij $hoofd['Yas'] wordt af en toe wat opgeteld :X

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Wiskunde B was ook niet mijn sterkste punt, dus inhoudelijk kan ik je niet helpen, maar ik heb wel een suggestie. Waarom teken je de lijntjes niet als laatste in plaats van tussendoor? Zoals je het nu doet loop je de kans dat de volgende taartpunt je lijn overschrijft. ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Je haalt een heleboel dingen door elkaar. Je gebruikt de offset van het centrum van de cirkel als straal. Waarom gebruik je niet gewoon de straal bij het berekenen van het eindpunt? Sowieso zie ik verder naar onderen dat bij het tekenen van de circel ergens 10 bij optelt.

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


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
-NMe- schreef op zondag 30 oktober 2005 @ 22:21:
[...] Waarom teken je de lijntjes niet als laatste in plaats van tussendoor? Zoals je het nu doet loop je de kans dat de volgende taartpunt je lijn overschrijft. ;)
Daar heb je gelijk in. De reden was dat ik dan zowel de taartpunten als de lijntjes in 1 loop kon tekenen. Ik heb er niet bij stil gestaan dat de volgende taartpunt dan een lijntje zal overlappen. Ik genereer voor het eerst plaatjes mbv PHP en moet nog wat wennen aan het feit dat een plaatje, net als bij PhotoShop, uit layers bestaat die boven elkaar liggen...
Ultra schreef op zondag 30 oktober 2005 @ 22:17:
Bij $hoofd['Yas'] wordt af en toe wat opgeteld :X
Het is een script dat duidelijk in ontwikkeling is ;) De reden dat ik een aantal pixels bij de Yas optel, is dat de cirkel 30 pixels vanaf de bovenkant moet liggen, om ruimte te maken voor de titel.

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • ILUsion
  • Registratie: Augustus 2003
  • Laatst online: 23-01 08:12
Eventjes gewoon de parametervergelijking van een cirkel erbij halen en dan komt het wel goed:
Voor een cirkel met middelpunt O (0,0)
code:
1
2
{ x= r cos a
{ y= r sin a

Als je dit gaat opschuiven met offset x1 en offset y1 krijg je:
code:
1
2
{ x= r cos a + x1
{ y= r sin a + y1

Alle punten met coördinaten (x,y) voor een bepaalde a (hoek) behoren tot de cirkel en je middelpunt is gegeven door beide offsets namelijk (x1,y1)

Zijn je X-en Y-offset ($hoofd['Xas'] en $hoofd['Yas']) identiek, want daar zit je probleem. Jouw code is wiskundig te schrijven als:
code:
1
2
{ x = x1 + x1 cos a
{ y = y1 + y1 sin a

Deze parametervergelijking is van de vorm:
code:
1
2
{ x = a cos t + x1
{ y = b sin t +y1

Zoals je misschien wel weet, geeft dat een ellips (b is maximale uitwijking op y-as, a op de x-as).

In jouw geval zou ik gewoon een extra variabele r invoeren om het makkelijker te maken. Eventueel kun je dat gelijkstellen met één van beide offsets.

In je code geeft dat:
PHP:
1
2
3
4
$end_x = round($hoofd['Xas'] + ($hoofd['straal'] * cos($input[$a][4] * pi() / 180)));  
$end_y = round($hoofd['Yas'] + ($hoofd['straal'] * sin($input[$a][4] * pi() / 180))); 

imageline($img, $hoofd['Xas'], $hoofd['Yas'], $end_x, $end_y, $black);

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Die variabele R bestaat al lang in het script (alhoewel het daar neit de straal, maar de diameter is). Bijkomend probleem is trouwens dat de cirkel wel verplaatst wordt met +10, maar de lijnen niet.

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


Acties:
  • 0 Henk 'm!

Verwijderd

Misschien best eens een kijkje nemen op http://www.aditus.nu/jpgraph/.
Dit is een volledige library om grafieken te tekenen.

Acties:
  • 0 Henk 'm!

  • ILUsion
  • Registratie: Augustus 2003
  • Laatst online: 23-01 08:12
Mijn bovenstaande code bleek niet te werken (hoewel het in theorie, zonder jouw verdere code te bekeken hebben, had moeten werken).

Blijkbaar had je nog wat extra offsets hier en daar ingevoerd, ik zouy je dus aanraden om die ook in je variabelen te verwerken, zodat je niet overal +10 moet tellen bij de Y-waarden.

In je huidige code moet het onderstaande het juiste resultaat geven:
PHP:
1
2
3
4
  $end_x = $hoofd['Xas'] + ($conf['diameter']/2 * cos($input[$a][4] * pi() / 180));  
  $end_y = $hoofd['Yas']+10 + ($conf['diameter']/2 * sin($input[$a][4] * pi() / 180)); 

  imageline($img, $hoofd['Xas'], $hoofd['Yas']+10, $end_x, $end_y, $black);


Het enige probleem zoals anderen al gezegd hebben: je lijntjes verdwijnen soms onder de gekleurde vlakken. Je zal dus het meeste halen uit een complete rewrite van je code, denk ik; probeer alles wat overzichtelijk te houden (je offset in variablen verwerken, eventueel ook in je input-array betere namen kiezen (1e index als echte index, 2e index in plaats van getallen gewoon benamingen voor de duidelijkheid zodat je de commentaar kunt laten vallen bij de declaratie) en zorg dat je afzonderlijke lussen maakt: 1e lus vlakken vullen, 2e lus lijnen tekenen.

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Dank je, ILUsion -- dat werkt perfect. Je hebt gelijk dat ik de code moet rewriten. Ik ga ermee aan de slag en zal hier nog het uiteindelijke resultaat posten :)

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Zoals beloofd. Ik wil nog steeds een aantal zaken aan deze functie veranderen:
  • code verkorten
  • breedte van de legenda automatisch berekenen adhv langste titel
Als iemand nog ideeen / tips heeft, hoor ik het altijd graag :)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
function stats_pie($titel, $input, $imagename) {
  $pie['diameter'] = 170;
  $pie['legenda']  = 280;
  $pie['centerx']  = ($pie['diameter'] / 2) + 10;
  $pie['centery']  = ($pie['diameter'] / 2) + 40; 
  $pie['colors']   = array('#7AC5CD','#66CD00','#EEB422', '#458B00', '#EEC591'); 
  $pie['dotx']     = $pie['diameter'] + 50;
  $pie['titel']    = $titel;

  $img    = imagecreate($pie['diameter'] + $pie['legenda'], ($pie['centery'] * 2) - 20); 
  $bg     = imagecolorallocate($img, 255, 255, 255); 
  $black  = imagecolorallocate($img, 0, 0, 0);
  $copyrt = imagecolorallocate($img, 180, 180, 180);

  for ($a = 0; $a < count($input); $a++) { 
    preg_match('/(#)*([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/', $pie['colors'][$a], $hex); 
    $pie['colors'][$a] = imagecolorallocate($img, hexdec($hex[2]), hexdec($hex[3]), hexdec($hex[4])); 
  }

  $pie['total'] = 0; 
  for ($a = 0; $a < count($input); $a++) {
    $pie['total'] += $input[$a][0]; 
  }

  for ($a = 0; $a < count($input); $a++) {
    $input[$a][2] = (($input[$a][0] / $pie['total']) * 360);
    $previous = ($a > 0) ? $input[$a-1][4] : 0;
    $input[$a][3] = $previous;
    $input[$a][4] = $input[$a][2] + $previous;
    $input[$a][5] = round((100 / $pie['total']) * $input[$a][0], 1);
  }

  imagestring($img, 3, ((($pie['diameter'] + $pie['legenda']) - (strlen($pie['titel']) * 7)) / 2), 10, $pie['titel'], $black);

  for ($a = 0; $a < count($input); $a++) {
    imagefilledarc($img, $pie['centerx'], $pie['centery'], $pie['diameter'], $pie['diameter'], $input[$a][3], $input[$a][4], $pie['colors'][$a], IMG_ARC_PIE);
  }

  for ($a = 0; $a < count($input); $a++) {
    $end_x = $pie['centerx'] + ($pie['diameter'] / 2 * cos($input[$a][4] * pi() / 180));   
    $end_y = $pie['centery'] + ($pie['diameter'] / 2 * sin($input[$a][4] * pi() / 180));  
    imageline($img, $pie['centerx'], $pie['centery'], $end_x, $end_y, $black); 
  } 

  imagearc($img, $pie['centerx'], $pie['centery'], $pie['diameter'], $pie['diameter'], 0, 360, $black); 

  for ($a = 0; $a < count($input); $a++) {
    imagefilledrectangle($img, $pie['dotx'], ($a * 20) + 40, $pie['dotx'] + 10, ($a * 20) + 50, $pie['colors'][$a]); 
    imagerectangle($img, $pie['dotx'], ($a * 20) + 40, $pie['dotx'] + 10, ($a * 20) + 50, $black);
    imagestring($img, 3, $pie['dotx'] + 15, ($a * 20) + 40, $input[$a][1].' ('.$input[$a][5].' %)', $black); 
  } 

  imagerectangle($img, 0, 0, $pie['diameter'] + $pie['legenda'] - 1, ($pie['centery'] * 2) - 21, $black);

  $insert   = imagecreatefromgif(BASE_PATH.'system/images/stats/logo.gif');
  $insert_x = imagesx($insert); 
  $insert_y = imagesy($insert); 

  imagecopymerge($img, $insert, ($pie['diameter'] + $pie['legenda'] - ($insert_x + 10)), ($pie['centery'] * 2) - 52, 0, 0, $insert_x, $insert_y, 100); 
  imagestring($img, 2, ($pie['diameter'] + $pie['legenda'] - ($insert_x + 70)), ($pie['centery'] * 2) - 55, 'copyright', $copyrt);
  imagestring($img, 2, ($pie['diameter'] + $pie['legenda'] - ($insert_x + 82)), ($pie['centery'] * 2) - 40, 'Reveller 2006', $copyrt);

  imagepng($img, BASE_PATH.'system/images/stats/'.$imagename.'.png'); 
  imagedestroy($img);

  return 'chart.png';
}

[ Voor 28% gewijzigd door Reveller op 02-11-2005 22:21 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
tip, maak de code dynamisch, elke keer dezelfde filename teruggeven is niet echt handig.. je zal eens 2 charts op je site willen..

mm je code is wazig.. je maakt je img dynamisch, maar returned een static naam :?

[ Voor 25% gewijzigd door BasieP op 02-11-2005 22:29 ]

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik zie ook nogal wat 'magic numbers'. Vervang die eens met wat defines zodat je heldere informatieve constanten krijgt. Dat maakt het configureren, naast de leesbaarheid ook een stuk makkelijker.

Noushka's Magnificent Dream | Unity

Pagina: 1