Background:
I've successfully written code that generates a sine wave from 0 to 2pi. Adjusting the constants xPrecision and yPrecision, you can stretch the graph horizontally or vertically.
I gain this neat output (in Eclipse), when xPrecision = yPrecision = 10:
My query:
I now wish to display digits 0 to 9 instead of the stars. So, the leftmost star is replaced by 0, the second left-most star is replaced by 1, and so on. When you reach 9, the next digit is again zero.
I am clueless as to how to do this. I have looked at wave patterns like this, but they are fixed width patterns, while mine is scalable.
The only way I can think of is converting my output to a 2D character array, then scraping the *s manually from left to right, and replacing them with the digits, and then printing it. However, this is extremely memory consuming at bigger values of x/yPrecision.
What is the most optimized way to achieve this output?
Code to print sine wave:
class sine {
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) (3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
public static void main(String[] args) {
double xd;
for(int start = (int) (1 * yPrecision), y = start; y >= -start; y--){
double x0 = Math.asin(y / yPrecision),
x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI/xPrecision - x0);
// for debug
//System.out.println(y + " " + x0 + " " + x1 + " " + x2 + " " + x3);
for(int x = 0; x <= TPI; x++){
xd = (x / xPrecision);
if(x1 == xd || x2 == xd || x3 == xd)
System.out.print("*");
else System.out.print(" ");
}
System.out.println();
}
}
public static double bringXValueWithinPrecision(double num){
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
}
"Draw" the graph in memory first, then assign digits to its vertical points, and print them in a separate pass.
01
9 2
8 3
7 4
6 5
5 6
4 7
3 8
2 9
1 0
0 1 2
2 1
3 0
4 9
5 8
6 7
7 6
8 5
9 4
0 3
12
See comments in the code for an explanation of how this works:
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) (3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
public static void main(String[] args) {
// This part is the same as OP's code, except that instead of printing '*'
// it stores the corresponding row number in the array of rows
double xd;
int[] row = new int[100];
Arrays.fill(row, -1);
int r = 0;
int maxc = 0; // Mark the rightmost column of all iterations
for(int start = (int) (1 * yPrecision), y = start; y >= -start; y--){
double x0 = Math.asin(y / yPrecision),
x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI/xPrecision - x0);
int c = 0;
for(int x = 0; x <= TPI; x++, c++){
xd = (x / xPrecision);
// This is where the asterisk used to go
if(x1 == xd || x2 == xd || x3 == xd)
row[c] = r;
}
maxc = Math.max(c, maxc);
r++;
}
// Walk the assigned rows, and give each one a consecutive digit
int[] digit = new int[100];
int current = 0;
for (int i = 0 ; i != 100 ; i++) {
if (row[i] != -1) {
digit[i] = (current++) % 10;
}
}
// Now walk the rows again, this time printing the pre-assigned digits
for (int i = 0 ; i != r ; i++) {
for (int c = 0 ; c != maxc ; c++) {
if (row[c] == i) {
System.out.print(digit[c]);
} else {
System.out.print(' ');
}
}
System.out.println();
}
}
public static double bringXValueWithinPrecision(double num){
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
The first part of the code fills row[i] array, which contains row for the asterisk in column i. First few numbers from row[] array would look like this:
10 9 8 7 6 5 4 - 3 2 - 1 - - - 0 0 - - - 1 - 2 3 - 4 5 6 7 8 9 10
- denotes cells with -1, which represents a missing value. The array says that the left-most asterisk is on row 10, the next asterisk is on row 9, then 8, 7, 6, and so on. Asterisks 11 and 12 are on row zero, which is at the top.
The second loop walks rows, skips -1s, and assign consecutive digits to all non-negative positions.
The third loop walks the entire field again going row-by-row, printing values from pre-assigned digit[] array when the current row matches the value in the row[] array.
Demo.
If you replace:
System.out.print("*");
with
System.out.print(""+(x%10));
it seems to nearly work.
56
1 0
9 2
8 3
6 5
5 6
4 7
3 8
2 9
1 0
0 1 2
2 1
3 0
4 9
5 8
6 7
7 6
9 4
0 3
2 1
67
Perhaps some further adjustments might get it perfect.
Doing it in a completely different way produces a different picture but achieves your effect.
Essentially,
for each y
for each x
calculate fx = sin(x)
if fx == y print * else print space
It's very inefficient as it calculates sin(x) x*y times when, if you filled a matrix, you could calculate sin(x) just x times.
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
private void sine() {
for (double y = 1; y >= -1; y -= 1.0 / yPrecision) {
int n = 0;
for (double x = 0; x < 2.0 * Math.PI; x += 1.0 / xPrecision, n++) {
double fx = Math.sin(x);
boolean star = Math.round(fx*xPrecision) == Math.round(y*yPrecision);
System.out.print((star ? ""+(n%10) : " "));
}
System.out.println();
}
}
public void test(String[] args) {
sine();
}
Gives you:
345678
12 901
90 2
8 34
67 5
5 6
4 7
3 8
2 9
1 0
0 1
2 2
3 1
4 0
56 9
7 8
8 67
9 5
01 34
23 12
4567890
Since this is Java, how about let's actually use some objects as objects rather than just as places to define a couple of functions.
Treat your wavy graph as if it is a composition of several different "branches" of the inverse sine function. (Mathematically, that's how we explain the way your version of the program uses Math.asin to produce multiple coordinates for stars.)
Branch 0 is the initial rising part of the curve,
Branch 1 is the falling part of the curve after Branch 0,
Branch 2 is the rising part of the curve after Branch 1, and so forth.
The branches cross the middle line of the output at x values 0,
PI, 2*PI, 3*PI, and so forth.
Depending on how far you want the graph to extend to the right, it is easy to determine how many branches you need.
For example, to plot from 0 to 8*PI you need nine branches
(Branch 0, Branch 8, and the seven branches between those two).
You can implement each branch using an object of some class,
let's call it ArcSineBranch.
It has a constructor, ArcSineBranch(int), that takes the branch number as a parameter.
Create some sort of ordered list (which could just be an ArcSineBranch[] array) and put these branch objects in it,
making sure the branch numbers go in sequence from 0 up to the largest number needed.
You'll also want to implement some way to tell the first ArcSineBranch where its leftmost end is--in the example in the question, the leftmost end of first branch is at y == 0, whereas for all other rising branches it is at y == -start and for all falling branches it is at y == start.
Now you call a mutator function of the first ArcSineBranch that tells it its leftmost symbol is 0. Treat this as an integer (rather than a string) for now to make the arithmetic easier.
You then query the first ArcSineBranch for the rightmost symbol it will write, which it can compute from the leftmost symbol and the number of lines it will write symbols on.
You also query it for the x coordinate of that rightmost symbol.
(The object computes the x-coordinate of the symbol for any y-coordinate by either adding or subtracting a rounded multiple of Math.asin(y / yPrecision) from a multiple of PI.)
Now for each ArcSineBranch in the list, you pass to it the rightmost symbol and x coordinate written by the previous branch.
This ArcSineBranch uses that information to determine the leftmost symbol it writes and the y coordinate of that symbol.
(I am being careful here about the y coordinate in case you choose a value of xPrecision that causes the rightmost x coordinate of one branch to be the same as the leftmost x coordinate of the next; we should only write one symbol at that place in the output, so we want the later branch to skip its leftmost x coordinate and write its leftmost symbol in the next place, one line up or down. But if the x coordinates are different we want the later branch to write a symbol on the same line.)
Now that the later ArcSineBranch "knows" the leftmost symbol it will print and thata symbol's y coordinate, you can query it for its rightmost symbol and x coordinate, and pass those to the next ArcSineBranch, and so forth.
Once you have traversed all the ArcSineBranch objects in this way,
so that each object knows what symbols need to be written for its branch and where to write them, you can loop for (y = start; y >= -start; y--);
within that loop you loop over the list of ArcSineBranch objects;
for each object you query whether it requires a symbol to be written at
y-coordinate y.
If the object requires a symbol to be written,
you query which symbol to write at which x-coordinate,
then space the output to the right until you reach that x-coordinate and write that symbol there.
But of course, first check that this would not plot a symbol beyond the
right-hand edge of the desired graph.
(This check really only applies to the last ArcSineBranch, so you can optimize the code a bit by looping over the other branches first and then dealing with the last ArcSineBranch separately.)
I've already described this algorithm in more detail than I initially wanted to. There should be enough information here to code this into Java in a relatively straightforward way, though there are still some localized details to be worked out.
Note that the design in this answer is intended to use the same mathematical ideas as the code in the question uses to decide where to plot the points.
Specifically, ArcSineBranch(0) produces the x1 values from the original code, ArcSineBranch(1) produces the x3 values, and ArcSineBranch(2) produces the x2 values.
The implementation of this design should plot a digit at the location of each star plotted by the original code, and should plot no other digits.
Care about a different approach?
3030
28 28
26 26
22 22
18 18
12 12
06 06
00 00 00
06 06
12 12
18 18
22 22
26 26
28 28
3030
Solution:
import static java.lang.Math.sin;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
public class Sine {
static final Integer points = 30; // points on x and y axis
public static void main(String[] args) {
// contains graph points
Boolean[][] graph = new Boolean[points + 1][points + 1];
for (Double x = 0.0; x <= points; x++) {
// x axis pi value
Double pi = (x / points) * 2 * PI;
// sin(x) plot for x
Integer sinx = (int) Math.round((sin(pi) * points / 2) + points / 2);
graph[sinx][x.intValue()] = true;
}
for (Integer i = 0; i <= points; i++) {
for (Integer j = 0; j <= points; j++) {
// space characters on x axis
Integer pt = (int) Math.floor(Math.log10(points) + 1);
String space = String.format("%" + pt + "s", " ");
// padding for p
String p = String.format("%0" + (pt) + "d", abs(i - points / 2) * 2);
System.out.print(graph[i][j] != null ? p : space);
}
System.out.println();
}
}
}
Approach:
points contains the number of characters on x and y axis.
graph contains true or null for each x and y characters.
1st for loop:
Since the value of x in sine graph is from 0 to 2π, we need to convert x accordingly. So pi contains the value of the same range but according to x.
sinx is the Integer value according to x.
No need to explain graph[sinx][x.intValue()] = true;.
2nd for loops:
1st for loop
Execute LOOPLABEL.
Break to next line at the end.
2nd for loop(LOOPLABEL)
pt holds the number for padding on y axis.
space is the space characters to be printed on y axis.
p is the converted range between 0 to points.
Printing graph[i][j]
DEMO
By using the fact that each row has one point (on each slope), you can calculate which digit to display at each point without using extra memory or loops. Here's my example. Note that I only checked that this example only works if xPrecision and yPrecision are integers. You'll have to modify it if you want to use doubles.
class sine {
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) Math.round(Math.PI * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
static final int cycles = 2; // prints from x=0 to 2*cycles*pi
public static void main(String[] args) {
double xd;
int cycleoffset, cycleoffset2, topbottomoffset = 1;
for (int start = (int) (1 * yPrecision), y = start; y >= -start; y--) {
double x0 = Math.asin(y / yPrecision), x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI / xPrecision - x0), tmp;
if (y == start) {
if (x1 == x3) // when there is only one point at the top/bottom
topbottomoffset = 0;
else if (x1 > x3) // swap x1 and x3
{
tmp = x1;
x1 = x3;
x3 = tmp;
}
} else if (y == -start) {
// I don't think this is needed, but just for safety make sure there is only one point on the bottom if there was only one point at the top
if (topbottomoffset == 0)
x2 = x3;
else if (x2 < x3) // swap x2 and x3
{
tmp = x2;
x2 = x3;
x3 = tmp;
}
}
cycleoffset = (int) (4 * yPrecision + 2 * topbottomoffset);
cycleoffset2 = -cycleoffset;
int start1 = topbottomoffset + 2 * (int) yPrecision, start2 = 2 * topbottomoffset + 4 * (int) yPrecision;
for (int x = 0, lim = cycles * TPI; x <= lim; x++) {
xd = ((x % TPI) / xPrecision);
if (x % TPI == 0)
cycleoffset2 += cycleoffset;
// x = 0 to pi/2
if (x1 == xd)
System.out.print((cycleoffset2 + y) % 10);
// x = 3pi/2 to 2pi
else if (x2 == xd)
System.out.print((cycleoffset2 + start2 + y) % 10);
// x = pi/2 to 3pi/2
else if (x3 == xd)
System.out.print((cycleoffset2 + start1 - y) % 10);
else
System.out.print(" ");
}
System.out.println();
}
}
public static double bringXValueWithinPrecision(double num) {
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
}
EDIT
The digits for the different ranges are calculated as follows
0 < x < π/2 : This one is simplest since it is the first range. Since the middle row is y=0 and that is where the sine wave starts, we can just use y to find the digit.
π/2 < x < 3π/2 : The digits here count up as we go down, but y decreases as we go down. So we have to use a -y term. On the top row, y=yPrecision, and the last digit from the previous range was yPrecision. So we use 2*yPrecision - y, because that includes the -y, and is equal to yPrecision at the first term (where y=yPrecision).
3π/2 < x < 2π : The digits here count down as we go down, so we need a +y term, but the tricky part is figuring where to start. Since the sine wave by this point has gone from 0 to yPrecision to 0 to -yPrecision, the bottom point (x=3π/2) should start at 3*yPrecision. Since y=-yPrecision at the bottom point, we use 4*yPrecision + y, since that includes a +y and is equal to 3*yPrecision at the first term (where y=-yPrecision).
The topbottomoffset term : Depending on the values used for xPrecision and yPrecision, there can be one or two points plotted on the top and bottom rows. If there are two points, we need to add one to digits in the π/2 to 3π/2 range, and two to the digits in the 3π/2 to 2π range.
The cycleoffset term : If multiple cycles of the sine wave are plotted, additional cycles need to start from the last digit used in the previous cycle. Each cycle goes from 0 to yPrecision to 0 to -yPrecision to 0, which is equal to 4*yPrecision. So each new cycle needs to start at 4*yPrecision*[the number of previous cycles]. If there are two points on the top and bottom rows, those need to be factored in as well.
Swapping values: When there are two points on the top row, then x1>x3. This happens because when y=yPrecision, we're taking Math.asin(1), which happens to be exactly pi/2=1.5707963267948966 in Java's double system. On lower xPrecision (<100.0), the rounding done by bringXValueWithinPrecision brings x1 up to 1.58 while x3 down to nearly 1.56. Hence, they need to be swapped in order to get the correct numerical order.
Here's my solution, which basically uses the half of the sine in 4 for loops:
from half to 0
from 0 to half
from half to the end
from the end to the half
And in each loop replace only the first asterisk.
class sine {
static final double xPrecision = 14.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 14.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int)(3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
public static void main(String[] args) {
double xd;
String str = "";
for (int start = (int)(1 * yPrecision), y = start; y >= -start; y--) {
double x0 = Math.asin(y / yPrecision),
x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI / xPrecision - x0);
// for debug
//System.out.println(y + " " + x0 + " " + x1 + " " + x2 + " " + x3);
for (int x = 0; x <= TPI; x++) {
xd = (x / xPrecision);
if (x1 == xd || x2 == xd || x3 == xd)
str += "*";
else str += " ";
}
str += "\n";
}
String[] rows = str.split("\n");
int half = (int)(1 * yPrecision);
// we use this half in for loops, from half to 0, from 0 to half, from half to the end and from the end to the half, and replace only the first asterisk.
int val = 0;
for (int i = half; i >= 0; i--) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
for (int i = 0; i <= half; i++) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
for (int i = half + 1; i < rows.length; i++) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
for (int i = rows.length - 1; i >= half; i--) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
System.out.println(String.join("\n", rows));
}
public static double bringXValueWithinPrecision(double num) {
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
}
Result:
01
9 2
8 3
7 4
6 5
5 6
4 7
3 8
2 9
1 0
0 1 2
2 1
3 0
4 9
5 8
6 7
7 6
8 5
9 4
0 3
12
Add a counter in your loop and reset it when 9 is reached:
for(int x = 0, counter = 0; x <= TPI; x++, counter++){
xd = (x / xPrecision);
if(x1 == xd || x2 == xd || x3 == xd) {
System.out.print("" + counter);
if (counter == 9) {
counter = 0;
}
} else {
System.out.print(" ");
}
}
The problem has been discussed on stackoverflow before, I'm specifically asking for opinion or answers regarding my code and whether or not it can work with imbalanced 2d arrays without a major overhaul. The reason it's failing to print the end of some balanced arrays must be some smaller issue. Update at the bottom
Basically we have a 2d array supplied by a command line driven text file. That file has each trial separated by a newline and follows like this: rows;columns;values(white space delimited)
Example: 4;4;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Output: 1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package spiralprinting;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
*
* #author Paul
*/
public class SpiralPrinting {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException, IOException {
// TODO code application logic here
File file = new File(args[0]);
BufferedReader in = new BufferedReader(new FileReader(file));
String line;
while ((line = in.readLine()) != null) {
String[] lineArray = line.split(";");
if (lineArray.length > 0) {//ignore blank line inputs
//Process line of input Here
//Max ,minimum, and current indexes in our matrix.
int maxX = Integer.parseInt(lineArray[0]) - 1;
int maxY = Integer.parseInt(lineArray[1]) - 1;
int minX = 0;
int minY = 0;
int x = 0;
int y = 0;
//Build our matrix
String[] valueArray = lineArray[2].split("\\s");
String[][] matrix = new String [Integer.parseInt(lineArray[0])][Integer.parseInt(lineArray[1])];
int count = 0;
for (int j = 0; j <= maxY; j++){
for (int i = 0; i <= maxX; i++){
matrix[i][j] = (valueArray[count]);
count++;
}
}
StringBuilder printString = new StringBuilder();
//Traverse and print our matrix in a spiral!
while (maxX > minX && maxY > minY){
//Leaving this in and commented so you can see my train of thought.
if (x != maxX){
while (x < maxX){
printString.append(matrix[x][y]).append(" ");
x++;
}maxX--;
}
if (y != maxY){
while (y < maxY){
printString.append(matrix[x][y]).append(" ");
y++;
}maxY--;
}
if (x != minX){
while (x > minX){
printString.append(matrix[x][y]).append(" ");
x--;
}minX++;
}
if (y != minY){
while (y > minY){
printString.append(matrix[x][y]).append(" ");
y--;
}minY++;
}
//One border done (4 passes). Next iteration of while-loop begins.
x = minX;
y = minY;
}//end of our traversal loop
//Print it !
System.out.println(printString.toString().trim());
}
}//end of input line analysis
}
}//end of class
Sample input and current output:
4;4;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ---> 1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 good
3;3;1 2 3 4 5 6 7 8 9 ---> 1 2 3 6 9 8 7 4 This fails to print the 5
3;4;1 2 3 4 5 6 7 8 9 10 11 12 ---> 1 2 3 6 9 12 11 10 7 4 ..fails to print the 5, 8 at the end...
4;3;1 2 3 4 5 6 7 8 9 10 11 12 ---> 1 2 3 4 8 12 11 10 9 5 ..fails to print the last 2 again: 6, 7"
2;10;1......20 ---> 1, 2, 4, 6, 8....good
After some quick revisions, my issue appears to be that it is not printing the last 2 for some sets. I'm convinced this is a special case and I'm going to sleep on it :)
Any help is still appreciated, especially if you think the issue is larger than I currently believe. My sleepy brain thinks I need 2 special cases to go along with my 4 checks in the while-loop...
Thank you =]
When your debugging something and you just CANT wrap your mind around whats going wrong... break it down into something easy to debug, throw out your hard test cases and try something very simple then move up to harder ones and find where it breaks, heres how i found it.
I commented out all your code where you input the file and made your input to a fixed string:
String[] lineArray = ("3;2;" +
"1 2 3 " +
"6 5 4 ").split(";");
// see how the output should be 123456...very easy to see and debug
Putting a breakpoint at while (maxX > minX || maxY > minY), I looked at the matrix array and saw that the matrix was of size 2x3 not 3x2, and my numbers were not stored how I would think they should be. And voila problem found.
/*if (maxY >= maxX){*/
// This for loop is what you want
for (int j = 0; j <= maxY; j++){
for (int i = 0; i <= maxX; i++){
matrix[i][j] = (valueArray[count]);
count++;
}
}
/*}/*delete this junk/ else if (maxX > maxY){
for (int i = 0; i <= maxX; i++){
for (int j = 0; j <= maxY; j++){
matrix[i][j] = (valueArray[count]);
count++;
}
}
}*/
This is a fun one for recursion. I assume you already submitted your code for your project so I took a stab at it. Heres what I ended up with: (I left in the printlns so you could see the program flow)
// called by System.out.println(getSpiral(matrix,0,0,0,0));
public static String getSpiral(String[][] array, int x, int y, double direction, int turnCount) {
int [] velocity = getDirection(direction);
if(x+velocity[0] >= array.length || y+velocity[1] >= array[x].length ||
x+velocity[0] < 0 || y+velocity[1] < 0 ||
array[x+velocity[0]][y+velocity[1]].equals("done")) {
System.out.println("turn");
if(turnCount>=3)
return array[x][y];
return getSpiral(array, x, y, direction+Math.PI/2,turnCount+1);
}
String value = array[x][y].toLowerCase();
array[x][y]="done";
System.out.println(value);
return value + " " + getSpiral(array, x+velocity[0], y+velocity[1], direction,0);
}
public static int[] getDirection(double angle) {
return new int[] {(int)Math.round(Math.cos(angle)), (int)Math.round(Math.sin(angle))};
}
clockwise traversal
public static String matrixTraverse(int[][] matrix, int startX, int startY){
String result = "";
boolean baseCase = startX + 1 == Math.ceil(matrix[0].length / 2.0)
|| startY + 1 == Math.ceil(matrix.length / 2.0);
for (int i = startX ; i < matrix[0].length - startX ; i++) {
result += " " + matrix[startY][i];
}
for (int i = startY + 1 ; i < matrix.length - startY - 1 ; i++){
result += " " + matrix[i][matrix[0].length - 1 - startX];
}
for (int i = startX ; (matrix.length - 1 != 2 * startY) && (i < matrix[0].length - startX) ; i++){
result += " " + matrix[matrix.length - 1 - startY][matrix[0].length - 1 - i];
}
for (int i = startY ; (matrix[0].length - 1 != 2 * startX) && (i < matrix.length - startY - 2) ; i++){
result += " " + matrix[matrix.length - 2 - i][startX];
}
if (!baseCase) {
result += matrixTraverse(matrix, ++startX, ++startY);
}
return result;
}
I'm trying to get Y,U,V values separately in order to pass them to openGL and map to a texture. I know these values can be found in AVPicture.data[0] (Y) and AVPicture.data[1] (U) and AVPicture.data[2] (V)
avcodec_decode_video2(ctx, frame, &frameFinished, packet_data->packet);
AVPicture _avPicture;
picSize = avpicture_get_size(ctx->pix_fmt, ctx->width, ctx->height);
avpicture_alloc(&_avPicture, ctx->pix_fmt,ctx->width, ctx->height );
avpicture_fill(&_avPicture, packet_data->packet, ctx->pix_fmt,ctx->width,ctx->height);
^^ That's working fine.
The issue I run into is passing the Y,U,V values back to Java via JNI. I have to know the size of the data the AVPicture.data[x] pointers point to. I've tried AVPicture.linesize to no avail, as well as:
for (y = 0; y < ctx->height; y++){
for (x = 0; x < ctx->width; x++){
yDataSize++;
}
}
/* Cb and Cr */
for (y = 0; y < ctx->height / 2; y++) {
for (x = 0; x < ctx->width / 2; x++) {
uDataSize++;
vDataSize++;
}
}
I'm really stuck, thanks!
The buffer size is the linesize times the height (linesize is bytes per row, multiply by number of rows to get total). So _avPicture.linesize[x] * ctx->height. Calculate on the C++ side, pass value back to Java.