I am making a sort of command based application to draw geometric figures. So if a user enters something like RECT 100, 50, 200, 120 I draw a rectangle at specified location on the drawing panel.
So for this i need to map RECT to g.drawRect(100, 50, 200, 120); and all such similar functions to draw geometric figures.
I will use a hash map for mapping, but i don't know how to build a array of functions in java. In C++ i have done this though.
The key can be 'RECT' and the value the offset of the index.
Please show me how can i index these functions. Or is there a still better way to address the primary concern?
There are no function pointers in Java, you need to do it through inheritance and/or interfaces. Here is an example:
interface Shape {
void draw(int[] data);
}
class Polygon implements Shape {
public void draw(int[] data) {
// Draw polygon using points data[i], data[i+1] for points
}
}
class Circle implements Shape {
public void draw(int[] data) {
// Draw circle using data[0], data[1] for the center, and data[2] for radius
}
}
In your main program's constructor or static initializer:
Map<String,Shape> shapes = new HashMap<String,Shape>();
shapes.put("POLY", new Polygon());
shapes.put("CIRC", new Circle());
In your drawing code:
shapes.get("CIRC").draw(new int[] {100, 100, 50});
I have to admit, I didn't really got your design, I'm not sure why do you need an array of functions as you said, but this is how this thing can be done in java.
Since Function (method in java terms) is not a "first-class-sitizen" in Java, you can't build an array of methods (at least in java 7) . What you can do instead is to use a more object oriented approach - define an interface, each method will be an implementation of the interface ( a class) so that you'll be able to store an array of interface implementation.
I would use a design pattern Command instead of array of methods or something... Hope this helps
Related
I am using Java's Rectangle class in a program.
I have two Rectangle objects:
Rectangle big = new Rectangle(...);
Rectangle small = new Rectangle(...);
The specific sizes of the rectangles are not important. However, big will always be larger than small (in both width and height).
Usually, small is entirely contained within big. I can use Rectangle#contains to verify this. However, when this is not the case, I would like to move small to be entirely contained within big. The dimensions of neither rectangle should change.
For example:
I know could use four conditionals with Math.max and Math.min, but is there a more elegant way of doing this?
You could do it with only Math.max and Math.min. Try something like this:
small.setLocation(
Math.max(Math.min(small.getX(),big.getX() - small.getWidth()),big.getX()),
Math.max(Math.min(small.getY(),big.getY() - small.getHeight()),big.getY())
);
You'd have to consider readability though.
You need a stronger design. If you extend upon the Rectangle class, you can add the exact functionality you're looking for. Apparently the "big rectangle" should act as a container, containing the smaller rectangle:
class BigRectangle extends Rectangle {
//reference to or list of rectangle(s) here
private boolean isAlignedWith(Rectangle rect) {
return /* bounds logic */;
}
private void align(Rectangle rect) {
//move rectangle to proper position
}
public void add(Rectangle rect) {
if(!isAlignedWith(rect)) {
align(rect);
}
//store in reference or add to list
}
}
Now, you can simply add the smaller rectangle to the bigger one:
Rectangle smallRectangle = new Rectangle();
BigRectangle bigRectangle = new BigRectangle();
bigRectangle.add(smallRectangle); //automatically aligns if needed
You are now hiding the (needed) logic, keeping your central unit of code clean. This is my opinion of the most elegant way to handle this. (I would also probably create an interface RectangleContainer or ShapeContainer, having BigRectangle implement that. The interface would contain a method add(Rectangle) or add(SmallShape))
I have this code:
public void paint(Graphics g) {
g.setColor(Color.black);
g.fill3DRect(myX, myY, 20, 20,true);
g.setColor(Color.red);
g.fillOval(nX, nY, 20, 20);
}
Coordinates of the 2 shapes are given by the user, how can i know if there's a intersection between them?
(I don't need coordinates of the intersection, just need to know if there is or not)
Thanks in advance!
It heavily depends on the context and the actual intention. A very simple solution is to use the Area class: Just create one Area object for each of the shapes that you want to check, and intersect these areas:
Shape shape0 = new Rectangle2D.Double(mxY, myY, 20, 20);
Shape shape1 = new Ellipse2D.Double(nX, nY, 20, 20);
Area a0 = new Area(shape0);
Area a1 = new Area(shape1);
a0.intersect(a1);
if (!a0.isEmpty()) { /* They intersect! */ }
(BTW: You can cast your Graphics object to Graphics2D and then paint the Shape objects directly)
Important : Note that this solution may be very inefficient compared to an analytic solution. If you only have to check "simple" objects (circles, rectangles...) for intersection, you might want to implement an analytic solution, especially if you have to check "many" of these simple objects. The advantage of the Area solution is its simplicity and genericity: It works for arbitrary shapes, even complex shapes like font letters or manually created Path2D objects.
We've just learned how to create our own class, and this particular assignment we had to work with graphics. We had to draw a crayon, and then create a test program where there are 5 crayons lined up next to one another (so we just change the color and x,y of each one). I know how to change the color and x,y coords, but my question is...
how do I 'print' each crayon? Yes, it's an applet and yes I know I need a .html file. But what exactly goes in the test program in order for the crayon to show up when I run the .html file? I've run non-applets before in test programs using System.out.println, but never any graphics. Would it just be System.out.println(Crayon); ?
Also, how do I get multiple crayons? I'm assuming it's Crayon crayons = new Crayon;, and then the next one might be 'Crayon crayons2 = new Crayons;`? I'm not sure.
The x,y coordinates need to be modified w/each crayon, but the UML for the assignment told me not to make them instance variables but instead to put it in 'public void paint (Graphics g, int x, int y)'. What I have so far for the test program (may or may not be correct):
import javax.swing.JApplet;
import java.awt.*;
public class BoxOfCrayons extends JApplet {
Crayon first = new Crayon (Color.red, 50, 250)
Start by having a read through 2D Graphics.
Basically, you will need to create some kind of list of Cryons. This can either be a Collection or array, depending on what you know. I would personally use a ArrayList as it's flexible and easy to use, but doesn't suffer from the same constraints as an array.
Next, create you're self a custom component (ie BoxOfCryons) which extends from JPanel. Override this classes paintComponent method. Within this method, run through the list of Cryons and paint each one, incrementing the x offset by the width of the last Cryon.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = 0;
int y = 0;
for (Crayon crayon : cryons) {
crayon.paint(g2d, x, y);
x += crayon.getWidth();
}
g2d.dispose();
}
Create yourself a new class that extends from JApplet. In it's init method, set the applets layout manager to BorderLayout and add an instance of the BoxOfCryons class to it.
Obviously based on the class assignment this is homework..so help me as much as you can/want, don't flame me for posting HW okay?
I have been dying, reading through my book, reading through online for the past two hours and can't find for the love of god WHY this stupid rectangle says "Cannot find Method setX()". Also is there a way to make the doubles, be ints without casting them as int? It looks really messy, and we aren't supposed to add anything except in the method enclosing...I think I have to cast??
Thanks for any help you can give..
import java.awt.Rectangle;
import java.util.ArrayList;
public class Homework18A
{
public static void main(String[] args)
{
ArrayList<Rectangle> test = new ArrayList<Rectangle>();
test.add(new Rectangle(10, 20, 30, 40));
test.add(new Rectangle(20, 10, 30, 40));
test.add(new Rectangle(10, 20, 40, 50));
test.add(new Rectangle(20, 10, 50, 30));
Rectangle enc = enclosing(test);
System.out.println(enc);
System.out.println("Expected: java.awt.Rectangle[x=10,y=10,width=60,height=60]");
}
/**
Computes the smallest rectangle enclosing all rectangles in
an array list.
#param rects an array list of rectangles of size >= 1
#return the smallest rectangle enclosing all rectangles in rect
*/
public static Rectangle enclosing(ArrayList<Rectangle> rects)
{
Rectangle containRec = new Rectangle(0, 0, 0, 0);
for(int i = 0; i < rects.size(); i++) {
if(rects.get(i).getX() < containRec.getX())
containRec.setX((int)rects.get(i).getX());
if(rects.get(i).getY() < containRec.getY())
containRec.setY((int)rects.get(i).getY());
if(rects.get(i).getX() + rects.get(i).getWidth() > containRec.getWidth())
containRec.setWidth(((int)rects.get(i).getX() + rects.get(i).getWidth()));
if(rects.get(i).getY() + rects.get(i).getHeight() > containRec.getHeight())
containRec.setHeight(((int)rects.get(i).getY() + rects.get(i).getHeight()));
}
return containRec;
}
}
Because Rectangle does not have a method setX() or setY(). If you're trying to set the position you want to use setLocation(x,y).
Edit: there is no setWidth() or setHeight() methods either, you want to use setSize(width, height). Even though the Rectangle class has fields for x, y, width, and height it does not follow the normal Java conventions where the fields are made private and public getter and setter methods are used. In this case you could access the fields directly and just say containRec.x = whatever, but it's a bad habit to get in to.
You don't want to remove the (int) casts, but you can definitely clean up that section. Instead of calling rects.get(i) you could put a line at the beginning of the loop that says Rectangle currentRect = rects.get(i); or better yet use a for-each loop.
Sorry but I had to lauch :D
Poor Matt :-*
Here is the link for the api: http://download.oracle.com/javase/1,5,0/docs/api/java/awt/Rectangle.html
There is no setX() or setY()
I assume you're using the java.awt.Rectangle class. It does not have a setX method (take a look at the Javadocs to confirm this), but it does declare it's x field to be public, so you can just set it directly:
containRec.x = whatever;
The same goes for y, of course. Directly setting public fields is generally A Bad Thing (as #Jordan Bently pointed out), but it'll work in this case.
Or you can use some combination of setLocation, setBounds, setSize, setRect or setFrame.
EDIT: You can get rid of all those nasty casts by using entirely integer arithmetic. Instead of using getX(), which returns a double, just look up the x field directly - it's an int.
The java.awt.Rectangle class is somewhat cumbersome to use.
I have a task to draw a circle and then fill in with the most amount of circles without touching the sides. I can draw the circle, and I can make loops to pack the circle in a hexagonal/honeycomb format, but can't control whether they are inside or outside the circle.
I have used this: g.drawOval(50, 50, 300, 300); to specify my circle. Given I'm actually specifying a square as my boundaries I can't actually determine where the circle boundaries are. So I'm basically packing the square full of circles rather than the circle full of circles.
Can some please point me in the right direction? I'm new to java so not sure if I have done this the complete wrong way. My code is below. I have another class for the frame and another with the main in it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class DrawCircle extends JPanel
{
private int width, height, diameter;
public DrawFrame d;
public DrawCircle()
{
width = 400;
height = 400;
diameter = 300;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
g.drawOval(50, 50, 300, 300);
for(int i=50; i<200; i=i+20)
{
for(int j=50; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=60; i<200; i=i+20)
{
for(int j=55; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=330; i>190; i=i-20)
{
for(int j=340; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=340; i>190; i=i-20)
{
for(int j=345; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
}
}
All those magic numbers make me cringe a bit. You're new to Java, and it's homework, so I understand why you're doing it, but I would not recommend it if you do much programming in the future.
You need an algorithm or recipe for deciding when a small circle on the inside falls outside the big one you're trying to pack. Think about the ways you might do this:
If the distance between the center of the big circle and the small circle is is greater than the difference in their radii, the small circle will overlap the big circle or fall completely outside it.
You can add this check to your code: Just before you draw the circle, perform this check. Only draw if that circle passes.
Don't worry about Java for a second; draw yourself a picture on a piece of paper, draw that enclosing and packed circle, and see if that statement is correct. Then think about any corner situations that it might not cover, just as a check.
I'll make two more recommendations. First, do this by hand without a computer once so you'll see what the "right" answer might look like. Second, see if you can separate the calculation of the circles from the drawing part. It might make your job easier, because you can concentrate on one thing at a time. It's called "decomposition". You solve complex problems by breaking them up into smaller, more manageable pieces. In this case, it's also called "model-view separation". You might need to know that someday.
Maybe another way to think about this problem would be to imagine a 2D arrangement of circles, packed in their closest arrangement, extending to infinity in both the x- and y-directions. Now take your enclosing circle, put it on top of the 2D arrangement, and eliminate all the circles that overlap the big circle. I don't know if it'll be optimal, but it's easy to visualize.