Let’s write two versions of the algorithm in Java to output a heart to the console in the form of a text image — let’s congratulate women on the eighth of March. Let’s draw a graph of the function in the form of a heart and, in addition, draw the symbol heart in the form of a picture, and output the picture as text — console congratulations on the eighth of March.
Let’s draw two half-circles and one half-rhombus, filled inside and outside. In the previous example, we output a function graph to console — we take the formulas for the circle and for the rhombus from it, and in this example, we add the filling of the figure inside and outside — instead of the equal sign in the formulas, we substitute less than or greater than signs. There will be many conditions, unlike the previous example.
Let’s draw a picture for clarity.
We output the upper part of the figure, the lower part of the figure, paint over in a checkerboard pattern and output the coordinate axes. We get several text images that look like this.
Radius: 5, in/out/axes: true/true/true.
· · · · · ↑y · · · · ·
· · o o o o o · ¦ · o o o o o · ·
· o * * o · o * * o ·
· o * * * o ¦ o * * * o ·
o * * * * o * * * * o
· o * * * * * o * * * * * o ·
--o --* --* --* --* --+---* --* --* --* --o >x
· o * * * * ¦ * * * * o ·
· o * * * * * * * o ·
· · o * * * ¦ * * * o · ·
· · o * * * * * o · ·
· · · o * * ¦ * * o · · ·
· · · o * * * o · · ·
· · · · o * ¦ * o · · · ·
· · · · o * o · · · ·
· · · · · o ¦ o · · · · ·
· · · · · o · · · · ·
· · · · · · ¦ · · · · · ·
Radius: 4, in/out/axes: false/true/false.
· · · · · · · · · ·
· o o o o o · o o o o o ·
· o o o o o o o o ·
o o o o o o o
· o o o ·
o o
· o o ·
· o o ·
· · o o · ·
· · o o · ·
· · · o o · · ·
· · · o o · · ·
· · · · o o · · · ·
· · · · o · · · ·
· · · · · · · · · ·
Radius: 3, in/out/axes: true/false/false.
o o o o o o
o * * o o * * o
o * * * o * * * o
o * * * * * o
o * * * * o
o * * * o
o * * o
o * o
o o
o
Radius: 2, in/out/axes: false/false/false.
o o o o o o
o o o
o o
o o
o o
o o
o
We bypass the coordinate range with two nested for
loops: first along the y
axis and then along
the x
axis. We check each point for compliance with the conditions and output it. In the upper part
we draw two half-circles and optionally paint over them inside and outside. In the lower part we draw
a half-rhombus and also optionally paint over inside and outside.
/**
* @param r radius
* @param gap offset
* @param in filling inside
* @param out filling outside
* @param axes coordinate axes
*/
public static void printHeartGraph(
int r, int gap, boolean in, boolean out, boolean axes) {
// boundaries of the text image
int xMax = 2*r+gap, xMin = -xMax;
int yMax = r+gap, yMin = -r-yMax;
System.out.println( // header with parameters
"Radius: "+r+", in/out/axes: "+in+"/"+out+"/"+axes+".");
// output to the console line by line from left to right from top to bottom
for (int y = yMax; y >= yMin; y--) {
for (int x = xMin; x <= xMax; x++) {
double[] circle = { // two circles left/right
Math.round(Math.sqrt(Math.pow(x+r,2)+Math.pow(y,2))), // left
Math.round(Math.sqrt(Math.pow(x-r,2)+Math.pow(y,2)))}; // right
int rhombus = Math.abs(x)+Math.abs(y); // rhombus
boolean inCh = in && (x+y)%2 == 0; // checkerboard pattern inside
boolean outCh = out && (x+y)%2 == 0; // checkerboard pattern outside
// check each point for compliance with the conditions and output it
if (axes && y == 0 && x == 0)
System.out.print("+-"); // origin of coordinates
else if (axes && y == 0 && x == xMax)
System.out.print(">x"); // maximum of abscissa axis (x)
else if (axes && x == 0 && y == yMax)
System.out.print("↑y"); // maximum of ordinate axis (y)
else if (y > 0 && (circle[0] == r || circle[1] == r))
System.out.print("o "); // two half circles, top
else if (y > 0 && inCh && (circle[0] < r || circle[1] < r))
System.out.print("* "); // top inside
else if (y > 0 && outCh && (circle[0] > r && circle[1] > r))
System.out.print("· "); // top outside
else if (y <= 0 && rhombus == 2*r)
System.out.print("o "); // half rhombus, bottom
else if (y <= 0 && inCh && rhombus < 2*r)
System.out.print("* "); // bottom inside
else if (y <= 0 && outCh && rhombus > 2*r)
System.out.print("· "); // bottom outside
else if (axes && y == 0)
System.out.print("--"); // abscissa axis (x)
else if (axes && x == 0)
System.out.print("¦ "); // ordinate axis (y)
else
System.out.print(" "); // empty space
} // transition to a new line
System.out.println();
}
}
// execute the program and output the result
public static void main(String[] args) {
printHeartGraph(5, 1, true, true, true);
printHeartGraph(4, 1, false, true, false);
printHeartGraph(3, 0, true, false, false);
printHeartGraph(2, 0, false, false, false);
}
In the previous example we drew a simple captcha — we take the font rendering algorithm from it, only this time we draw a binary black-and-white image in a monospaced font, we do not use anti-aliasing. The symbol heart in the form of a picture looks like this.
Since the character is in the middle of the line, half of the pixels in the resulting image are empty. We bypass the pixels line by line and output only non-empty lines, that is the central part of the image.
Monospaced.plain, 22, symbols: ♡
o o o
o o o o o o o
o o o o
o o o
o o o
o o
o o
o o
o o
o o
o o
o o
o o
o
Monospaced.plain, 28, symbols: ♡
o o
o o o o o o o o
o o o o
o o o o
o o o
o o o
o o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o
Monospaced.plain, 36, symbols: ♡
o o o o o o o
o o o o o o o
o o o o
o o o o
o o o o
o o o
o o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
We draw a line of text as a black-and-white image, then iterate over the pixels of this image and print them as text to the console line by line. We draw only the central part of the image with text, do not display empty lines of pixels.
// draw a text in the form of a picture and a picture in the form of a text
public static void printTextImage(String str, Font font) {
FontRenderContext ctx = // font rendering context
new FontRenderContext(font.getTransform(), false, false);
// get the dimensions of the picture with text when rendering
Rectangle bnd = font.getStringBounds(str, ctx).getBounds();
// create a new binary black-and-white image
BufferedImage image = new BufferedImage(
bnd.width, bnd.height, BufferedImage.TYPE_BYTE_BINARY);
// turn on the editing mode of the new image
Graphics2D graphics = image.createGraphics();
// font for rendering, do not use anti-aliasing
graphics.setFont(font);
// draw a picture with text
graphics.drawString(str, bnd.x, -bnd.y);
// disable the editing mode
graphics.dispose();
// output the header
System.out.println(
font.getFontName()+", "+font.getSize()+", symbols: "+str);
// bypass the pixels line by line and output non-empty lines
for (int y = 0; y < bnd.height; y++) {
StringBuilder line = new StringBuilder();
for (int x = 0; x < bnd.width; x++)
line.append(image.getRGB(x, y) == -1 ? "o " : " ");
// draw only non-empty lines
if (line.indexOf("o") != -1) System.out.println(line);
}
}
// execute the program and output the result
public static void main(String[] args) {
printTextImage("♡", new Font(Font.MONOSPACED, Font.PLAIN, 22));
printTextImage("♡", new Font(Font.MONOSPACED, Font.PLAIN, 28));
printTextImage("♡", new Font(Font.MONOSPACED, Font.PLAIN, 36));
}
The last example uses the Java AWT library.
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.image.BufferedImage;
© Golovin G.G., Code with comments, translation from Russian, 2023