package com.haogrgr.test.main;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class EllipseStampMain {
static int width = 4000, height = 4000; //图片长宽
public static void main(String[] args) throws Exception {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = image.createGraphics();
graphics.translate(width / 2, height / 2);// 把绘制起点挪到圆中心点
int ew = 3000, eh = 2000;//红圈椭圆长短轴
//外围红框椭圆
Ellipse2D ellipse = new Ellipse2D.Double(-ew / 2, -eh / 2, ew, eh);// 椭圆
graphics.setStroke(new BasicStroke(80.0f));// 线条粗细
graphics.setColor(Color.RED); // 线条颜色
graphics.draw(ellipse);// 绘制
drawFirm(graphics, "美国阿帕奇科技有限公司", ew, eh, 600);
ImageIO.write(image, "png", new File("D:/test2.png"));
image.flush();
}
/**
* 沿着椭圆画字符
* @param graphics
* @param firm 字符
* @param ew 外围椭圆长轴
* @param eh 外围椭圆短轴
* @param space 红圈和字符所在的椭圆直接的间距
*/
public static void drawFirm(Graphics2D graphics, String firm, int ew, int eh, int space) {
graphics.setColor(Color.RED);
graphics.setFont(new Font("宋体", Font.BOLD, 200));
//space 为字符所在的椭圆和外面的红圈椭圆的差距
int a = (ew - space) / 2, b = (eh - space) / 2;
//算出椭圆半周长
double halfLenCount = getHalfEllipseLenth(a, b);
System.out.println(String.format("椭圆半周长: %s", halfLenCount));
//第一个字符和最后一个字符先画
drawFirmChar(graphics, firm.charAt(0), -a, 0, b);//画第一个字符
drawFirmChar(graphics, firm.charAt(firm.length() - 1), a, 0, b);//画第最好一个字符
//误差调整
double[] adjustment = { 0, 0, 420, 200, 100, 70, 45, 30, 23, 13, 9, 8 };
//根据椭圆周长等分, 然后循环椭圆坐标, 当长度达到等分时, 写下字符
double x1 = -a, y1 = 0, step = halfLenCount / (firm.length()) + adjustment[firm.length() - 1], len = 0;
for (double x = -a, i = 1; x <= a; x++) {
double y = getEllipseY(x, a, b);
len += getLenth(x1, y1, x, y);
if (len >= step & i < firm.length() - 1) {
System.out.println(String.format("%s, %s, %s, len", x, firm.charAt((int) i), i));
drawFirmChar(graphics, firm.charAt((int) i++), x, y, b);
len = 0;
}
x1 = x;
y1 = y;
}
}
/**
* 椭圆标准方程, 根据x坐标, 求y坐标
* @param x x坐标
* @param a 椭圆长轴
* @param b 椭圆短轴
* @return y坐标
*/
public static double getEllipseY(double x, int a, int b) {
double a_a = Math.pow(a, 2), b_b = Math.pow(b, 2);
double y = Math.sqrt((1 - (x * x) / a_a) * b_b);
return y;
}
/**
* 画字符
* @param graphics
* @param c 字符
* @param x 小椭圆x坐标
* @param y 小椭圆y坐标
* @param theta 字符旋转弧度
*/
public static void drawFirmChar(Graphics2D graphics, char c, double x, double y, int b) {
double theta = Math.atan(((b * b) / y - y) / x); //椭圆上点(x, y)的切线的弧度
//反转角度, 比如到了90度了
if (Double.isNaN(theta)) {
theta = Math.toRadians(0);
}
//最后一个字符, 因为其实角度为0度, 字符会靠下, 所以要偏移y轴为字符宽度
if (theta == 1.5707963267948966d) {
y = y + graphics.getFontMetrics().stringWidth(c + "");
}
//转换坐标 -> 旋转坐标 -> 画字符 -> 还原坐标
graphics.translate(x, -y);
graphics.rotate(theta);
graphics.drawString(c + "", 0, 0);
graphics.rotate(-theta);
graphics.translate(-x, y);
}
/**
* http://zhidao.baidu.com/link?url=SHMm_XY72VHIqBiqZErGVDAVnDX5vQl2gYXJ2-3tffC-pElzfT0atmQ3FxNeIrMgE8-1Gmuru1-jQIOWslJhH_
*
* 根据角度, 求该角度所表示的直线(y = kx + 0)与椭圆的交点x坐标
**/
public static double getFriends(double degrees, int a, int b) {
double k = Math.tan(Math.toRadians(degrees));
double top = a * b * Math.sqrt(b * b + k * k * a * a);
double button = b * b + a * a * k * k;
double ret = top / button;
return ret;
}
/**
* 椭圆近视半周长
* @param a 椭圆长轴
* @param b 椭圆短轴
* @return 周长
*/
public static double getHalfEllipseLenth(int a, int b) {
//先近视计算椭圆周长(lenCount)(椭圆上一个点和下一个点的直线距离累加)
double halfLenCount = 0;
double x1 = -a, y1 = 0;
for (double x = -a; x <= a; x++) {
double y = getEllipseY(x, a, b);
halfLenCount += getLenth(x1, y1, x, y);//三角函数求斜边长, 就是两个坐标点的距离
x1 = x;
y1 = y;
}
return halfLenCount;
}
/**
* 获取坐标系中, 两个点(x1, y1), (x2, y2)的直线距离
*/
public static double getLenth(double x1, double y1, double x2, double y2) {
double ret = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
return ret;
}
}