简体   繁体   English

Java中的fillArc()未按预期混合颜色

[英]fillArc() in Java not blending color as expected

I'm trying to blend all the colors into a circle using arcs. 我正在尝试使用圆弧将所有颜色混合成一个圆形。 However, the arc comes as one solid color and not a blend of color as I thought. 但是,圆弧是一种纯色,而不是我所想到的混合色。 Is it possible to? 是否有可能?

 public static void main(String[] args) {
    DrawingPanel panel = new DrawingPanel(512,512);
    Graphics g = panel.getGraphics(); 

    int width = 100; 
    int height = 100; 

        g.drawOval(0,0,width, height);
        //yellow
        for( int i = 0; i < 100 ; i++){ 
            Color c = new Color(255/100*i,255,0);
            g.setColor(c);
            g.fillArc(0,0,width,height,95,11);
        }
g.fillArc(0,0,width,height,95,11);

You need to change the arc angle for every iteration and the arc size should be fixed at a certain value. 您需要为每次迭代更改圆弧角度,并且圆弧大小应固定为某个值。 I'm not sure what the value would be because I would expect you should iterate 360 times (in which case the size would be 1), not 100. 我不确定值是多少,因为我希望您应该迭代360次(在这种情况下,大小为1),而不是100。

You can use the HSL Color class to do this simply. 您可以使用HSL Color类简单地执行此操作。

在此处输入图片说明

An HSL color allows you to change the "hue" of the color in degrees. HSL颜色允许您以度为单位更改颜色的“色相”。 So you just need a simple loop to set/paint the color in a 1 degree arc: 因此,您只需要一个简单的循环即可以1度弧线设置/绘制颜色:

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;

public class ColorWheel extends JPanel
{
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        HSLColor color = new HSLColor( Color.YELLOW );

        for (int i = 0; i < 360; i++)
        {
            g.setColor( color.adjustHue(i) );
            g.fillArc( 25, 25, 200, 200, i, 1);
        }
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(250, 250);
    }

    private static void createAndShowGUI()
    {
        JComponent wheel = new ColorWheel();

        JFrame frame = new JFrame("Color Wheel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane( wheel );
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

I used the HSL Color because it has a simple API to change the hue. 我使用HSL Color是因为它具有更改色相的简单API。

If you don't want to use that class then you can use Color.getHSBColor(...) method to get the color for each degree of change. 如果您不想使用该类,则可以使用Color.getHSBColor(...)方法获取每个更改程度的颜色。 Again the saturation and brightness would be fixed values and then you just change the hue. 同样,饱和度和亮度将是固定值,然后您只需更改色相即可。

@Override
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);

    float hueDegree = 1 / 360.0f;

    for (int i = 0; i < 360; i++)
    {
        Color color = Color.getHSBColor(i * hueDegree, 1.0f, 1.0f);
        g.setColor( color );
        g.fillArc( 25, 25, 200, 200, i, 1);
    }
}

Along time ago, I stumbled across a ConicalGradientPaint from Harmonic Code (there source is there somewhere, I just can't seem to find it again, but I've included my copy of it in the example). 很久以前,我偶然发现了Harmonic CodeConicalGradientPaint (那里有来源,我似乎再也找不到了,但在示例中包含了它的副本)。

在此处输入图片说明

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ColorWheel {

    public static void main(String[] args) {
        new ColorWheel();
    }

    public ColorWheel() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            ConicalGradientPaint rgp = new ConicalGradientPaint(
                            true,
                            new Point(getWidth() / 2, getHeight() / 2),
                            0.5f,
                            new float[]{0, 60, 120, 180, 240, 300, 360},
                            new Color[]{Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.RED});
            g2d.setPaint(rgp);

            int radius = Math.min(getWidth(), getHeight());

            int x = (getWidth() - radius) / 2;
            int y = (getHeight() - radius) / 2;

            g2d.fillOval(x, y, radius, radius);
            g2d.dispose();
        }

    }

    public final class ConicalGradientPaint implements java.awt.Paint {

        private final java.awt.geom.Point2D CENTER;
        private final double[] FRACTION_ANGLES;
        private final double[] RED_STEP_LOOKUP;
        private final double[] GREEN_STEP_LOOKUP;
        private final double[] BLUE_STEP_LOOKUP;
        private final double[] ALPHA_STEP_LOOKUP;
        private final java.awt.Color[] COLORS;
        private static final float INT_TO_FLOAT_CONST = 1f / 255f;

        /**
         * Standard constructor which takes the FRACTIONS in values from 0.0f to
         * 1.0f
         *
         * @param CENTER
         * @param GIVEN_FRACTIONS
         * @param GIVEN_COLORS
         * @throws IllegalArgumentException
         */
        public ConicalGradientPaint(final java.awt.geom.Point2D CENTER, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException {
            this(false, CENTER, 0.0f, GIVEN_FRACTIONS, GIVEN_COLORS);
        }

        /**
         * Enhanced constructor which takes the FRACTIONS in degress from 0.0f to
         * 360.0f and also an GIVEN_OFFSET in degrees around the rotation CENTER
         *
         * @param USE_DEGREES
         * @param CENTER
         * @param GIVEN_OFFSET
         * @param GIVEN_FRACTIONS
         * @param GIVEN_COLORS
         * @throws IllegalArgumentException
         */
        public ConicalGradientPaint(final boolean USE_DEGREES, final java.awt.geom.Point2D CENTER, final float GIVEN_OFFSET, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException {
            // Check that fractions and colors are of the same size
            if (GIVEN_FRACTIONS.length != GIVEN_COLORS.length) {
                throw new IllegalArgumentException("Fractions and colors must be equal in size");
            }

            final java.util.ArrayList<Float> FRACTION_LIST = new java.util.ArrayList<Float>(GIVEN_FRACTIONS.length);
            final float OFFSET;
            if (USE_DEGREES) {
                final double DEG_FRACTION = 1f / 360f;
                if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), -0.5) == 0) {
                    OFFSET = -0.5f;
                } else if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), 0.5) == 0) {
                    OFFSET = 0.5f;
                } else {
                    OFFSET = (float) (GIVEN_OFFSET * DEG_FRACTION);
                }
                for (float fraction : GIVEN_FRACTIONS) {
                    FRACTION_LIST.add((float) (fraction * DEG_FRACTION));
                }
            } else {
                // Now it seems to work with rotation of 0.5f, below is the old code to correct the problem
//            if (GIVEN_OFFSET == -0.5)
//            {
//                // This is needed because of problems in the creation of the Raster
//                // with a angle offset of exactly -0.5
//                OFFSET = -0.49999f;
//            }
//            else if (GIVEN_OFFSET == 0.5)
//            {
//                // This is needed because of problems in the creation of the Raster
//                // with a angle offset of exactly +0.5
//                OFFSET = 0.499999f;
//            }
//            else
                {
                    OFFSET = GIVEN_OFFSET;
                }
                for (float fraction : GIVEN_FRACTIONS) {
                    FRACTION_LIST.add(fraction);
                }
            }

            // Check for valid offset
            if (OFFSET > 0.5f || OFFSET < -0.5f) {
                throw new IllegalArgumentException("Offset has to be in the range of -0.5 to 0.5");
            }

            // Adjust fractions and colors array in the case where startvalue != 0.0f and/or endvalue != 1.0f
            final java.util.List<java.awt.Color> COLOR_LIST = new java.util.ArrayList<java.awt.Color>(GIVEN_COLORS.length);
            COLOR_LIST.addAll(java.util.Arrays.asList(GIVEN_COLORS));

            // Assure that fractions start with 0.0f
            if (FRACTION_LIST.get(0) != 0.0f) {
                FRACTION_LIST.add(0, 0.0f);
                final java.awt.Color TMP_COLOR = COLOR_LIST.get(0);
                COLOR_LIST.add(0, TMP_COLOR);
            }

            // Assure that fractions end with 1.0f
            if (FRACTION_LIST.get(FRACTION_LIST.size() - 1) != 1.0f) {
                FRACTION_LIST.add(1.0f);
                COLOR_LIST.add(GIVEN_COLORS[0]);
            }

            // Recalculate the fractions and colors with the given offset
            final java.util.Map<Float, java.awt.Color> FRACTION_COLORS = recalculate(FRACTION_LIST, COLOR_LIST, OFFSET);

            // Clear the original FRACTION_LIST and COLOR_LIST
            FRACTION_LIST.clear();
            COLOR_LIST.clear();

            // Sort the hashmap by fraction and add the values to the FRACION_LIST and COLOR_LIST
            final java.util.SortedSet<Float> SORTED_FRACTIONS = new java.util.TreeSet<Float>(FRACTION_COLORS.keySet());
            final java.util.Iterator<Float> ITERATOR = SORTED_FRACTIONS.iterator();
            while (ITERATOR.hasNext()) {
                final float CURRENT_FRACTION = ITERATOR.next();
                FRACTION_LIST.add(CURRENT_FRACTION);
                COLOR_LIST.add(FRACTION_COLORS.get(CURRENT_FRACTION));
            }

            // Set the values
            this.CENTER = CENTER;
            COLORS = COLOR_LIST.toArray(new java.awt.Color[]{});

            // Prepare lookup table for the angles of each fraction
            final int MAX_FRACTIONS = FRACTION_LIST.size();
            this.FRACTION_ANGLES = new double[MAX_FRACTIONS];
            for (int i = 0; i < MAX_FRACTIONS; i++) {
                FRACTION_ANGLES[i] = FRACTION_LIST.get(i) * 360;
            }

            // Prepare lookup tables for the color stepsize of each color
            RED_STEP_LOOKUP = new double[COLORS.length];
            GREEN_STEP_LOOKUP = new double[COLORS.length];
            BLUE_STEP_LOOKUP = new double[COLORS.length];
            ALPHA_STEP_LOOKUP = new double[COLORS.length];

            for (int i = 0; i < (COLORS.length - 1); i++) {
                RED_STEP_LOOKUP[i] = ((COLORS[i + 1].getRed() - COLORS[i].getRed()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
                GREEN_STEP_LOOKUP[i] = ((COLORS[i + 1].getGreen() - COLORS[i].getGreen()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
                BLUE_STEP_LOOKUP[i] = ((COLORS[i + 1].getBlue() - COLORS[i].getBlue()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
                ALPHA_STEP_LOOKUP[i] = ((COLORS[i + 1].getAlpha() - COLORS[i].getAlpha()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
            }
        }

        /**
         * Recalculates the fractions in the FRACTION_LIST and their associated
         * colors in the COLOR_LIST with a given OFFSET. Because the conical
         * gradients always starts with 0 at the top and clockwise direction you
         * could rotate the defined conical gradient from -180 to 180 degrees which
         * equals values from -0.5 to +0.5
         *
         * @param FRACTION_LIST
         * @param COLOR_LIST
         * @param OFFSET
         * @return Hashmap that contains the recalculated fractions and colors after
         * a given rotation
         */
        private java.util.HashMap<Float, java.awt.Color> recalculate(final java.util.List<Float> FRACTION_LIST, final java.util.List<java.awt.Color> COLOR_LIST, final float OFFSET) {
            // Recalculate the fractions and colors with the given offset
            final int MAX_FRACTIONS = FRACTION_LIST.size();
            final java.util.HashMap<Float, java.awt.Color> FRACTION_COLORS = new java.util.HashMap<Float, java.awt.Color>(MAX_FRACTIONS);
            for (int i = 0; i < MAX_FRACTIONS; i++) {
                // Add offset to fraction
                final float TMP_FRACTION = FRACTION_LIST.get(i) + OFFSET;

                // Color related to current fraction
                final java.awt.Color TMP_COLOR = COLOR_LIST.get(i);

                // Check each fraction for limits (0...1)
                if (TMP_FRACTION <= 0) {
                    FRACTION_COLORS.put(1.0f + TMP_FRACTION + 0.0001f, TMP_COLOR);

                    final float NEXT_FRACTION;
                    final java.awt.Color NEXT_COLOR;
                    if (i < MAX_FRACTIONS - 1) {
                        NEXT_FRACTION = FRACTION_LIST.get(i + 1) + OFFSET;
                        NEXT_COLOR = COLOR_LIST.get(i + 1);
                    } else {
                        NEXT_FRACTION = 1 - FRACTION_LIST.get(0) + OFFSET;
                        NEXT_COLOR = COLOR_LIST.get(0);
                    }
                    if (NEXT_FRACTION > 0) {
                        final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, NEXT_COLOR, (int) ((NEXT_FRACTION - TMP_FRACTION) * 10000), (int) ((-TMP_FRACTION) * 10000));
                        FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR);
                        FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR);
                    }
                } else if (TMP_FRACTION >= 1) {
                    FRACTION_COLORS.put(TMP_FRACTION - 1.0f - 0.0001f, TMP_COLOR);

                    final float PREVIOUS_FRACTION;
                    final java.awt.Color PREVIOUS_COLOR;
                    if (i > 0) {
                        PREVIOUS_FRACTION = FRACTION_LIST.get(i - 1) + OFFSET;
                        PREVIOUS_COLOR = COLOR_LIST.get(i - 1);
                    } else {
                        PREVIOUS_FRACTION = FRACTION_LIST.get(MAX_FRACTIONS - 1) + OFFSET;
                        PREVIOUS_COLOR = COLOR_LIST.get(MAX_FRACTIONS - 1);
                    }
                    if (PREVIOUS_FRACTION < 1) {
                        final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, PREVIOUS_COLOR, (int) ((TMP_FRACTION - PREVIOUS_FRACTION) * 10000), (int) (TMP_FRACTION - 1.0f) * 10000);
                        FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR);
                        FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR);
                    }
                } else {
                    FRACTION_COLORS.put(TMP_FRACTION, TMP_COLOR);
                }
            }

            // Clear the original FRACTION_LIST and COLOR_LIST
            FRACTION_LIST.clear();
            COLOR_LIST.clear();

            return FRACTION_COLORS;
        }

        /**
         * With the START_COLOR at the beginning and the DESTINATION_COLOR at the
         * end of the given RANGE the method will calculate and return the color
         * that equals the given VALUE. e.g. a START_COLOR of BLACK (R:0, G:0, B:0,
         * A:255) and a DESTINATION_COLOR of WHITE(R:255, G:255, B:255, A:255) with
         * a given RANGE of 100 and a given VALUE of 50 will return the color that
         * is exactly in the middle of the gradient between black and white which is
         * gray(R:128, G:128, B:128, A:255) So this method is really useful to
         * calculate colors in gradients between two given colors.
         *
         * @param START_COLOR
         * @param DESTINATION_COLOR
         * @param RANGE
         * @param VALUE
         * @return Color calculated from a range of values by given value
         */
        public java.awt.Color getColorFromFraction(final java.awt.Color START_COLOR, final java.awt.Color DESTINATION_COLOR, final int RANGE, final int VALUE) {
            final float SOURCE_RED = START_COLOR.getRed() * INT_TO_FLOAT_CONST;
            final float SOURCE_GREEN = START_COLOR.getGreen() * INT_TO_FLOAT_CONST;
            final float SOURCE_BLUE = START_COLOR.getBlue() * INT_TO_FLOAT_CONST;
            final float SOURCE_ALPHA = START_COLOR.getAlpha() * INT_TO_FLOAT_CONST;

            final float DESTINATION_RED = DESTINATION_COLOR.getRed() * INT_TO_FLOAT_CONST;
            final float DESTINATION_GREEN = DESTINATION_COLOR.getGreen() * INT_TO_FLOAT_CONST;
            final float DESTINATION_BLUE = DESTINATION_COLOR.getBlue() * INT_TO_FLOAT_CONST;
            final float DESTINATION_ALPHA = DESTINATION_COLOR.getAlpha() * INT_TO_FLOAT_CONST;

            final float RED_DELTA = DESTINATION_RED - SOURCE_RED;
            final float GREEN_DELTA = DESTINATION_GREEN - SOURCE_GREEN;
            final float BLUE_DELTA = DESTINATION_BLUE - SOURCE_BLUE;
            final float ALPHA_DELTA = DESTINATION_ALPHA - SOURCE_ALPHA;

            final float RED_FRACTION = RED_DELTA / RANGE;
            final float GREEN_FRACTION = GREEN_DELTA / RANGE;
            final float BLUE_FRACTION = BLUE_DELTA / RANGE;
            final float ALPHA_FRACTION = ALPHA_DELTA / RANGE;
            //System.out.println(DISTANCE + "     " + CURRENT_FRACTION);

            return new java.awt.Color(SOURCE_RED + RED_FRACTION * VALUE, SOURCE_GREEN + GREEN_FRACTION * VALUE, SOURCE_BLUE + BLUE_FRACTION * VALUE, SOURCE_ALPHA + ALPHA_FRACTION * VALUE);
        }

        @Override
        public java.awt.PaintContext createContext(final java.awt.image.ColorModel COLOR_MODEL, final java.awt.Rectangle DEVICE_BOUNDS, final java.awt.geom.Rectangle2D USER_BOUNDS, final java.awt.geom.AffineTransform TRANSFORM, final java.awt.RenderingHints HINTS) {
            final java.awt.geom.Point2D TRANSFORMED_CENTER = TRANSFORM.transform(CENTER, null);
            return new ConicalGradientPaintContext(TRANSFORMED_CENTER);
        }

        @Override
        public int getTransparency() {
            return java.awt.Transparency.TRANSLUCENT;
        }

        private final class ConicalGradientPaintContext implements java.awt.PaintContext {

            final private java.awt.geom.Point2D CENTER;

            public ConicalGradientPaintContext(final java.awt.geom.Point2D CENTER) {
                this.CENTER = new java.awt.geom.Point2D.Double(CENTER.getX(), CENTER.getY());
            }

            @Override
            public void dispose() {
            }

            @Override
            public java.awt.image.ColorModel getColorModel() {
                return java.awt.image.ColorModel.getRGBdefault();
            }

            @Override
            public java.awt.image.Raster getRaster(final int X, final int Y, final int TILE_WIDTH, final int TILE_HEIGHT) {
                final double ROTATION_CENTER_X = -X + CENTER.getX();
                final double ROTATION_CENTER_Y = -Y + CENTER.getY();

                final int MAX = FRACTION_ANGLES.length;

                // Create raster for given colormodel
                final java.awt.image.WritableRaster RASTER = getColorModel().createCompatibleWritableRaster(TILE_WIDTH, TILE_HEIGHT);

                // Create data array with place for red, green, blue and alpha values
                int[] data = new int[(TILE_WIDTH * TILE_HEIGHT * 4)];

                double dx;
                double dy;
                double distance;
                double angle;
                double currentRed = 0;
                double currentGreen = 0;
                double currentBlue = 0;
                double currentAlpha = 0;

                for (int py = 0; py < TILE_HEIGHT; py++) {
                    for (int px = 0; px < TILE_WIDTH; px++) {

                        // Calculate the distance between the current position and the rotation angle
                        dx = px - ROTATION_CENTER_X;
                        dy = py - ROTATION_CENTER_Y;
                        distance = Math.sqrt(dx * dx + dy * dy);

                        // Avoid division by zero
                        if (distance == 0) {
                            distance = 1;
                        }

                        // 0 degree on top
                        angle = Math.abs(Math.toDegrees(Math.acos(dx / distance)));

                        if (dx >= 0 && dy <= 0) {
                            angle = 90.0 - angle;
                        } else if (dx >= 0 && dy >= 0) {
                            angle += 90.0;
                        } else if (dx <= 0 && dy >= 0) {
                            angle += 90.0;
                        } else if (dx <= 0 && dy <= 0) {
                            angle = 450.0 - angle;
                        }

                        // Check for each angle in fractionAngles array
                        for (int i = 0; i < (MAX - 1); i++) {
                            if ((angle >= FRACTION_ANGLES[i])) {
                                currentRed = COLORS[i].getRed() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * RED_STEP_LOOKUP[i];
                                currentGreen = COLORS[i].getGreen() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * GREEN_STEP_LOOKUP[i];
                                currentBlue = COLORS[i].getBlue() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * BLUE_STEP_LOOKUP[i];
                                currentAlpha = COLORS[i].getAlpha() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * ALPHA_STEP_LOOKUP[i];
                                continue;
                            }
                        }

                        // Fill data array with calculated color values
                        final int BASE = (py * TILE_WIDTH + px) * 4;
                        data[BASE + 0] = (int) (currentRed * 255);
                        data[BASE + 1] = (int) (currentGreen * 255);
                        data[BASE + 2] = (int) (currentBlue * 255);
                        data[BASE + 3] = (int) (currentAlpha * 255);
                    }
                }

                // Fill the raster with the data
                RASTER.setPixels(0, 0, TILE_WIDTH, TILE_HEIGHT, data);

                return RASTER;
            }
        }
    }
}

To try and do what you're doing with a pie slices, you need to slow alter the color from one point to another, using very small slices. 要尝试使用饼状切片进行操作,您需要使用很小的切片将颜色从一个点缓慢更改为另一点。 So, while you might start with Color.RED and want to blend to Color.YELLOW , you would actually need to generate each color between them (based on the distance) 所以,虽然你可能会开始Color.RED ,想融入到Color.YELLOW ,你实际上需要在它们之间产生每种颜色(基于距离)

For example... 例如...

混色

import core.ui.ColorUtilities;
import static core.ui.ColorUtilities.blend;
import static core.ui.ColorUtilities.getFractionIndicies;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ColorWheel {

    public static void main(String[] args) {
        new ColorWheel();
    }

    public ColorWheel() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            float fractions[] = new float[]{0, 0.16f, 0.33f, 0.5f, 0.66f, 0.83f, 1f};
            Color colors[] = new Color[]{Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.RED};
            for (int index = 0; index < getWidth(); index++) {

                float progress = (float) index / getWidth();
                System.out.println(progress);
                Color color = blendColors(fractions, colors, progress);
                g2d.setColor(color);
                g2d.drawLine(index, 0, index, getHeight());
            }

            g2d.dispose();
        }

    }

    /**
     * This will attempt to blend two colors that site between the supplied
     * progress value, based on the distance of the progress value...
     *
     * For example, if you have a series of fractions of {0f, 0.5f, 1f} and a
     * progress of 25%, the resulting color will be a 50% blend of the first and
     * second color (as the progress is half between those two points)
     *
     * @param fractions
     * @param colors
     * @param progress
     * @return
     */
    public static Color blendColors(float[] fractions, Color[] colors, float progress) {

        Color color = null;

        if (fractions != null) {

            if (colors != null) {

                if (fractions.length == colors.length) {

                    int[] indicies = getFractionIndicies(fractions, progress);

                    float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]};
                    Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]};

                    float max = range[1] - range[0];
                    float value = progress - range[0];
                    float weight = value / max;

                    color = blend(colorRange[0], colorRange[1], 1f - weight);

                } else {

                    throw new IllegalArgumentException("Fractions and colours must have equal number of elements");

                }

            } else {

                throw new IllegalArgumentException("Colours can't be null");

            }

        } else {

            throw new IllegalArgumentException("Fractions can't be null");

        }

        return color;

    }
}

I know, it's note a wheel, but i was demonstrating the blending algorithm, I'll leave the pie slicing up to you ;) 我知道,这是一个轮子,但我正在演示混合算法,我将把切片切成小块给您;)

Just proving to myself it could work... 只是向自己证明这可能行得通...

色轮

int dimeter = Math.min(getWidth(), getHeight());
int x = (getWidth() - dimeter) / 2;
int y = (getHeight() - dimeter) / 2;

for (int angle = 0; angle < 360; angle++) {

    float progress = (float) angle / 360;
    System.out.println(progress);
    Color color = blendColors(fractions, colors, progress);
    g2d.setColor(color);
    g2d.fillArc(x, y, dimeter, dimeter, angle + 90, 2);

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM