How do I draw Random Lines that are connected? - random

I need to draw random lines in a program that I have. I have figured out how to draw the Random lines, using the Random class, but I can't figure out how to make them connect. The second part of the class is to draw black lines over the white ones to "make them disappear".
Basically, if line1 has coordinates (0,0,300,300), then the second line should have the coordinates (300,300,random number, random number). I can't figure out how to make this happen using the Random class.
My teacher included a hint: Inserting a number into the parameters of the Random class "seeds" a list that is not random. Once you call the Random class again with that same seed, then the same list will appear. I don't know how to implement this so that the black lines will completely cover the white lines.
Here is my code so far:
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.black);
g.fillRect(0, 0, 600, 600);
Point2D.Double one = new Point2D.Double(50,50);
Point2D.Double two = new Point2D.Double(300,300);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
g.setColor(Color.white);
for (int i = 0; i < 10; i++)
{
Random gen = new Random();
/*one.setLocation(gen.nextInt(600), gen.nextInt(600));
two.setLocation(gen.nextInt(600), gen.nextInt(600));
g.drawLine((int)one.getX(), (int)one.getY(), (int)two.getX(), (int)two.getY());*/
int x1 = gen.nextInt(600);
int y1 = gen.nextInt(600);
int x2 = gen.nextInt(600);
int y2 = gen.nextInt(600);
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
try
{
Thread.currentThread().sleep(300);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
/*for (int i = 0; i < 10; i++)
{
g.setColor(Color.BLACK);
Random gen = new Random(1);
one.setLocation(gen.nextInt(600), gen.nextInt(600));
two.setLocation(gen.nextInt(600), gen.nextInt(600));
g.drawLine((int)one.getX(), (int)one.getY(), (int)two.getX(), (int)two.getY());
try
{
Thread.currentThread().sleep(300);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}*/
}
public static void main(String[] args)
{
/*int x = 0;
for (int i = 0; i < 20; i++)
{
x = x + 1;
Random gen = new Random(x);
System.out.println(gen.nextInt(100));
}*/
PointsAndLines application = new PointsAndLines();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
The commented stuff is just things that we went over in class. I don't know if this will help me.
Please, no complicated stuff. This is only my second year of programming, and I'm not adept at it yet.

You are doing it correct except that you don't need to generate x1,y1 again but assign it the older value. The initial random x1, y1 will be calculated beforehand, before getting inside the loop to draw lines. Below code may give you an insight.
Random gen = new Random();
int x1 = gen.nextInt(600);
int y1 = gen.nextInt(600);//We get the first x1, y1 random values here itself
for (int i = 0; i < 10; i++)
{
int x2 = gen.nextInt(600);
int y2 = gen.nextInt(600);
g.drawLine(x1, y1, x2, y2);//Once we draw the line we assign x2, y2 to x1, y1 as you did below
x1 = x2;
y1 = y2;
//Now the next time you enter this loop your line will start from where the line had ended and next point will be random
//rest of the code goes below
I can't say how do you plan to make the lines disappear again. Do you intend to draw the lines and erase them?

This should be the working version :)
I think the goal of your teacher is to make you understand the workings of the Random class.
package test;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
public class PointsAndLines extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
private int seed;
public static void main(String[] args)
{
PointsAndLines application = new PointsAndLines(12); // <- upon changing the seed a different pattern will emerge
application.setVisible(true);
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public PointsAndLines(int seed)
{
this.seed = seed;
setBounds(100, 100, 600, 600);
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.black);
g.fillRect(0, 0, 600, 600);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
g.setColor(Color.white);
Random gen = new Random(seed); // apply the seed
int x1 = gen.nextInt(600);
int y1 = gen.nextInt(600);
for (int i = 0; i < 10; i++)
{
int x2 = gen.nextInt(600);
int y2 = gen.nextInt(600);
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
try
{
Thread.sleep(300);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
Random genTwo = new Random(seed); // <- apply the same seed again
x1 = genTwo.nextInt(600);
y1 = genTwo.nextInt(600);
for (int i = 0; i < 10; i++)
{
g.setColor(Color.BLACK);
int x2 = genTwo.nextInt(600);
int y2 = genTwo.nextInt(600);
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
try
{
Thread.sleep(300);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}

Related

Genetic Algorithm Fitness and Cross Over selection

I'm attempting to use a genetic algorithm to arrange a random list of seats for a given section in a classroom so that all the groups in that classroom sit together.
Here is my current attempt, I'm unclear about the best way to improve this algorithm as this is very very early days in my GA learnings.
I'm using the Java library Jenetics, which has been pretty awesome at getting me started, here is the Engine.
final Engine<EnumGene<Seat>, Double> ENGINE = Engine
.builder(SeatingFitness::fitness, encoding)
.populationSize(200)
.selector(new RouletteWheelSelector<>())
.alterers(
new PartiallyMatchedCrossover<>(0.2),
new Mutator<>(0.01)
)
.optimize(Optimize.MINIMUM)
.build();
The encoding looks like this
static final ISeq<Seat> seats = ISeq.of(createSeats());
static final Codec<ISeq<Seat>, EnumGene<Seat>> encoding = Codecs.ofPermutation(seats);
public static List<Seat> createSeats() {
return new ArrayList<>(Arrays.asList(
new Seat("Group C", 1),
new Seat("Group A", 2),
new Seat("Group B", 3)
.....more seats here....)
}
My fitness function can be improved for sure, I'm not using any libraries, so any suggestions here would be great, but it looks like this.
Essentially what I'm doing is just finding the x and y coordinates of each seat in the group and calculating how far each one is from the others in the group, and summing those values up. The lower value the better, hence the Optimize.MINIMUM in the Engine
private static int numberOfSeatsInRow = 8;
public static double fitness(final ISeq<Seat> seats) {
AtomicDouble score = new AtomicDouble();
// Group together all the seats that belong to a particular group.
Map<String, List<Seat>> grouping = seats.stream().collect(groupingBy(Seat::getGroup));
grouping.forEach((group, groupsSeats) -> {
// Find the location in the overall list of the seats for the group.
if (!group.equals(Seat.EMPTY_SEAT)) {
List<Integer> indexOfSeatInOverallList = groupsSeats.stream().map(seats::indexOf).collect(Collectors.toList());
if (indexOfSeatInOverallList.size() > 2) {
// Get the first element positioned correctly on the x and y axis
double totalCalculated = indexOfSeatInOverallList.stream().reduce(0, (subTotal, currentElement) -> {
int xReferenceCoordinate = calculateXCoordinate(currentElement);
int yReferenceCoordinate = calculateYCoordinate(currentElement);
double totalDistance = 0;
int multiplier = groupsSeats.size() <= numberOfSeatsInRow ? 10 : 500;
for (Integer integer : indexOfSeatInOverallList) {
int xSecondary = calculateXCoordinate(integer);
int ySecondary = calculateYCoordinate(integer);
if (ySecondary != yReferenceCoordinate) {
totalDistance += multiplier * Math.abs(yReferenceCoordinate - ySecondary);
}
totalDistance += calculateDistanceBetweenTwoPoints(xReferenceCoordinate, yReferenceCoordinate, xSecondary, ySecondary);
}
return (int) totalDistance;
});
score.getAndAdd(totalCalculated);
}
}
});
return score.get();
}
private static int calculateXCoordinate(int positionInList) {
int xPosition = positionInList % numberOfSeatsInRow;
if (xPosition == 0) {
xPosition = numberOfSeatsInRow;
}
return xPosition;
}
private static int calculateYCoordinate(int positionInList) {
int xPosition = positionInList % numberOfSeatsInRow;
int yPosition = positionInList / numberOfSeatsInRow;
if (xPosition == 0) {
yPosition = yPosition - 1;
}
return yPosition + 1;
}
private static double calculateDistanceBetweenTwoPoints(int x1, int y1, int x2, int y2) {
// https://dqydj.com/2d-distance-calculator/
double xValue = Math.pow((x2 - x1), 2);
double yValue = Math.pow((y2 - y1), 2);
return Math.sqrt(xValue + yValue);
}
See the results image below, as you can see it's pretty good (although it takes about 3 minutes to run to produce a proper result).
I had a look at the fitness function. Some things you are calculating for every fitness function call, can be calculated once.
private static final ISeq<Seat> SEATS = ISeq.of(
new Seat("Group C", 1),
new Seat("Group A", 2),
new Seat("Group B", 3)
);
private static final Map<String, List<Seat>> SEAT_GROUPS = SEATS.stream()
.collect(groupingBy(Seat::getGroup));
The SEAT_GROUPS map is defined by the seats list and will not change. If I'm right, the reduce function in your fitness function is ignoring the previously calculated distance.
double totalCalculated = indexOfSeatInOverallList.stream()
.reduce(0, (subTotal, currentElement) -> {
// subTotal is ignored in your code, but should be added to the result.
return (int) totalDistance + subTotal;
})
Your calculateDistanceBetweenTwoPoints can be implemented as
double distance(final int x1, final int y1, final int x2, final int y2) {
// sqrt(x^2 + y^2)
return Math.hypot(x2 - x1, y2 - y1);
}
My "cleaned" version will look like this.
private static final int SEATS_PER_ROW = 8;
private static final ISeq<Seat> SEATS = ISeq.of(
new Seat("Group C", 1),
new Seat("Group A", 2),
new Seat("Group B", 3)
);
private static final Map<String, List<Seat>> SEAT_GROUPS = SEATS.stream()
.collect(groupingBy(Seat::getGroup));
public static double fitness(final ISeq<Seat> seats) {
double score = 0;
for (var entry : SEAT_GROUPS.entrySet()) {
final var group = entry.getKey();
final var groupsSeats = entry.getValue();
final int multiplier = groupsSeats.size() <= SEATS_PER_ROW ? 10 : 500;
if (!group.equals(Seat.EMPTY_SEAT)) {
final int[] indexes = groupsSeats.stream()
.mapToInt(seats::indexOf)
.toArray();
if (indexes.length > 2) {
final double dist = IntStream.of(indexes)
.reduce(0, (a, b) -> toDistance(multiplier, indexes, a, b));
score += dist;
}
}
}
return score;
}
private static int toDistance(
final int multiplier,
final int[] indexes,
final int sum,
final int index
) {
final int x1 = toX(index);
final int y = toY(index);
int total = 0;
for (int i : indexes) {
final int x2 = toX(i);
final int y2 = toY(i);
if (y2 != y) {
total += multiplier*Math.abs(y - y2);
}
total += distance(x1, y, x2, y2);
}
return sum + total;
}
private static double distance(final int x1, final int y1, final int x2, final int y2) {
// sqrt(x^2 + y^2)
return Math.hypot(x2 - x1, y2 - y1);
}
private static int toX(final int index) {
int x = index%SEATS_PER_ROW;
if (x == 0) {
x = SEATS_PER_ROW;
}
return x;
}
private static int toY(final int index) {
final int x = index%SEATS_PER_ROW;
int y = index/SEATS_PER_ROW;
if (x == 0) {
y = y - 1;
}
return y + 1;
}
One point I can see about your Engine definition is that you are using a Mutator alterer for a combinatorial problem. This causes the poor performance you have (most likely). A Mutator doesn't obey the unique element property in your chromosome. Mutating a chromosome means invalidating it, which causes a constant recreation of new chromosomes. For combinatorial problems, only SwapMutator and PartiallyMatchedCrossover are valid alterers.
final Engine<EnumGene<Seat>, Double> ENGINE = Engine
.builder(SeatingFitness::fitness, encoding)
.populationSize(200)
.selector(new RouletteWheelSelector<>())
.alterers(
new PartiallyMatchedCrossover<>(0.2),
new SwapMutator<>(0.01))
.optimize(Optimize.MINIMUM)
.build();
There might be also improvements in your fitness function, but for commenting on this, the whole fitness function code would be nice.

How to not overwrite existing list of objects?

I want to draw lines as I click on the canvas, so if I clicked once then save the point, and if I clicked the second time then draw a line behind these two points. But, I want to make this multiple times, so, If I clicked the third time then this point will be the starting point of a new line.
I created like this:
This is in the main:
ArrayList<Shape> shapes = new ArrayList<Shape>();
Shape selected_shape = null;
Boolean drawmode = true;
void setup() {
size(1000, 600);
}
void draw() {
//update();
background(224, 224, 224);
//draw the existing
for(Shape s: shapes){
pushMatrix();
//list all
s.Draw();
s.Log();
popMatrix();
}
println("shape size: "+shapes.size());
}
//menu
int value = 0;
void keyPressed() {
if(key == '0'){
System.out.println("Draw mode OFF"); // exit from draw mode
value = 0;
}
if(key == '1'){
println("Draw a line: select the start point of the line and the end point!"); // line
value = 1;
}
//System.out.println("key: " + key);
}
Line l = new Line();
void mousePressed() {
if(value == 1){
if(l.centerIsSet){
if (mouseButton == LEFT) {
l.x2 = mouseX;
l.y2 = mouseY;
println("end point added");
l.centerIsSet = false;
}
shapes.add(l);
l.Log();
} else {
if (mouseButton == LEFT) {
l.x1 = mouseX;
l.y1 = mouseY;
l.centerIsSet = true;
println("start point added");
}
}
}
}
And I use a shape class and this class is extended with line:
abstract class Shape {
PVector position = new PVector();
PVector fill_color = new PVector(0, 0, 0);
PVector stroke_color = new PVector(0, 0, 0);
PVector select_fill_color = new PVector(255, 0, 0);
PVector select_stroke_color = new PVector(255, 0, 0);
Boolean selected = false;
int shape_color_r;
int shape_color_g;
int shape_color_b;
int shape_rotation_angle = 0;
int detailness = 10;
abstract void Draw();
abstract void Log();
}
and:
class Line extends Shape {
int x1, x2, y1, y2;
Boolean centerIsSet = false;
Line(){}
Line(int x1, int y1){
this.x1 = x1;
this.y1 = y1;
}
Line(int x1, int y1, int x2, int y2){
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
void Draw(){
line(x1, y1, x2, y2);
}
void Log(){
System.out.println("x1: "+x1+" x2: "+x2+" y1: "+y1+" y2: "+y2);
}
}
But always the last created line overwrite the old ones, how can I resolve this? I think I need a new instance for each line, but I don't know how can I do this.
The variable l refers to the Line object which holds the coordinates of the line which is currently drawn.
If you have finished a line, then the reference to line object l is add to the container shapes. Now you have to create a new line object, for the next line and assign it to l:
shapes.add(l);
l = new Line();

How to generate "inner shape" of 2D concave polygon?

I have a list of 2d points which is a closed loop, 2D, concave polygon.
I want to generate a second polygon, which is fully inside the first polygon and each vertex/edge of the first polygon has a constant distance to each vertex/edge of the second polygon.
Basically, the first polygon would be "outer wall" and the second would be "inner wall", with the distance between two walls constant.
How to do something like that?
For the case that you do not care about self-intersections, the construction is pretty straightforward:
For each vertex of the polygon:
Take the previous and next line segment
Compute the normals of these line segments
Shift the line segments along the normal
Compute the intersection of the shifted line segments
Below is a MCVE implemented in Java/Swing. The actual computation takes place in computeOffsetPolygonPoints, and it should be easy to translate this to other languages and APIs.
For the case that you also have to handle self-intersections, things might become trickier. Then it would be necessary to define the intended result, particularly for the case that the polygon itself self-intersects...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
public class InnerPolygonShape
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
InnerPolygonShapePanel innerPolygonShapePanel =
new InnerPolygonShapePanel();
JSlider offsetSlider = new JSlider(0, 100, 40);
offsetSlider.addChangeListener(e ->
{
double alpha = offsetSlider.getValue() / 100.0;
double offset = -50.0 + alpha * 100.0;
innerPolygonShapePanel.setOffset(offset);
});
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(innerPolygonShapePanel, BorderLayout.CENTER);
f.getContentPane().add(offsetSlider, BorderLayout.SOUTH);
f.setSize(800,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class InnerPolygonShapePanel extends JPanel
implements MouseListener, MouseMotionListener
{
private final List<Point2D> points;
private Point2D draggedPoint;
private double offset = -10.0;
public InnerPolygonShapePanel()
{
this.points = new ArrayList<Point2D>();
points.add(new Point2D.Double(132,532));
points.add(new Point2D.Double(375,458));
points.add(new Point2D.Double(395,267));
points.add(new Point2D.Double(595,667));
addMouseListener(this);
addMouseMotionListener(this);
}
public void setOffset(double offset)
{
this.offset = offset;
repaint();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.BLACK);
paint(g, points);
List<Point2D> offsetPolygonPoints =
computeOffsetPolygonPoints(points, offset);
g.setColor(Color.BLUE);
paint(g, offsetPolygonPoints);
}
private static void paint(Graphics2D g, List<Point2D> points)
{
for (int i = 0; i < points.size(); i++)
{
int i0 = i;
int i1 = (i + 1) % points.size();
Point2D p0 = points.get(i0);
Point2D p1 = points.get(i1);
g.draw(new Line2D.Double(p0, p1));
}
g.setColor(Color.RED);
for (Point2D p : points)
{
double r = 5;
g.draw(new Ellipse2D.Double(p.getX()-r, p.getY()-r, r+r, r+r));
}
}
private static List<Point2D> computeOffsetPolygonPoints(
List<Point2D> points, double offset)
{
List<Point2D> result = new ArrayList<Point2D>();
Point2D absoluteLocation = new Point2D.Double();
for (int i = 0; i < points.size(); i++)
{
// Consider three consecutive points (previous, current, next)
int ip = (i - 1 + points.size()) % points.size();
int ic = i;
int in = (i + 1) % points.size();
Point2D pp = points.get(ip);
Point2D pc = points.get(ic);
Point2D pn = points.get(in);
// Compute the line segments between the previous and the current
// point, and the current and the next point, and compute their
// normal
Point2D line0 = difference(pc, pp);
Point2D direction0 = normalize(line0);
Point2D normal0 = rotateCw(direction0);
Point2D line1 = difference(pn, pc);
Point2D direction1 = normalize(line1);
Point2D normal1 = rotateCw(direction1);
// Shift both line segments along the normal
Point2D segment0p0 = add(pp, offset, normal0);
Point2D segment0p1 = add(pc, offset, normal0);
Point2D segment1p0 = add(pc, offset, normal1);
Point2D segment1p1 = add(pn, offset, normal1);
// Compute the intersection between the shifted line segments
intersect(
segment0p0.getX(), segment0p0.getY(),
segment0p1.getX(), segment0p1.getY(),
segment1p0.getX(), segment1p0.getY(),
segment1p1.getX(), segment1p1.getY(),
null, absoluteLocation);
result.add(new Point2D.Double(
absoluteLocation.getX(), absoluteLocation.getY()));
}
return result;
}
#Override
public void mouseDragged(MouseEvent e)
{
if (draggedPoint != null)
{
draggedPoint.setLocation(e.getX(), e.getY());
repaint();
}
}
#Override
public void mousePressed(MouseEvent e)
{
final double thresholdSquared = 10 * 10;
Point2D p = e.getPoint();
Point2D closestPoint = null;
double minDistanceSquared = Double.MAX_VALUE;
for (Point2D point : points)
{
double dd = point.distanceSq(p);
if (dd < thresholdSquared && dd < minDistanceSquared)
{
minDistanceSquared = dd;
closestPoint = point;
}
}
draggedPoint = closestPoint;
}
#Override
public void mouseReleased(MouseEvent e)
{
draggedPoint = null;
}
#Override
public void mouseMoved(MouseEvent e)
{
// Nothing to do here
}
#Override
public void mouseClicked(MouseEvent e)
{
// Nothing to do here
}
#Override
public void mouseEntered(MouseEvent e)
{
// Nothing to do here
}
#Override
public void mouseExited(MouseEvent e)
{
// Nothing to do here
}
private static Point2D difference(Point2D p0, Point2D p1)
{
double dx = p0.getX() - p1.getX();
double dy = p0.getY() - p1.getY();
return new Point2D.Double(dx, dy);
}
private static Point2D add(Point2D p0, double factor, Point2D p1)
{
double x0 = p0.getX();
double y0 = p0.getY();
double x1 = p1.getX();
double y1 = p1.getY();
return new Point2D.Double(x0 + factor * x1, y0 + factor * y1);
}
private static Point2D rotateCw(Point2D p)
{
return new Point2D.Double(p.getY(), -p.getX());
}
private static Point2D normalize(Point2D p)
{
double x = p.getX();
double y = p.getY();
double length = Math.hypot(x, y);
return new Point2D.Double(x / length, y / length);
}
// From https://github.com/javagl/Geom/blob/master/src/main/java/
// de/javagl/geom/Intersections.java
private static final double DOUBLE_EPSILON = 1e-6;
/**
* Computes the intersection of the specified lines.
*
* Ported from
* http://www.geometrictools.com/LibMathematics/Intersection/
* Wm5IntrSegment2Segment2.cpp
*
* #param s0x0 x-coordinate of point 0 of line segment 0
* #param s0y0 y-coordinate of point 0 of line segment 0
* #param s0x1 x-coordinate of point 1 of line segment 0
* #param s0y1 y-coordinate of point 1 of line segment 0
* #param s1x0 x-coordinate of point 0 of line segment 1
* #param s1y0 y-coordinate of point 0 of line segment 1
* #param s1x1 x-coordinate of point 1 of line segment 1
* #param s1y1 y-coordinate of point 1 of line segment 1
* #param relativeLocation Optional location that stores the
* relative location of the intersection point on
* the given line segments
* #param absoluteLocation Optional location that stores the
* absolute location of the intersection point
* #return Whether the lines intersect
*/
public static boolean intersect(
double s0x0, double s0y0,
double s0x1, double s0y1,
double s1x0, double s1y0,
double s1x1, double s1y1,
Point2D relativeLocation,
Point2D absoluteLocation)
{
double dx0 = s0x1 - s0x0;
double dy0 = s0y1 - s0y0;
double dx1 = s1x1 - s1x0;
double dy1 = s1y1 - s1y0;
double invLen0 = 1.0 / Math.sqrt(dx0*dx0+dy0*dy0);
double invLen1 = 1.0 / Math.sqrt(dx1*dx1+dy1*dy1);
double dir0x = dx0 * invLen0;
double dir0y = dy0 * invLen0;
double dir1x = dx1 * invLen1;
double dir1y = dy1 * invLen1;
double dot = dotPerp(dir0x, dir0y, dir1x, dir1y);
if (Math.abs(dot) > DOUBLE_EPSILON)
{
if (relativeLocation != null || absoluteLocation != null)
{
double c0x = s0x0 + dx0 * 0.5;
double c0y = s0y0 + dy0 * 0.5;
double c1x = s1x0 + dx1 * 0.5;
double c1y = s1y0 + dy1 * 0.5;
double cdx = c1x - c0x;
double cdy = c1y - c0y;
double dot0 = dotPerp(cdx, cdy, dir0x, dir0y);
double dot1 = dotPerp(cdx, cdy, dir1x, dir1y);
double invDot = 1.0/dot;
double s0 = dot1*invDot;
double s1 = dot0*invDot;
if (relativeLocation != null)
{
double n0 = (s0 * invLen0) + 0.5;
double n1 = (s1 * invLen1) + 0.5;
relativeLocation.setLocation(n0, n1);
}
if (absoluteLocation != null)
{
double x = c0x + s0 * dir0x;
double y = c0y + s0 * dir0y;
absoluteLocation.setLocation(x, y);
}
}
return true;
}
return false;
}
/**
* Returns the perpendicular dot product, i.e. the length
* of the vector (x0,y0,0)x(x1,y1,0).
*
* #param x0 Coordinate x0
* #param y0 Coordinate y0
* #param x1 Coordinate x1
* #param y1 Coordinate y1
* #return The length of the cross product vector
*/
private static double dotPerp(double x0, double y0, double x1, double y1)
{
return x0*y1 - y0*x1;
}
}

How to access the co-ordinates of a shape stored as an object in an array

I have stored the co-ordinates of several randomly plotted lines in an object array.
I would now like to be able to be able to programatically manipulate for example x1 in all the objects in the array. I cannot work out how to do this or even how to see the co-ordinates of the stored lines. If I do println() I just get the memory reference of the objects.
Here is the code so far:
class Line{
public float x1, y1, x2, y2;
public Line(float x1, float y1, float x2, float y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public void draw(){
line(x1, y1, x2, y2);
float rot = random(360);
rotate(rot);
}
//public boolean intersects(Line other){
// //left as exercise for reader
//}
}
ArrayList<Line> lines = new ArrayList<Line>();
void setup(){
background(204);
size(600, 600);
for(int i = 0; i < 20; i++){
float r = random(500);
float s = random(500);
lines.add(new Line(r,s,r+10,s+10));
printArray(lines);
for(Line line : lines){
line.draw();
}
}
}
Simply use dot notation. Using your Line class, you can create a Line object (or instance) using the new keyword and the constructor (the special function that has the same name as the class):
Line aLine = new Lines(0,100,200,300);
Once you have an instance, you can access it's variables(known as properties) using the instance name, then the . symbol, then the variable name:
println("aLine's x1 is " + aLine.x1);
In the example code you have, in the draw() function you access the .draw() function(known as method) of the each Line instance:
for(Line line : lines){
line.draw();
}
}
It's just a matter of using the same concept to access the rest of Line's members:
for(Line line : lines){
//wiggle first point's x coordinate a little (read/write x1 property)
line.x1 = random(line.x1 - 3,line.x1 + 3);
line.draw();
}
}
Be sure to read Daniel Shiffman's Objects tutorial for more details.

How to return value from a class, derived from an array in Processing

I'm new to Processing. I want to learn how to graph some modelling I am doing so I'm using gwoptics to do it. They have an example called RollingGraph. This basically plots out whatever you want along a time dependent scrolling x axis.
The problem is that I don't quite understand how I get it to plot what I want.
I have an array, let's say which plots ellipses randomly on a canvas and these rotate randomly every frame. How can I get the Rolling Graph to plot the sum of all the rotations, which could be circle.rot?
So far I have the best MCVE I could get:
import org.gwoptics.graphics.graph2D.Graph2D;
import org.gwoptics.graphics.graph2D.traces.ILine2DEquation;
import org.gwoptics.graphics.graph2D.traces.RollingLine2DTrace;
class eq implements ILine2DEquation{
public double computePoint(double x,int pos) {
return mouseX; //////HOW DO I GET THIS TO RETURN THE SUM OF circle.rot??????
}
}
class eq2 implements ILine2DEquation{
public double computePoint(double x,int pos) {
return mouseY;
}
}
class eq3 implements ILine2DEquation{
public double computePoint(double x,int pos) {
if(mousePressed)
return 400;
else
return 0;
}
}
RollingLine2DTrace roll,roll2,roll3;
Graph2D g;
class Circle{
public float x1;
public float y1;
public float x2;
public float y2;
public color cB;
public float rot;
public float authority;
public float fert = 1;
public float r = x1; //radius
public Circle(float x1, float y1, float x2, float y2, color tempcB, float rot, float authority, float fert){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.cB = tempcB;
this.authority = random(255);
this.fert = random(1);
this.rot= random(360);
}
}
public ArrayList<Circle> circles = new ArrayList<Circle>();
void setup(){
size(1000, 1000);
frameRate(6);
rectMode(CENTER);
ellipseMode(CENTER);
int sec = second();
roll = new RollingLine2DTrace(new eq() ,100,0.01f);
roll.setTraceColour(0, 255, 0);
roll2 = new RollingLine2DTrace(new eq2(),100,0.01f);
roll2.setTraceColour(255, 0, 0);
roll3 = new RollingLine2DTrace(new eq3(),100,0.05f);
roll3.setTraceColour(255, 255, 255);
g = new Graph2D(this, 400, 200, false);
g.setYAxisMax(600);
g.addTrace(roll);
g.addTrace(roll2);
g.addTrace(roll3);
g.position.y = 50;
g.position.x = 100;
g.setYAxisTickSpacing(100);
g.setXAxisMax(5f);
smooth();
background(204);
noStroke();
fill(255, 204,100);
for(int i = 1; i < 48; i++){
float r = random(100,height-200);
float s = random(100,width-200);
float t = 20;
float u = 20;
circles.add(new Circle(r,s,t,u,color(100,14,14),random(360),color(100,14,14),random(10)));
}
}
void draw() {
background(204);
g.draw();
for(Circle circle : circles){
pushMatrix();
translate(circle.x1, circle.y1);
rotate(random(360));
translate(-circle.x1, -circle.y1);
fill(circle.authority);
strokeWeight(0);
stroke(100,0,0);
rect(circle.x1, circle.y1, 24, 36,0, 0, 12, 18);
popMatrix();
}
}
If I understand your question, all you have to do is iterate over the instances and calculate the total.
First, you're going to need a data structure that holds all of your instances. You've said you're using an array, so it sounds like you've go that covered. You have to make sure that this array is in scope for the next step, so this probably means declaring it at the sketch level (not inside a function or class).
Secondly, you're going to need a for loop that iterates over the instances in the data structure. You can use a variable to add up the total. Something like this:
float total = 0;
for(Circle c : yourCircleArray){
total += c.rot;
}
You might put that into a function so that you can call it whenever you want.
Edit: Looking at your code more closely, you actually have an ArrayList, not an array. It looks like it's already initialized at the sketch level, so all you need to do is this:
public double computePoint() {
float total = 0;
for(Circle c : circles){
total += c.rot;
}
return total;
}
If you can't get that working, try creating an MCVE by eliminating your dependencies on whatever library you're importing at the top of your sketch. Remember that an MCVE is supposed to narrow it down to one specific problem (how to get a total from an array), not do your whole end goal.

Resources