Related
I'm trying to create a section of a page in EPS and then have that portion of EPS be imported into my PS document at a specific location using Tools for Adobe Postscript: https://xmlgraphics.apache.org/commons/postscript.html
So far I've got a basic generation for the postscript file, and I want to add EPS to it. Here's a pseudo version of what I'd like to do.
OutputStream out = new java.io.FileOutputStream(outputFile);
out = new java.io.BufferedOutputStream(out);
try {
//Instantiate the PSDocumentGraphics2D instance
PSDocumentGraphics2D g2d = new PSDocumentGraphics2D(false);
g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
EPSDocumentGraphics2D eg2d = new EPSDocumentGraphics2D(false);
eg2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
//Set up the document size
g2d.setupDocument(out, pageWidthPT, pageHeightPT);
eg2d.setupDocument(out, 400, 200); //400pt x 200pt
g2d.setFont(new Font(font, Font.PLAIN, fontSize));
//Paint a bounding box
eg2d.drawRect(0, 0, 400, 200);
//A few rectangles rotated and with different color
Graphics2D copy = (Graphics2D)eg2d.create();
int c = 12;
for (int i = 0; i < c; i++) {
float f = ((i + 1) / (float)c);
Color col = new Color(0.0f, 1 - f, 0.0f);
copy.setColor(col);
copy.fillRect(70, 90, 50, 50);
copy.rotate(-2 * Math.PI / (double)c, 70, 90);
}
copy.dispose();
//Some text
eg2d.rotate(-0.25);
eg2d.setColor(Color.RED);
eg2d.setFont(new Font("sans-serif", Font.PLAIN, 36));
eg2d.drawString("Hello world!", 140, 140);
eg2d.setColor(Color.RED.darker());
//Cleanup
eg2d.finish();
g2d.insertEPS(eg2d, 0,0); // something like this?
g2d.nextPage();
g2d.drawString("Hello World!", 10, 20);
g2d.finish();//Cleanup
} finally {
IOUtils.closeQuietly(out);
}
If you know how to accomplish this goal I would appreciate some enlightenment. Thanks.
I have a polygon with the vertices (0,0), (100,0), (100,100), and (0,100).
I debugged the program and those are the exact lines that java is drawing.
Instead of drawing an exact square, some of the lines are a pixel too long:
http://gyazo.com/7418546c51c9a10fc690b18afcc96360.png
(The green circle is just me testing the centroid).
When I move the square out of the corner, you can see that the top left corner is the only corner that is exactly correct.
Why is this happening?
Right before drawLine, I wrote the lines to the console after they were converted to integer coordinates, and they were correct. So I can't see what could possibly be wrong except for the drawLine functions.
drawLine:
g.drawLine((int) line.getStart().getX(), (int) line.getStart().getY(),
(int) line.getEnd().getX(), (int) line.getEnd().getY());
The line has a start vector and an end vector. The vectors contain an x and y.
Even when doing this:
g.drawLine(0, 0, 100, 0);
g.drawLine(100, 0, 100, 100);
g.drawLine(100, 100, 0, 100);
g.drawLine(0, 100, 0, 0);
It still produces the same result.
This works though:
g.drawLine(0, 0, 100, 0);
g.drawLine(101, 0, 101, 100);
g.drawLine(100, 101, 0, 101);
g.drawLine(0, 100, 0, 0);
The example you provided is working:
BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.fillRect(0, 0, bi.getWidth(), bi.getHeight());
g.setColor(Color.red);
g.translate(50, 50);
g.drawLine(0, 0, 100, 0);
g.drawLine(100, 0, 100, 100);
g.drawLine(100, 100, 0, 100);
g.drawLine(0, 100, 0, 0);
JOptionPane.showMessageDialog(null, new ImageIcon(bi));
There is a bug https://bugs.openjdk.java.net/browse/JDK-8049901 that describes one possible issue.
I am trying to create a program that solves the popular Towers of Hanoi game. I have succeeded in printing the disks and pegs, but I want the disks to print with a delay. For example, I want disk 7 to print, then disk 6 to print 1 second later. I tried this by putting it to sleep, but all it does is delay the whole frame from displaying, how do I make it display the shape with a delay. I have attached my code, thanks for any help!
package towersofhanoi;
import javax.swing.*;
import java.awt.*;
/*g.fillOval(60 = horizontal distance , 540= vertical distance, 400 = width, 60 = height) */
public class TowersOfHanoi extends JPanel {
public static void main(String[]args){
//Print the shapes and frame
TowersOfHanoi drawRectangle = new TowersOfHanoi();
JFrame frame = new JFrame("Towers of Hanoi");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawRectangle);
frame.setSize(1250, 800);
frame.setVisible(true);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Color pegs = new Color (251, 129, 56);
g.setColor(pegs);
//peg 1
g.fillRect(250, 300, 25, 450);
//peg 2
g.fillRect(600, 300, 25, 450);
//peg 3
g.fillRect(950, 300, 25, 450);
//bottom
g.fillRect(200, 700, 825, 50);
//create a color for circles
Color circles = new Color (176,56, 251);
//cirle 7 (Labeled from bottom to top)
g.setColor(circles);
g.fillOval(60, 640, 400, 60);
g.setColor(Color.BLACK);
g.drawOval(60, 640, 400, 60);
try {
Thread.sleep(1000);
}
catch (InterruptedException ie) {
}
//circle 6
g.setColor(circles);
g.fillOval(85, 580, 350, 60);
g.setColor(Color.BLACK);
g.drawOval(85, 580, 350, 60);
try {
Thread.sleep(1000);
}
catch (InterruptedException ie) {
}
//circle 5
g.setColor(circles);
g.fillOval(110, 520, 300, 60);
g.setColor(Color.BLACK);
g.drawOval(110, 520, 300, 60);
//circle 4
g.setColor(circles);
g.fillOval(135, 465, 250, 55);
g.setColor(Color.BLACK);
g.drawOval(135, 465, 250, 55);
//circle 3
g.setColor(circles);
g.fillOval(160, 420, 200, 45);
g.setColor(Color.BLACK);
g.drawOval(160, 420, 200, 45);
//circle 2
g.setColor(circles);
g.fillOval(185, 380, 150, 40);
g.setColor(Color.BLACK);
g.drawOval(185, 380, 150, 40);
//circle 1
g.setColor(circles);
g.fillOval(210, 345, 100, 35);
g.setColor(Color.BLACK);
g.drawOval(210, 345, 100, 35);
}
}
My recommendation
separate out drawing in paintComponent() into the 3 constitute parts, these were previously separated by sleep statements
Use state inside the TowersOfHanoi object to control what should be drawn, I've used a simple counter
Use javax.swing.Timer to update the counter and request a repaint.
Notes
You cannot sleep on the UI thread. Swing is single threaded and this would stop events being processed.
javax.swing.Timer automatically fires the callback you give it on the UI thread.
paintComponent() can be called multiple times if windows are resized etc, therefore it is important to make it independent, hence my use of a counter.
Working example
public class TowersOfHanoi extends JPanel {
private int clock = 0;
private Color circles = new Color(176, 56, 251);
public static void main(String[] args) {
// Print the shapes and frame
TowersOfHanoi drawRectangle = new TowersOfHanoi();
JFrame frame = new JFrame("Towers of Hanoi");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawRectangle);
frame.setSize(1250, 800);
frame.setVisible(true);
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
drawRectangle.nextFrame();
drawRectangle.repaint();
}
});
timer.setRepeats(true);
timer.start();
}
public void nextFrame() {
clock++;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
frame1(g);
if (clock >= 1) {
frame2(g);
}
if (clock >= 2) {
frame3(g);
}
}
private Color frame1(Graphics g) {
Color pegs = new Color(251, 129, 56);
g.setColor(pegs);
// peg 1
g.fillRect(250, 300, 25, 450);
// peg 2
g.fillRect(600, 300, 25, 450);
// peg 3
g.fillRect(950, 300, 25, 450);
// bottom
g.fillRect(200, 700, 825, 50);
// create a color for circles
// cirle 7 (Labeled from bottom to top)
g.setColor(circles);
g.fillOval(60, 640, 400, 60);
g.setColor(Color.BLACK);
g.drawOval(60, 640, 400, 60);
return circles;
}
private void frame2(Graphics g) {
// circle 6
g.setColor(circles);
g.fillOval(85, 580, 350, 60);
g.setColor(Color.BLACK);
g.drawOval(85, 580, 350, 60);
}
private void frame3(Graphics g) {
// circle 5
g.setColor(circles);
g.fillOval(110, 520, 300, 60);
g.setColor(Color.BLACK);
g.drawOval(110, 520, 300, 60);
// circle 4
g.setColor(circles);
g.fillOval(135, 465, 250, 55);
g.setColor(Color.BLACK);
g.drawOval(135, 465, 250, 55);
// circle 3
g.setColor(circles);
g.fillOval(160, 420, 200, 45);
g.setColor(Color.BLACK);
g.drawOval(160, 420, 200, 45);
// circle 2
g.setColor(circles);
g.fillOval(185, 380, 150, 40);
g.setColor(Color.BLACK);
g.drawOval(185, 380, 150, 40);
// circle 1
g.setColor(circles);
g.fillOval(210, 345, 100, 35);
g.setColor(Color.BLACK);
g.drawOval(210, 345, 100, 35);
}
}
Have you tried using Caldender() or System.currentTimeMillis()? If you do, you can get the current time. After you have gotten the time, do a while loop to check what the time is now. When you do LastTime - Now, to check how much time has passed.
This code is not tested, (But it should work).
long lastTime = System.currentTimeMillis();
while(true){
long now = System.currentTimeMillis();
if(lastTime - now == [YOUR PREFFERD WAITING TIME IN MS]){
break;
}
}
And now draw your graphics.
You should probably restructure you code so that paint component draws the current state of the system of pegs and rings. Then use a Swing timer to call a method that moves the state of the system then calls repaint().
I am doing this small race between two cars, in a java applet.
Just two pictures moving at random speed. I am calculating the distance between current position and the finish line, and you are suppose to be able to see the distance in the upper corner.
The thing is I am not able to refresh the text field, instead it just applies a new layer on top of the old number so it is almost impossible to read.
Here are pictures to demonstrate my problem.
I thought I would be able to solve it by creating the blue rectangle at the start of each loop but that does not seem to solve it.
public void action(){
Random rand = new Random();
boolean race = true;
int x1 =500, y1 = 233;
int x2 = 500, y2 = 333;
int speed1 = rand.nextInt(15) + -16;
int speed2 = rand.nextInt(15) + -16;
int finishline = 30;
Text winnerBlue = new Text("Winner: BLUE",new Font("SansSerif",Font.BOLD,20), Color.blue,Color.white);
Text winnerRed = new Text("Winner: RED",new Font("SansSerif",Font.BOLD,20), Color.red,Color.white);
//background
Text text =null;
Text text2 = null;
window.fillRect(0, 0, 600, 400, Color.GREEN);
//track 1
window.fillRect(20, 330, 550, 39, Color.gray);
//track2
window.fillRect(20, 230, 550, 39, Color.gray);
//Finish line
window.fillRect(40, 210, 10, 180, Color.BLACK);
while(race){
text = new Text(Integer.toString(x1),new Font("Courier",Font.BOLD,20), Color.WHITE);
text2 = new Text(Integer.toString(x2),new Font("SansSerif",Font.BOLD,20), Color.WHITE);
window.fillRect(0, 0, 70, 50, Color.blue);
window.fillRect(70, 0, 70, 50, Color.red);
window.showImage(text, 0, 0);
window.showImage(text2, 70, 0);
window.showImage(car1.getImage(), x1, y1);
window.showImage(car2.getImage(), x2, y2);
car1.moveTo(x1 += speed1, y1);
car2.moveTo(x2 += speed2, y2);
window.pause(50);
if(x1 <= (finishline ) ){
speed1 = 0;
speed2 = 0;
window.showImage(winnerBlue, 200, 200);
race = false;
}
if(x2 <= (finishline)){
speed2 = 0;
speed1 = 0;
window.showImage(winnerRed, 200, 200);
race = false;
}
}
}
}
For the two screen shots and supplied code snippt, it's clear that you don't understand how painting works in Swing/AWT.
Do NOT ever, maintain any kind of refernce to the Graphics context out side of the paintXxx methods.
The paint methods perform a number of very important steps to prepare the Graphics context for painting
Start by taking a look through Performing Custom Painting
Could anyone share with me why I am getting this error? Basically it's a program where I want to simulate basic basic plant growth. I want to do it in such a way that the petals are all stored in an array of circles.
Stem myStem;
Circle circles;
float scaleFactor=0.5;
void setup() {
size(floor(400*scaleFactor), floor(800*scaleFactor));
myStem = new Stem(200,800);
}
void draw() {
background(150);
smooth();
Circle circles[];
circles = new Circle[5];
circles[0] = new Circle(0, -40, 50, 50);
circles[1] = new Circle(0, -40, 50, 50);
circles[2] = new Circle(0, -40, 50, 50);
circles[3] = new Circle(0, -40, 50, 50);
circles[4] = new Circle(0, -40, 50, 50);
for (int i = 0; i < circles.length; i++) {
circles = ellipse(circles[i].c1, circles[i].c2, circles[i].c3, circles[i].c4);
rotate(radians(72));
circles[i] = Circle;
}
myStem.drawStem();
}
class Stem {
int initalloX=200;
int initalloY=800;
Stem(int tempInitalloX, int tempInitalloY) {
initalloX = tempInitalloX;
initalloY = tempInitalloY;
}
void drawStem() {
background(#0DBADB);
scale(scaleFactor, scaleFactor);
stroke (12, 149, 11);
fill (12, 149, 11);
strokeWeight(10);
line(initalloX, initalloY, initalloX, ((frameCount>250)?initalloY-500:initalloY-(2*frameCount)));
//stem1
if (frameCount>101) {
noStroke();
translate(initalloX, initalloY-200);
scale(min((float)(frameCount-100)/100, 1), min((float)(frameCount-100)/100, 1));
beginShape();
vertex(0, 0);
bezierVertex(-40, -5, -30, -40, -80, -20);
bezierVertex(-47, -16, -52, 8, 0, 0);
endShape(CLOSE);
scale(1/min((float)(frameCount-100)/100, 1), 1/min((float)(frameCount-100)/100, 1));
translate(-initalloX, -(initalloY-200));
}
//stem2
if (frameCount>151) {
noStroke();
translate(initalloX, initalloY-300);
scale(-min((float)(frameCount-150)/150, 1), min((float)(frameCount-150)/150, 1));
beginShape();
vertex(0, 0);
bezierVertex(-40, -5, -30, -40, -80, -20);
bezierVertex(-47, -16, -52, 8, 0, 0);
endShape(CLOSE);
scale(-1/min((float)(frameCount-150)/150, 1), 1/min((float)(frameCount-150)/150, 1));
translate(-initalloX, -(initalloY-300));
}
}
}
class Circle {
int c1 = 0;
int c2 = -40;
int c3 = 50;
int c4 = 50;
Circle(int tc1, int tc2, int tc3, int tc4) {
c1 = tc1;
c2 = tc2;
c3 = tc3;
c4 = tc4;
}
}
Thanks in advance... All help is much appreciated.
Besides all thing already pointed, note that ellipse() is a void method, and so, it won't return anything. Thus a line like
circle = ellipse(x,y,z,z)
has no meaning. You probably wan to use the values stored in ciclcle[i] to draw ellipses, so just call
ellipse(circles[i].c1, circles[i].c2, circles[i].c3, circles[i].c4);
no need for assigning it. Also i don't see why create 5 equal circles. If your circle object is just storing data, why store the same data five times? The call:
for (int i = 0; i < circles.length; i++) {
ellipse(0, -40, 50, 50);
rotate(radians(72));
}
Will have the same effect.
Besides that calling background() at the end of draw (trough myStem.drawStem()) will hide all things previously drawn.
And yet there is no need to recreate the array and reassign the values 60 times per second, you can move it to setup.
I made those changes to your code. It will compile now. Still the "petals" is beeing drawn at origin, and the fill/stroke of them needs to be handled, but at least it is running :)
You may want to make a display method in your circle class... More like i pointed in the other post you made. cheers!
Stem myStem;
//Circle circles; // double declaration
Circle circles[]; // keeping the array one only
float scaleFactor=0.5;
void setup() {
size(floor(400*scaleFactor), floor(800*scaleFactor));
myStem = new Stem(200,800);
//mpoved this to setup, no need to recreate each frame
circles = new Circle[5];
circles[0] = new Circle(0, -40, 50, 50);
circles[1] = new Circle(0, -40, 50, 50);
circles[2] = new Circle(0, -40, 50, 50);
circles[3] = new Circle(0, -40, 50, 50);
circles[4] = new Circle(0, -40, 50, 50);
// also smooth only needs to be called once
// unless ther is a noSmooth() somewhere
smooth();
}
void draw() {
// moved this here
background(#0DBADB);
for (int i = 0; i < circles.length; i++) {
ellipse(circles[i].c1, circles[i].c2, circles[i].c3, circles[i].c4);
// note you may use this instead
//ellipse(0, -40, 50, 50);
rotate(radians(72));
}
myStem.drawStem();
}
class Stem {
int initalloX=200;
int initalloY=800;
Stem(int tempInitalloX, int tempInitalloY) {
initalloX = tempInitalloX;
initalloY = tempInitalloY;
}
void drawStem() {
//background(#0DBADB); // this was hiding all other draws
scale(scaleFactor, scaleFactor);
stroke (12, 149, 11);
fill (12, 149, 11);
strokeWeight(10);
line(initalloX, initalloY, initalloX, ((frameCount>250)?initalloY-500:initalloY-(2*frameCount)));
//stem1
if (frameCount>101) {
noStroke();
translate(initalloX, initalloY-200);
scale(min((float)(frameCount-100)/100, 1), min((float)(frameCount-100)/100, 1));
beginShape();
vertex(0, 0);
bezierVertex(-40, -5, -30, -40, -80, -20);
bezierVertex(-47, -16, -52, 8, 0, 0);
endShape(CLOSE);
scale(1/min((float)(frameCount-100)/100, 1), 1/min((float)(frameCount-100)/100, 1));
translate(-initalloX, -(initalloY-200));
}
//stem2
if (frameCount>151) {
noStroke();
translate(initalloX, initalloY-300);
scale(-min((float)(frameCount-150)/150, 1), min((float)(frameCount-150)/150, 1));
beginShape();
vertex(0, 0);
bezierVertex(-40, -5, -30, -40, -80, -20);
bezierVertex(-47, -16, -52, 8, 0, 0);
endShape(CLOSE);
scale(-1/min((float)(frameCount-150)/150, 1), 1/min((float)(frameCount-150)/150, 1));
translate(-initalloX, -(initalloY-300));
}
}
}
class Circle {
int c1 = 0;
int c2 = -40;
int c3 = 50;
int c4 = 50;
Circle(int tc1, int tc2, int tc3, int tc4) {
c1 = tc1;
c2 = tc2;
c3 = tc3;
c4 = tc4;
}
}
Learned something new I guess for declaring an array.
As for what is going wrong, it looks like you're using a Circle variable called "circle" and confusing it with an array of Circles by also calling it circle which probably is leading to all sorts of problems. That's probably what you should focus on fixing.
Guessing...
There are two definitions of circles in the class
Circle circles
Circle[] circles
I think this circles[i] = Circle; is the error. You cannot asign a Type (the class Circle) to a variable (i.e. an Object or an instance of a class)