001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Denis M. Kishenko
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.render;
021:
022: import org.apache.harmony.awt.gl.MultiRectArea;
023:
024: public class JavaArcRasterizer {
025:
026: /**
027: * Adds particular arc segment to mra
028: */
029: static void addX0LineSeg(MultiRectArea mra, int[] line, int cx,
030: int cy, int b, int start, int finish) {
031: int x1 = 0;
032: for (int i = 0; i < line.length; i++) {
033: int x2 = line[i];
034: int y = cy + (b - i);
035: if (x1 <= finish && x2 >= start) {
036: mra.addRect(cx + Math.max(x1, start), y, cx
037: + Math.min(x2, finish), y);
038: }
039: x1 = x2 + 1;
040: }
041: }
042:
043: static void addX1LineSeg(MultiRectArea mra, int[] line, int cx,
044: int cy, int b, int start, int finish) {
045: int x1 = 0;
046: for (int i = 0; i < line.length; i++) {
047: int x2 = line[i];
048: int y = cy - (b - i);
049: if (x1 <= finish && x2 >= start) {
050: mra.addRect(cx + Math.max(x1, start), y, cx
051: + Math.min(x2, finish), y);
052: }
053: x1 = x2 + 1;
054: }
055: }
056:
057: static void addX2LineSeg(MultiRectArea mra, int[] line, int cx,
058: int cy, int b, int start, int finish) {
059: int x1 = 0;
060: for (int i = 0; i < line.length; i++) {
061: int x2 = line[i];
062: int y = cy - (b - i);
063: if (x1 <= finish && x2 >= start) {
064: mra.addRect(cx - Math.min(x2, finish), y, cx
065: - Math.max(x1, start), y);
066: }
067: x1 = x2 + 1;
068: }
069: }
070:
071: static void addX3LineSeg(MultiRectArea mra, int[] line, int cx,
072: int cy, int b, int start, int finish) {
073: int x1 = 0;
074: for (int i = 0; i < line.length; i++) {
075: int x2 = line[i];
076: int y = cy + (b - i);
077: if (x1 <= finish && x2 >= start) {
078: mra.addRect(cx - Math.min(x2, finish), y, cx
079: - Math.max(x1, start), y);
080: }
081: x1 = x2 + 1;
082: }
083: }
084:
085: static void addY0LineSeg(MultiRectArea mra, int[] line, int cx,
086: int cy, int b, int start, int finish) {
087: int y1 = 0;
088: for (int i = 0; i < line.length; i++) {
089: int x = cx + (b - i);
090: int y2 = line[i];
091: if (y1 <= finish && y2 >= start) {
092: mra.addRect(x, cy + Math.max(y1, start), x, cy
093: + Math.min(y2, finish));
094: }
095: y1 = y2 + 1;
096: }
097: }
098:
099: static void addY1LineSeg(MultiRectArea mra, int[] line, int cx,
100: int cy, int b, int start, int finish) {
101: int y1 = 0;
102: for (int i = 0; i < line.length; i++) {
103: int x = cx - (b - i);
104: int y2 = line[i];
105: if (y1 <= finish && y2 >= start) {
106: mra.addRect(x, cy + Math.max(y1, start), x, cy
107: + Math.min(y2, finish));
108: }
109: y1 = y2 + 1;
110: }
111: }
112:
113: static void addY2LineSeg(MultiRectArea mra, int[] line, int cx,
114: int cy, int b, int start, int finish) {
115: int y1 = 0;
116: for (int i = 0; i < line.length; i++) {
117: int x = cx - (b - i);
118: int y2 = line[i];
119: if (y1 <= finish && y2 >= start) {
120: mra.addRect(x, cy - Math.min(y2, finish), x, cy
121: - Math.max(y1, start));
122: }
123: y1 = y2 + 1;
124: }
125: }
126:
127: static void addY3LineSeg(MultiRectArea mra, int[] line, int cx,
128: int cy, int b, int start, int finish) {
129: int y1 = 0;
130: for (int i = 0; i < line.length; i++) {
131: int x = cx + (b - i);
132: int y2 = line[i];
133: if (y1 <= finish && y2 >= start) {
134: mra.addRect(x, cy - Math.min(y2, finish), x, cy
135: - Math.max(y1, start));
136: }
137: y1 = y2 + 1;
138: }
139: }
140:
141: static void addX0Line(MultiRectArea mra, int[] line, int cx,
142: int cy, int b) {
143: int prev = 0;
144: for (int i = 0; i < line.length; i++) {
145: mra.addRect(cx + prev, cy + (b - i), cx + line[i], cy
146: + (b - i));
147: prev = line[i] + 1;
148: }
149: }
150:
151: static void addX1Line(MultiRectArea mra, int[] line, int cx,
152: int cy, int b) {
153: int prev = 0;
154: for (int i = 0; i < line.length; i++) {
155: mra.addRect(cx + prev, cy - (b - i), cx + line[i], cy
156: - (b - i));
157: prev = line[i] + 1;
158: }
159: }
160:
161: static void addX2Line(MultiRectArea mra, int[] line, int cx,
162: int cy, int b) {
163: int prev = 0;
164: for (int i = 0; i < line.length; i++) {
165: mra.addRect(cx - line[i], cy - (b - i), cx - prev, cy
166: - (b - i));
167: prev = line[i] + 1;
168: }
169: }
170:
171: static void addX3Line(MultiRectArea mra, int[] line, int cx,
172: int cy, int b) {
173: int prev = 0;
174: for (int i = 0; i < line.length; i++) {
175: mra.addRect(cx - line[i], cy + (b - i), cx - prev, cy
176: + (b - i));
177: prev = line[i] + 1;
178: }
179: }
180:
181: static void addY0Line(MultiRectArea mra, int[] line, int cx,
182: int cy, int a) {
183: int prev = 0;
184: for (int i = 0; i < line.length; i++) {
185: mra.addRect(cx + (a - i), cy + prev, cx + (a - i), cy
186: + line[i]);
187: prev = line[i] + 1;
188: }
189: }
190:
191: static void addY1Line(MultiRectArea mra, int[] line, int cx,
192: int cy, int a) {
193: int prev = 0;
194: for (int i = 0; i < line.length; i++) {
195: mra.addRect(cx - (a - i), cy + prev, cx - (a - i), cy
196: + line[i]);
197: prev = line[i] + 1;
198: }
199: }
200:
201: static void addY2Line(MultiRectArea mra, int[] line, int cx,
202: int cy, int a) {
203: int prev = 0;
204: for (int i = 0; i < line.length; i++) {
205: mra.addRect(cx - (a - i), cy - line[i], cx - (a - i), cy
206: - prev);
207: prev = line[i] + 1;
208: }
209: }
210:
211: static void addY3Line(MultiRectArea mra, int[] line, int cx,
212: int cy, int a) {
213: int prev = 0;
214: for (int i = 0; i < line.length; i++) {
215: mra.addRect(cx + (a - i), cy - line[i], cx + (a - i), cy
216: - prev);
217: prev = line[i] + 1;
218: }
219: }
220:
221: /**
222: * Returns normalized angle (from 0 to 360 degrees)
223: */
224: static double getNormAngle(double angle) {
225: angle -= Math.floor(angle / 360) * 360;
226: if (angle < 0) {
227: angle += 360;
228: }
229: return angle;
230: }
231:
232: /**
233: * Creates arc lookup table
234: */
235: static int[] createLine(int a, int b, int xcount, int ycount) {
236: int[] buf = new int[b - ycount + 1];
237: int d = a * a + 2 * b * b - 2 * a * a * b;
238: int x = 0;
239: int y = b;
240: while (y >= ycount) {
241: if (d < 0) {
242: d = d + b * b * (4 * x + 6);
243: } else {
244: buf[b - y] = x;
245: d = d + b * b * (4 * x + 6) + 4 * a * a * (1 - y);
246: y--;
247: }
248: x++;
249: }
250: return buf;
251: }
252:
253: /**
254: * Adds head/tail arc segment to MultiRectArea
255: */
256: static void addSeg(MultiRectArea mra, int cx1, int cy1, int cx2,
257: int cy2, int a, int b, int[] xline, int[] yline,
258: int[] bounds) {
259: switch (bounds[0]) {
260: case 0:
261: addY3LineSeg(mra, yline, cx2, cy1, a, bounds[1], bounds[2]);
262: break;
263: case 1:
264: addX1LineSeg(mra, xline, cx2, cy1, b, bounds[1], bounds[2]);
265: break;
266: case 2:
267: addX2LineSeg(mra, xline, cx1, cy1, b, bounds[1], bounds[2]);
268: break;
269: case 3:
270: addY2LineSeg(mra, yline, cx1, cy1, a, bounds[1], bounds[2]);
271: break;
272: case 4:
273: addY1LineSeg(mra, yline, cx1, cy2, a, bounds[1], bounds[2]);
274: break;
275: case 5:
276: addX3LineSeg(mra, xline, cx1, cy2, b, bounds[1], bounds[2]);
277: break;
278: case 6:
279: addX0LineSeg(mra, xline, cx2, cy2, b, bounds[1], bounds[2]);
280: break;
281: case 7:
282: addY0LineSeg(mra, yline, cx2, cy2, a, bounds[1], bounds[2]);
283: break;
284: }
285: }
286:
287: /**
288: * Returns bounds for non quadratic arc head
289: */
290: static int[] getSegment1(double angle, int ax, int ay, int xcount,
291: int ycount) {
292: int[] bounds = new int[3];
293: switch ((int) (angle / 90)) {
294: case 0:
295: if (xcount < ax) {
296: bounds[0] = 0; // Y3
297: bounds[1] = -ay;
298: bounds[2] = ycount;
299: } else {
300: bounds[0] = 1; // X1
301: bounds[1] = 0;
302: bounds[2] = ax;
303: }
304: break;
305: case 1:
306: if (xcount > -ax) {
307: bounds[0] = 2; // X2
308: bounds[1] = -ax;
309: bounds[2] = xcount;
310: } else {
311: bounds[0] = 3; // Y2
312: bounds[1] = 0;
313: bounds[2] = -ay;
314: }
315: break;
316: case 2:
317: if (xcount < -ax) {
318: bounds[0] = 4; // Y1
319: bounds[1] = ay;
320: bounds[2] = ycount;
321: } else {
322: bounds[0] = 5; // X3
323: bounds[1] = 0;
324: bounds[2] = -ax;
325: }
326: break;
327: case 3:
328: if (xcount > ax) {
329: bounds[0] = 6; // X0
330: bounds[1] = ax;
331: bounds[2] = xcount;
332: } else {
333: bounds[0] = 7; // Y0
334: bounds[1] = 0;
335: bounds[2] = ay;
336: }
337: break;
338: }
339: return bounds;
340: }
341:
342: /**
343: * Returns bounds for non quadratic arc tail
344: */
345: static int[] getSegment2(double angle, int ax, int ay, int xcount,
346: int ycount) {
347: int[] bounds = new int[3];
348: switch ((int) (angle / 90)) {
349: case 0:
350: if (xcount < ax) {
351: bounds[0] = 0; // Y3
352: bounds[1] = 0;
353: bounds[2] = -ay;
354: } else {
355: bounds[0] = 1; // X1
356: bounds[1] = ax;
357: bounds[2] = xcount;
358: }
359: break;
360: case 1:
361: if (xcount > -ax) {
362: bounds[0] = 2; // X2
363: bounds[1] = 0;
364: bounds[2] = -ax;
365: } else {
366: bounds[0] = 3; // Y2
367: bounds[1] = -ay;
368: bounds[2] = ycount;
369: }
370: break;
371: case 2:
372: if (xcount < -ax) {
373: bounds[0] = 4; // Y1
374: bounds[1] = 0;
375: bounds[2] = ay;
376: } else {
377: bounds[0] = 5; // X3
378: bounds[1] = -ax;
379: bounds[2] = xcount;
380: }
381: break;
382: case 3:
383: if (xcount > ax) {
384: bounds[0] = 6; // X0
385: bounds[1] = 0;
386: bounds[2] = ax;
387: } else {
388: bounds[0] = 7; // Y0
389: bounds[1] = ay;
390: bounds[2] = ycount;
391: }
392: break;
393: }
394: return bounds;
395: }
396:
397: /**
398: * Rasterizes arc using clippind and dashing style
399: * @param x1 - the x coordinate of the left-upper corner of the arc bounds
400: * @param y1 - the y coordinate of the left-upper corner of the arc bounds
401: * @param width - the width of the arc bounds
402: * @param height - the height of the arc bounds
403: * @param angleStart - the start angle of the arc in degrees
404: * @param angleExtent - the angle extent in degrees
405: * @param clip - the MultiRectArea object of clipping area
406: * @return a MultiRectArea of rasterizer arc
407: */
408: public static MultiRectArea rasterize(int x, int y, int width,
409: int height, double angleStart, double angleExtent,
410: MultiRectArea clip) {
411:
412: MultiRectArea mra = new MultiRectArea(false);
413:
414: int cx1, cx2, cy1, cy2;
415: cx1 = cx2 = x + width / 2;
416: cy1 = cy2 = y + height / 2;
417:
418: if (width % 2 == 0) {
419: cx2--;
420: }
421:
422: if (height % 2 == 0) {
423: cy2--;
424: }
425:
426: int a = width / 2;
427: int b = height / 2;
428: double c = Math.sqrt(a * a + b * b);
429:
430: int xcount, ycount;
431: if (a < b) {
432: xcount = (int) Math.ceil(a * a / c);
433: ycount = (int) Math.floor(b * b / c);
434: } else {
435: xcount = (int) Math.floor(a * a / c);
436: ycount = (int) Math.ceil(b * b / c);
437: }
438:
439: int[] xline = createLine(a, b, xcount, ycount);
440: int[] yline = createLine(b, a, ycount, xcount);
441:
442: // Correct lines
443: int i = xline.length;
444: while (xline[--i] > xcount) {
445: xline[i] = xcount;
446: }
447:
448: i = yline.length;
449: while (yline[--i] > ycount) {
450: yline[i] = ycount;
451: }
452:
453: if (Math.abs(angleExtent) >= 360) {
454: // Rasterize CIRCLE
455: addX0Line(mra, xline, cx2, cy2, b);
456: addX1Line(mra, xline, cx2, cy1, b);
457: addX2Line(mra, xline, cx1, cy1, b);
458: addX3Line(mra, xline, cx1, cy2, b);
459: addY0Line(mra, yline, cx2, cy2, a);
460: addY1Line(mra, yline, cx1, cy2, a);
461: addY2Line(mra, yline, cx1, cy1, a);
462: addY3Line(mra, yline, cx2, cy1, a);
463: } else {
464: // Rasterize ARC
465: angleStart = getNormAngle(angleStart);
466: double angleFinish = getNormAngle(angleStart + angleExtent);
467:
468: if (angleExtent < 0) {
469: double tmp = angleStart;
470: angleStart = angleFinish;
471: angleFinish = tmp;
472: }
473:
474: double radStart = -Math.toRadians(angleStart);
475: double radFinish = -Math.toRadians(angleFinish);
476: int ax1 = (int) (a * Math.cos(radStart));
477: int ay1 = (int) (b * Math.sin(radStart));
478: int ax2 = (int) (a * Math.cos(radFinish));
479: int ay2 = (int) (b * Math.sin(radFinish));
480:
481: int[] seg1 = getSegment1(angleStart, ax1, ay1, xcount,
482: ycount);
483: int[] seg2 = getSegment2(angleFinish, ax2, ay2, xcount,
484: ycount);
485:
486: // Start and Finish located in the same quater
487: if (angleStart < angleFinish && seg1[0] == seg2[0]) {
488: if (seg1[0] % 2 == 0) {
489: seg1[2] = seg2[2];
490: } else {
491: seg1[1] = seg2[1];
492: }
493: addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline,
494: seg1);
495: return mra;
496: }
497:
498: addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
499: addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg2);
500:
501: int startSeg = (seg1[0] + 1) % 8;
502: int finishSeg = seg2[0];
503:
504: while (startSeg != finishSeg) {
505: switch (startSeg) {
506: case 0:
507: addY3Line(mra, yline, cx2, cy1, a);
508: break;
509: case 1:
510: addX1Line(mra, xline, cx2, cy1, b);
511: break;
512: case 2:
513: addX2Line(mra, xline, cx1, cy1, b);
514: break;
515: case 3:
516: addY2Line(mra, yline, cx1, cy1, a);
517: break;
518: case 4:
519: addY1Line(mra, yline, cx1, cy2, a);
520: break;
521: case 5:
522: addX3Line(mra, xline, cx1, cy2, b);
523: break;
524: case 6:
525: addX0Line(mra, xline, cx2, cy2, b);
526: break;
527: case 7:
528: addY0Line(mra, yline, cx2, cy2, a);
529: break;
530: }
531: startSeg = (startSeg + 1) % 8;
532: }
533: }
534:
535: if (clip != null) {
536: mra.intersect(clip);
537: }
538:
539: return mra;
540: }
541:
542: }
|