Попытка нарисовать вертикальный линейный градиент, используя карту цветов, но используются только первые 9 цветов: почему? - PullRequest
0 голосов
/ 01 января 2019

(примечание: в конце этого вопроса приведен минимальный, полный и проверяемый пример)

Резюме

  1. Контекст, цель и проблема

  2. То, что я уже попробовал

  3. Соответствующие источники объяснены

  4. Ожидаемые результаты, фактические результаты и вопрос

  5. Пример минимального, полного и проверяемого значения

Контекст, цель и проблема

Я пытаюсь анимировать некоторые пиксели для созданияанимация огня в Java.Каждый пиксель окрашен так, что рисуется вертикальный линейный градиент от белого до желтого, от желтого до красного и от красного до черного.Этот градиент идет снизу вверх холста.

В начале выполнения все пиксели являются черными, кроме белой линии, которая определяется координатой y = height - 1, height, являющейся высотойхолст.Эта белая линия используется для инициации градиента (« от белого до желтого , от желтого до… и т. Д.»).

Проблема в том, что градиент начинается правильно, но останавливаетсякогда используется 9-й цвет.Тогда только этот цвет используется, чтобы заполнить мой градиент, и я не знаю почему.

То, что я уже пробовал

У меня есть карта значений RGB, которая определяет градиент.

Идея узнать, какой цвет применить к пикселю с именем «A», состоит в том, чтобы извлечь RGB пикселя чуть ниже него, а затем получить идентификатор этого RGB среди всех RGB моей карты.Затем я получаю RGB под этим ID + 1 на этой же карте и применяю его к пикселю A.

Итак:

  1. Я проверил функцию, которая возвращаетИдентификатор RGB с учетом этого RGB: кажется, все в порядке, поскольку я не выдал никакого исключения

  2. Я проверил, правильно ли обновлено используемое мной буферизованное изображение.Другими словами: если факт, что пиксель был окрашен, действительно имеет значение для определения цвета пикселя выше: это тоже нормально

Соответствующие источники объяснили

Вызов методов для рисования градиента

Идея состоит в том, чтобы установить все пиксели в черный цвет, кроме нижней линии, которая является белой.Затем я перебираю пиксель каждого холста и присваиваю ему цвет ниже прямого вертикального соседа.Точнее, я даю ему цвет, идентификатор которого = идентификатор цвета этого соседнего пикселя + 1, в моей карте цветов.

    Colors colors = new FireColors(new ArrayList<>());
    gui.colorize(colors.getColorAtIndex(34), -1, -1);  // Setting black anywhere
    gui.colorize(colors.getColorAtIndex(0), -1, height - 1);  // Setting white, in a lower line

    try {
        for(int y = height - 2; y >= 0; y--) {
            for(int x = 0; x < width; x++) {
                int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
                int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
                int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
                gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x, y);
            }
        }
    } catch (Exception e) {
        System.err.println(e.getMessage());
    }

Как я окрашиваю пиксели

Я простоитерация по холсту.

void colorize(Color color, int x_parameter, int y_parameter) {
    for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
        for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
            buffered_image.setRGB(x, y, color.getRGB());
        }
    }
    panel.repaint();
}

Как найти индекс цвета пикселя в списке цветов?

int getIndexOfColor(int rgb) throws Exception {
    for (int x = 0; x < colors.size(); x++) {
        if(colors.get(x).getRGB() == rgb) {
            return x;
        }
    }
    throw new Exception("Color not found in the list!");
}

Ожидаемые результаты, фактические результаты и вопрос

Я ожидаю иметь несколько вертикальных градиентов (каждый снизу вверх).«Несколько», потому что высота моего холста больше, чем количество цветов моих градиентов, и потому что я использую по модулю, чтобы выбрать цвет для применения.

Фактические результаты: Я получаю градиент, который начинается сот белого до желтого, всего 9 цветов и все.Ни оранжевого, ни красного, ни черного.Действительно: https://imgur.com/oQFJ52k

Мой вопрос таков: так как хороший идентификатор получен, а хороший сосед выбран для данного пикселя, почему мой градиент заблокирован до 9-го цвета?Другими словами: почему в определенный момент не выбраны хорошие цвета?

Пример минимального, полного и проверяемого

Launcher.java

import java.util.ArrayList;

public class Launcher {

    public static void main(String args[]) {
        int width = 150, height = 150;
        Gui gui = new Gui(width, height);
        gui.setUp("DOOM-like fire");
        gui.setVisible(true);

        Colors colors = new FireColors(new ArrayList<>());
        gui.colorize(colors.getColorAtIndex(34), -1, -1);  // Setting black anywhere
        gui.colorize(colors.getColorAtIndex(0), -1, height - 1);  // Setting white, in a lower line

        try {
            for(int y = height - 2; y >= 0; y--) {
                for(int x = 0; x < width; x++) {
                    int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
                    int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
                    int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
                    gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x, y);
                }
            }
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }

}

Gui.java

import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;

class Gui extends JFrame {

    private JPanel panel;
    private BufferedImage buffered_image;

    Gui(int width, int height) {
        buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        panel = new JPanel() {
            public void paintComponent(Graphics graphics) {
                super.paintComponent(graphics);
                graphics.drawImage(buffered_image, 0, 0, null);
            }
        };
    }

    void setUp(String title) {
        setTitle(title);
        setLayout(null);
        setSize(buffered_image.getWidth(), buffered_image.getHeight());
        setContentPane(panel);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    void colorize(Color color, int x_parameter, int y_parameter) {
        for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
            for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
                buffered_image.setRGB(x, y, color.getRGB());
            }
        }
        panel.repaint();
    }

    int getRGBAtCoordinates(int x, int y) {
        return buffered_image.getRGB(x, y);
    }

}

Colors.java

import java.awt.Color;
import java.util.List;

abstract class Colors {
    List<Color> colors;

    Color getColorAtIndex(int index) {
        return colors.get(index);
    }

    int getIndexOfColor(int rgb) throws Exception {
        for (int x = 0; x < colors.size(); x++) {
            if(colors.get(x).getRGB() == rgb) {
                return x;
            }
        }
        throw new Exception("Color not found in the list!");
    }

    int getSize() {
        return colors.size();
    }
}

FireColors.java

import java.awt.Color;
import java.util.List;

class FireColors extends Colors {

    FireColors(List<Color> colors) {

        this.colors = colors;

        this.colors.add(new Color(255, 255, 255));
        this.colors.add(new Color(239, 239, 199));
        this.colors.add(new Color(223, 223, 159));
        this.colors.add(new Color(207, 207, 111));
        this.colors.add(new Color(183, 183, 55));
        this.colors.add(new Color(183, 183, 47));
        this.colors.add(new Color(183, 175, 47));
        this.colors.add(new Color(191, 175, 47));
        this.colors.add(new Color(191, 167, 39));
        this.colors.add(new Color(191, 167, 39));
        this.colors.add(new Color(191, 159, 31));
        this.colors.add(new Color(191, 159, 31));
        this.colors.add(new Color(199, 151, 31));
        this.colors.add(new Color(199, 143, 23));
        this.colors.add(new Color(199, 135, 23));
        this.colors.add(new Color(207, 135, 23));
        this.colors.add(new Color(207, 127, 15));
        this.colors.add(new Color(207, 119, 15));
        this.colors.add(new Color(207, 111, 15));
        this.colors.add(new Color(215, 103, 15));
        this.colors.add(new Color(215, 95, 7));
        this.colors.add(new Color(223, 87, 7));
        this.colors.add(new Color(223, 87, 7));
        this.colors.add(new Color(223, 79, 7));
        this.colors.add(new Color(199, 71, 7));
        this.colors.add(new Color(191, 71, 7));
        this.colors.add(new Color(175, 63, 7));
        this.colors.add(new Color(159, 47, 7));
        this.colors.add(new Color(143, 39, 7));
        this.colors.add(new Color(119, 31, 7));
        this.colors.add(new Color(103, 31, 7));
        this.colors.add(new Color(87, 23, 7));
        this.colors.add(new Color(71, 15, 7));
        this.colors.add(new Color(47, 15, 7));
        this.colors.add(new Color(7, 7, 7));

    }

}

1 Ответ

0 голосов
/ 01 января 2019

Ваша проблема в том, что FireColors содержит дубликаты цветов:

// FireColors, lines 20 and 21:
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 167, 39));
// more duplicate colors found later on!

Проблема связана с вашим алгоритмом выбора цвета:

// Launcher lines 20 to 22:
int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();

Для 8-й строки она читаетцвет из строки под ним, находит его индекс (7), добавляет единицу и окрашивает эту строку цветом # 8.

Для 9-й строки он считывает цвет из строки под ним, находит его индекс(8) добавляет единицу и цвета, совпадающие с цветом # 9 (который совпадает с цветом # 8)

Для 10-й строки он считывает цвет из строки под ним, находит его индекс (8, поскольку getIndexOfColor() возвращает первый найденный индекс, который равен 8, а не 9!), Добавляет единицу и окрашивает эту строку в цвет # 9 (который совпадает с цветом # 8)

Исправитьэто, вы должны либо изменить свой алгоритм выбора цвета или сделать ваши FireColor цвета уникальными.

...