Total Complexity | 182 |
Total Lines | 1049 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like PiePlot3D often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use PiePlot3D, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | class PiePlot3D extends PiePlot |
||
27 | { |
||
28 | private $labelhintcolor = 'red'; |
||
29 | private $showlabelhint = true; |
||
30 | private $angle = 50; |
||
31 | private $edgecolor = ''; |
||
32 | private $edgeweight = 1; |
||
33 | private $iThickness = false; |
||
34 | |||
35 | /** |
||
36 | * CONSTRUCTOR. |
||
37 | * |
||
38 | * @param mixed $data |
||
39 | */ |
||
40 | public function __construct($data) |
||
41 | { |
||
42 | $this->radius = 0.5; |
||
43 | $this->data = $data; |
||
44 | $this->title = new Text\Text(''); |
||
45 | $this->title->SetFont(FF_FONT1, FS_BOLD); |
||
46 | $this->value = new DisplayValue(); |
||
47 | $this->value->Show(); |
||
48 | $this->value->SetFormat('%.0f%%'); |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * PUBLIC METHODS. |
||
53 | * |
||
54 | * @param mixed $aLegend |
||
55 | */ |
||
56 | // Set label arrays |
||
57 | public function SetLegends($aLegend) |
||
58 | { |
||
59 | $this->legends = array_reverse(array_slice($aLegend, 0, safe_count($this->data))); |
||
60 | } |
||
61 | |||
62 | public function SetSliceColors($aColors) |
||
63 | { |
||
64 | $this->setslicecolors = $aColors; |
||
65 | } |
||
66 | |||
67 | public function Legend($aGraph) |
||
68 | { |
||
69 | parent::Legend($aGraph); |
||
70 | $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol); |
||
71 | } |
||
72 | |||
73 | public function SetCSIMTargets($aTargets, $aAlts = '', $aWinTargets = '') |
||
74 | { |
||
75 | $this->csimtargets = $aTargets; |
||
76 | $this->csimwintargets = $aWinTargets; |
||
77 | $this->csimalts = $aAlts; |
||
78 | } |
||
79 | |||
80 | // Should the slices be separated by a line? If color is specified as "" no line |
||
81 | // will be used to separate pie slices. |
||
82 | public function SetEdge($aColor = 'black', $aWeight = 1) |
||
86 | } |
||
87 | |||
88 | // Specify projection angle for 3D in degrees |
||
89 | // Must be between 20 and 70 degrees |
||
90 | public function SetAngle($a) |
||
97 | } |
||
98 | } |
||
99 | |||
100 | public function Add3DSliceToCSIM($i, $xc, $yc, $height, $width, $thick, $sa, $ea) |
||
101 | { |
||
102 | //Slice number, ellipse centre (x,y), height, width, start angle, end angle |
||
103 | |||
104 | $sa *= M_PI / 180; |
||
105 | $ea *= M_PI / 180; |
||
106 | |||
107 | //add coordinates of the centre to the map |
||
108 | $coords = "${xc}, ${yc}"; |
||
109 | |||
110 | //add coordinates of the first point on the arc to the map |
||
111 | $xp = floor($width * cos($sa) / 2 + $xc); |
||
112 | $yp = floor($yc - $height * sin($sa) / 2); |
||
113 | $coords .= ", ${xp}, ${yp}"; |
||
114 | |||
115 | //If on the front half, add the thickness offset |
||
116 | if ($sa >= M_PI && $sa <= 2 * M_PI * 1.01) { |
||
117 | $yp = floor($yp + $thick); |
||
118 | $coords .= ", ${xp}, ${yp}"; |
||
119 | } |
||
120 | |||
121 | //add coordinates every 0.2 radians |
||
122 | $a = $sa + 0.2; |
||
123 | while ($a < $ea) { |
||
124 | $xp = floor($width * cos($a) / 2 + $xc); |
||
125 | if ($a >= M_PI && $a <= 2 * M_PI * 1.01) { |
||
126 | $yp = floor($yc - ($height * sin($a) / 2) + $thick); |
||
127 | } else { |
||
128 | $yp = floor($yc - $height * sin($a) / 2); |
||
129 | } |
||
130 | $coords .= ", ${xp}, ${yp}"; |
||
131 | $a += 0.2; |
||
132 | } |
||
133 | |||
134 | //Add the last point on the arc |
||
135 | $xp = floor($width * cos($ea) / 2 + $xc); |
||
136 | $yp = floor($yc - $height * sin($ea) / 2); |
||
137 | |||
138 | if ($ea >= M_PI && $ea <= 2 * M_PI * 1.01) { |
||
139 | $coords .= ", ${xp}, " . floor($yp + $thick); |
||
140 | } |
||
141 | $coords .= ", ${xp}, ${yp}"; |
||
142 | $alt = ''; |
||
|
|||
143 | |||
144 | if (!empty($this->csimtargets[$i])) { |
||
145 | $this->csimareas .= "<area shape=\"poly\" coords=\"${coords}\" href=\"" . $this->csimtargets[$i] . '"'; |
||
146 | |||
147 | if (!empty($this->csimwintargets[$i])) { |
||
148 | $this->csimareas .= ' target="' . $this->csimwintargets[$i] . '" '; |
||
149 | } |
||
150 | |||
151 | if (!empty($this->csimalts[$i])) { |
||
152 | $tmp = sprintf($this->csimalts[$i], $this->data[$i]); |
||
153 | $this->csimareas .= "alt=\"${tmp}\" title=\"${tmp}\" "; |
||
154 | } |
||
155 | $this->csimareas .= " />\n"; |
||
156 | } |
||
157 | } |
||
158 | |||
159 | public function SetLabels($aLabels, $aLblPosAdj = 'auto') |
||
160 | { |
||
161 | $this->labels = $aLabels; |
||
162 | $this->ilabelposadj = $aLblPosAdj; |
||
163 | } |
||
164 | |||
165 | // Distance from the pie to the labels |
||
166 | public function SetLabelMargin($m) |
||
169 | } |
||
170 | |||
171 | // Show a thin line from the pie to the label for a specific slice |
||
172 | public function ShowLabelHint($f = true) |
||
173 | { |
||
174 | $this->showlabelhint = $f; |
||
175 | } |
||
176 | |||
177 | // Set color of hint line to label for each slice |
||
178 | public function SetLabelHintColor($c) |
||
179 | { |
||
180 | $this->labelhintcolor = $c; |
||
181 | } |
||
182 | |||
183 | public function SetHeight($aHeight) |
||
186 | } |
||
187 | |||
188 | // Normalize Angle between 0-360 |
||
189 | public function NormAngle($a) |
||
190 | { |
||
191 | // Normalize anle to 0 to 2M_PI |
||
192 | // |
||
193 | if ($a > 0) { |
||
194 | while ($a > 360) { |
||
195 | $a -= 360; |
||
196 | } |
||
197 | } else { |
||
198 | while ($a < 0) { |
||
199 | $a += 360; |
||
200 | } |
||
201 | } |
||
202 | if ($a < 0) { |
||
203 | $a = 360 + $a; |
||
204 | } |
||
205 | |||
206 | if ($a == 360) { |
||
207 | $a = 0; |
||
208 | } |
||
209 | |||
210 | return $a; |
||
211 | } |
||
212 | |||
213 | // Draw one 3D pie slice at position ($xc,$yc) with height $z |
||
214 | public function Pie3DSlice($img, $xc, $yc, $w, $h, $sa, $ea, $z, $fillcolor, $shadow = 0.65) |
||
215 | { |
||
216 | // Due to the way the 3D Pie algorithm works we are |
||
217 | // guaranteed that any slice we get into this method |
||
218 | // belongs to either the left or right side of the |
||
219 | // pie ellipse. Hence, no slice will cross 90 or 270 |
||
220 | // point. |
||
221 | if (($sa < 90 && $ea > 90) || (($sa > 90 && $sa < 270) && $ea > 270)) { |
||
222 | Util\JpGraphError::RaiseL(14003); //('Internal assertion failed. Pie3D::Pie3DSlice'); |
||
223 | exit(1); |
||
224 | } |
||
225 | |||
226 | $p[] = []; |
||
227 | |||
228 | // Setup pre-calculated values |
||
229 | $rsa = $sa / 180 * M_PI; // to Rad |
||
230 | $rea = $ea / 180 * M_PI; // to Rad |
||
231 | $sinsa = sin($rsa); |
||
232 | $cossa = cos($rsa); |
||
233 | $sinea = sin($rea); |
||
234 | $cosea = cos($rea); |
||
235 | |||
236 | // p[] is the points for the overall slice and |
||
237 | // pt[] is the points for the top pie |
||
238 | |||
239 | // Angular step when approximating the arc with a polygon train. |
||
240 | $step = 0.05; |
||
241 | |||
242 | if ($sa >= 270) { |
||
243 | if ($ea > 360 || ($ea > 0 && $ea <= 90)) { |
||
244 | if ($ea > 0 && $ea <= 90) { |
||
245 | // Adjust angle to simplify conditions in loops |
||
246 | $rea += 2 * M_PI; |
||
247 | } |
||
248 | |||
249 | $p = [$xc, $yc, $xc, $yc + $z, |
||
250 | $xc + $w * $cossa, $z + $yc - $h * $sinsa, ]; |
||
251 | $pt = [$xc, $yc, $xc + $w * $cossa, $yc - $h * $sinsa]; |
||
252 | |||
253 | for ($a = $rsa; $a < 2 * M_PI; $a += $step) { |
||
254 | $tca = cos($a); |
||
255 | $tsa = sin($a); |
||
256 | $p[] = $xc + $w * $tca; |
||
257 | $p[] = $z + $yc - $h * $tsa; |
||
258 | $pt[] = $xc + $w * $tca; |
||
259 | $pt[] = $yc - $h * $tsa; |
||
260 | } |
||
261 | |||
262 | $pt[] = $xc + $w; |
||
263 | $pt[] = $yc; |
||
264 | |||
265 | $p[] = $xc + $w; |
||
266 | $p[] = $z + $yc; |
||
267 | $p[] = $xc + $w; |
||
268 | $p[] = $yc; |
||
269 | $p[] = $xc; |
||
270 | $p[] = $yc; |
||
271 | |||
272 | for ($a = 2 * M_PI + $step; $a < $rea; $a += $step) { |
||
273 | $pt[] = $xc + $w * cos($a); |
||
274 | $pt[] = $yc - $h * sin($a); |
||
275 | } |
||
276 | |||
277 | $pt[] = $xc + $w * $cosea; |
||
278 | $pt[] = $yc - $h * $sinea; |
||
279 | $pt[] = $xc; |
||
280 | $pt[] = $yc; |
||
281 | } else { |
||
282 | $p = [$xc, $yc, $xc, $yc + $z, |
||
283 | $xc + $w * $cossa, $z + $yc - $h * $sinsa, ]; |
||
284 | $pt = [$xc, $yc, $xc + $w * $cossa, $yc - $h * $sinsa]; |
||
285 | |||
286 | $rea = $rea == 0.0 ? 2 * M_PI : $rea; |
||
287 | for ($a = $rsa; $a < $rea; $a += $step) { |
||
288 | $tca = cos($a); |
||
289 | $tsa = sin($a); |
||
290 | $p[] = $xc + $w * $tca; |
||
291 | $p[] = $z + $yc - $h * $tsa; |
||
292 | $pt[] = $xc + $w * $tca; |
||
293 | $pt[] = $yc - $h * $tsa; |
||
294 | } |
||
295 | |||
296 | $pt[] = $xc + $w * $cosea; |
||
297 | $pt[] = $yc - $h * $sinea; |
||
298 | $pt[] = $xc; |
||
299 | $pt[] = $yc; |
||
300 | |||
301 | $p[] = $xc + $w * $cosea; |
||
302 | $p[] = $z + $yc - $h * $sinea; |
||
303 | $p[] = $xc + $w * $cosea; |
||
304 | $p[] = $yc - $h * $sinea; |
||
305 | $p[] = $xc; |
||
306 | $p[] = $yc; |
||
307 | } |
||
308 | } elseif ($sa >= 180) { |
||
309 | $p = [$xc, $yc, $xc, $yc + $z, $xc + $w * $cosea, $z + $yc - $h * $sinea]; |
||
310 | $pt = [$xc, $yc, $xc + $w * $cosea, $yc - $h * $sinea]; |
||
311 | |||
312 | for ($a = $rea; $a > $rsa; $a -= $step) { |
||
313 | $tca = cos($a); |
||
314 | $tsa = sin($a); |
||
315 | $p[] = $xc + $w * $tca; |
||
316 | $p[] = $z + $yc - $h * $tsa; |
||
317 | $pt[] = $xc + $w * $tca; |
||
318 | $pt[] = $yc - $h * $tsa; |
||
319 | } |
||
320 | |||
321 | $pt[] = $xc + $w * $cossa; |
||
322 | $pt[] = $yc - $h * $sinsa; |
||
323 | $pt[] = $xc; |
||
324 | $pt[] = $yc; |
||
325 | |||
326 | $p[] = $xc + $w * $cossa; |
||
327 | $p[] = $z + $yc - $h * $sinsa; |
||
328 | $p[] = $xc + $w * $cossa; |
||
329 | $p[] = $yc - $h * $sinsa; |
||
330 | $p[] = $xc; |
||
331 | $p[] = $yc; |
||
332 | } elseif ($sa >= 90) { |
||
333 | if ($ea > 180) { |
||
334 | $p = [$xc, $yc, $xc, $yc + $z, $xc + $w * $cosea, $z + $yc - $h * $sinea]; |
||
335 | $pt = [$xc, $yc, $xc + $w * $cosea, $yc - $h * $sinea]; |
||
336 | |||
337 | for ($a = $rea; $a > M_PI; $a -= $step) { |
||
338 | $tca = cos($a); |
||
339 | $tsa = sin($a); |
||
340 | $p[] = $xc + $w * $tca; |
||
341 | $p[] = $z + $yc - $h * $tsa; |
||
342 | $pt[] = $xc + $w * $tca; |
||
343 | $pt[] = $yc - $h * $tsa; |
||
344 | } |
||
345 | |||
346 | $p[] = $xc - $w; |
||
347 | $p[] = $z + $yc; |
||
348 | $p[] = $xc - $w; |
||
349 | $p[] = $yc; |
||
350 | $p[] = $xc; |
||
351 | $p[] = $yc; |
||
352 | |||
353 | $pt[] = $xc - $w; |
||
354 | $pt[] = $z + $yc; |
||
355 | $pt[] = $xc - $w; |
||
356 | $pt[] = $yc; |
||
357 | |||
358 | for ($a = M_PI - $step; $a > $rsa; $a -= $step) { |
||
359 | $pt[] = $xc + $w * cos($a); |
||
360 | $pt[] = $yc - $h * sin($a); |
||
361 | } |
||
362 | |||
363 | $pt[] = $xc + $w * $cossa; |
||
364 | $pt[] = $yc - $h * $sinsa; |
||
365 | $pt[] = $xc; |
||
366 | $pt[] = $yc; |
||
367 | } else { |
||
368 | // $sa >= 90 && $ea <= 180 |
||
369 | $p = [$xc, $yc, $xc, $yc + $z, |
||
370 | $xc + $w * $cosea, $z + $yc - $h * $sinea, |
||
371 | $xc + $w * $cosea, $yc - $h * $sinea, |
||
372 | $xc, $yc, ]; |
||
373 | |||
374 | $pt = [$xc, $yc, $xc + $w * $cosea, $yc - $h * $sinea]; |
||
375 | |||
376 | for ($a = $rea; $a > $rsa; $a -= $step) { |
||
377 | $pt[] = $xc + $w * cos($a); |
||
378 | $pt[] = $yc - $h * sin($a); |
||
379 | } |
||
380 | |||
381 | $pt[] = $xc + $w * $cossa; |
||
382 | $pt[] = $yc - $h * $sinsa; |
||
383 | $pt[] = $xc; |
||
384 | $pt[] = $yc; |
||
385 | } |
||
386 | } else { |
||
387 | // sa > 0 && ea < 90 |
||
388 | |||
389 | $p = [$xc, $yc, $xc, $yc + $z, |
||
390 | $xc + $w * $cossa, $z + $yc - $h * $sinsa, |
||
391 | $xc + $w * $cossa, $yc - $h * $sinsa, |
||
392 | $xc, $yc, ]; |
||
393 | |||
394 | $pt = [$xc, $yc, $xc + $w * $cossa, $yc - $h * $sinsa]; |
||
395 | |||
396 | for ($a = $rsa; $a < $rea; $a += $step) { |
||
397 | $pt[] = $xc + $w * cos($a); |
||
398 | $pt[] = $yc - $h * sin($a); |
||
399 | } |
||
400 | |||
401 | $pt[] = $xc + $w * $cosea; |
||
402 | $pt[] = $yc - $h * $sinea; |
||
403 | $pt[] = $xc; |
||
404 | $pt[] = $yc; |
||
405 | } |
||
406 | |||
407 | $img->PushColor($fillcolor . ':' . $shadow); |
||
408 | $img->FilledPolygon($p); |
||
409 | $img->PopColor(); |
||
410 | |||
411 | $img->PushColor($fillcolor); |
||
412 | $img->FilledPolygon($pt); |
||
413 | $img->PopColor(); |
||
414 | } |
||
415 | |||
416 | public function SetStartAngle($aStart) |
||
422 | } |
||
423 | |||
424 | // Draw a 3D Pie |
||
425 | public function Pie3D( |
||
426 | $aaoption, |
||
427 | $img, |
||
428 | $data, |
||
429 | $colors, |
||
430 | $xc, |
||
431 | $yc, |
||
432 | $d, |
||
433 | $angle, |
||
434 | $z, |
||
435 | $shadow = 0.65, |
||
436 | $startangle = 0, |
||
437 | $edgecolor = '', |
||
438 | $edgeweight = 1 |
||
439 | ) { |
||
440 | /** |
||
441 | * As usual the algorithm get more complicated than I originally |
||
442 | * // envisioned. I believe that this is as simple as it is possible |
||
443 | * // to do it with the features I want. It's a good exercise to start |
||
444 | * // thinking on how to do this to convince your self that all this |
||
445 | * // is really needed for the general case. |
||
446 | * // |
||
447 | * // The algorithm two draw 3D pies without "real 3D" is done in |
||
448 | * // two steps. |
||
449 | * // First imagine the pie cut in half through a thought line between |
||
450 | * // 12'a clock and 6'a clock. It now easy to imagine that we can plot |
||
451 | * // the individual slices for each half by starting with the topmost |
||
452 | * // pie slice and continue down to 6'a clock. |
||
453 | * // |
||
454 | * // In the algortithm this is done in three principal steps |
||
455 | * // Step 1. Do the knife cut to ensure by splitting slices that extends |
||
456 | * // over the cut line. This is done by splitting the original slices into |
||
457 | * // upto 3 subslices. |
||
458 | * // Step 2. Find the top slice for each half |
||
459 | * // Step 3. Draw the slices from top to bottom |
||
460 | * // |
||
461 | * // The thing that slightly complicates this scheme with all the |
||
462 | * // angle comparisons below is that we can have an arbitrary start |
||
463 | * // angle so we must take into account the different equivalence classes. |
||
464 | * // For the same reason we must walk through the angle array in a |
||
465 | * // modulo fashion. |
||
466 | * // |
||
467 | * // Limitations of algorithm: |
||
468 | * // * A small exploded slice which crosses the 270 degree point |
||
469 | * // will get slightly nagged close to the center due to the fact that |
||
470 | * // we print the slices in Z-order and that the slice left part |
||
471 | * // get printed first and might get slightly nagged by a larger |
||
472 | * // slice on the right side just before the right part of the small |
||
473 | * // slice. Not a major problem though. |
||
474 | */ |
||
475 | // Determine the height of the ellippse which gives an |
||
476 | // indication of the inclination angle |
||
477 | $h = ($angle / 90.0) * $d; |
||
478 | $sum = 0; |
||
479 | for ($i = 0; $i < safe_count($data); ++$i) { |
||
480 | $sum += $data[$i]; |
||
481 | } |
||
482 | |||
483 | // Special optimization |
||
484 | if ($sum == 0) { |
||
485 | return; |
||
486 | } |
||
487 | |||
488 | if ($this->labeltype == 2) { |
||
489 | $this->adjusted_data = $this->AdjPercentage($data); |
||
490 | } |
||
491 | |||
492 | // Setup the start |
||
493 | $accsum = 0; |
||
494 | $a = $startangle; |
||
495 | $a = $this->NormAngle($a); |
||
496 | |||
497 | // |
||
498 | // Step 1 . Split all slices that crosses 90 or 270 |
||
499 | // |
||
500 | $idx = 0; |
||
501 | $adjexplode = []; |
||
502 | $numcolors = safe_count($colors); |
||
503 | for ($i = 0; $i < safe_count($data); ++$i, ++$idx) { |
||
504 | $da = $data[$i] / $sum * 360; |
||
505 | |||
506 | if (empty($this->explode_radius[$i])) { |
||
507 | $this->explode_radius[$i] = 0; |
||
508 | } |
||
509 | |||
510 | $expscale = 1; |
||
511 | if ($aaoption == 1) { |
||
512 | $expscale = 2; |
||
513 | } |
||
514 | |||
515 | $la = $a + $da / 2; |
||
516 | $explode = [$xc + $this->explode_radius[$i] * cos($la * M_PI / 180) * $expscale, |
||
517 | $yc - $this->explode_radius[$i] * sin($la * M_PI / 180) * ($h / $d) * $expscale, ]; |
||
518 | $adjexplode[$idx] = $explode; |
||
519 | $labeldata[$i] = [$la, $explode[0], $explode[1]]; |
||
520 | $originalangles[$i] = [$a, $a + $da]; |
||
521 | |||
522 | $ne = $this->NormAngle($a + $da); |
||
523 | if ($da <= 180) { |
||
524 | // If the slice size is <= 90 it can at maximum cut across |
||
525 | // one boundary (either 90 or 270) where it needs to be split |
||
526 | $split = -1; // no split |
||
527 | if (($da <= 90 && ($a <= 90 && $ne > 90)) || |
||
528 | (($da <= 180 && $da > 90) && (($a < 90 || $a >= 270) && $ne > 90))) { |
||
529 | $split = 90; |
||
530 | } elseif (($da <= 90 && ($a <= 270 && $ne > 270)) || |
||
531 | (($da <= 180 && $da > 90) && ($a >= 90 && $a < 270 && ($a + $da) > 270))) { |
||
532 | $split = 270; |
||
533 | } |
||
534 | if ($split > 0) { |
||
535 | // split in two |
||
536 | $angles[$idx] = [$a, $split]; |
||
537 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
538 | $adjexplode[$idx] = $explode; |
||
539 | $angles[++$idx] = [$split, $ne]; |
||
540 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
541 | $adjexplode[$idx] = $explode; |
||
542 | } else { |
||
543 | // no split |
||
544 | $angles[$idx] = [$a, $ne]; |
||
545 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
546 | $adjexplode[$idx] = $explode; |
||
547 | } |
||
548 | } else { |
||
549 | // da>180 |
||
550 | // Slice may, depending on position, cross one or two |
||
551 | // bonudaries |
||
552 | |||
553 | if ($a < 90) { |
||
554 | $split = 90; |
||
555 | } elseif ($a <= 270) { |
||
556 | $split = 270; |
||
557 | } else { |
||
558 | $split = 90; |
||
559 | } |
||
560 | |||
561 | $angles[$idx] = [$a, $split]; |
||
562 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
563 | $adjexplode[$idx] = $explode; |
||
564 | //if( $a+$da > 360-$split ) { |
||
565 | // For slices larger than 270 degrees we might cross |
||
566 | // another boundary as well. This means that we must |
||
567 | // split the slice further. The comparison gets a little |
||
568 | // bit complicated since we must take into accound that |
||
569 | // a pie might have a startangle >0 and hence a slice might |
||
570 | // wrap around the 0 angle. |
||
571 | // Three cases: |
||
572 | // a) Slice starts before 90 and hence gets a split=90, but |
||
573 | // we must also check if we need to split at 270 |
||
574 | // b) Slice starts after 90 but before 270 and slices |
||
575 | // crosses 90 (after a wrap around of 0) |
||
576 | // c) If start is > 270 (hence the firstr split is at 90) |
||
577 | // and the slice is so large that it goes all the way |
||
578 | // around 270. |
||
579 | if (($a < 90 && ($a + $da > 270)) || ($a > 90 && $a <= 270 && ($a + $da > 360 + 90)) || ($a > 270 && $this->NormAngle($a + $da) > 270)) { |
||
580 | $angles[++$idx] = [$split, 360 - $split]; |
||
581 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
582 | $adjexplode[$idx] = $explode; |
||
583 | $angles[++$idx] = [360 - $split, $ne]; |
||
584 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
585 | $adjexplode[$idx] = $explode; |
||
586 | } else { |
||
587 | // Just a simple split to the previous decided |
||
588 | // angle. |
||
589 | $angles[++$idx] = [$split, $ne]; |
||
590 | $adjcolors[$idx] = $colors[$i % $numcolors]; |
||
591 | $adjexplode[$idx] = $explode; |
||
592 | } |
||
593 | } |
||
594 | $a += $da; |
||
595 | $a = $this->NormAngle($a); |
||
596 | } |
||
597 | |||
598 | // Total number of slices |
||
599 | $n = safe_count($angles); |
||
600 | |||
601 | for ($i = 0; $i < $n; ++$i) { |
||
602 | list($dbgs, $dbge) = $angles[$i]; |
||
603 | } |
||
604 | |||
605 | // |
||
606 | // Step 2. Find start index (first pie that starts in upper left quadrant) |
||
607 | // |
||
608 | $minval = $angles[0][0]; |
||
609 | $min = 0; |
||
610 | for ($i = 0; $i < $n; ++$i) { |
||
611 | if ($angles[$i][0] < $minval) { |
||
612 | $minval = $angles[$i][0]; |
||
613 | $min = $i; |
||
614 | } |
||
615 | } |
||
616 | $j = $min; |
||
617 | $cnt = 0; |
||
618 | while ($angles[$j][1] <= 90) { |
||
619 | ++$j; |
||
620 | if ($j >= $n) { |
||
621 | $j = 0; |
||
622 | } |
||
623 | if ($cnt > $n) { |
||
624 | Util\JpGraphError::RaiseL(14005); |
||
625 | //("Pie3D Internal error (#1). Trying to wrap twice when looking for start index"); |
||
626 | } |
||
627 | ++$cnt; |
||
628 | } |
||
629 | $start = $j; |
||
630 | |||
631 | // |
||
632 | // Step 3. Print slices in z-order |
||
633 | // |
||
634 | $cnt = 0; |
||
635 | |||
636 | // First stroke all the slices between 90 and 270 (left half circle) |
||
637 | // counterclockwise |
||
638 | |||
639 | while ($angles[$j][0] < 270 && $aaoption !== 2) { |
||
640 | list($x, $y) = $adjexplode[$j]; |
||
641 | |||
642 | $this->Pie3DSlice( |
||
643 | $img, |
||
644 | $x, |
||
645 | $y, |
||
646 | $d, |
||
647 | $h, |
||
648 | $angles[$j][0], |
||
649 | $angles[$j][1], |
||
650 | $z, |
||
651 | $adjcolors[$j], |
||
652 | $shadow |
||
653 | ); |
||
654 | |||
655 | $last = [$x, $y, $j]; |
||
656 | |||
657 | ++$j; |
||
658 | if ($j >= $n) { |
||
659 | $j = 0; |
||
660 | } |
||
661 | |||
662 | if ($cnt > $n) { |
||
663 | Util\JpGraphError::RaiseL(14006); |
||
664 | //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); |
||
665 | } |
||
666 | ++$cnt; |
||
667 | } |
||
668 | |||
669 | $slice_left = $n - $cnt; |
||
670 | $j = $start - 1; |
||
671 | if ($j < 0) { |
||
672 | $j = $n - 1; |
||
673 | } |
||
674 | |||
675 | $cnt = 0; |
||
676 | |||
677 | // The stroke all slices from 90 to -90 (right half circle) |
||
678 | // clockwise |
||
679 | while ($cnt < $slice_left && $aaoption !== 2) { |
||
680 | list($x, $y) = $adjexplode[$j]; |
||
681 | |||
682 | $this->Pie3DSlice( |
||
683 | $img, |
||
684 | $x, |
||
685 | $y, |
||
686 | $d, |
||
687 | $h, |
||
688 | $angles[$j][0], |
||
689 | $angles[$j][1], |
||
690 | $z, |
||
691 | $adjcolors[$j], |
||
692 | $shadow |
||
693 | ); |
||
694 | --$j; |
||
695 | if ($cnt > $n) { |
||
696 | Util\JpGraphError::RaiseL(14006); |
||
697 | //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); |
||
698 | } |
||
699 | if ($j < 0) { |
||
700 | $j = $n - 1; |
||
701 | } |
||
702 | |||
703 | ++$cnt; |
||
704 | } |
||
705 | |||
706 | // Now do a special thing. Stroke the last slice on the left |
||
707 | // halfcircle one more time. This is needed in the case where |
||
708 | // the slice close to 270 have been exploded. In that case the |
||
709 | // part of the slice close to the center of the pie might be |
||
710 | // slightly nagged. |
||
711 | if ($aaoption !== 2) { |
||
712 | $this->Pie3DSlice( |
||
713 | $img, |
||
714 | $last[0], |
||
715 | $last[1], |
||
716 | $d, |
||
717 | $h, |
||
718 | $angles[$last[2]][0], |
||
719 | $angles[$last[2]][1], |
||
720 | $z, |
||
721 | $adjcolors[$last[2]], |
||
722 | $shadow |
||
723 | ); |
||
724 | } |
||
725 | |||
726 | if ($aaoption !== 1) { |
||
727 | // Now print possible labels and add csim |
||
728 | $this->value->ApplyFont($img); |
||
729 | $margin = $img->GetFontHeight() / 2 + $this->value->margin; |
||
730 | for ($i = 0; $i < safe_count($data); ++$i) { |
||
731 | $la = $labeldata[$i][0]; |
||
732 | $x = $labeldata[$i][1] + cos($la * M_PI / 180) * ($d + $margin) * $this->ilabelposadj; |
||
733 | $y = $labeldata[$i][2] - sin($la * M_PI / 180) * ($h + $margin) * $this->ilabelposadj; |
||
734 | if ($this->ilabelposadj >= 1.0) { |
||
735 | if ($la > 180 && $la < 360) { |
||
736 | $y += $z; |
||
737 | } |
||
738 | } |
||
739 | if ($this->labeltype == 0) { |
||
740 | if ($sum > 0) { |
||
741 | $l = 100 * $data[$i] / $sum; |
||
742 | } else { |
||
743 | $l = 0; |
||
744 | } |
||
745 | } elseif ($this->labeltype == 1) { |
||
746 | $l = $data[$i]; |
||
747 | } else { |
||
748 | $l = $this->adjusted_data[$i]; |
||
749 | } |
||
750 | if (isset($this->labels[$i]) && is_string($this->labels[$i])) { |
||
751 | $l = sprintf($this->labels[$i], $l); |
||
752 | } |
||
753 | |||
754 | $this->StrokeLabels($l, $img, $labeldata[$i][0] * M_PI / 180, $x, $y, $z); |
||
755 | |||
756 | $this->Add3DSliceToCSIM( |
||
757 | $i, |
||
758 | $labeldata[$i][1], |
||
759 | $labeldata[$i][2], |
||
760 | $h * 2, |
||
761 | $d * 2, |
||
762 | $z, |
||
763 | $originalangles[$i][0], |
||
764 | $originalangles[$i][1] |
||
765 | ); |
||
766 | } |
||
767 | } |
||
768 | |||
769 | // |
||
770 | // Finally add potential lines in pie |
||
771 | // |
||
772 | |||
773 | if ($edgecolor == '' || $aaoption !== 0) { |
||
774 | return; |
||
775 | } |
||
776 | |||
777 | $accsum = 0; |
||
778 | $a = $startangle; |
||
779 | $a = $this->NormAngle($a); |
||
780 | |||
781 | $a *= M_PI / 180.0; |
||
782 | |||
783 | $idx = 0; |
||
784 | $img->PushColor($edgecolor); |
||
785 | $img->SetLineWeight($edgeweight); |
||
786 | |||
787 | $fulledge = true; |
||
788 | for ($i = 0; $i < safe_count($data) && $fulledge; ++$i) { |
||
789 | if (empty($this->explode_radius[$i])) { |
||
790 | $this->explode_radius[$i] = 0; |
||
791 | } |
||
792 | if ($this->explode_radius[$i] > 0) { |
||
793 | $fulledge = false; |
||
794 | } |
||
795 | } |
||
796 | |||
797 | for ($i = 0; $i < safe_count($data); ++$i, ++$idx) { |
||
798 | $da = $data[$i] / $sum * 2 * M_PI; |
||
799 | $this->StrokeFullSliceFrame( |
||
800 | $img, |
||
801 | $xc, |
||
802 | $yc, |
||
803 | $a, |
||
804 | $a + $da, |
||
805 | $d, |
||
806 | $h, |
||
807 | $z, |
||
808 | $edgecolor, |
||
809 | $this->explode_radius[$i], |
||
810 | $fulledge |
||
811 | ); |
||
812 | $a += $da; |
||
813 | } |
||
814 | $img->PopColor(); |
||
815 | } |
||
816 | |||
817 | public function StrokeFullSliceFrame($img, $xc, $yc, $sa, $ea, $w, $h, $z, $edgecolor, $exploderadius, $fulledge) |
||
872 | } |
||
873 | } |
||
874 | } |
||
875 | |||
876 | public function Stroke($img, $aaoption = 0) |
||
982 | } |
||
983 | } |
||
984 | |||
985 | /** |
||
986 | * PRIVATE METHODS. |
||
987 | * |
||
988 | * @param mixed $label |
||
989 | * @param mixed $img |
||
990 | * @param mixed $a |
||
991 | * @param mixed $xp |
||
992 | * @param mixed $yp |
||
993 | * @param mixed $z |
||
994 | */ |
||
995 | |||
996 | // Position the labels of each slice |
||
997 | public function StrokeLabels($label, $img, $a, $xp, $yp, $z) |
||
1079 |