扫描线填充

Java

  1. import javax.swing.*;
  2. import java.awt.*;
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. public class FillTest extends JFrame {
  6. private ArrayList<Edge> edgeTable = new ArrayList<>();
  7. private int getYmin() {
  8. int yMin = edgeTable.get(0).y1;
  9. for (Edge edge : edgeTable) {
  10. if (edge.y1 < yMin)
  11. yMin = edge.y1;
  12. }
  13. return yMin;
  14. }
  15. private int getYmax() {
  16. int yMax = edgeTable.get(0).y1;
  17. for (Edge edge : edgeTable) {
  18. if (edge.y1 > yMax)
  19. yMax = edge.y1;
  20. }
  21. return yMax;
  22. }
  23. private boolean isActive(Edge edge, int currentY) {
  24. return edge.y1 < currentY && currentY <= edge.y2 || edge.y1 >= currentY && currentY > edge.y2;
  25. }
  26. private void updateActiveEdges(ArrayList<Edge> activeEdges, int y) {
  27. for (Edge edge : edgeTable) {
  28. if (isActive(edge, y)) {
  29. if (!activeEdges.contains(edge)) {
  30. activeEdges.add(edge);
  31. }
  32. } else {
  33. activeEdges.remove(edge);
  34. }
  35. }
  36. }
  37. private void findIntersections(ArrayList<Integer> intersections, ArrayList<Edge> activeEdges, int currentY) {
  38. intersections.clear();
  39. for (Edge edge : activeEdges) {
  40. int x = edge.x1 + ((currentY - edge.y1) * (edge.dx)) / (edge.dy);
  41. intersections.add(x);
  42. }
  43. }
  44. public void fill() {
  45. ArrayList<Edge> activeEdges = new ArrayList(10);
  46. ArrayList<Integer> intersections = new ArrayList(20);
  47. Graphics g = getGraphics();
  48. g.setColor(Color.red);
  49. // x1,y1,x2,y2
  50. edgeTable.add(new Edge(100, 100, 100, 600));
  51. edgeTable.add(new Edge(100, 600,500,400));
  52. edgeTable.add(new Edge(500,400, 100, 100));
  53. int yMin = getYmin();
  54. int yMax = getYmax();
  55. for (int y = yMin; y < yMax; y++) {
  56. updateActiveEdges(activeEdges, y);
  57. findIntersections(intersections, activeEdges, y);
  58. Collections.sort(intersections);
  59. for (int i = 0; i < intersections.size(); i += 2) {
  60. int x1 = intersections.get(i);
  61. if (i + 1 >= intersections.size()){
  62. break;
  63. }
  64. int x2 = intersections.get(i + 1);
  65. g.drawLine(x1, y, x2, y);
  66. }
  67. }
  68. }
  69. public static void main(String[] args) {
  70. FillTest s = new FillTest();
  71. s.setSize(800, 800);
  72. s.setVisible(true);
  73. s.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  74. s.fill();
  75. }
  76. }
  77. class Edge {
  78. int x1, y1, x2, y2, dx, dy;
  79. Edge(int x1, int y1, int x2, int y2) {
  80. this.x1 = x1;
  81. this.y1 = y1;
  82. this.x2 = x2;
  83. this.y2 = y2;
  84. this.dx = x2 - x1;
  85. this.dy = y2 - y1;
  86. }
  87. }

C++

ScanlineFilling.h
  1. #include <iostream>
  2. #include <vector>
  3. class ScanlineFilling
  4. {
  5. public:
  6. class Edge {
  7. public:
  8. int x1, y1, x2, y2, dx, dy;
  9. Edge(int x1, int y1, int x2, int y2);
  10. };
  11. private:
  12. std::vector<Edge> edgeTable;
  13. int getYmin();
  14. int getYmax();
  15. bool isActive(Edge edge, int currentY);
  16. void updateActiveEdges(std::vector<Edge>& activeEdges, int y);
  17. void findIntersections(std::vector<int>& intersections, std::vector <Edge> activeEdges, int currentY);
  18. public:
  19. // 多边形填充
  20. void fill(int** matrix, int x, int y, int** position, int len, int fillValue);
  21. };

ScanlineFilling.cpp
  1. #include "ScanlineFilling.h"
  2. #include <iostream>
  3. #include <vector>
  4. #include <algorithm>
  5. using namespace std;
  6. ScanlineFilling::Edge::Edge(int x1, int y1, int x2, int y2) {
  7. this->x1 = x1;
  8. this->y1 = y1;
  9. this->x2 = x2;
  10. this->y2 = y2;
  11. this->dx = x2 - x1;
  12. this->dy = y2 - y1;
  13. }
  14. int ScanlineFilling::getYmin() {
  15. int yMin = edgeTable.front().y1;
  16. for (Edge edge : edgeTable) {
  17. if (edge.y1 < yMin)
  18. yMin = edge.y1;
  19. }
  20. return yMin;
  21. }
  22. int ScanlineFilling::getYmax() {
  23. int yMax = edgeTable.front().y1;
  24. for (Edge edge : edgeTable) {
  25. if (edge.y1 > yMax)
  26. yMax = edge.y1;
  27. }
  28. return yMax;
  29. }
  30. bool ScanlineFilling::isActive(Edge edge, int currentY) {
  31. return edge.y1 < currentY && currentY <= edge.y2 || edge.y1 >= currentY && currentY > edge.y2;
  32. }
  33. void ScanlineFilling::updateActiveEdges(std::vector<Edge>& activeEdges, int y) {
  34. for (Edge edge : edgeTable) {
  35. if (isActive(edge, y)) {
  36. activeEdges.push_back(edge);
  37. }
  38. }
  39. }
  40. void ScanlineFilling::findIntersections(std::vector<int>& intersections, std::vector<Edge> activeEdges, int currentY) {
  41. for (Edge edge : activeEdges) {
  42. int x = edge.x1 + ((currentY - edge.y1) * (edge.dx)) / (edge.dy);
  43. intersections.push_back(x);
  44. }
  45. }
  46. //参数:要填充的二维数组,数组的行列,多边形的坐标[x,y],多边形坐标的个数(从起点到终点的个数,其中起点==终点),填充的值
  47. void ScanlineFilling::fill(int** matrix, int x, int y, int** position, int len,int fillValue) {
  48. vector<Edge> activeEdges;
  49. vector<int> intersections;
  50. int firstX, firstY;
  51. edgeTable.clear();
  52. // 获取面的点
  53. for (int i = 0; i < len; i++) {
  54. if (i == 0) {
  55. firstX = position[i][0];
  56. firstY = position[i][1];
  57. continue;
  58. }
  59. edgeTable.push_back(*(new Edge(firstX, firstY, position[i][0], position[i][1])));
  60. firstX = position[i][0];
  61. firstY = position[i][1];
  62. }
  63. int yMin = getYmin();
  64. int yMax = getYmax();
  65. for (int y = yMin; y < yMax; y++) {
  66. activeEdges.clear();
  67. intersections.clear();
  68. updateActiveEdges(activeEdges, y);
  69. findIntersections(intersections, activeEdges, y);
  70. // 升序
  71. sort(intersections.begin(),intersections.end());
  72. for (int i = 0; i < intersections.size(); i += 2) {
  73. int x1 = intersections[i];
  74. if ((i + 1) >= intersections.size()) {
  75. break;
  76. }
  77. int x2 = intersections[i + 1];
  78. for (int k = x1; k < x2; k++) {
  79. matrix[k][y] = fillValue;
  80. }
  81. }
  82. }
  83. }