I am making 3D-Objects made of Triangles. These Triangles have 3 Vectors.
Now I have a file with alot of numbers... If a line starts with "v" the line has x-, y-, and z-coordinates of a Vector.
If a line starts with "f" the line has the line of the Vector in the .txt file that I need for my Triangle.
The file starts with all "v"s first and then continues with the "f"s.
Example: (the number at the beginning is just the line)
21 v 1.2000 0.20000 -1.0000 -> Vector1(1.2, 0.2, -1)
22 v 1.2000 0.20000 1.00000 -> Vector2(1.2, 0.2, 1)
23 v -1.200 -0.2000 1.00000 -> Vector3(-1.2, -0.2, 1)
...
71 f 21 23 22 -> Triangle(Vector1, Vector3, Vector2)
And this is what i tried, which obviously did not work since I am a Java newbie :P
public static ArrayList<Triangle> mesh = new ArrayList<>();
public static void loadObject(String fileName) {
try {
Scanner scan = new Scanner(fileName);
ArrayList<Vector> vectors = new ArrayList<>();
while (scan.hasNextLine()) {
if (scan.equals("v")) {
Vector v = new Vector();
int i = 0;
while (scan.hasNextDouble() && i < 3) {
if (i == 0) {
v.setX(scan.nextDouble());
}
if (i == 1) {
v.setY(scan.nextDouble());
}
if (i == 2) {
v.setZ(scan.nextDouble());
}
i++;
}
vectors.add(v);
}
if (scan.equals("f")) {
Triangle t = new Triangle();
int j = 0;
while (scan.hasNextInt() && j < 3) {
if (j == 0) {
t.setVec1(vectors.get(scan.nextInt() - 1));
}
if (j == 1) {
t.setVec2(vectors.get(scan.nextInt() - 1));
}
if (j == 2) {
t.setVec3(vectors.get(scan.nextInt() - 1));
}
j++;
}
mesh.add(t);
}
}
} catch (Exception e) {
}
}
Thanks for the help
You are describing the Wavefron OBJ file format for which many loaders already exist. You should consider using an existing loader instead of rolling your own.
Googling for it I find three Java .obj loaders on Github right away:
javagl/Obj
seanrowens/oObjLoader
Blunderchips/LWJGL-OBJ-Loader
I have not used any of these so you would need to try them out yourself and see if they provide the right API for you and solve your concrete problem.
How about something like this:
static List<Triangle> parse(String fileName)
{
List<Triangle> mesh = new ArrayList<>();
Map<String, Vector> vm = new HashMap<>();
try (Scanner scan = new Scanner(new FileReader(fileName)))
{
while(scan.hasNextLine())
{
String[] p = scan.nextLine().split("\\s");
if("v".equals(p[1]))
{
vm.put(p[0], new Vector(Double.parseDouble(p[2]), Double.parseDouble(p[3]), Double.parseDouble(p[4])));
}
else if("f".equals(p[1]))
{
mesh.add(new Triangle(vm.get(p[2]), vm.get(p[3]), vm.get(p[4])));
}
}
}
catch(IOException e)
{
e.printStackTrace();
}
return mesh;
}
Related
I need to display/list the contents of a txt file in the ascending order of priority. So, should I need to take a seperate input for priority of task or can I splice the input line?
private static void show() {
String[] items = getData("task.txt");
if (items.length == 0) {
System.out.println("There are no pending tasks!");
} else {
for (int i = items.length - 1; i >=0; i--) {
System.out.printf("[%d] %s\n", i + 1, items[i]);
}
}
My getData looks like this:
private static String[] getData(String file) {
ArrayList<String> dataList = new ArrayList<>();
Scanner s=null;
try {
s = new Scanner(new FileReader(file));
while (s.hasNextLine()){
dataList.add(s.nextLine());
}s.close();
} catch (Exception e) {
System.out.println("Problem to open \"task.txt\".");
} finally {
if (s != null) {
try {
s.close();
} catch (Exception e) {
}
}
}
String[] items = new String[dataList.size()];
for (int i = 0; i < items.length; i++) {
items[i] = dataList.get(i);
}
return items;
}
Input:
10 the thing i need to do
5 water the plants
11 clean house
Output: 5 water the plants
10 the thing i need to do
11 clean house
You can just sort the ArrayList datalist:
(I am assuming that the "priority item" format is already in it)
dataList.sort((o1, o2) -> {
Integer priority1 = Integer.parseInt(o1.split(" ")[0]);
Integer priority2 = Integer.parseInt(o2.split(" ")[0]);
return priority1.compareTo(priority2);
});
Put this right after the try-catch-finally-block.
I'm creating a program for an assignment which takes an input from System.in in the following format:
Inky Pinky Blinky Clyde Luigi Mario Bowser
0 2
1 2
5 6
3 5
2 4
4 5
2 3
1 4
closefriends 1 2 4
where the first line is persons, the numbers are friendships.
The program checks whether or not the people listed in the last line are in a "close friendship", where they're all friends.
I represent the network as an incident matrix, and it passes every test on the test site we use, except one, which fails with a "Runtime Error". I know it's not an exception, because catching all exceptions does nothing to the error, while catching all errors does.
Here's the code:
public class CloseFriends {
// Contains edges represented as an incident matrix
private static boolean edges[][];
// Adds a directed edge between v1 and v2
// The method sorts the edges to reduce space used
public static void addEdge(int v1, int v2) {
if (v1 > v2) {
edges[v1][v2] = true;
}
else {
edges[v2][v1] = true;
}
}
// Creates a graph with V vertices
public static void createVertices(int V) {
edges = new boolean[V][V];
}
// Checks if an edge exists between v1 and v2
public static boolean isFriends(int v1, int v2) {
if (v1 > v2) {
return edges[v1][v2];
}
else {
return edges[v2][v1];
}
}
// Checks if an ArrayList of vertices is close friends
public static void closeFriends(ArrayList<Integer> vertices) {
int count = 0;
int size = vertices.size();
for (int i = 0; i < size; i++) {
for (int j = i + 1; j < size; j++) {
if (isFriends(vertices.get(i), vertices.get(j))) {
count++;
}
}
}
// The clique should contain n*(n-1)/2 edges for everyone to be connected
if (count == (size * (size - 1) / 2)) {
System.out.println("yes");
}
else {
System.out.println("no");
}
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(in.readLine());
// Count vertices, and create that amount
int V = 0;
while (st.hasMoreTokens()) {
st.nextToken();
V++;
}
createVertices(V);
ArrayList<Integer> friends = new ArrayList<Integer>();
// While System.in has something to be read
while (in.ready()) {
// Read the line and add edges based on input, or run the algorithm
String edge = "";
edge = in.readLine();
if (edge != null) {
st = new StringTokenizer(edge);
if (!edge.startsWith("closefriends")) {
addEdge(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
}
else {
st.nextToken();
while (st.hasMoreTokens()) {
friends.add(Integer.parseInt(st.nextToken()));
}
}
}
}
closeFriends(friends);
}
}
Thanks!
I have a constructor ID3 and I need to start by executing it from the main. Is it possible?
I tried doing this:
public class ID3
{
public static void main(String[] args) throws Exception
{
System.out.print("\f"); //clears the screen
ID3 instance = new ID3("data.txt", 5 , 14 , "", 5);
instance.ID3("data.txt", 3 , 5 , " ", 2); //error given here since this line had to be removed
}
public ID3(String fName, int numAttributes, int testCases, String delimiter, int limitSplits) throws IOException, FileNotFoundException
{
fileName = fName;
n = numAttributes;
t = testCases;
numSplits = limitSplits;
FileInputStream fstream = new FileInputStream(fileName);
DataInputStream in = new DataInputStream(fstream);
//Parse the first line to see if continuous or discrete attributes.
firstLine = new String[n];
firstLine = in.readLine().split(delimiter);
int i, j, lineCount = 0;
for(i=0; i<n; i++)
unusedAttr.add(new Integer(i));
input = new String[t][n+1];
String line;
int invalidLines = 0;
while((lineCount + invalidLines)<t)
{
try
{
input[lineCount] = (in.readLine()).split(delimiter);
}
catch(NullPointerException e)
{
invalidLines++;continue;
}
if (Array.getLength(input[lineCount]) != n+1 || (Array.get(input[lineCount],n).toString().compareTo("?") == 0)) //number of attributes provided in the line is incorrect.
{
invalidLines++;continue;
}
lineCount++;
}
if(invalidLines == t)
{
System.out.println("All lines invalid - Check the supplied attribute number");
System.exit(0);
}
if (invalidLines > 0)
System.out.println("Not Considering "+invalidLines+" invalid training cases");
if(numSplits > maxSplits || numSplits > (t/2))
{
System.out.println("numSplits should be less than or equal to "+Math.min(t/2,limitSplits));
System.exit(1);
}
t = testCases - invalidLines;
thresholdVal = new String[n][numSplits - 1];
boolean allCont = false;
if(Array.getLength(firstLine) == 1)
{
if(firstLine[0].compareTo("c") == 0)
allCont = true;
else if(firstLine[0].compareTo("d") == 0)
return;
else
{
System.out.println("Invalid first line - it should be c or d");
System.exit(1);
}
}
for(i=0; i<n; i++)
{
if(allCont || firstLine[i].compareTo("c") == 0) //Continuous Attribute
{
for(j=0; j<numSplits-1; j++)
thresholdVal[i][j] = calculateThreshold(i,j);
}
else if(firstLine[i].compareTo("d") != 0)
{
System.out.println("Invalid first line - Training data (it should specify if the attributes are c or d)");
System.exit(1);
}
}
for(i=0; i<t; i++)
{
for(j=0; j<n; j++)
{
if(allCont || firstLine[j].compareTo("c") == 0)
input[i][j] = makeContinuous(input[i][j], j);
}
}
}
The code for the constructor is shown above, however it finds the file but doesn't process the data and prints the errors out. How should the file be exactly?
Used text file has:
d
Span Shape Slab
long square waffle
long rectangle waffle
short square two-way
short rectangle one-way
You are already calling the constructor here - ID3 instance = new ID3("data.txt", 5 , 14 , "", 5);. You can't call it as a regular method. Just remove the instance.ID3("data.txt", 5 , 14 , "", 5); line.
You cannot call constructors like regular methods. The constructor is automatically called when you create an instance of a class,i.e,when you do
ID3 instance = new ID3("data.txt", 5 , 14 , "", 5);
Contructors are not methods. One of the key feature of a method is that it should have a return type (event if it is 'void').
Here, you do not need to explicitly call the constructor again. The functionality you implement in the constructor will be executed at instantiation itself. However, this is not recommended and is bug-prone. You should only be instantiating any variables. The actual functionality should be defined in another method.
I've been asked to make this more space efficient, I'm assuming that I need to use loops but I'm not entirely sure how to, some help would be appreciated.
(For reference the aim of this piece of code is to display a graph into another program using data which has already been collected in the other program)
public class StudentChart
{
public StudentChart(int[] moduleMarks) //Constructor
{
Bar y = new Bar();
y.makeVisible();
y.changeSize(1, 100);
y.moveVertical(100);
y.moveHorizontal(-1);
y.changeColour(Colour.BLACK);
//y-axis is produced
Bar x = new Bar();
x.makeVisible();
x.changeSize(200,1);
x.moveVertical(200);
x.changeColour(Colour.BLACK);
//x-axis is produced
draw(moduleMarks);
printSummary(moduleMarks);
}
public static void draw(int[] moduleMarks)
{
int a = moduleMarks[0];
int b = moduleMarks[1];
int c = moduleMarks[2];
int d = moduleMarks[3];
int e = moduleMarks[4];
int f = moduleMarks[5];
//stores module marks from array as variables to be used later
Bar mod1 = new Bar();
Bar mod2 = new Bar();
Bar mod3 = new Bar();
Bar mod4 = new Bar();
Bar mod5 = new Bar();
Bar mod6 = new Bar();
mod1.makeVisible();
mod2.makeVisible();
mod3.makeVisible();
mod4.makeVisible();
mod5.makeVisible();
mod6.makeVisible();
//Bars are initialised and made visible
mod1.moveVertical(200-a);
mod2.moveVertical(200-b);
mod3.moveVertical(200-c);
mod4.moveVertical(200-d);
mod5.moveVertical(200-e);
mod6.moveVertical(200-f);
//Bars are moved based on their height so that they touch the x-axis
mod1.changeSize(15, a);
mod2.changeSize(15, b);
mod3.changeSize(15, c);
mod4.changeSize(15, d);
mod5.changeSize(15, e);
mod6.changeSize(15, f);
//Bar height changes depending on the module marks
mod1.moveHorizontal(0);
mod2.moveHorizontal(35);
mod3.moveHorizontal(70);
mod4.moveHorizontal(105);
mod5.moveHorizontal(140);
mod6.moveHorizontal(175);
//Bars are moved across so can be seen on chart
if (a<35)
{
mod1.changeColour(Colour.RED);
}
if (a>= 35 && a<40)
{
mod1.changeColour(Colour.YELLOW);
}
if (a>= 40 && a<70)
{
mod1.changeColour(Colour.GREEN);
}
if (a>= 70)
{
mod1.changeColour(Colour.MAGENTA);
}
if (b<35)
{
mod2.changeColour(Colour.RED);
}
if (b>= 35 && a<40)
{
mod2.changeColour(Colour.YELLOW);
}
if (b>= 40 && a<70)
{
mod2.changeColour(Colour.GREEN);
}
if (b>= 70)
{
mod2.changeColour(Colour.MAGENTA);
}
if (c<35)
{
mod3.changeColour(Colour.RED);
}
if (c>= 35 && a<40)
{
mod3.changeColour(Colour.YELLOW);
}
if (c>= 40 && a<70)
{
mod3.changeColour(Colour.GREEN);
}
if (c>= 70)
{
mod3.changeColour(Colour.MAGENTA);
}
if (d<35)
{
mod4.changeColour(Colour.RED);
}
if (d>= 35 && a<40)
{
mod4.changeColour(Colour.YELLOW);
}
if (d>= 40 && a<70)
{
mod4.changeColour(Colour.GREEN);
}
if (d>= 70)
{
mod4.changeColour(Colour.MAGENTA);
}
if (e<35)
{
mod5.changeColour(Colour.RED);
}
if (e>= 35 && a<40)
{
mod5.changeColour(Colour.YELLOW);
}
if (e>= 40 && a<70)
{
mod5.changeColour(Colour.GREEN);
}
if (e>= 70)
{
mod5.changeColour(Colour.MAGENTA);
}
if (f<35)
{
mod6.changeColour(Colour.RED);
}
if (f>= 35 && a<40)
{
mod6.changeColour(Colour.YELLOW);
}
if (f>= 40 && a<70)
{
mod6.changeColour(Colour.GREEN);
}
if (f>= 70)
{
mod6.changeColour(Colour.MAGENTA);
}
//Colour changes depending on module mark
//Could be improved
}
public static void printSummary(int[] moduleMarks)
{
for(int i =0; i<moduleMarks.length; i=i+1)
{
System.out.println("Module "+ (i+1) + " " + moduleMarks[i]);
}
//Prints module marks in a table
}
public static void main(String[] args)
{
}
}
You could do something like this:
int horizontalMovement = 0;
for (int moduleMark : moduleMarks) {
Bar bar = new Bar();
bar.makeVisible();
bar.moveVertical(200 - moduleMark);
bar.changeSize(15, moduleMark);
bar.moveHorizontal(horizontalMovement);
horizontalMovement = horizontalMovement + 35;
if (moduleMark < 35) {
bar.changeColour(Colour.RED);
} else if (moduleMark < 40) {
bar.changeColour(Colour.YELLOW);
} else if (moduleMark < 70) {
bar.changeColour(Colour.GREEN);
} else {
bar.changeColour(Colour.MAGENTA);
}
}
There are lots of things you can do here:
int a = moduleMarks[0];
int b = moduleMarks[1];
int c = moduleMarks[2];
int d = moduleMarks[3];
int e = moduleMarks[4];
int f = moduleMarks[5];
Here you can make an int array:
int modules[] = new int[moduleMarks.length()];
Then you can go through with a for-loop and add:
for(int i = 0; i < 6; i++) {
modules[i] = moduleMarks[i];
}
You can do similar changes to the rest of your code using this as inspiration.
Right now this code will only work if the elements in moduleMarks is only 6 elements long. If there were 9 elements in that array only the first 6 would be drawn. Sorta makes this code not terribly useful. However, you can write code that will accept an array of any length and respond accordingly.
You've been given a hint how to start that process in the code you were given:
for(int i =0; i<moduleMarks.length; i=i+1)
{
System.out.println("Module "+ (i+1) + " " + moduleMarks[i]);
}
That will iterate over every member of moduleMark regardless of length. So you need to apply this idea to the rest of your program so that whatever draw is doing will work regardless of moduleMark's size.
You'll see there is a lot of code repeated for each element corresponding to a member in moduleMark. Use loops to reduce that repeated code. You'll have to model things with data (ie arrays) in order to rewrite that code using for loops.
I'm trying not to give the answer away because this is clearly homework and you should figure it out yourself.
Put your bars into an array (Bar[]). Keep your moduleMarks in the array that they originally came in. Then you can use a loop or set of nested loops:
for(int i = 0; i < modArray.size; ++i) {
modArray[i].makeVisible();
modArray[i].moveVertical(200-moduleMarks[i]);
modArray[i].changeSize(15, moduleMarks[i]);
modArray[i].moveHorizontal(35*i);
//etc.
}
I have a .txt file with following format data(co-ordinates)
0 1 12.56
2 0 -56.2
1 2 78.2
0 -56.2 2
-2 8 0
I imported this data into using the following code.
public ArrayList<Point3d> loadFile(String filename) {
ArrayList<Point3d> words = new ArrayList<Point3d>();
try {
Scanner chopper = new Scanner(new File(filename));
while (chopper.hasNext()) {
double x=chopper.nextDouble();
double y=chopper.nextDouble();
double z=chopper.nextDouble();
Point3d p=new Point3d(x, y, z);
words.add(p);
// just calling nextLine will cause an exception at the end of the file unless you have an blank line there on purpose, so this makes sure it does
}
chopper.close();
} catch (Exception e) {
System.out.println(e);
}
return words;
}
importing is working fine.Know I want to separate negative, positive coordinates also I want to append their corresponding index values.
Finally I want result in the following way.
Result :
positiveList= {{0,0,1,12.56},{2,1,2,78.2}}
negativeList={{1,2,0,-56.2},{3,0,-56.2,2},{4,-2,8,0}}
How can I do this.
My solution here uses the Map data structure, but you can create 2 Lists of Lists if you wish.
Outside the while loop add:
Map<Integer, Point3D> negativeCoord = new HashMap<>();
Map<Integer, Point3D> positivetiveCoord = new HashMap<>();
int currentIndex = 0;
and inside it:
Point3d p = new Point3d(x, y, z);
if(x < 0 || y < 0 || z < 0) {
negativeCoord.put(currentIndex, p);
} else {
positiveCoord.put(currentIndex, p);
}
currentIndex++;
You could do this after loading the file, like so:
Map<Integer, Point3d> positiveList = new java.util.HashMap<Integer, Point3d>();
Map<Integer, Point3d> negativeList = new java.util.HashMap<Integer, Point3d>();
for (int i = 0; i < words.size(); i++) {
Point3d p = words.get(i);
if (p.x < 0 || p.y < 0 || p.z < 0) {
negativeList.put(i + 1, p);
} else {
positiveList.put(i + 1, p);
}
}
or integrate the above in your while-loop, what saves you from iterating over all the words twice.
This would be the solution to just have the positives and negatives, without knowing their order.
public ArrayList<Point3D> getPositives(ArrayList<Point3D> points) {
ArrayList<Point3D> positives = new ArrayList<>();
for(Point3D next : points) {
if(next.getX() >= 0 && next.getY() >= 0 && next.getZ() >= 0)
posivites.add(next);
}
return positives.
}
public ArrayList<Point3D> getNegatives(ArrayList<Point3D> points) {
ArrayList<Point3D> negatives = new ArrayList<>();
for(Point3D next : points) {
if(next.getX() < 0 || next.getY() < 0 || next.getZ() < 0)
negatives.add(next);
}
return negatives.
}
Depending on your scenario it could be wise to have an own container class for the information.
public class PointContainer {
public final Point3D point;
public final int order;
public PointCoordinates (Point3D p, int order) {
this.point = p;
this.order = order;
}
public boolean isNegative() {
return point.getX() < 0 || point.getY() < 0 || point.getZ() < 0;
}
}
and then populate your list with it.
public ArrayList<Point3d> loadFile(String filename) {
ArrayList<PointContainer> words = new ArrayList<PointContainer>();
try {
Scanner chopper = new Scanner(new File(filename));
for (int line = 0; chopper.hasNext(); line ++) {
double x=chopper.nextDouble();
double y=chopper.nextDouble();
double z=chopper.nextDouble();
Point3d p=new Point3d(x, y, z);
PointCoordinates pc = new PointCoordinates(p, line);
words.add(pc);
// just calling nextLine will cause an exception at the end of the file unless you have an blank line there on purpose, so this makes sure it does
}
chopper.close();
} catch (Exception e) {
System.out.println(e);
}
return words;
}
That way you have that information ready to use for everything you want to do.