public static void paint(final @NotNull Graphics2D g,
                           double x1, double y1, double x2, double y2,
                           @NotNull StrokeType strokeType,
                           double strokeWidth,
                           @NotNull Object valueAA) {
    boolean horizontal = y1 == y2;
    boolean vertical = x1 == x2;
    boolean straight = horizontal || vertical;
    boolean centered = strokeType == StrokeType.CENTERED || strokeType == StrokeType.CENTERED_CAPS_SQUARE;
    boolean thickStroke = PaintUtil.devValue(strokeWidth, g) > 1;

    if (g.getStroke() instanceof BasicStroke && (straight || thickStroke)) {
      double sw = PaintUtil.alignToInt(strokeWidth, g);

      boolean dot = horizontal && vertical;
      if (dot) y2 += strokeWidth - 1; // draw a dot as [strokeWidth x strokeWidth] vertical line

      double angle = dot ? 0 : Math.atan2(y1 - y2, x2 - x1); // invert the sign of Y-axis, directing it bottom to top
      double sin = dot ? 1 : Math.sin(angle);
      double cos = dot ? 0 : Math.cos(angle);
      if (straight && !dot) {
        sin = Math.abs(sin);
        cos = Math.abs(cos);
      }

      // caps offsets
      double capy_1 = 0;
      double capy_2 = 0;
      double capx_1 = 0;
      double capx_2 = 0;
      if (strokeType == StrokeType.CENTERED_CAPS_SQUARE) {
        // the caps repeat the stroke split logic
        double[] strokeSplit = getStrokeSplit(ScaleContext.create(g), strokeType, sw, false);
        double cap_1 = strokeSplit[0];
        double cap_2 = strokeSplit[1];
        double y_sign = straight ? 1 : -1;
        // cap_1 >= cap_2 for x1/y1 < x2/y2, otherwise swap for diagonal line
        capx_1 = (straight || x1 <= x2 ? cap_1 : cap_2) * cos;
        capx_2 = (straight || x1 <= x2 ? cap_2 : cap_1) * cos;
        capy_1 = (straight || y1 <= y2 ? cap_1 : cap_2) * sin * y_sign;
        capy_2 = (straight || y1 <= y2 ? cap_2 : cap_1) * sin * y_sign;
      }

      // below x/y are aligned to int dev pixels to conform to RectanglePainter2D edges painting

      if (vertical/*|| dot*/) {
        double y_min = Math.min(y1, y2);
        double y_max = Math.max(y1, y2);
        y1 = PaintUtil.alignToInt(y_min, g);
        y2 = y1 + y_max - y1 + 1;
        x1 = x2 = PaintUtil.alignToInt(x2, g);
      }
      else if (horizontal) {
        double x_min = Math.min(x1, x2);
        double x_max = Math.max(x1, x2);
        x1 = PaintUtil.alignToInt(x_min, g);
        x2 = x1 + x_max - x1 + 1;
        y1 = y2 = PaintUtil.alignToInt(y2, g);
      }
      else {
        x1 = PaintUtil.alignToInt(x1, g);
        x2 = PaintUtil.alignToInt(x2, g);
        y1 = PaintUtil.alignToInt(y1, g);
        y2 = PaintUtil.alignToInt(y2, g);

        if (Math.abs(angle) > Math.PI / 2) {
          sin *= -1;
          cos *= -1;
        }
      }
      // stroke offsets
      double swx_2 = 0;
      double swx_1 = 0;
      double swy_2 = 0;
      double swy_1 = 0;
      if (strokeType == StrokeType.OUTSIDE) {
        swx_1 = sw * sin;
        swy_1 = sw * cos;
      }
      else if (strokeType == StrokeType.INSIDE) {
        swx_2 = sw * sin;
        swy_2 = sw * cos;
      }
      else if (centered) {
        double sw_1;
        double sw_2;
        if (straight) {
          // stroke is painted around the center of the line pixel (or within the line pixel, when the stroke is smaller)
          double[] strokeSplit = getStrokeSplit(ScaleContext.create(g), strokeType, sw);
          sw_1 = strokeSplit[0];
          sw_2 = strokeSplit[1];
        }
        else {
          // stroke is painted around the line
          sw_1 = PaintUtil.alignToInt(Math.max(sw / 2, 0), g);
          sw_2 = Math.max(sw - sw_1, 0);
        }
        swx_1 = sw_1 * sin;
        swx_2 = sw_2 * sin;
        swy_1 = sw_1 * cos;
        swy_2 = sw_2 * cos;
      }
      final Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
      path.moveTo(x1 - swx_1 - capx_1, y1 - swy_1 - capy_1);
      path.lineTo(x2 - swx_1 + capx_2, y2 - swy_1 + capy_2);
      path.lineTo(x2 + swx_2 + capx_2, y2 + swy_2 + capy_2);
      path.lineTo(x1 + swx_2 - capx_1, y1 + swy_2 - capy_1);
      path.closePath();

      PaintUtil.paintWithAA(g, valueAA,
                            () -> g.fill(path));
    }
    else {
      final Line2D line = new Line2D.Double(x1, y1, x2, y2);
      PaintUtil.paintWithAA(g, valueAA,
                            () -> g.draw(line));
    }
  }
public static void paint(final @NotNull Graphics2D g,
                           double x1, double y1, double x2, double y2,
                           @NotNull StrokeType strokeType,
                           double strokeWidth,
                           @NotNull Object valueAA)