Java: Drawing a Star from a Polygon Circle w/Point Connections - java

So, I have been working on this program for drawing a star from a circle created using g.fillPolygon(int, int, int). I was intially having issues with creating an entire circle, but changed double angle = (i * 360) to (i * 720) to fix that (may be a band-aid fix, not sure yet). Now I'm in the process of attempting to connect all the points together (as shown in the "Target Output" section).
Note: I believe that the labeling of the points shown in the modification section was not done wih Java.
My Code: (Where I'm at right now)
import java.awt.*;
public class StarSampler {
public static void main(String[] args)
{
DrawingPanel panel = new DrawingPanel(500, 500);
Graphics2D g = panel.getGraphics();
g.setColor(Color.YELLOW);
fillStar(g, 250, 250, 150, 50, .7);
}
public static void fillStar(Graphics2D g, int ctrX, int ctrY, int radius, int nPoints, double spikiness)
{
double xDouble[] = new double[2*nPoints];
double yDouble[] = new double[2*nPoints];
int xPoint[] = new int[100];
int yPoint[] = new int[100];
for (int i = 0; i < 2*nPoints; i++)
{
double iRadius = (i % 2 == 0) ? radius : (radius * spikiness);
double angle = (i * 720.0) / (2*nPoints);
xDouble[i] = ctrX + iRadius * Math.cos(Math.toRadians(angle));
yDouble[i] = ctrY + iRadius * Math.sin(Math.toRadians(angle));
for (int j = 0; j < nPoints; j++) // Casts for ints and doubles
{
xPoint[j] = (int) xDouble[j];
yPoint[j] = (int) yDouble[j];
}
}
g.fillPolygon(xPoint, yPoint, nPoints); // Creates polygon but
}
}
My Code's Output:
Target Output (What I'm generally aiming for, not both together):

Related

Using for loop to make multiple drawLine shapes [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am making a star using a draw line. I want to run a for loop to expand a star into multiple stars in a grid-like pattern. I am fairly new to java and could use some help with my code. The gride pattern that I would like the stars to open up too isn't too specific as far as columns x rows go. even making 6 stars or 9 stars is fine, as long as they are in a grid-like pattern.
So far, I have the star drawn with drawLine. At one point I got two stars but they were to close to each other. When I run the code it looks like I have a whole bunch of stars sort of staggered on top of each other and being able to get two stars on Star Field, I would like to get more in such 5x6 pattern or something close. I believe I might be having a hard time computing the math in the for loops to get this to happen.
Should I run, multiple nested for loops or is there a way to do this with using a minimal amount of for loops?
public static void drawFlag(int stars, int stripes, java.awt.Graphics
g, int x, int y, int width, int height) {
// Sets backround rectangle color to white
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
// Draw filled red rectangles *stripes*
int stripeHeight = height/stripes;
g.setColor(Color.RED);
int lastStripeDrawnY = 0;
// For loop runs red stripes
for (int i = y; i < y + height - 2*stripeHeight; i = i + 2*stripeHeight)
{
g.fillRect(x, i, width, stripeHeight);
lastStripeDrawnY = i;
}
// expands strips across the rectangle
int lastStripeY = lastStripeDrawnY+2*stripeHeight;
int lastStripeHeight = y + height - lastStripeY;
if (stripes%2 != 0) {
g.fillRect(x, lastStripeY, width, lastStripeHeight);
}
int stars1 = 15;
for (int cols = 1; cols <= stars1; cols++) {
int rows = stars1/cols;
if (cols > rows && cols <2*rows && cols*rows == stars1) {
}
}
// Draws the starField
int numberOfRedStripes = (int)Math.ceil(stripes/2.0);
int starFieldHeight = numberOfRedStripes*stripeHeight;
int starFieldWidth = starFieldHeight*width/height;
g.setColor(Color.BLUE);
g.fillRect(x, y, starFieldWidth, starFieldHeight);
for (int x1 = 0; x1+100 <+ starFieldWidth-5; x1++) {
if(x1/5*4 == stars) {
drawStar(g,x1,y,50);
for(int y1 = 0; y1 <=starFieldHeight-5;y1++) {
if(y1/4*2 == stars) {
drawStar(g,x,y1,50);
}
}
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.setColor(Color.WHITE);
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}
Expand one star into a checkered grid-like pattern.
There are a number of ways you can approach this problem, you can, as you've started, simply try and build each star individually based on the required x/y position.
You could make a single star that was always at 0x0 and translate the Graphics context to the desire x/y position
Or, you could take advantage of the Shape API.
This allows you to define a self contained object which describes the shape you are trying to create.
public class StarShape extends Path2D.Double {
public StarShape(double size) {
double mid = size / 2d;
moveTo(mid, 0);
lineTo((size * 0.6d), (size * 0.4d));
lineTo(size, (size * 0.4d));
lineTo((size * 0.72d), (size * 0.58d));
lineTo((size * 0.85d), size);
lineTo((size * 0.5d), (size * 0.72d));
lineTo((size * 0.2), size);
lineTo((size * 0.325d), (size * 0.58d));
lineTo(0, (size * 0.4d));
lineTo((size * 0.4d), (size * 0.4d));
closePath();
}
}
There are lots of side benefits to this, but the immediate benefit is that it's "paintable". You can pass an instance of it directly to Graphics2D and have it painted and/or filled based on your needs.
Now, with that in hand, you can do something like...
public class TestPane extends JPanel {
private StarShape star;
private double starSize = 10;;
public TestPane() {
star = new StarShape(starSize);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
PathIterator path = star.getPathIterator(at);
GeneralPath p = new GeneralPath();
p.append(path, true);
g2d.fill(p);
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
}
The reason I'd prefer this method, is it doesn't affect the origin of the original starShape. You could also use the technique to cache the results, so you're not repeatedly doing it in the paintComponent method.
You could also do something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
Graphics2D starg = (Graphics2D) g2d.create();
starg.translate(x, y);
starg.fill(star);
starg.dispose();
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
Which changes the origin of the Graphics context instead or something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double xCount = getWidth() / starSize;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
g2d.fill(star);
star.transform(AffineTransform.getTranslateInstance(starSize, 0));
}
star.transform(AffineTransform.getTranslateInstance(-(starSize) * xCount, starSize));
}
g2d.dispose();
}
which changes the origin of the star itself.
Personally, I prefer not to affect the original and instead simply change the context in how it's painted, but which method you use will come down to your needs.
Okay, that might seem like a lot of work for little gain, but the Shapes API is extremely powerful. Because it's point based (instead of pixel based), it can be more easily resized, without generating pixilation. It's very simple to rotate, through the use of AffineTransform and makes for a much simpler point of re-use.
Want to make the stars bigger? Simply change starStar, for example...
private double starSize = 50;
and the API takes care of the rest...
I used your drawStar() function and built this StarPanel. Try it and see if it gives you some hints for what you are trying to achieve.
Note that I removed g.setColor(Color.WHITE); line from your drawStar() function. We need to be careful when we set color of Graphics object. In many cases, this is the reason why we don't see what we draw.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
public class StarPanel extends JPanel
{
private int xStarting;
private int yStarting;
private int numberOfRows;
private int numberOfColumns;
private int xDisplacement;
private int yDisplacement;
public StarPanel(int xStarting, int yStarting,
int numberOfRows, int numberOfColumns,
int xDisplacement, int yDisplacement)
{
this.xStarting = xStarting;
this.yStarting = yStarting;
this.numberOfRows = numberOfRows;
this.numberOfColumns = numberOfColumns;
this.xDisplacement = xDisplacement;
this.yDisplacement = yDisplacement;
}
public static void main(String[] args)
{
StarPanel starPanel = new StarPanel(50, 50, 5, 6, 75, 75);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(starPanel);
frame.setBounds(300, 200, 500, 600);
frame.setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int row = 0; row < numberOfRows; row++) {
for (int column = 0; column < numberOfColumns; column++) {
drawStar(g, xStarting + (row * xDisplacement), yStarting + (column * yDisplacement), 50);
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}

Java Code not working. Using loops to draw stripes on the US Flag

I am attempting to draw the US flag using java. I have pretty much done all this coding using lots of variables. It should be at least displaying the stripes, blue box, and the stars(ovals in this case). However, when I run the code through the compiler, and run it, all it displayes is a white background with a red stripe on the top. Could I please receive some help to see where my error is? I have tried everything.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class UsFlag extends JPanel {
int w = getWidth();
int h = getHeight();
int numberStripes = 13;
int numStarCol = 8;
int numStarRow = 6;
int stripeHeight = h/numberStripes;
int boxWidth = (int)(w*0.4);
int boxHeight = 7 * stripeHeight;
int starWidth = boxWidth/numStarCol;
int starHeight = boxHeight/numStarRow;
/*public UsFlag() {
//ask user to enter number of stripes, star columns, and star rows
}*/
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
//Background
g.setColor(Color.RED);
g.fillRect(0, 0, w, h);
//Stripes
g.setColor(Color.WHITE);
for (int i = 0; i < numberStripes; i += 1) {
g.fillRect(0,stripeHeight, w, stripeHeight);
stripeHeight = stripeHeight + 45;
}
//Blue Rect
g.setColor(Color.BLUE);
g.fillRect(0, 0, boxWidth, boxHeight);
//stars
int y = 0;
int x = 0;
for (int j = 0; j < numStarRow; j++){
for (int i = 0; i < numStarCol; i++){
g.setColor(Color.WHITE);
g.fillOval(5, 5, starWidth, starHeight);
x += starWidth;
}
y += starHeight;
x = 0;
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 400);
window.setContentPane(new UsFlag());
window.setVisible(true);
}
}
The first two parameters for the fillRect() method and the fillOval() method are considered coordinates (x & y) for the object you want to paint. This means that for x you need to place a integer pixel value as to where you want the Left edge of the object is to Start being painting from along the horizontal plain, and for y you need to place a integer pixel value as to where you want the Top edge of the object is to Start being painting from along the vertical plain. For fillRect() for example:
g.fillRect(20, 20, 100, 30);
The other two parameters are for the Width (w) and Height (h) in pixels of the object to paint. Use the the variable i from your for loop (y = i + 30; for example) to draw objects below one another. Read this for more information.

How to fit small cubes into a given volume and represent it graphically on a web page?

My query is to show programmatically, the fitting of many given non regular (but rectangular) cubes (i.e. boxes) of individually different sizes, inside a larger volume cube, such as a storage unit.
The mathematics part is understood. Like in Linear programming / linear algebra, we can add fit volume of all smaller cubes to find out the best fit for the volume of the larger cube.
The actual requirement is to show or allow this fitting graphically on a web-page, preferably in 3d. If possible, to allow user to interact with the fitting, i.e. shuffling the placement of the cubes, etc.
Also, since I am a Java developer by profession, Java or related languages / frameworks would be my choice. However, I can use any other technology / framework / language if the end results are met.
NB: Weight is also a concern (parameter). There is a maximum weight which can be stacked in any given storage unit.
Also, since storage units can be accessed without permission (by thieves), cost of the cubes stacked in one unit is also limited. The user may desire to fit cubes of higher cost in one unit which has higher security and vice versa.
Example: allow fitting many rectangular boxes containing household electronics in a given room. The boxes maybe of TVs, refrigerators, washing machines, dishwashers, playstations, xbox 360s, etc. The different dimensions of these boxes, is to give you an idea of what to expect while fitting to the limited volume.
If there is any FOSS library / project (or even non FOSS library or project) for the same, a pointer towards it would be welcome.
Disclaimer: Okay, I know it does not 100% answer your question and also the code it veeery old (as can be concluded from the old-fashioned CVS comments) and today I would not write it that way anymore. It does still run on Java 8, though, I tested it. But in addition to solving the little informatics challenge problem of water flowing through a 3D matrix of cuboids from top to bottom depending how "leaky" the matrix (symbolising some kind of Swiss cheese) is, it also uses some very simple 3D visualisation via Java 3D. Thus, you need to install Java 3D and put the corresponding libraries onto your classpath.
The 3D output looks something like this:
package vhs.bwinfo.cheese;
// $Id: Cuboid.java,v 1.1.2.1 2006/01/10 19:48:41 Robin Exp $
import javax.media.j3d.Appearance;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3f;
public class Cuboid extends Shape3D {
private static final float POS = +0.5f;
private static final float NEG = -0.5f;
private static final Point3f[] POINTS = new Point3f[] {
new Point3f(NEG, NEG, NEG),
new Point3f(POS, NEG, NEG),
new Point3f(POS, NEG, POS),
new Point3f(NEG, NEG, POS),
new Point3f(NEG, POS, NEG),
new Point3f(POS, POS, NEG),
new Point3f(POS, POS, POS),
new Point3f(NEG, POS, POS)
};
private static final TexCoord2f[] TEX_COORDS = new TexCoord2f[] {
new TexCoord2f(0, 1),
new TexCoord2f(1, 1),
new TexCoord2f(1, 0),
new TexCoord2f(0, 0)
};
private static final int VERTEX_FORMAT =
QuadArray.COORDINATES |
QuadArray.NORMALS |
QuadArray.TEXTURE_COORDINATE_2;
public Cuboid(float scaleX, float scaleY, float scaleZ) {
Point3f[] points = new Point3f[8];
for (int i = 0; i < 8; i++)
points[i] = new Point3f(
POINTS[i].x * scaleX,
POINTS[i].y * scaleY,
POINTS[i].z * scaleZ
);
Point3f[] vertices = {
points[3], points[2], points[1], points[0], // bottom
points[4], points[5], points[6], points[7], // top
points[7], points[3], points[0], points[4], // left
points[6], points[5], points[1], points[2], // right
points[7], points[6], points[2], points[3], // front
points[5], points[4], points[0], points[1] // back
};
QuadArray geometry = new QuadArray(24, VERTEX_FORMAT);
geometry.setCoordinates(0, vertices);
for (int i = 0; i < 24; i++)
geometry.setTextureCoordinate(0, i, TEX_COORDS[i % 4]);
Vector3f normal = new Vector3f();
Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f();
Point3f[] pts = new Point3f[4];
for (int i = 0; i < 4; i++)
pts[i] = new Point3f();
for (int face = 0; face < 6; face++) {
geometry.getCoordinates(face * 4, pts);
v1.sub(pts[0], pts[2]);
v2.sub(pts[1], pts[3]);
normal.cross(v1, v2);
normal.normalize();
for (int i = 0; i < 4; i++)
geometry.setNormal((face * 4 + i), normal);
}
setGeometry(geometry);
setAppearance(new Appearance());
}
public Cuboid(float scaleFactor) {
this(scaleFactor, scaleFactor, scaleFactor);
}
}
package vhs.bwinfo.cheese;
// $Id: LeakyCheese.java,v 1.2.2.2 2006/01/10 15:37:14 Robin Exp $
import com.sun.j3d.utils.applet.JMainFrame;
import javax.swing.*;
import java.util.Random;
import static java.lang.System.out;
public class LeakyCheese {
private int width = 20, height = 20, depth = 20;
private int numClasses = 100, samplesPerClass = 100;
private double pMin = 0, pMax = 1;
private double pDiff = pMax - pMin;
private double classSize = pDiff / numClasses;
private int[] stats;
enum CubeState {CHEESE, AIR, WATER}
final private CubeState[][][] cheese;
private static final Random RND = new Random();
public LeakyCheese(
int width, int height, int depth,
int numClasses, int samplesPerClass,
double pMin, double pMax
) {
this.width = width;
this.height = height;
this.depth = depth;
this.numClasses = numClasses;
this.samplesPerClass = samplesPerClass;
this.pMin = pMin;
this.pMax = pMax;
pDiff = pMax - pMin;
classSize = pDiff / numClasses;
cheese = new CubeState[width][height][depth];
}
public LeakyCheese(
int width, int height, int depth,
int numClasses, int samplesPerClass
) {
this(width, height, depth, numClasses, samplesPerClass, 0, 1);
}
public LeakyCheese() {
cheese = new CubeState[width][height][depth];
}
private boolean pourWater(int x, int y, int z) {
if (x < 0 || x >= width || y < 0 || y >= height || z < 0 || z >= depth)
return false;
if (cheese[x][y][z] != CubeState.AIR)
return false;
cheese[x][y][z] = CubeState.WATER;
boolean retVal = (y == 0);
retVal = pourWater(x + 1, y, z) || retVal;
retVal = pourWater(x - 1, y, z) || retVal;
retVal = pourWater(x, y + 1, z) || retVal;
retVal = pourWater(x, y - 1, z) || retVal;
retVal = pourWater(x, y, z + 1) || retVal;
retVal = pourWater(x, y, z - 1) || retVal;
return retVal;
}
private boolean isLeaky(double p) {
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
for (int z = 0; z < depth; z++)
cheese[x][y][z] = (RND.nextDouble() < p)
? CubeState.CHEESE
: CubeState.AIR;
boolean retVal = false;
for (int x = 0; x < width; x++)
for (int z = 0; z < depth; z++)
retVal = pourWater(x, height - 1, z) || retVal;
return retVal;
}
private void generateStats() {
if (stats != null)
return;
stats = new int[numClasses];
for (int i = 0; i < numClasses; i++) {
for (int j = 0; j < samplesPerClass; j++) {
double p = pMin + classSize * (RND.nextDouble() + i);
if (isLeaky(p))
stats[i]++;
}
}
}
public void printStats() {
generateStats();
out.println(
"p (cheese) | p (leaky)\n" +
"------------------+-----------"
);
for (int i = 0; i < numClasses; i++) {
out.println(
String.format(
"%1.5f..%1.5f | %1.5f",
pMin + classSize * i,
pMin + classSize * (i + 1),
(double) stats[i] / samplesPerClass
)
);
}
}
public static void main(String[] args) {
//new LeakyCheese().printStats();
//new LeakyCheese(40, 40, 40, 50, 100, 0.66, .71).printStats();
LeakyCheese cheeseBlock = new LeakyCheese(5, 20, 5, 20, 100);
//LeakyCheese cheeseBlock = new LeakyCheese(20, 20, 20, 20, 100);
while (!cheeseBlock.isLeaky(0.65))
;
out.println("*** required solution found - now rendering... ***");
JMainFrame f = new JMainFrame(new LeakyCheeseGUI(cheeseBlock.cheese), 512, 512);
f.setLocationRelativeTo(null);
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
package vhs.bwinfo.cheese;
// $Id: LeakyCheeseGUI.java,v 1.1.2.1 2006/01/10 15:25:18 Robin Exp $
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.SimpleUniverse;
import vhs.bwinfo.cheese.LeakyCheese.CubeState;
import javax.media.j3d.*;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import java.applet.Applet;
import java.awt.*;
import java.util.Random;
public class LeakyCheeseGUI extends Applet {
static final long serialVersionUID = -8194627556699837928L;
public BranchGroup createSceneGraph(CubeState[][][] cheese) {
// Create the root of the branch graph
BranchGroup bgRoot = new BranchGroup();
// Composite of two rotations around different axes. The resulting
// TransformGroup is the parent of all our cheese cubes, because their
// orientation is identical. They only differ in their translation
// values and colours.
Transform3D tRotate = new Transform3D();
Transform3D tRotateTemp = new Transform3D();
tRotate.rotX(Math.PI / 8.0d);
tRotateTemp.rotY(Math.PI / -4.0d);
tRotate.mul(tRotateTemp);
TransformGroup tgRotate = new TransformGroup(tRotate);
bgRoot.addChild(tgRotate);
// Bounding sphere for rendering
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
// Set background colour
// Note: Using Canvas3D.setBackground does not work, because it is an
// AWT method. Java 3D, though, gets its background colour from its
// background node (black, if not present).
Background background = new Background(0.5f, 0.5f, 0.5f);
background.setApplicationBounds(bounds);
bgRoot.addChild(background);
TransparencyAttributes transpAttr;
// Little cheese cubes
Appearance cheeseAppearance = new Appearance();
transpAttr =
new TransparencyAttributes(TransparencyAttributes.NICEST, 0.98f);
cheeseAppearance.setTransparencyAttributes(transpAttr);
cheeseAppearance.setColoringAttributes(
new ColoringAttributes(1, 1, 0, ColoringAttributes.NICEST));
PolygonAttributes pa = new PolygonAttributes();
//pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
pa.setCullFace(PolygonAttributes.CULL_NONE);
cheeseAppearance.setPolygonAttributes(pa);
// Little water cubes
Appearance waterAppearance = new Appearance();
transpAttr =
new TransparencyAttributes(TransparencyAttributes.NICEST, 0.85f);
waterAppearance.setTransparencyAttributes(transpAttr);
waterAppearance.setColoringAttributes(
new ColoringAttributes(0, 0, 1, ColoringAttributes.NICEST));
pa = new PolygonAttributes();
pa.setCullFace(PolygonAttributes.CULL_NONE);
waterAppearance.setPolygonAttributes(pa);
// Little air cubes
Appearance airAppearance = new Appearance();
transpAttr =
new TransparencyAttributes(TransparencyAttributes.NICEST, 0.95f);
airAppearance.setTransparencyAttributes(transpAttr);
airAppearance.setColoringAttributes(
new ColoringAttributes(1, 1, 1, ColoringAttributes.NICEST));
pa = new PolygonAttributes();
//pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
pa.setCullFace(PolygonAttributes.CULL_NONE);
airAppearance.setPolygonAttributes(pa);
// Water-coloured (i.e. blue) wire frame around cheese block, if leaky
Appearance waterWireFrameAppearance = new Appearance();
waterWireFrameAppearance.setColoringAttributes(
new ColoringAttributes(0, 0, 1, ColoringAttributes.NICEST));
pa = new PolygonAttributes();
pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
pa.setCullFace(PolygonAttributes.CULL_NONE);
waterWireFrameAppearance.setPolygonAttributes(pa);
// Cheese-coloured (i.e. yellow) wire frame around cheese block, if not leaky
Appearance cheeseWireFrameAppearance = new Appearance();
cheeseWireFrameAppearance.setColoringAttributes(
new ColoringAttributes(1, 1, 0, ColoringAttributes.NICEST));
pa = new PolygonAttributes();
pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
pa.setCullFace(PolygonAttributes.CULL_NONE);
cheeseWireFrameAppearance.setPolygonAttributes(pa);
// Absolute offsets for the cheese block to fit into the viewing canvas
final float xOffs = -0.8f;
final float yOffs = -0.55f;
final float zOffs = 0;
// Create all those little cubes ;-)
final int xSize = cheese.length;
final int ySize = cheese[0].length;
final int zSize = cheese[0][0].length;
final int maxSize = Math.max(xSize, Math.max(ySize, zSize));
final float xCenterOffs = 0.5f * (maxSize - xSize) / maxSize;
final float yCenterOffs = 0.5f * (maxSize - ySize) / maxSize;
final float zCenterOffs = -0.5f * (maxSize - zSize) / maxSize;
boolean isLeaky = false;
for (int x = 0; x < xSize; x++)
for (int y = 0; y < ySize; y++)
for (int z = 0; z < zSize; z++) {
Transform3D tTranslate = new Transform3D();
tTranslate.setTranslation(
new Vector3f(
xOffs + xCenterOffs + 1.0f * x / maxSize,
yOffs + yCenterOffs + 1.0f * y / maxSize,
zOffs + zCenterOffs - 1.0f * z / maxSize
)
);
TransformGroup tgTranslate = new TransformGroup(tTranslate);
tgRotate.addChild(tgTranslate);
Cuboid cube = new Cuboid(1.0f / maxSize);
switch (cheese[x][y][z]) {
case CHEESE:
cube.setAppearance(cheeseAppearance);
break;
case WATER:
cube.setAppearance(waterAppearance);
if (y == 0)
isLeaky = true;
break;
case AIR:
cube.setAppearance(airAppearance);
}
tgTranslate.addChild(cube);
}
// If cheese block is leaky, visualise it by drawing a water-coloured
// (i.e. blue) wire frame around it. Otherwise use a cheese-coloured
// (i.e. yellow) one.
Transform3D tTranslate = new Transform3D();
tTranslate.setTranslation(
new Vector3f(
xOffs + xCenterOffs + 0.5f * (xSize - 1) / maxSize,
yOffs + yCenterOffs + 0.5f * (ySize - 1) / maxSize,
zOffs + zCenterOffs - 0.5f * (zSize - 1) / maxSize
)
);
TransformGroup tgTranslate = new TransformGroup(tTranslate);
tgRotate.addChild(tgTranslate);
Cuboid cuboid = new Cuboid(
1.0f * xSize / maxSize,
1.0f * ySize / maxSize,
1.0f * zSize / maxSize
);
cuboid.setAppearance(isLeaky ? waterWireFrameAppearance : cheeseWireFrameAppearance);
tgTranslate.addChild(cuboid);
// Let Java 3D perform optimizations on this scene graph.
bgRoot.compile();
return bgRoot;
}
public LeakyCheeseGUI(CubeState[][][] cheese) {
// Create a simple scene and attach it to the virtual universe
GraphicsConfiguration graphCfg = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(graphCfg);
setLayout(new BorderLayout());
add(canvas, "Center");
SimpleUniverse universe = new SimpleUniverse(canvas);
// This will move the ViewPlatform back a bit so the objects
// in the scene can be viewed.
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(createSceneGraph(cheese));
}
public static void main(String[] args) {
final Random RND = new Random(System.currentTimeMillis());
CubeState[][][] testCheese = new CubeState[5][8][11];
for (int x = 0; x < 5; x++)
for (int y = 0; y < 8; y++)
for (int z = 0; z < 11; z++)
testCheese[x][y][z] = (RND.nextFloat() < 0.7f)
? CubeState.CHEESE
: (RND.nextBoolean() ? CubeState.WATER : CubeState.AIR);
// Applet can also run as a stand-alone application
new MainFrame(new LeakyCheeseGUI(testCheese), 512, 512);
}
}
You will probably want to use Javascript, and specifically WebGL. Javascript is the de facto language for interactive web pages, and WebGL is a Javascript API for rendering 2D and 3D scenes on an HTML5 canvas element. A solution using WebGL should be compatible with all major browsers. Programming even simple scenes in WebGL can be pretty involved though, so I'd recommend using a framework such as three.js to simplify things.
Here is an example of interactive, draggable cubes using three.js. Some of the key lines of code from that example are:
// create the cube
var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
// set coordinates, rotation, and scale of the cubes
object.position.x = ...
object.position.y = ...
object.position.z = ...
object.rotation.x = ...
object.rotation.y = ...
object.rotation.z = ...
object.scale.x = ...
object.scale.y = ...
object.scale.z = ...
// lighting stuff
object.castShadow = true;
object.receiveShadow = true;
// add to scene and list of objects
scene.add( object );
objects.push( object );
Again, the full, working example is found at this link (click view source on that page to view the code on github).

Java: Drawing "Random" Stars

I'm trying to take this code I finally got working for drawing one star and am confused on how to get it working for drawing 25 different stars (such as different sides and spikinness but I am unsure how to go about it exactly. I assume I would make a new random variable int randomStars = (int)(Math.random()*25+1); // Variable for 25 Random Stars to randomly generate the stars but I'm kind of confused where to take it from there.
I'd appreciate the help.
My Code (Using DrawingPanel.java):
import java.awt.*;
public class StarSampler {
public static void main(String[] args)
{
DrawingPanel panel = new DrawingPanel(500, 500);
Graphics2D g = panel.getGraphics();
g.setColor(Color.BLUE);
panel.setBackground(new Color(250, 0, 0));
fillStar(g, 250, 250, 150, 5, .3); // How to rotate it to start at center?
}
public static void fillStar(Graphics2D g, int ctrX, int ctrY, int radius, int nPoints, double spikiness)
{
double xDouble[] = new double[2*nPoints];
double yDouble[] = new double[2*nPoints];
int xPoint[] = new int[2*nPoints];
int yPoint[] = new int[2*nPoints];
nPoints = (int) (nPoints * 2);
int randomStars = (int)(Math.random()*25+1); // Variable for 25 Random Stars
// Would Nestest loop go here? for (randomStars++; randomStars < 25; randomStars++)
for (int i = 0; i < nPoints; i++)
{
double iRadius = (i % 2 == 0) ? radius : (radius * spikiness);
double angle = (270) + (i * 360.0) / (nPoints);
xPoint[i] = (int) (ctrX + iRadius * Math.cos(Math.toRadians(angle)));
yPoint[i] = (int) (ctrY + iRadius * Math.sin(Math.toRadians(angle)));
}
g.fillPolygon(xPoint, yPoint, nPoints); // Creates polygon
}
}
My Output:
Build up slowly. First concentrate on positioning two stars, just two. Pick the coordinates for the centre of the stars and place them. Adjust to get it right (your first attempt will probably have errors). Test, fix, test again, fix again. Repeat.
Then play with the spikiness and other changes so the stars aren't identical. When, and only when, that is tested and working move on to three, four etc. stars. With more stars you will have to be more careful to avoid overlaps.

How To Turn Main Code Into A Class (Snowfall)

I'm working on trying to use this free source code I found (http://solemone.de/demos/snow-effect-processing/) into a class that I can utilize within a larger, more complex "game" code. It's a pretty basic snow fall code:
int quantity = 15;
float [] xPosition = new float[quantity];
float [] yPosition = new float[quantity];
int [] flakeSize = new int[quantity];
int [] direction = new int[quantity];
int minFlakeSize = 10;
int maxFlakeSize = 20;
void setup() {
size(800, 350);
frameRate(30);
noStroke();
smooth();
for(int i = 0; i < quantity; i++) {
flakeSize[i] = round(random(minFlakeSize, maxFlakeSize));
xPosition[i] = random(0, width);
yPosition[i] = random(0, height);
direction[i] = round(random(0, 1));
}
}
void draw() {
background(0);
for(int i = 0; i < xPosition.length; i++) {
ellipse(xPosition[i], yPosition[i], flakeSize[i], flakeSize[i]);
if(direction[i] == 0) {
xPosition[i] += map(flakeSize[i], minFlakeSize, maxFlakeSize, .1, .5);
} else {
xPosition[i] -= map(flakeSize[i], minFlakeSize, maxFlakeSize, .1, .5);
}
yPosition[i] += flakeSize[i] + direction[i];
if(xPosition[i] > width + flakeSize[i] || xPosition[i] < -flakeSize[i] || yPosition[i] > height + flakeSize[i]) {
xPosition[i] = random(0, width);
yPosition[i] = -flakeSize[i];
}
}
}
I just haven't quite grasped on how to separate the for() loops, integers, and arrays into functions I can put into a separate class that I've titled Snow so that I can easily move it and manipulate it within the greater code. Here's one of my (many) attempts so far:
Class Tab:
class Snow{
int quantity = 15;
float [] xPosition = new float[quantity];
float [] yPosition = new float[quantity];
int [] flakeSize = new int[quantity];
int [] direction = new int[quantity];
int minFlakeSize = 10;
int maxFlakeSize = 20;
Snow(){
frameRate(30);
noStroke();
smooth();
}
void display() {
flakeSize = round(random(minFlakeSize, maxFlakeSize));
xPosition = random(0, width);
yPosition = random(0, height);
direction = round(random(0, 1));
}
void update() {
for(int i = 0; i < xPosition.length; i++) {
ellipse(xPosition[i], yPosition[i], flakeSize[i], flakeSize[i]);
if(direction[i] == 0) {
xPosition[i] += map(flakeSize[i], minFlakeSize, maxFlakeSize, .1, .5);
} else {
xPosition[i] -= map(flakeSize[i], minFlakeSize, maxFlakeSize, .1, .5);
}
yPosition[i] += flakeSize[i] + direction[i];
if(xPosition[i] > width + flakeSize[i] || xPosition[i] < -flakeSize[i] || yPosition[i] > height + flakeSize[i]) {
xPosition[i] = random(0, width);
yPosition[i] = -flakeSize[i];
}
}
}
}
Main Tab:
//Ice
Snow [] flakes = new Snow[15];
int quantity = 15;
void setup(){
size(600,800);
flakes = new Snow[15];
}
void draw(){
background(0);
for(int i = 0; i < quantity; i++){
flakes[i].display();
flakes[i].update();
}
}
I'm sure it's a really simple method of breaking down the code and separating them into the proper places, but I can't seem to grasp it.
If anyone could help me with this process, I would really appreciate it.
This code doesn't make sense, because the Snow class seems to be keeping track of every snowflake, but you then have multiple instances of Snow.
Instead of trying to copy-paste random code into your sketch, you'll have much better luck if you take a step back, start a little smaller, try to understand what the code does, and then write your own code.
Step 1: Can you create a class that encapsulates the data and behavior for a single snowflake?
Don't worry about multiple snowflakes yet. Just get something very basic working. Here's a simple example class:
class SnowFlake{
float x = random(width);
float y = random(height);
float r = random(10);
void draw(){
ellipse(x, y, r, r);
y++;
if(y > height){
y = 0;
x = random(width);
}
}
}
Step 2: Can you use that class in a single variable to draw a single snowflake?
You might create a little example sketch like this:
SnowFlake snowFlake;
void setup(){
size(500, 500);
snowFlake = new SnowFlake();
}
void draw(){
background(0);
snowFlake.draw();
}
Get this single snowflake working perfectly before moving on.
Step 3: Now that you have the single snowflake working, can you use an array or ArrayList to create multiple snowflakes?
If you work in small steps, it will be easy to add one thing at a time:
ArrayList<SnowFlake> snowFlakes = new ArrayList<SnowFlake>();
void setup() {
size(500, 500);
for (int i = 0; i < 100; i++) {
snowFlakes.add(new SnowFlake());
}
}
void draw() {
background(0);
for (SnowFlake snowFlake : snowFlakes) {
snowFlake.draw();
}
}
You can't program by trying to blindly copy-paste code into your sketch. You have to really understand what it's doing, and you're usually better off just writing your own code based on that understanding. Good luck!

Categories

Resources