I have an algorithm in JavaScript which I want to transform into Java.
Here is the JavaScript code:
function downScaleCanvas(cv, scale) {
if (!(scale < 1) || !(scale > 0)) throw ('scale must be a positive number <1 ');
var sqScale = scale * scale; // square scale = area of source pixel within target
var sw = cv.width; // source image width
var sh = cv.height; // source image height
var tw = Math.ceil(sw * scale); // target image width
var th = Math.ceil(sh * scale); // target image height
var sx = 0, sy = 0, sIndex = 0; // source x,y, index within source array
var tx = 0, ty = 0, yIndex = 0, tIndex = 0; // target x,y, x,y index within target array
var tX = 0, tY = 0; // rounded tx, ty
var w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0; // weight / next weight x / y
// weight is weight of current source point within target.
// next weight is weight of current source point within next target's point.
var crossX = false; // does scaled px cross its current px right border ?
var crossY = false; // does scaled px cross its current px bottom border ?
var sBuffer = cv.getContext('2d').getImageData(0, 0, sw, sh).data; // source buffer 8 bit rgba
var tBuffer = new Float32Array(4 * sw * sh); // target buffer Float32 rgb
var sR = 0, sG = 0, sB = 0; // source's current point r,g,b
// untested !
var sA = 0; //source alpha
for (sy = 0; sy < sh; sy++) {
ty = sy * scale; // y src position within target
tY = 0 | ty; // rounded : target pixel's y
yIndex = 4 * tY * tw; // line index within target array
crossY = (tY != (0 | ty + scale));
if (crossY) { // if pixel is crossing botton target pixel
wy = (tY + 1 - ty); // weight of point within target pixel
nwy = (ty + scale - tY - 1); // ... within y+1 target pixel
}
for (sx = 0; sx < sw; sx++, sIndex += 4) {
tx = sx * scale; // x src position within target
tX = 0 | tx; // rounded : target pixel's x
tIndex = yIndex + tX * 4; // target pixel index within target array
crossX = (tX != (0 | tx + scale));
if (crossX) { // if pixel is crossing target pixel's right
wx = (tX + 1 - tx); // weight of point within target pixel
nwx = (tx + scale - tX - 1); // ... within x+1 target pixel
}
sR = sBuffer[sIndex ]; // retrieving r,g,b for curr src px.
sG = sBuffer[sIndex + 1];
sB = sBuffer[sIndex + 2];
sA = sBuffer[sIndex + 3];
if (!crossX && !crossY) { // pixel does not cross
// just add components weighted by squared scale.
tBuffer[tIndex ] += sR * sqScale;
tBuffer[tIndex + 1] += sG * sqScale;
tBuffer[tIndex + 2] += sB * sqScale;
tBuffer[tIndex + 3] += sA * sqScale;
} else if (crossX && !crossY) { // cross on X only
w = wx * scale;
// add weighted component for current px
tBuffer[tIndex ] += sR * w;
tBuffer[tIndex + 1] += sG * w;
tBuffer[tIndex + 2] += sB * w;
tBuffer[tIndex + 3] += sA * w;
// add weighted component for next (tX+1) px
nw = nwx * scale;
tBuffer[tIndex + 4] += sR * nw; // not 3
tBuffer[tIndex + 5] += sG * nw; // not 4
tBuffer[tIndex + 6] += sB * nw; // not 5
tBuffer[tIndex + 7] += sA * nw; // not 6
} else if (crossY && !crossX) { // cross on Y only
w = wy * scale;
// add weighted component for current px
tBuffer[tIndex ] += sR * w;
tBuffer[tIndex + 1] += sG * w;
tBuffer[tIndex + 2] += sB * w;
tBuffer[tIndex + 3] += sA * w;
// add weighted component for next (tY+1) px
nw = nwy * scale;
tBuffer[tIndex + 4 * tw ] += sR * nw; // *4, not 3
tBuffer[tIndex + 4 * tw + 1] += sG * nw; // *4, not 3
tBuffer[tIndex + 4 * tw + 2] += sB * nw; // *4, not 3
tBuffer[tIndex + 4 * tw + 3] += sA * nw; // *4, not 3
} else { // crosses both x and y : four target points involved
// add weighted component for current px
w = wx * wy;
tBuffer[tIndex ] += sR * w;
tBuffer[tIndex + 1] += sG * w;
tBuffer[tIndex + 2] += sB * w;
tBuffer[tIndex + 3] += sA * w;
// for tX + 1; tY px
nw = nwx * wy;
tBuffer[tIndex + 4] += sR * nw; // same for x
tBuffer[tIndex + 5] += sG * nw;
tBuffer[tIndex + 6] += sB * nw;
tBuffer[tIndex + 7] += sA * nw;
// for tX ; tY + 1 px
nw = wx * nwy;
tBuffer[tIndex + 4 * tw ] += sR * nw; // same for mul
tBuffer[tIndex + 4 * tw + 1] += sG * nw;
tBuffer[tIndex + 4 * tw + 2] += sB * nw;
tBuffer[tIndex + 4 * tw + 3] += sA * nw;
// for tX + 1 ; tY +1 px
nw = nwx * nwy;
tBuffer[tIndex + 4 * tw + 4] += sR * nw; // same for both x and y
tBuffer[tIndex + 4 * tw + 5] += sG * nw;
tBuffer[tIndex + 4 * tw + 6] += sB * nw;
tBuffer[tIndex + 4 * tw + 7] += sA * nw;
}
} // end for sx
} // end for sy
// create result canvas
var resCV = document.createElement('canvas');
resCV.width = tw;
resCV.height = th;
var resCtx = resCV.getContext('2d');
var imgRes = resCtx.getImageData(0, 0, tw, th);
var tByteBuffer = imgRes.data;
// convert float32 array into a UInt8Clamped Array
var pxIndex = 0; //
for (sIndex = 0, tIndex = 0; pxIndex < tw * th; sIndex += 4, tIndex += 4, pxIndex++) {
tByteBuffer[tIndex] = Math.ceil(tBuffer[sIndex]);
tByteBuffer[tIndex + 1] = Math.ceil(tBuffer[sIndex + 1]);
tByteBuffer[tIndex + 2] = Math.ceil(tBuffer[sIndex + 2]);
tByteBuffer[tIndex + 3] = Math.ceil(tBuffer[sIndex + 3]);
}
// writing result to canvas.
resCtx.putImageData(imgRes, 0, 0);
return resCV;
}
Here is what I did so far in Java:
public static final CanvasElement scaleCanvas(CanvasElement cv, double scale) {
if (!(scale < 1) || !(scale > 0)) {
// throw new Exception("scale must be a positive number <1 ");
}
double sqScale = scale * scale; // square scale = area of source pixel within target
int sw = cv.getWidth(); // source image width
int sh = cv.getHeight(); // source image height
double tw = Math.ceil(sw * scale); // target image width
double th = Math.ceil(sh * scale); // target image height
int sx = 0, sy = 0, sIndex = 0; // source x,y, index within source array
double tx = 0, ty = 0;
int yIndex = 0, tIndex = 0; // target x,y, x,y index within target array
double tX = 0, tY = 0; // rounded tx, ty
double w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0; // weight / next weight x / y
// weight is weight of current source point within target.
// next weight is weight of current source point within next target's point.
boolean crossX = false; // does scaled px cross its current px right border ?
boolean crossY = false; // does scaled px cross its current px bottom border ?
CanvasPixelArray sBuffer = cv.getContext2d().getImageData(0, 0, sw, sh).getData(); // source buffer 8 bit rgba
Float32Array tBuffer = TypedArrays.createFloat32Array(4 * sw * sh);
double sR = 0, sG = 0, sB = 0; // source's current point r,g,b
// untested !
double sA = 0; //source alpha
for (sy = 0; sy < sh; sy++) {
GWT.log("sy: "+sy+" sh: "+sh);
ty = sy * scale; // y src position within target
tY = (long)ty; // rounded : target pixel's y // ?????
yIndex = (int)Math.floor(4 * tY * tw); // line index within target array
crossY = (tY != ( (long)(ty + scale) )); // ?????
if (crossY) { // if pixel is crossing botton target pixel
wy = (tY + 1 - ty); // weight of point within target pixel
nwy = (ty + scale - tY - 1); // ... within y+1 target pixel
}
for (sx = 0; sx < sw; sx++, sIndex += 4) {
tx = sx * scale; // x src position within target
tX = (long)tx; // rounded : target pixel's x // ?????
tIndex = (int)Math.floor(yIndex + tX * 4); // target pixel index within target array // ?????
crossX = (tX != ((int)Math.floor(tx + scale)));
if (crossX) { // if pixel is crossing target pixel's right
wx = (tX + 1 - tx); // weight of point within target pixel
nwx = (tx + scale - tX - 1); // ... within x+1 target pixel
}
sR = sBuffer.get(sIndex); // retrieving r,g,b for curr src px.
sG = sBuffer.get(sIndex + 1);
sB = sBuffer.get(sIndex + 2);
sA = sBuffer.get(sIndex + 3);
if (!crossX && !crossY) { // pixel does not cross
// just add components weighted by squared scale.
tBuffer.set(tIndex , (float)(tBuffer.get(tIndex) + sR * sqScale));
tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * sqScale));
tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * sqScale));
tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * sqScale));
} else if (crossX && !crossY) { // cross on X only
w = wx * scale;
// add weighted component for current px
tBuffer.set(tIndex , (float)(tBuffer.get(tIndex) + sR * w));
tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * w));
tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * w));
tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * w));
// add weighted component for next (tX+1) px
nw = nwx * scale;
tBuffer.set(tIndex + 4, (float)(tBuffer.get(tIndex + 4) + sR * nw)); // not 3
tBuffer.set(tIndex + 5, (float)(tBuffer.get(tIndex + 5) + sG * nw)); // not 4
tBuffer.set(tIndex + 6, (float)(tBuffer.get(tIndex + 6) + sB * nw)); // not 5
tBuffer.set(tIndex + 7, (float)(tBuffer.get(tIndex + 7) + sA * nw)); // not 6
} else if (crossY && !crossX) { // cross on Y only
w = wy * scale;
// add weighted component for current px
tBuffer.set(tIndex , (float)(tBuffer.get(tIndex) + sR * w));
tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * w));
tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * w));
tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * w));
// add weighted component for next (tY+1) px
nw = nwy * scale;
tBuffer.set((int)Math.floor(tIndex + 4 * tw) , (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw)) + sR * nw)); // *4, not 3
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 1), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 1)) + sG * nw)); // *4, not 3
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 2), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 2)) + sB * nw)); // *4, not 3
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 3), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 3)) + sA * nw)); // *4, not 3
} else { // crosses both x and y : four target points involved
// add weighted component for current px
w = wx * wy;
tBuffer.set(tIndex , (float)(tBuffer.get(tIndex) + sR * w));
tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * w));
tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * w));
tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * w));
// for tX + 1; tY px
nw = nwx * wy;
tBuffer.set(tIndex + 4, (float)(tBuffer.get(tIndex + 4) + sR * nw)); // same for x
tBuffer.set(tIndex + 5, (float)(tBuffer.get(tIndex + 5) + sG * nw));
tBuffer.set(tIndex + 6, (float)(tBuffer.get(tIndex + 6) + sB * nw));
tBuffer.set(tIndex + 7, (float)(tBuffer.get(tIndex + 7) + sA * nw));
// for tX ; tY + 1 px
nw = wx * nwy;
tBuffer.set((int)Math.floor(tIndex + 4 * tw) , (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw)) + sR * nw)); // same for mul
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 1), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 1)) + sG * nw));
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 2), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 2)) + sB * nw));
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 3), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 3)) + sA * nw));
// for tX + 1 ; tY +1 px
nw = nwx * nwy;
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 4), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 4)) + sR * nw)); // same for both x and y
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 5), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 5)) + sG * nw));
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 6), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 6)) + sB * nw));
tBuffer.set((int)Math.floor(tIndex + 4 * tw + 7), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 7)) + sA * nw));
}
} // end for sx
} // end for sy
// create result canvas
Canvas resCV = Canvas.createIfSupported();
resCV.getCanvasElement().setWidth((int)Math.floor(tw));
resCV.getCanvasElement().setHeight((int)Math.floor(th));
Context2d resCtx = resCV.getContext2d();
ImageData imgRes = resCtx.getImageData(0, 0, tw, th);
CanvasPixelArray tByteBuffer = imgRes.getData();
// convert float32 array into a UInt8Clamped Array
int pxIndex = 0;
for (sIndex = 0, tIndex = 0; pxIndex < tw * th; sIndex += 4, tIndex += 4, pxIndex++) {
tByteBuffer.set(tIndex, (int)Math.ceil(tBuffer.get(sIndex)));
tByteBuffer.set(tIndex + 1, (int)Math.ceil(tBuffer.get(sIndex + 1)));
tByteBuffer.set(tIndex + 2, (int)Math.ceil(tBuffer.get(sIndex + 2)));
tByteBuffer.set(tIndex + 3, (int)Math.ceil(tBuffer.get(sIndex + 3)));
}
// writing result to canvas.
resCtx.putImageData(imgRes, 0, 0);
return resCV.getCanvasElement();
}
I am not sure how to write an expression like thit tY = 0 | ty in Java. I am also not sure if canvas.width(value); transforms into canvas.setCoordinateSpaceWidth(value);
Edit:
Is (0 | ty + scale) in JS is ((long)ty + scale) in Java?
What is the translation of
var sBuffer = cv.getContext('2d').getImageData(0, 0, sw, sh).data
is it CanvasPixelArray
CanvasPixelArray sBuffer = cv.getContext2d().getImageData(0, 0, sw, sh).getData()
Can someone help me with the translation?
Edit: It turns out that my Java code is very slow. I cannot run it in dev mode. In prod mode it is event slower than the JavaScript code. Why is this code slower?
0 | tY is rounding a JS Number (equivalent to a Java double) to an integer value; equivalent to Math.floor(tY) or (long) tY (int is too small for all integer values that can be expressed in a double, but might be OK in this specific case).
canvas.width maps to Canvas#getCoordinateSpaceWidth, as you can see in GWT sources.
Finally, new Float32Array(n) maps to TypedArrays.createFloat32Array.
Related
I am trying to have a JavaFX 3D Sphere, textured with a texture of the earth. The texture is this one (from Wikipedia, an equirectangular projection):
The sphere is rendered as follows:
You can clearly see that, at the poles, the texture is not preserving the proportions anymore. I found a bug files on the openJDK system, which I think is related to this behaviour: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8092112
Sadly, in 7 years nobody made the change that the person filing the bug requested. Do you know if there is an alternative way to properly render an equirectangular sphere projection on a JavaFX 3D Sphere?
Just for reference, the code that I using is:
Sphere earthSphere = new Sphere(EARTH_RADIUS, 256);
PhongMaterial material = new PhongMaterial();
material.setDiffuseMap(new Image(Main.class.getResourceAsStream("/images/earth2.jpg")));
earthSphere.setMaterial(material);
At the end I implement it myself using a mesh, for the purposes I needed for. Here is the code, in case you are interested (it will end up in a GitHub project anyway):
public static Group createEarthSphere() {
// Use triangular mesh
int latLevels = 90;
int lonLevels = 180;
TriangleMesh mesh = new TriangleMesh(VertexFormat.POINT_NORMAL_TEXCOORD);
double radius = EARTH_RADIUS;
double latIncAngle = (Math.PI/latLevels);
double lonIncAngle = (Math.PI * 2)/lonLevels;
double textLatIncr = 1.0/latLevels;
double textLonIncr = 1.0/lonLevels;
int currentPointOffset = 0;
int currentNormalOffset = 0;
int currentTextOffset = 0;
for(int i = 0; i < latLevels; ++i) {
for(int j = 0; j < lonLevels; ++j) {
// The point list is: top left - bottom left - bottom right - top right
// The faces-normal points are: (0,0) (1,1) (2,2) (0,3) (2,4) (3,5)
Point3D tp1 = new Point3D(0,radius * Math.cos(Math.PI - (i * latIncAngle)), radius * Math.sin(Math.PI - (i * latIncAngle)));
Point3D tp2 = new Point3D(0,radius * Math.cos(Math.PI - (i * latIncAngle + latIncAngle)), radius * Math.sin(Math.PI - (i * latIncAngle + latIncAngle)));
Point3D topLeft = new Rotate(Math.toDegrees(j * lonIncAngle), new Point3D(0, 1, 0)).transform(tp1);
Point3D bottomLeft = new Rotate(Math.toDegrees(j * lonIncAngle), new Point3D(0, 1, 0)).transform(tp2);
Point3D bottomRight = new Rotate(Math.toDegrees(j * lonIncAngle + lonIncAngle), new Point3D(0, 1, 0)).transform(tp2);
Point3D topRight = new Rotate(Math.toDegrees(j * lonIncAngle + lonIncAngle), new Point3D(0, 1, 0)).transform(tp1);
// Compute normals
Point3D topLeftNormal_1 = computeNormal(topLeft, bottomLeft, bottomRight); // 0
Point3D bottomLeftNormal_1 = computeNormal(bottomLeft, bottomRight, topLeft); // 1
Point3D bottomRightNormal_1 = computeNormal(bottomRight, topLeft, bottomLeft); // 2
Point3D topLeftNormal_2 = computeNormal(topLeft, bottomRight, topRight); // 3
Point3D bottomRightNormal_2 = computeNormal(bottomRight, topRight, topLeft); // 4
Point3D topRightNormal_2 = computeNormal(topRight, topLeft, bottomRight); // 5
// Add points
mesh.getPoints().addAll((float) topLeft.getX(), (float) topLeft.getY(), (float) topLeft.getZ()); // 0
mesh.getPoints().addAll((float) bottomLeft.getX(), (float) bottomLeft.getY(), (float) bottomLeft.getZ()); // 1
mesh.getPoints().addAll((float) bottomRight.getX(), (float) bottomRight.getY(), (float) bottomRight.getZ()); // 2
mesh.getPoints().addAll((float) topRight.getX(), (float) topRight.getY(), (float) topRight.getZ()); // 3
// Add normals
mesh.getNormals().addAll((float) topLeftNormal_1.getX(), (float) topLeftNormal_1.getY(), (float) topLeftNormal_1.getZ()); // 0
mesh.getNormals().addAll((float) bottomLeftNormal_1.getX(), (float) bottomLeftNormal_1.getY(), (float) bottomLeftNormal_1.getZ()); // 1
mesh.getNormals().addAll((float) bottomRightNormal_1.getX(), (float) bottomRightNormal_1.getY(), (float) bottomRightNormal_1.getZ()); // 2
mesh.getNormals().addAll((float) topLeftNormal_2.getX(), (float) topLeftNormal_2.getY(), (float) topLeftNormal_2.getZ()); // 3
mesh.getNormals().addAll((float) bottomRightNormal_2.getX(), (float) bottomRightNormal_2.getY(), (float) bottomRightNormal_2.getZ()); // 4
mesh.getNormals().addAll((float) topRightNormal_2.getX(), (float) topRightNormal_2.getY(), (float) topRightNormal_2.getZ()); // 5
// Add texture
float[] p0t = { (float) (i * textLatIncr), 1.0f - (float) (j * textLonIncr) };
float[] p1t = { (float) (i * textLatIncr + textLatIncr), 1.0f - (float) (j * textLonIncr) };
float[] p2t = { (float) (i * textLatIncr + textLatIncr), 1.0f - (float) (j * textLonIncr + textLonIncr) };
float[] p3t = { (float) (i * textLatIncr), 1.0f - (float) (j * textLonIncr + textLonIncr) };
mesh.getTexCoords().addAll(
p0t[1], p0t[0],
p1t[1], p1t[0],
p2t[1], p2t[0],
p3t[1], p3t[0]
);
// Add faces
mesh.getFaces().addAll(
currentPointOffset + 0, currentNormalOffset + 0, currentTextOffset + 0,
currentPointOffset + 2, currentNormalOffset + 2, currentTextOffset + 2,
currentPointOffset + 1, currentNormalOffset + 1, currentTextOffset + 1,
currentPointOffset + 0, currentNormalOffset + 3, currentTextOffset + 0,
currentPointOffset + 3, currentNormalOffset + 5, currentTextOffset + 3,
currentPointOffset + 2, currentNormalOffset + 4, currentTextOffset + 2
);
currentPointOffset += 4;
currentNormalOffset += 6;
currentTextOffset += 4;
}
}
MeshView meshView = new MeshView(mesh);
meshView.setCullFace(CullFace.BACK);
PhongMaterial material = new PhongMaterial();
material.setDiffuseMap(new Image(Main.class.getResourceAsStream("/images/earth.jpg")));
meshView.setMaterial(material);
return new Group(meshView);
}
private static Point3D computeNormal(Point3D p1, Point3D p2, Point3D p3) {
return (p3.subtract(p1).normalize()).crossProduct(p2.subtract(p1).normalize()).normalize();
}
The result is:
Now everything is exactly where it should be, and lat/lon are correctly matching the texture.
I made a java implementation of the new perceptualy uniform color space JzAzBz. OSA publication is : https://www.osapublishing.org/oe/fulltext.cfm?uri=oe-25-13-15131&id=368272.
My java code is :
private double b = 1.15;
private double g = 0.66;
private double c1 = 3424 / Math.pow(2, 12);
private double c2 = 2413 / Math.pow(2, 7);
private double c3 = 2392 / Math.pow(2, 7);
private double n = 2610 / Math.pow(2, 14);
private double p = 1.7 * 2523 / Math.pow(2, 5);
private double d = -0.56;
private double d0 = 1.6295499532821566 * Math.pow(10, -11);
public void XYZToJab(double[] xyz, double[] jab) {
double[] XYZp = new double[3];
XYZp[0] = b * xyz[0] - ((b - 1) * xyz[2]);
XYZp[1] = g * xyz[1] - ((g - 1) * xyz[0]);
XYZp[2] = xyz[2];
double[] LMS = new double[3];
LMS[0] = 0.41478972 * XYZp[0] + 0.579999 * XYZp[1] + 0.0146480 * XYZp[2];
LMS[1] = -0.2015100 * XYZp[0] + 1.120649 * XYZp[1] + 0.0531008 * XYZp[2];
LMS[2] = -0.0166008 * XYZp[0] + 0.264800 * XYZp[1] + 0.6684799 * XYZp[2];
double[] LMSp = new double[3];
for (int i = 0; i < 3; i++) {
LMSp[i] = Math.pow((c1 + c2 * Math.pow((LMS[i] / 10000.0), n)) / (1 + c3 * Math.pow((LMS[i] / 10000.0), n)), p);
}
double[] Iab = new double[3];
Iab[0] = 0.5 * LMSp[0] + 0.5 * LMSp[1];
Iab[1] = 3.524000 * LMSp[0] - 4.066708 * LMSp[1] + 0.542708 * LMSp[2];
Iab[2] = 0.199076 * LMSp[0] + 1.096799 * LMSp[1] - 1.295875 * LMSp[2];
jab[0] = (((1 + d) * Iab[0]) / (1 + d * Iab[0])) - d0;
jab[1] = Iab[1];
jab[2] = Iab[2];
}
public void JabToXYZ(double[] jab, double[] xyz) {
double[] Iab = new double[3];
Iab[0] = (jab[0] + d0) / (1 + d - d * (jab[0] + d0));
Iab[1] = jab[1];
Iab[2] = jab[2];
double[] LMSp = new double[3];
LMSp[0] = 1.0 * Iab[0] + 0.13860504 * Iab[1] + 0.05804732 * Iab[2];
LMSp[1] = 1.0 * Iab[0] - 0.13860504 * Iab[1] - 0.05804732 * Iab[2];
LMSp[2] = 1.0 * Iab[0] - 0.09601924 * Iab[1] - 0.81189190 * Iab[2];
double[] LMS = new double[3];
for (int i = 0; i < 3; i++) {
LMS[i] = 10000 * Math.pow((c1 - Math.pow(LMSp[i], 1 / p)) / ((c3 * Math.pow(LMSp[i], 1 / p)) - c2), 1 / n);
}
double[] XYZp = new double[3];
XYZp[0] = 1.92422644 * LMS[0] - 1.00479231 * LMS[1] + 0.03765140 * LMS[2];
XYZp[1] = 0.35031676 * LMS[0] + 0.72648119 * LMS[1] - 0.06538442 * LMS[2];
XYZp[2] = -0.09098281 * LMS[0] - 0.31272829 * LMS[1] + 1.52276656 * LMS[2];
xyz[0] = (XYZp[0] + (b - 1) * XYZp[2]) / b;
xyz[1] = (XYZp[1] + (g - 1) * XYZp[0]) / g;
xyz[2] = XYZp[2];
}
When I test it running XYZToJab and then JabToXYZ I get a good precision for X and Z (delta order is E-9) but for Y I get a bad precision (delta order is 1-5%).
Is there anyone who can help me ?
The implementation is almost correct: The error lies in JabToXYZ where the prior to last line should be changed from
(XYZp[1] + (g - 1) * XYZp[0]) / g;
to
(XYZp[1] + (g - 1) * xyz[0]) / g;
However the fact that you are using rounded invert matrices to 6 decimal places in the JabToXYZ function will prevent you to get a clean inversion. You should try to compute the inverse at full double precision:
>>> import numpy as np
>>> np.set_printoptions(formatter={'float': '{:0.15f}'.format})
>>> import colour.models.jzazbz
>>> colour.models.jzazbz.JZAZBZ_IZAZBZ_TO_LMS_P_MATRIX
array([[1.000000000000000, 0.138605043271539, 0.058047316156119],
[1.000000000000000, -0.138605043271539, -0.058047316156119],
[1.000000000000000, -0.096019242026319, -0.811891896056039]])
>>> colour.models.jzazbz.JZAZBZ_LMS_TO_XYZ_MATRIX
array([[1.924226435787607, -1.004792312595365, 0.037651404030618],
[0.350316762094999, 0.726481193931655, -0.065384422948085],
[-0.090982810982848, -0.312728290523074, 1.522766561305260]])
I am making a software that has a screen filtering process. The code can already shift the colors and apply it to the frame the only problem is that It takes around 40-50 seconds for the filtered window to render. Is there any way I can make it faster? I would also like to ask which part of the code makes the process longer and time consuming. I will really appreciate the help. Thanks!
Here is my code.
public RedGreenFilter(int k1, int k2, int k3) {
this.k1 = k1;
this.k2 = k2;
this.k3 = k3;
}
#Override
public BufferedImage filter(final BufferedImage src, BufferedImage dst) {
if (dst == null) {
dst = this.createCompatibleDestImage(src, null);
}
// make sure the two images have the same size, color space, etc.
// MISSING !!! ???
DataBufferInt inBuffer = (DataBufferInt) src.getRaster().getDataBuffer();
DataBufferInt outBuffer = (DataBufferInt) dst.getRaster().getDataBuffer();
int[] inData = inBuffer.getData();
int[] outData = outBuffer.getData();
int simR = 0, simG = 0, simB = 0, mild = 10, moderate = 20, strong = 40;
float cIndex = MyDeficiency.cIndex;
float angle = MyDeficiency.angle;
float x = 0, y = 0, z = 0;
int prevIn = 0;
int prevOut = 0;
final int length = inData.length;
int corrG;
int corrR;
int corrB;
int SizeOfScreen = src.getHeight() * src.getWidth();
final int[] redArray = new int[SizeOfScreen];
final int[] blueArray = new int[SizeOfScreen];
final int[] greenArray = new int[SizeOfScreen];
for (int i = 0; i < SizeOfScreen; i++) {
final int in = inData[i];
if (in == prevIn) {
outData[i] = prevOut;
} else {
final int r = (0xff0000 & in) >> 16;
final int g = (0xff00 & in) >> 8;
final int b = 0xff & in;
// get linear rgb values in the range 0..2^15-1
final int r_lin = rgb2lin_red_LUT[r];
final int g_lin = rgb2lin_red_LUT[g];
final int b_lin = rgb2lin_red_LUT[b];
//http://publication.gunadarma.ac.id/bitstream/123456789/12232/1/Slide_Mahendra_54411250.pdf
float L = (17.8824f * r + 43.5161f * g + 4.11935f * b);
float M = (3.4565f * r + 27.1554f * g + 3.86714f * b);
float S = (0.02996f * r + 0.18431f * g + 1.46709f * b);
float dL = ( 0 * L + 2.02344f * M - 2.52581f * S);
float dM = ( 0 * L + 1 * M + 0 * S);
float dS = ( 0 * L + 0 * M + 1 * S);
float pL = ( 1 * L + 0 * M + 0 * S);
float pM = ( 0.494207f * L + 0 * M + 1.24827f * S);
float pS = ( 0 * L + 0 * M + 1 * S);
// simulated red and green are identical
// scale the matrix values to 0..2^15 for integer computations
// of the simulated protan values.
// divide after the computation by 2^15 to rescale.
// also divide by 2^15 asnd multiply by 2^8 to scale the linear rgb to 0..255
// total division is by 2^15 * 2^15 / 2^8 = 2^22
// shift the bits by 22 places instead of dividing
int r_blind = (int) (k1 * r_lin + k2 * g_lin) >> 22;
int b_blind = (int) (k3 * r_lin - k3 * g_lin + 32768 * b_lin) >> 22;
if (r_blind < 0) {
r_blind = 0;
} else if (r_blind > 255) {
r_blind = 255;
}
if (b_blind < 0) {
b_blind = 0;
} else if (b_blind > 255) {
b_blind = 255;
}
// convert reduced linear rgb to gamma corrected rgb
int red = lin2rgb_LUT[r_blind];
red = red >= 0 ? red : 256 + red; // from unsigned to signed
int blue = lin2rgb_LUT[b_blind];
blue = blue >= 0 ? blue : 256 + blue; // from unsigned to signed
if(k1 == 9591 && k2 == 23173){
x = dL;
y = dM;
z = dS;
}
if(k1 == 3683 && k2 == 29084){
x = pL;
y = pM;
z = pS;
}
//SEVERITY
//PROTAN
//normal to mild
if (angle > 0.70 && cIndex < 1.2){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//mild to moderate
else if (angle > 0.70 && cIndex < 3 && cIndex > 1.20){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + mild;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//moderate to strong
else if (angle > 0.70 && cIndex < 4 && cIndex > 3){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + moderate;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//strong to super strong
else if (angle > 0.70 && cIndex > 4){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + strong;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//DEUTAN
//normal to mild
if (angle < 0.70 && angle > -65.00 && cIndex < 1.2){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//mild to moderate
else if (angle < 0.70 && angle > -65.00 && cIndex < 3 && cIndex > 1.20){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + mild;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//moderate to strong
else if (angle < 0.70 && angle > -65 && cIndex < 4 && cIndex > 3){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + moderate;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z) ;
}
//strong to super strong
else if (angle < 0.7 && angle > -65 && cIndex > 4){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + strong;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z) ;
}
int errR = r - simR;
int errG = g - simG;
int errB = b - simB;
float errModR = (0 * errR + 0 * errG + 0 * errB);
float errModG = (0.7f * errR + 1 * errG + 0 * errB);
float errModB = (0.7f * errR + 0 * errG + 1 * errB);
corrR = (int) errModR + r;
corrG = (int) errModG + g;
corrB = (int) errModB + b;
/*
int corrR = 0;
int corrG = 0;
int corrB = 0;
*/
//MyDeficiency my = new MyDeficiency();
if(r == 255 && g == 255 && b == 255){
corrR = corrG = corrB = 255;
}
if(r == 0 && g == 0 && b == 0){
corrR = corrG = corrB = 0;
}
final int out = 0xff000000 | (corrR << 16) | (corrG << 8) | corrB ;
redArray[i] = (out >> 16) & 0xFF;
greenArray[i] = (out >> 8) & 0xFF;
blueArray[i] = (out >> 0) & 0xFF;
//System.out.println("r: " +" " + redArray[i]+ " "+ " g:" +" " +greenArray[i] +" " +"b:"+" "+ blueArray[i] + " " +"i:"+ " "+i);
//System.out.println("sR: " + (red << 16) + "sG: " +(red <<8)+ " sB: " + blue);
//outData[i] = out;
//prevIn = in;
//prevOut = out;
}
}
//System.out.println(SizeOfScreen);
Window w = new Window(null);
w.add(new JComponent() {
public void paintComponent(Graphics g) {
int alpha = 190; // 50% transparent
int pixelcounter = 0;
for(int i = 0; i < src.getHeight(); i++){
for(int j = 0; j < src.getWidth(); j++){
Color myColour = new Color(redArray[pixelcounter],greenArray[pixelcounter],blueArray[pixelcounter], alpha);
g.setColor(myColour);
g.fillRect(j,i,1,1);
pixelcounter++;
}
}
}
public Dimension getPreferredSize() {
return new Dimension(src.getWidth(), src.getHeight());
}
});
w.pack();
w.setLocationRelativeTo(null);
w.setAlwaysOnTop(true);
/**
* This sets the background of the window to be transparent.
*/
AWTUtilities.setWindowOpaque(w, false);
setTransparent(w);
w.setVisible(true);
//w.setVisible(false);
return dst;
}
}
I've tried to port these 2 functions from Lua to Java (bspline2D and bspline3D), but they doen't work. The output is completely different, and I can't figure out why.
I've already tried messing with the array numbers, the subdivision value, the for loops, and everything that came up my head.
The test provided should give numbers that are totally different one another, but they're not.
These are the Java results:
bspline2D
0.0, 0.0, 0.0
-1.0, 0.0, 0.0
-1.0, 0.0, 0.0
-1.0, 0.0, 0.0
-1.0, 0.0, 0.0
0.0, 0.0, 0.0
0.0, 0.0, 0.0
0.0, 0.0, 0.0
0.0, 0.0, 0.0
bspline3D
-2.0, 0.0, 0.0
-1.0, 0.0, 0.0
-1.0, 0.0, 0.0
0.0, 0.0, 0.0
0.0, 0.0, 0.0
...which are clearly wrong.
These are the outputs from the Lua version, the correct ones.
bspline2D
0, 0
-0.75, 0
-0.5, 0
-0.25, 0
0, 0
0.24739583, 0.0026041667
0.47916666, 0.020833334
0.6796875, 0.0703125
0.8333333, 0.16666667
0.9270833, 0.31770834
0.9583333, 0.5
0.9270833, 0.6822917
0.8333333, 0.8333333
0.6796875, 0.9296875
0.47916666, 0.9791667
0.24739583, 0.9973958
0, 1
bspline3D
0, 0, 0
0.24739583, 0.0026041667, 0
0.47916666, 0.020833334, 0
0.6796875, 0.0703125, 0
0.8333333, 0.16666667, 0
0.9270833, 0.31770834, 0
0.9583333, 0.5, 0
0.9270833, 0.6822917, 0
0.8333333, 0.8333333, 0
0.6796875, 0.9296875, 0
0.47916666, 0.9791667, 0
0.24739583, 0.9973958, 0
0, 1, 0
-0.25, 1, 0
-0.5, 1, 0
-0.75, 1, 0
-1, 1, 0
-1.25, 1, 0
-1.5, 1, 0
-1.75, 1, 0
-2, 1, 0
I've been scratching my head for days on this, and I have just no ideas, so I thought maybe someone here at StackOverflow would.
Here's the Java version that needs to be fixed:
public static List<Vector3> bspline2D(Vector3[] pointz, int subdivision) {
ArrayList spline = new ArrayList();
int pointsNumber = pointz.length;
Vector3[] points = new Vector3[pointsNumber + 4];
System.arraycopy(pointz, 0, points, 2, pointsNumber);
points[1] = points[2].add(points[2].minus(points[3]));
points[0] = points[1].add(points[1].minus(points[2]));
points[pointsNumber + 2] = points[pointsNumber - 3].add(points[pointsNumber - 3].minus(points[pointsNumber - 4]));
points[pointsNumber + 3] = points[pointsNumber].add(points[pointsNumber].minus(points[pointsNumber - 3]));
spline.add(pointz[0]);
for(int i = 1; i < pointsNumber - 1; ++i) {
double[] a = new double[4];
double[] b = new double[4];
a[0] = (-points[i - 1].x + 3.0D * points[i].x - 3.0D * points[i + 1].x + points[i + 2].x) / 6.0D;
a[1] = (3.0D * points[i - 1].x - 6.0D * points[i].x + 3.0D * points[i + 1].x) / 6.0D;
a[2] = (-3.0D * points[i - 1].x + 3.0D * points[i + 1].x) / 6.0D;
a[3] = (points[i - 1].x + 4.0D * points[i].x + points[i + 1].x) / 6.0D;
b[0] = (-points[i - 1].y + 3.0D * points[i].y - 3.0D * points[i + 1].y + points[i + 2].y) / 6.0D;
b[1] = (3.0D * points[i - 1].y - 6.0D * points[i].y + 3.0D * points[i + 1].y) / 6.0D;
b[2] = (-3.0D * points[i - 1].y + 3.0D * points[i + 1].y) / 6.0D;
b[3] = (points[i - 1].y + 4.0D * points[i].y + points[i + 1].y) / 6.0D;
for(int j = 0; j < subdivision; ++j) {
double t = j / subdivision;
spline.add(new Vector3((a[2] + t * (a[1] + t * a[0])) * t + a[3], (b[2] + t * (b[1] + t * b[0])) * t + b[3]));
}
}
return spline;
}
public static List<Vector3> bspline3D(Vector3[] pointz, int subdivision) {
ArrayList spline = new ArrayList();
int pointsNumber = pointz.length;
Vector3[] points = new Vector3[pointsNumber + 4];
System.arraycopy(pointz, 0, points, 2, pointsNumber);
points[1] = points[2].add(points[2].minus(points[3]));
points[0] = points[1].add(points[1].minus(points[2]));
points[pointsNumber + 2] = pointz[pointsNumber - 1].add(pointz[pointsNumber - 1].minus(pointz[pointsNumber - 2]));
points[pointsNumber + 3] = points[pointsNumber].add(points[pointsNumber].minus(pointz[pointsNumber - 1]));
spline.add(points[0]);
for(int i = 1; i < pointsNumber - 1; ++i) {
double[] a = new double[4];
double[] b = new double[4];
double[] c = new double[4];
a[0] = (-points[i - 1].x + 3.0D * points[i].x - 3.0D * points[i + 1].x + points[i + 2].x) / 6.0D;
a[1] = (3.0D * points[i - 1].x - 6.0D * points[i].x + 3.0D * points[i + 1].x) / 6.0D;
a[2] = (-3.0D * points[i - 1].x + 3.0D * points[i + 1].x) / 6.0D;
a[3] = (points[i - 1].x + 4.0D * points[i].x + points[i + 1].x) / 6.0D;
b[0] = (-points[i - 1].y + 3.0D * points[i].y - 3.0D * points[i + 1].y + points[i + 2].y) / 6.0D;
b[1] = (3.0D * points[i - 1].y - 6.0D * points[i].y + 3.0D * points[i + 1].y) / 6.0D;
b[2] = (-3.0D * points[i - 1].y + 3.0D * points[i + 1].y) / 6.0D;
b[3] = (points[i - 1].y + 4.0D * points[i].y + points[i + 1].y) / 6.0D;
c[0] = (-points[i - 1].z + 3.0D * points[i].z - 3.0D * points[i + 1].z + points[i + 2].z) / 6.0D;
c[1] = (3.0D * points[i - 1].z - 6.0D * points[i].z + 3.0D * points[i + 1].z) / 6.0D;
c[2] = (-3.0D * points[i - 1].z + 3.0D * points[i + 1].z) / 6.0D;
c[3] = (points[i - 1].z + 4.0D * points[i].z + points[i + 1].z) / 6.0D;
for(int j = 1; j < subdivision; ++j) {
double t = j / subdivision;
Vector3 sp = new Vector3();
sp.x = (a[2] + t * (a[1] + t * a[0])) * t + a[3];
sp.y = (b[2] + t * (b[1] + t * b[0])) * t + b[3];
sp.z = (c[2] + t * (c[1] + t * c[0])) * t + c[3];
spline.add(sp);
}
}
return spline;
}
public static void main(String[] args) {
Vector3[] v = new Vector3[] {new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 1, 0), new Vector3(0, 1, 0)};
System.out.println("\nbspline2D");
for(Vector3 v3 : bspline2D(v, 4)) {
System.out.println(v3.x + ", " + v3.y + ", " + v3.z);
}
System.out.println("\nbspline3D");
for(Vector3 v3 : bspline3D(v, 4)) {
System.out.println(v3.x + ", " + v3.y + ", " + v3.z);
}
}
And here's the Lua version:
function M.bspline2D(points, subdivision)
local spline = {}
local wbvector2 = dofile('wbvector3.lua')
local pointsNumber = #points
-- extend the points array
points[0] = wbvector2.add(points[1], wbvector2.minus(points[1], points[2]))
points[-1] = wbvector2.add(points[0], wbvector2.minus(points[0], points[1]))
points[pointsNumber + 1] = wbvector2.add(points[pointsNumber], wbvector2.minus(points[pointsNumber], points[pointsNumber - 1]))
points[pointsNumber + 2] = wbvector2.add(points[pointsNumber + 1], wbvector2.minus(points[pointsNumber + 1], points[pointsNumber]))
-- Interpolation
local index = 1
spline[index] = points[1] -- first point
for i = 0, pointsNumber - 1 do
local a = {} -- compute the third order coefficients for x
local b = {} -- compute the third order coefficients for y
a[1] = (-points[i-1].x + 3 * points[i].x - 3 * points[i+1].x + points[i+2].x) / 6.0;
a[2] = (3 * points[i-1].x - 6 * points[i].x + 3 * points[i+1].x) / 6.0;
a[3] = (-3 * points[i-1].x + 3 * points[i+1].x) / 6.0;
a[4] = (points[i-1].x + 4 * points[i].x + points[i+1].x) / 6.0;
b[1] = (-points[i-1].y + 3 * points[i].y - 3 * points[i+1].y + points[i+2].y) / 6.0;
b[2] = (3 * points[i-1].y - 6 * points[i].y + 3 * points[i+1].y) / 6.0;
b[3] = (-3 * points[i-1].y + 3 * points[i+1].y) / 6.0;
b[4] = (points[i-1].y + 4 * points[i].y + points[i+1].y) / 6.0;
for j = 1, subdivision do
index = index + 1
spline[index] = {}
local t = j / subdivision
spline[index].x = (a[3] + t * (a[2] + t * a[1])) * t + a[4]
spline[index].y = (b[3] + t * (b[2] + t * b[1])) * t + b[4]
end
end
return spline
end
function M.bspline3D(points, subdivision)
local spline = {}
local wbcore = require('wbcore')
local wbvector3 = require('wbvector3')
local pointsNumber = wbcore.tablelength(points)
-- extend the points array
points[0] = wbvector3.add(points[1], wbvector3.minus(points[1], points[2]))
points[-1] = wbvector3.add(points[0], wbvector3.minus(points[0], points[1]))
points[pointsNumber + 1] = wbvector3.add(points[pointsNumber], wbvector3.minus(points[pointsNumber], points[pointsNumber - 1]))
points[pointsNumber + 2] = wbvector3.add(points[pointsNumber + 1], wbvector3.minus(points[pointsNumber + 1], points[pointsNumber]))
-- Interpolation
local index = 1
spline[index] = points[1] -- first point
for i = 1, pointsNumber - 1 do
local a = {} -- compute the third order coefficients for x
local b = {} -- compute the third order coefficients for y
local c = {} -- compute the third order coefficients for z
a[1] = (-points[i-1].x + 3 * points[i].x - 3 * points[i+1].x + points[i+2].x) / 6.0;
a[2] = (3 * points[i-1].x - 6 * points[i].x + 3 * points[i+1].x) / 6.0;
a[3] = (-3 * points[i-1].x + 3 * points[i+1].x) / 6.0;
a[4] = (points[i-1].x + 4 * points[i].x + points[i+1].x) / 6.0;
b[1] = (-points[i-1].y + 3 * points[i].y - 3 * points[i+1].y + points[i+2].y) / 6.0;
b[2] = (3 * points[i-1].y - 6 * points[i].y + 3 * points[i+1].y) / 6.0;
b[3] = (-3 * points[i-1].y + 3 * points[i+1].y) / 6.0;
b[4] = (points[i-1].y + 4 * points[i].y + points[i+1].y) / 6.0;
c[1] = (-points[i-1].z + 3 * points[i].z - 3 * points[i+1].z + points[i+2].z) / 6.0;
c[2] = (3 * points[i-1].z - 6 * points[i].z + 3 * points[i+1].z) / 6.0;
c[3] = (-3 * points[i-1].z + 3 * points[i+1].z) / 6.0;
c[4] = (points[i-1].z + 4 * points[i].z + points[i+1].z) / 6.0;
for j = 1, subdivision do
index = index + 1
spline[index] = {}
local t = j / subdivision
spline[index].x = (a[3] + t * (a[2] + t * a[1])) * t + a[4]
spline[index].y = (b[3] + t * (b[2] + t * b[1])) * t + b[4]
spline[index].z = (c[3] + t * (c[2] + t * c[1])) * t + c[4]
end
end
return spline
end
local v = {{x = 0, y = 0, z = 0}, {x = 1, y = 0, z = 0}, {x = 1, y = 1, z = 0}, {x = 0, y = 1, z = 0}}
print()
print("bspline2D");
for _, v3 in ipairs(M.bspline2D(v, 4)) do
print(v3.x .. ", " .. v3.y .. ", " .. v3.z)
end
print()
print("bspline3D");
for _, v3 in ipairs(M.bspline3D(v, 4)) do
print(v3.x .. ", " .. v3.y .. ", " .. v3.z)
end
I've been looking for hours now to find a good way to draw a textured sphere in JOGL. All I need is a point in the right direction or some code that works for someone. So far all I have been able to find is helloTexture (while it works, it is obviously not a sphere), would there be a way to convert this into a sphere or should i try my luck somewhere else?
I wrote this for you, it's untested since I modified it to work with GL_TRIANGLES, try and let me know
radius is the sphere radius, rings are the horizontal slices, sectors the vertical ones
private void createGeometry(float radius, short rings, short sectors) {
float R = 1f / (float)(rings - 1);
float S = 1f / (float)(sectors - 1);
short r, s;
float x, y, z;
points = new float[rings * sectors * 3];
normals = new float[rings * sectors * 3];
texcoords = new float[rings * sectors * 2];
int t = 0, v = 0, n = 0;
for(r = 0; r < rings; r++) {
for(s = 0; s < sectors; s++) {
x = (float) (Math.cos(2 * Math.PI * s * S) * Math.sin(Math.PI * r * R ));
y = (float) Math.sin(-Math.PI / 2 + Math.PI * r * R );
z = (float) (Math.sin(2 * Math.PI * s * S) * Math.sin(Math.PI * r * R ));
texcoords[t++] = s * S;
texcoords[t++] = r * R;
points[v++] = x * radius;
points[v++] = y * radius;
points[v++] = z * radius;
normals[n++] = x;
normals[n++] = y;
normals[n++] = z;
}
}
int counter = 0;
indices = new short[rings * sectors * 6];
for(r = 0; r < rings - 1; r++){
for(s = 0; s < sectors-1; s++) {
indices[counter++] = (short) (r * sectors + s);
indices[counter++] = (short) (r * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + (s + 1));
indices[counter++] = (short) (r * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + s);
}
}
}