getRotateInstance

import java.awt.Canvas; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import javax.swing.JFrame; /** * 返回表示旋转变换的变换。表示返回变换的矩阵是: [ cos(theta) -sin(theta) 0 ] [ sin(theta) cos(theta) 0 ] [ 0 0 1 ] 用正角度 theta 进行的旋转将 X 正半轴上的点向 Y 正半轴旋转。还要注意上文处理 90 度旋转的讨论。 参数: theta - 用弧度测量的旋转角度 返回: 使用指定旋转角度创建的、作为旋转变换的 AffineTransform 对象。 */ public class Draw2DRotate extends JFrame{ public Draw2DRotate(){ add("Center",new MyCanvas2()); setSize(400, 400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { Draw2DRotate d2 = new Draw2DRotate(); } } class MyCanvas2 extends Canvas{ public void paint(Graphics g){ Graphics2D g2d = (Graphics2D)g; //rotate:旋转 循环 指定的原点和方向旋转 AffineTransform at = AffineTransform.getRotateInstance(Math.PI/16.0d); g2d.setTransform(at); Line2D.Double shape = new Line2D.Double(0.0,0.0,300.0,300.0);//一条线 g2d.draw(shape); g2d.setFont(new Font("Helvetica",Font.BOLD,24)); String text = "Java2s"; g2d.drawString(text, 300, 50);//画这个字 Toolkit toolkit = Toolkit.getDefaultToolkit();//获取默认工具包。 Image image = toolkit.getImage("E:\\java\\Test\\icon\\44.png"); g2d.drawImage(image, 100, 50, this); } }


下面算法,水印不能平铺,优化下面算法,使得水印能够铺满,输出Java样例, private static void addWatermarkToPage(PDDocument doc, PDPage page, PDType0Font chineseFont){ try (PDPageContentStream contentStream = new PDPageContentStream( doc, page, PDPageContentStream.AppendMode.APPEND, true, true)) { // 获取页面实际尺寸 PDRectangle pageSize = page.getMediaBox(); float pageWidth = pageSize.getWidth(); float pageHeight = pageSize.getHeight(); // 动态计算字体大小(基于页面尺寸) contentStream.setFont(chineseFont, 48f); // 设置半透明水印颜色 contentStream.setNonStrokingColor(GRAY_R, GRAY_G, GRAY_B, OPACITY); // 计算水印密度(基于页面尺寸) float horizontalSpacing = pageWidth / DENSITY_FACTOR; float verticalSpacing = pageHeight / DENSITY_FACTOR; // 平铺布局算法(覆盖整个页面) for (float y = verticalSpacing; y < pageHeight; y += verticalSpacing) { for (float x = horizontalSpacing; x < pageWidth; x += horizontalSpacing) { drawWatermark(contentStream, WATERMARK_TEXT, x, y, pageWidth, FILE_SIZE); } } } catch (Exception e) { System.out.println(e); } } private static void drawWatermark(PDPageContentStream stream, String text, float x, float y, float pageWidth, float fontSize) throws IOException { // 保存当前图形状态 stream.saveGraphicsState(); // 绘制水印文本 stream.beginText(); // 计算旋转中心并应用旋转矩阵 float centerX = x + pageWidth / 20f; float centerY = y - fontSize / 2f; stream.transform(Matrix.getRotateInstance( Math.toRadians(ROTATION_ANGLE), centerX, centerY)); stream.newLineAtOffset(x, y); stream.showText(text); stream.endText(); // 恢复原始图形状态 stream.restoreGraphicsState(); }
09-02
下面Java算法还是没铺满,优化下面算法,是的水印才能铺满 private static void addWatermarkToPage(PDDocument doc, PDPage page, PDType0Font font) { try (PDPageContentStream stream = new PDPageContentStream( doc, page, PDPageContentStream.AppendMode.APPEND, true, true)) { // 获取页面尺寸 PDRectangle pageSize = page.getMediaBox(); float pageWidth = pageSize.getWidth(); float pageHeight = pageSize.getHeight(); // 设置水印样式 stream.setFont(font, FONT_SIZE); stream.setNonStrokingColor(GRAY_R, GRAY_G, GRAY_B, OPACITY); // 计算文本尺寸(核心优化) float textWidth = font.getStringWidth(WATERMARK_TEXT) * FONT_SIZE / 1000; float textHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() * FONT_SIZE / 1000; // 计算旋转后实际占位尺寸 double rads = Math.toRadians(ROTATION_ANGLE); float rotatedWidth = (float) (Math.abs(textWidth * Math.cos(rads)) + Math.abs(textHeight * Math.sin(rads))); float rotatedHeight = (float) (Math.abs(textWidth * Math.sin(rads)) + Math.abs(textHeight * Math.cos(rads))); // 计算行列数(确保覆盖边界) int cols = (int) Math.ceil((pageWidth + rotatedWidth) / rotatedWidth); int rows = (int) Math.ceil((pageHeight + rotatedHeight) / rotatedHeight); // 添加偏移量覆盖边缘区域(关键优化点) float offsetX = -rotatedWidth / 2; float offsetY = -rotatedHeight / 2; // 平铺水印(全覆盖算法) for (int row = 0; row <= rows; row++) { float y = offsetY + row * rotatedHeight; // 交错布局(奇数行偏移) float rowOffset = (row % 2 == 0) ? 0 : rotatedWidth / 2; for (int col = 0; col <= cols; col++) { float x = offsetX + col * rotatedWidth + rowOffset; drawWatermark(stream, WATERMARK_TEXT, font, x + rotatedWidth/2, y + rotatedHeight/2); } } } catch (Exception e) { System.err.println("水印添加失败: " + e.getMessage()); } } private static void drawWatermark(PDPageContentStream stream, String text, PDType0Font font, float centerX, float centerY) throws IOException { stream.saveGraphicsState(); stream.beginText(); // 设置旋转中心(优化定位) stream.transform(Matrix.getRotateInstance( Math.toRadians(ROTATION_ANGLE), centerX, centerY)); // 计算文本偏移量(居中显示) float textOffsetX = -font.getStringWidth(text) * FONT_SIZE / 1000; float textOffsetY = -font.getFontDescriptor().getFontBoundingBox().getHeight() * FONT_SIZE / 1000; stream.newLineAtOffset(centerX + textOffsetX, centerY + textOffsetY); stream.showText(text); stream.endText(); stream.restoreGraphicsState(); }
最新发布
09-02
package pkg202205002164何鑫; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; public class FractalTreeSimulator extends JPanel implements ActionListener { private int iteration = 2; // 分形迭代次数 private String fractalType = "Koch"; // 当前分形类型 private Timer timer; // 动画定时器 public FractalTreeSimulator() { setPreferredSize(new Dimension(800, 600)); setBackground(Color.WHITE); // 初始化滑块和按钮 JSlider slider = new JSlider(JSlider.HORIZONTAL, 1, 6, 2); slider.addChangeListener(e -> iteration = slider.getValue()); JButton kochButton = new JButton("Koch Curve"); kochButton.addActionListener(e -> fractalType = "Koch"); JButton treeButton = new JButton("Fractal Tree"); treeButton.addActionListener(e -> fractalType = "Tree"); JPanel controlPanel = new JPanel(); controlPanel.add(slider); controlPanel.add(kochButton); controlPanel.add(treeButton); JFrame frame = new JFrame("202205002164何鑫 - 分形树生长模拟器"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(this, BorderLayout.CENTER); frame.add(controlPanel, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); // 启动动画 timer = new Timer(100, this); timer.start(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.translate(getWidth() / 2, getHeight()); // 移动坐标系到中心底部 if ("Koch".equals(fractalType)) { drawKochCurve(g2d, getWidth() / 3, -Math.PI / 2, iteration); } else if ("Tree".equals(fractalType)) { drawFractalTree(g2d, 100, -Math.PI / 2, iteration); } } private void drawKochCurve(Graphics2D g2d, double length, double angle, int iter) { if (iter == 0) { AffineTransform at = AffineTransform.getRotateInstance(angle, 0, 0); Line2D line = new Line2D.Double(0, 0, length, 0); Graphics2D draw = g2d.draw(at.createTransformedShape(line)); } else { double newLength = length / 3.0; drawKochCurve(g2d, newLength, angle, iter - 1); drawKochCurve(g2d, newLength, angle - Math.PI / 3, iter - 1); drawKochCurve(g2d, newLength, angle + Math.PI / 3, iter - 1); drawKochCurve(g2d, newLength, angle, iter - 1); } } private void drawFractalTree(Graphics2D g2d, double length, double angle, int iter) { if (iter == 0) return; AffineTransform at = AffineTransform.getRotateInstance(angle, 0, 0); Line2D line = new Line2D.Double(0, 0, 0, -length); g2d.draw(at.createTransformedShape((Shape) line)); drawFractalTree(g2d, length * 0.7, angle - Math.PI / 6, iter - 1); // 左分支 drawFractalTree(g2d, length * 0.7, angle + Math.PI / 6, iter - 1); // 右分支 } @Override public void actionPerformed(ActionEvent e) { repaint(); // 每次定时器触发重新绘制 } public static void main(String[] args) { SwingUtilities.invokeLater(FractalTreeSimulator::new); } private static class Line2D { public Line2D() { } private static class Double extends Line2D { public Double(int i, int i0, int i1, double d) { } } } }修改代码使得能够在netbeans8.2上运行项目名称为202205002164何鑫
06-17
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值