Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.shape;
027
028import javafx.beans.property.DoubleProperty;
029import javafx.beans.property.DoublePropertyBase;
030import javafx.scene.paint.Paint;
031
032import com.sun.javafx.geom.BaseBounds;
033import com.sun.javafx.geom.Ellipse2D;
034import com.sun.javafx.geom.transform.BaseTransform;
035import com.sun.javafx.scene.DirtyBits;
036import com.sun.javafx.sg.PGCircle;
037import com.sun.javafx.sg.PGNode;
038import com.sun.javafx.sg.PGShape.Mode;
039import com.sun.javafx.tk.Toolkit;
040
041
042
043/**
044 * The {@code Circle} class creates a new circle
045 * with the specified radius and center location measured in pixels
046 *
047 * Example usage. The following code creates a circle with radius 50px centered
048 * at (100,100)px.
049 *
050<PRE>
051import javafx.scene.shape.*;
052
053Circle circle = new Circle();
054circle.setCenterX(100.0f);
055circle.setCenterY(100.0f);
056circle.setRadius(50.0f);
057}
058</PRE>
059 */
060public class Circle extends Shape {
061
062    private final Ellipse2D shape = new Ellipse2D();
063
064    /**
065     * Creates a new instance of Circle with a specified radius.
066     * @param radius the radius of the circle in pixels
067     */
068    public Circle(double radius) {
069        setRadius(radius);
070    }
071
072    /**
073     * Creates a new instance of Circle with a specified radius and fill.
074     * @param radius the radius of the circle
075     * @param fill determines how to fill the interior of the Circle
076     */
077    public Circle(double radius, Paint fill) {
078        setRadius(radius);
079        setFill(fill);
080    }
081
082    /**
083     * Creates an empty instance of Circle.
084     */
085    public Circle() {
086    }
087
088    /**
089     * Creates a new instance of Circle with a specified position and radius.
090     * @param centerX the horizontal position of the center of the circle in pixels
091     * @param centerY the vertical position of the center of the circle in pixels
092     * @param radius the radius of the circle in pixels
093     */
094    public Circle(double centerX, double centerY, double radius) {
095        setCenterX(centerX);
096        setCenterY(centerY);
097        setRadius(radius);
098    }
099
100    /**
101     * Creates a new instance of Circle with a specified position, radius and fill.
102     * @param centerX the horizontal position of the center of the circle in pixels
103     * @param centerY the vertical position of the center of the circle in pixels
104     * @param radius the radius of the circle in pixels
105     * @param fill determines how to fill the interior of the Circle
106     */
107    public Circle(double centerX, double centerY, double radius, Paint fill) {
108        setCenterX(centerX);
109        setCenterY(centerY);
110        setRadius(radius);
111        setFill(fill);
112    }
113
114    /**
115     * Defines the horizontal position of the center of the circle in pixels.
116     *
117     * @defaultValue 0.0
118     */
119    private DoubleProperty centerX;
120
121
122
123    public final void setCenterX(double value) {
124        if (centerX != null || value != 0.0) {
125            centerXProperty().set(value);
126        }
127    }
128
129    public final double getCenterX() {
130        return centerX == null ? 0.0 : centerX.get();
131    }
132
133    public final DoubleProperty centerXProperty() {
134        if (centerX == null) {
135            centerX = new DoublePropertyBase(0.0) {
136
137                @Override
138                public void invalidated() {
139                    impl_markDirty(DirtyBits.NODE_GEOMETRY);
140                    impl_geomChanged();
141                }
142
143                @Override
144                public Object getBean() {
145                    return Circle.this;
146                }
147
148                @Override
149                public String getName() {
150                    return "centerX";
151                }
152            };
153        }
154        return centerX;
155    }
156
157    /**
158     * Defines the vertical position of the center of the circle in pixels.
159     *
160     * @defaultValue 0.0
161     */
162    private DoubleProperty centerY;
163
164
165
166    public final void setCenterY(double value) {
167        if (centerY != null || value != 0.0) {
168            centerYProperty().set(value);
169        }
170    }
171
172    public final double getCenterY() {
173        return centerY == null ? 0.0 : centerY.get();
174    }
175
176    public final DoubleProperty centerYProperty() {
177        if (centerY == null) {
178            centerY = new DoublePropertyBase(0.0) {
179
180                @Override
181                public void invalidated() {
182                    impl_markDirty(DirtyBits.NODE_GEOMETRY);
183                    impl_geomChanged();
184                }
185
186                @Override
187                public Object getBean() {
188                    return Circle.this;
189                }
190
191                @Override
192                public String getName() {
193                    return "centerY";
194                }
195            };
196        }
197        return centerY;
198    }
199
200    /**
201     * Defines the radius of the circle in pixels.
202     *
203     * @defaultValue 0.0
204     */
205    private DoubleProperty radius = new DoublePropertyBase() {
206
207        @Override
208        public void invalidated() {
209            impl_markDirty(DirtyBits.NODE_GEOMETRY);
210            impl_geomChanged();
211        }
212
213        @Override
214        public Object getBean() {
215            return Circle.this;
216        }
217
218        @Override
219        public String getName() {
220            return "radius";
221        }
222    };
223
224    public final void setRadius(double value) {
225        radius.set(value);
226    }
227
228    public final double getRadius() {
229        return radius.get();
230    }
231
232    public final DoubleProperty radiusProperty() {
233        return radius;
234    }
235
236    /**
237     * @treatAsPrivate implementation detail
238     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
239     */
240    @Deprecated
241    @Override protected PGNode impl_createPGNode() {
242        return Toolkit.getToolkit().createPGCircle();
243    }
244
245    PGCircle getPGCircle() {
246        return (PGCircle)impl_getPGNode();
247    }
248
249    /**
250     * @treatAsPrivate implementation detail
251     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
252     */
253    @Deprecated
254    @Override protected com.sun.javafx.sg.PGShape.StrokeLineJoin toPGLineJoin(StrokeLineJoin t) {
255        // The MITER join style can produce anomalous results for very thin or
256        // very wide ellipses when the bezier curves that approximate the arcs
257        // become so distorted that they shoot out MITER-like extensions.  This
258        // effect complicates matters because it makes the circles very non-round,
259        // and also because it means we might have to pad the bounds to account
260        // for this rare and unpredictable circumstance.
261        // To avoid the problem, we set the Join style to BEVEL for any
262        // circle.  The BEVEL join style is more predictable for
263        // anomalous angles and is the simplest join style to compute in
264        // the stroking code.
265        // These problems do not necessarily happen for circles which have a
266        // fixed and balanced aspect ratio, but why waste time computing a
267        // conversion of a MITER join style when it has no advantage for
268        // circles and technically requires more computation?
269        return com.sun.javafx.sg.PGShape.StrokeLineJoin.BEVEL;
270    }
271
272    /**
273     * @treatAsPrivate implementation detail
274     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
275     */
276    @Deprecated
277    @Override public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
278        // if there is no fill or stroke, then there are no bounds. The bounds
279        // must be marked empty in this case to distinguish it from 0,0,0,0
280        // which would actually contribute to the bounds of a group.
281        if (impl_mode == Mode.EMPTY) {
282            return bounds.makeEmpty();
283        }
284
285        final double cX = getCenterX();
286        final double cY = getCenterY();
287
288        if ((tx.getType() & ~(BaseTransform.TYPE_MASK_ROTATION | BaseTransform.TYPE_TRANSLATION)) == 0) {
289
290            double tCX = cX * tx.getMxx() + cY * tx.getMxy() + tx.getMxt();
291            double tCY = cX * tx.getMyx() + cY * tx.getMyy() + tx.getMyt();
292            double r = getRadius();
293
294            if (impl_mode != Mode.FILL && getStrokeType() != StrokeType.INSIDE) {
295                double upad = getStrokeWidth();
296                if (getStrokeType() == StrokeType.CENTERED) {
297                    upad /= 2.0f;
298                }
299                r += upad;
300            }
301
302            return bounds.deriveWithNewBounds((float) (tCX - r), (float) (tCY - r), 0,
303                    (float) (tCX + r), (float) (tCY + r), 0);
304        } else if ((tx.getType() & ~(BaseTransform.TYPE_MASK_SCALE | BaseTransform.TYPE_TRANSLATION | BaseTransform.TYPE_FLIP)) == 0) {
305            final double r = getRadius();
306            final double x = getCenterX() - r;
307            final double y = getCenterY() - r;
308            final double width = 2.0 * r;
309            final double height = width;
310            double upad;
311            if (impl_mode == Mode.FILL || getStrokeType() == StrokeType.INSIDE) {
312                upad = 0.0f;
313            } else {
314                upad = getStrokeWidth();
315            }
316            return computeBounds(bounds, tx, upad, 0, x, y, width, height);
317        }
318
319        return computeShapeBounds(bounds, tx, impl_configShape());
320    }
321
322    /**
323     * @treatAsPrivate implementation detail
324     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
325     */
326    @Deprecated
327    @Override public Ellipse2D impl_configShape() {
328        double r = getRadius();
329        shape.setFrame(
330            (float)(getCenterX() - r), // x
331            (float)(getCenterY() - r), // y
332            (float)(r * 2.0), // w
333            (float)(r * 2.0)); // h
334        return shape;
335    }
336
337    /**
338     * @treatAsPrivate implementation detail
339     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
340     */
341    @Deprecated
342    @Override public void impl_updatePG() {
343        super.impl_updatePG();
344
345        if (impl_isDirty(DirtyBits.NODE_GEOMETRY)) {
346            PGCircle peer = getPGCircle();
347            peer.updateCircle((float)getCenterX(),
348                (float)getCenterY(),
349                (float)getRadius());
350        }
351    }
352
353    /**
354     * Returns a string representation of this {@code Circle} object.
355     * @return a string representation of this {@code Circle} object.
356     */
357    @Override
358    public String toString() {
359        final StringBuilder sb = new StringBuilder("Circle[");
360
361        String id = getId();
362        if (id != null) {
363            sb.append("id=").append(id).append(", ");
364        }
365
366        sb.append("centerX=").append(getCenterX());
367        sb.append(", centerY=").append(getCenterY());
368        sb.append(", radius=").append(getRadius());
369
370        sb.append(", fill=").append(getFill());
371
372        Paint stroke = getStroke();
373        if (stroke != null) {
374            sb.append(", stroke=").append(stroke);
375            sb.append(", strokeWidth=").append(getStrokeWidth());
376        }
377
378        return sb.append("]").toString();
379    }
380}
381