JavaFX Dynamically add Nodes to pane with fx:id or id - javafx

I can create Nodes on a pane with a for next loop, but do not have the ability
to assign these nodes a fx:id or a id
Is this possible number one? If so what do I need to add to my code?
Or do I have the option to write the information to a FXML file with the for next loop?
private void MakeNode(){
for (int A = 1; A <= 42; A++){
if(A==1){
X=40;
Y=40;
}else if(A>1 && A<=7){
X = X + 120;
Y = 40;
}else if(A==8){
X = 40;
Y = 160;
}else if(A>8&& A<=14){
X = X + 120;
Y = 160;
}else if(A==15){
X = 40;
Y = 280;
}else if(A>15&& A<=21){
X = X + 120;
Y = 280;
}else if(A==22){
X = 40;
Y = 400;
}else if(A>22&& A<=28){
X = X + 120;
Y = 400;
}else if(A==29){
X = 40;
Y = 520;
}else if(A>29&& A<=35){
X = X + 120;
Y = 520;
}else if(A==36){
X = 40;
Y = 640;
}else if(A>36&& A<=42){
X = X + 120;
Y = 640;
}
cirA = new Circle(X,Y,16);
//fxid = cir.concat(String.valueOf(A));
//fxid = cir+String.valueOf(A);
//cirA.setId(fxid);
cirA.setFill(Color.YELLOW);
cirA.setStroke(Color.BLACK);
cirA.setStrokeWidth(4.0);
pane.getChildren().add(cirA);
}
}

fx:id is just a mechanism for getting a reference to elements defined in FXML to the controller. If you are defining nodes in the controller anyway, there is no need for (or indeed, no way to use) fx:id at all.
You already have a reference to the Circle when you create it. So just do whatever you need right there. Here's a simple example (I cleaned your code up to make it much less verbose):
private void makeNode() {
for (int circleIndex = 0 ; circleIndex < 42 ; circleIndex++) {
int column = circleIndex % 7 ;
int row = circleIndex / 7 ;
double x = 40 + 120 * column ;
double y = 40 + 120 * row ;
Circle circle = new Circle(x, y, 16);
circle.setFill(Color.YELLOW);
circle.setStroke(Color.BLACK);
circle.setStrokeWidth(4.0);
pane.getChildren().add(circle);
circle.setOnMouseClicked(e -> {
System.out.println("Clicked on ["+column+", "+row+"]");
});
}
}

Related

color points based on what side of line they are on

I am trying to make a little algorithm that colors a point a certain color based on what side of a line the point is on. This is what i have at the moment. The code doesnt give any errors, but the colors also arent correct for the dots.. Could someone point out to me what i am doing wrong?
See the code:
PVector[] points;
void setup() {
size(500, 500);
points = new PVector[10];
for (int i = 0; i < points.length; i++) {
points[i] = new PVector(random(0, width), random(0, height));
}
ExtremesLine(points);
}
void ExtremesLine(PVector[] pts) {
float maxx = 0, minx = width+1;
PVector min = new PVector(), max = new PVector();
ArrayList<PVector> groupA = new ArrayList<PVector>(), groupB = new ArrayList<PVector>();
for (int i = 0; i < pts.length; i++) {
if (pts[i].x > maxx) {
maxx = pts[i].x;
max = pts[i];
}
if (pts[i].x < minx) {
minx = pts[i].x;
min = pts[i];
}
}
PVector divisionLine = new PVector();
PVector.sub(max, min, divisionLine);
PVector normal = new PVector(-divisionLine.y, divisionLine.x).normalize();
for (int i = 0; i < pts.length; i++) {
float s = PVector.dot(normal, pts[i].copy().normalize());
if ( s < 0) groupA.add(pts[i]);
else if ( s > 0) groupB.add(pts[i]);
}
fill(0);
line(min.x, min.y, max.x, max.y);
for (int i = 0; i < groupA.size(); i++) {
fill(255, 0, 0);
ellipse(groupA.get(i).x, groupA.get(i).y, 10, 10);
}
for (int i = 0; i < groupB.size(); i++) {
fill(0, 0, 255);
ellipse(groupB.get(i).x, groupB.get(i).y, 10, 10);
}
}
As you can see from the images below sometimes it works but 90% of the time it doesnt. First image is the correct result, second image is the incorrect result
If there is anything unclear pls let me know so i can clarify!
You need to dot with vectors from min:
replace
float s = PVector.dot(normal, pts[i].copy().normalize());
by
float s = PVector.dot(normal, pts[i].copy().sub(min).normalize());
and it will work as expected:
Tangentially, since min and max are Processing built-ins, are you sure that you want to use them as variable names?

What is the most practical way to create coordinate grid with JavaFX 3D?

I would like to create a 3D demo application with JavaFX to visualize movements of points in 3D space and first I need to set up a coordinate grid for visual reference. Unfortunately, I was not able to find a sample code for a grid like in this picture:
Does anyone know what is the most practical way to create something like it?
There are a few solutions out there already.
FXyz3D library has a CubeWorld class, that gives you precisely a reference grid.
It is quite easy to use. Just import the 'org.fxyz3d:fxyz3d:0.3.0' dependency from JCenter and use it:
CubeWorld cubeWorld = new CubeWorld(5000, 500, true);
Sphere sphere = new Sphere(100);
sphere.setMaterial(new PhongMaterial(Color.FIREBRICK));
sphere.getTransforms().add(new Translate(100, 200, 300));
Scene scene = new Scene(new Group(cubeWorld, sphere), 800, 800, true, SceneAntialiasing.BALANCED);
As you can see, the solution is based on using 2D rectangles for each face, and the grid lines are created with 3D cylinders. It has very nice features (like self lightning or frontal faces according to camera don't show grid), but it is quite intensive in nodes (sample above has 168 nodes).
There are other solutions that use a lower number of nodes. For instance, for this sample, that also happens to be related to Leap Motion, I used a TriangleMesh.
This is an easy solution, and with just two meshes. However, you see the triangles, instead of squares.
So let's try to get rid of the triangles. For that I'll use a PolygonMesh, as in this other question, based on the 3DViewer project that is available at the OpenJFX repository, contains already a PolygonalMesh implementation, that allows any number of points per face, so any polygon can be a face.
This will give you a plane grid based in square faces:
private PolygonMesh createQuadrilateralMesh(float width, float height, int subDivX, int subDivY) {
final float minX = - width / 2f;
final float minY = - height / 2f;
final float maxX = width / 2f;
final float maxY = height / 2f;
final int pointSize = 3;
final int texCoordSize = 2;
// 4 point indices and 4 texCoord indices per face
final int faceSize = 8;
int numDivX = subDivX + 1;
int numVerts = (subDivY + 1) * numDivX;
float points[] = new float[numVerts * pointSize];
float texCoords[] = new float[numVerts * texCoordSize];
int faceCount = subDivX * subDivY;
int faces[][] = new int[faceCount][faceSize];
// Create points and texCoords
for (int y = 0; y <= subDivY; y++) {
float dy = (float) y / subDivY;
double fy = (1 - dy) * minY + dy * maxY;
for (int x = 0; x <= subDivX; x++) {
float dx = (float) x / subDivX;
double fx = (1 - dx) * minX + dx * maxX;
int index = y * numDivX * pointSize + (x * pointSize);
points[index] = (float) fx;
points[index + 1] = (float) fy;
points[index + 2] = 0.0f;
index = y * numDivX * texCoordSize + (x * texCoordSize);
texCoords[index] = dx;
texCoords[index + 1] = dy;
}
}
// Create faces
int index = 0;
for (int y = 0; y < subDivY; y++) {
for (int x = 0; x < subDivX; x++) {
int p00 = y * numDivX + x;
int p01 = p00 + 1;
int p10 = p00 + numDivX;
int p11 = p10 + 1;
int tc00 = y * numDivX + x;
int tc01 = tc00 + 1;
int tc10 = tc00 + numDivX;
int tc11 = tc10 + 1;
faces[index][0] = p00;
faces[index][1] = tc00;
faces[index][2] = p10;
faces[index][3] = tc10;
faces[index][4] = p11;
faces[index][5] = tc11;
faces[index][6] = p01;
faces[index++][7] = tc01;
}
}
int[] smooth = new int[faceCount];
PolygonMesh mesh = new PolygonMesh(points, texCoords, faces);
mesh.getFaceSmoothingGroups().addAll(smooth);
return mesh;
}
So you can use 2 or 3 of them to create a coordinate system like this:
public Group createGrid(float size, float delta) {
if (delta < 1) {
delta = 1;
}
final PolygonMesh plane = createQuadrilateralMesh(size, size, (int) (size / delta), (int) (size / delta));
final PolygonMesh plane2 = createQuadrilateralMesh(size, size, (int) (size / delta / 5), (int) (size / delta / 5));
PolygonMeshView meshViewXY = new PolygonMeshView(plane);
meshViewXY.setDrawMode(DrawMode.LINE);
meshViewXY.setCullFace(CullFace.NONE);
PolygonMeshView meshViewXZ = new PolygonMeshView(plane);
meshViewXZ.setDrawMode(DrawMode.LINE);
meshViewXZ.setCullFace(CullFace.NONE);
meshViewXZ.getTransforms().add(new Rotate(90, Rotate.X_AXIS));
PolygonMeshView meshViewYZ = new PolygonMeshView(plane);
meshViewYZ.setDrawMode(DrawMode.LINE);
meshViewYZ.setCullFace(CullFace.NONE);
meshViewYZ.getTransforms().add(new Rotate(90, Rotate.Y_AXIS));
PolygonMeshView meshViewXY2 = new PolygonMeshView(plane2);
meshViewXY2.setDrawMode(DrawMode.LINE);
meshViewXY2.setCullFace(CullFace.NONE);
meshViewXY2.getTransforms().add(new Translate(size / 1000f, size / 1000f, 0));
PolygonMeshView meshViewXZ2 = new PolygonMeshView(plane2);
meshViewXZ2.setDrawMode(DrawMode.LINE);
meshViewXZ2.setCullFace(CullFace.NONE);
meshViewXZ2.getTransforms().add(new Translate(size / 1000f, size / 1000f, 0));
meshViewXZ2.getTransforms().add(new Rotate(90, Rotate.X_AXIS));
PolygonMeshView meshViewYZ2 = new PolygonMeshView(plane2);
meshViewYZ2.setDrawMode(DrawMode.LINE);
meshViewYZ2.setCullFace(CullFace.NONE);
meshViewYZ2.getTransforms().add(new Translate(size / 1000f, size / 1000f, 0));
meshViewYZ2.getTransforms().add(new Rotate(90, Rotate.Y_AXIS));
return new Group(meshViewXY, meshViewXY2, meshViewXZ, meshViewXZ2 /*, meshViewYZ, meshViewYZ2 */);
}
Note that I've duplicated the plane to mock a wider stroke every 5 lines.
Finally adding axes:
public Group getAxes(double scale) {
Cylinder axisX = new Cylinder(1, 200);
axisX.getTransforms().addAll(new Rotate(90, Rotate.Z_AXIS), new Translate(0, -100, 0));
axisX.setMaterial(new PhongMaterial(Color.RED));
Cylinder axisY = new Cylinder(1, 200);
axisY.getTransforms().add(new Translate(0, 100, 0));
axisY.setMaterial(new PhongMaterial(Color.GREEN));
Cylinder axisZ = new Cylinder(1, 200);
axisZ.setMaterial(new PhongMaterial(Color.BLUE));
axisZ.getTransforms().addAll(new Rotate(90, Rotate.X_AXIS), new Translate(0, 100, 0));
Group group = new Group(axisX, axisY, axisZ);
group.getTransforms().add(new Scale(scale, scale, scale));
return group;
}
Now you have:
final Group axes = getAxes(0.5);
final Group grid = createGrid(200, 10);
final Sphere sphere = new Sphere(5);
sphere.getTransforms().add(new Translate(20, 15, 40));
Scene scene = new Scene(new Group(axes, grid, sphere), 800, 800, true, SceneAntialiasing.BALANCED);
The total amount of nodes of this sample is 14.
Of course, it can be improved to add labels and many other features.

Paperjs inserting segments to a rectangle gives strange result

I am trying to add random segments along the path of a rectangle. Here is my jsfiddle http://jsfiddle.net/hhND7/1/
<canvas id='canvas' resize style='' style='padding:0; margin:0;'></canvas>
<script type="text/paperscript" canvas="canvas" >
var rect = new Path.Rectangle({x:200, y:100}, new Size(80, 100))
rect.strokeColor = 'gray'
rect.selected = true;
var pathCuts = rands(20, 0, 360).sort(function(a,b){return a - b});
var tArr = [];
for ( var i=0; i<pathCuts.length; i++){
var loc = rect.getLocationAt(pathCuts[i]);
tArr.push(loc.point);
var sE = new Path.Circle(loc.point, 2);
sE.strokeColor = 'red';
}
rect.insertSegments(1, tArr);
function rands(n, min, max) {
var range = max - min;
if (range < n)
throw new RangeError("Specified number range smaller than count requested");
function shuffle() {
var deck = [], p, t;
for (var i = 0; i < range; ++i)
deck[i] = i + min;
for (i = range - 1; i > 0; --i) {
p = Math.floor(Math.random() * i);
t = deck[i];
deck[i] = deck[p];
deck[p] = t;
}
return deck.slice(0, n);
}
function find() {
var used = {}, rv = [], r;
while (rv.length < n) {
r = Math.floor(Math.random() * range + min);
if (!used[r]) {
used[r] = true;
rv.push(r);
}
}
return rv;
}
return range < 3 * n ? shuffle() : find();
}
</script>
I think the problem is with the insertSegments function. But i can not find a solution.
If you want it to still look like the original polygon, you need to sort in the positions of the original segments. Since you can replace a path's segments with an array of curveLocation , you can just add the locations of these points to tArr, then sort by each element by it's offset:
var pathCuts = rands(20, 0, rect.length);
var tArr = [];
for ( var i=0; i<pathCuts.length; i++){
var loc = rect.getLocationAt(pathCuts[i]);
tArr.push(loc);
var sE = new Path.Circle(loc.point, 2);
sE.strokeColor = 'red';
}
for ( var i = 0, l = rect.segments.length; i < l; i++){
tArr.push(rect.segments[i].location);
}
tArr.sort(function(a,b){return a.offset - b.offset})
rect.segments = tArr;

getPixel-method - how do i get the R value of RGB?

i have a greyscale image and i want to scan the pixels out of the Image and this is what i get :
var i:int;
var j:int;
for (i = 0; i < img.contentWidth ; i++)
{
for(j = 0; j < img.contentHeight; j++){
pixeldaten.addItem({x:i,y:j,pixel:bmd.getPixel(i,j)});
}
}
but the table doesn't look like RGB Values . (R , B , and G must be the same)
: example
getPixel should return the hex value value of the pixel, you could then do something like
// get the red value
bmd.getPixel(i,j) >> 16
//for Image processing
Bitmap myBitmap = new Bitmap(CurrentBitmap);
int imgH = myBitmap.Height;
int imgW = myBitmap.Width;
ARed = new double[imgH, imgW];
AGreen = new double[imgH, imgW];
ABlue = new double[imgH, imgW];
doubles = new double[imgH, imgW];
var max = new double[imgH, imgW];
var min = new double[0, 0];
//seperating each RGB components
for (int x = 0; x < imgH; x++)
{
for (int y = 0; y < imgW; y++)
{
Color color = myBitmap.GetPixel(x, y);
// things we do with pixelColor
//ARed[x][y] = myBitmap.GetPixel >> 16;
ARed[x, y] = color.R;
ABlue[x, y] = color.B;
AGreen[x, y] = color.G;
max[x, y] = ARed[x, y];
}
}
Bitmap bmp = new Bitmap(pictureBox1.Image);
bmp.getPixel(i,j).R

ZedGraph labels

In ZedGraph, how do I show text labels for each point and in the XAxis all together?
If I do
myPane.XAxis.Type = AxisType.Text;
myPane.XAxis.Scale.TextLabels = array_of_string;
I get labels on the XAxis like this
And if I do
for (int i = 0; i < myCurve.Points.Count; i++)
{
PointPair pt = myCurve.Points[i];
// Create a text label from the Y data value
TextObj text = new TextObj(
pt.Y.ToString("f0"), pt.X, pt.Y + 0.1,
CoordType.AxisXYScale, AlignH.Left, AlignV.Center);
text.ZOrder = ZOrder.A_InFront;
text.FontSpec.Angle = 0;
myPane.GraphObjList.Add(text);
}
I get labels on the curve, like this
But if I do both at the same time, labels on the curve disappear.
Is there a way to combine both kind of labels?
I've changed my answer after you clarified the question.
You just have to remember to position the labels correctly:
<%
System.Collections.Generic.List<ZedGraphWebPointPair> points = new System.Collections.Generic.List<ZedGraphWebPointPair>();
for (int i = 0; i < 15; i++)
{
// Let's have some fun with maths
points.Add(new ZedGraphWebPointPair
{
X = i,
Y = Math.Pow(i - 10, 2) * -1 + 120
});
}
System.Collections.Generic.List<string> XAxisLabels = new System.Collections.Generic.List<string>();
TestGraph.CurveList.Add(new ZedGraphWebLineItem { Color = System.Drawing.Color.Red });
TestGraph.XAxis.Scale.FontSpec.Size = 9;
int j = 1;
foreach (ZedGraphWebPointPair point in points)
{
// Add the points we calculated
TestGraph.CurveList[0].Points.Add(point);
// Add the labels for the points
TestGraph.GraphObjList.Add(new ZedGraphWebTextObj
{
Location =
{
CoordinateFrame = ZedGraph.CoordType.XChartFractionYScale,
// Make sure we position them according to the CoordinateFrame
X = Convert.ToSingle(j) / points.Count - 0.05f,
Y = Convert.ToSingle(point.Y) + 3f,
AlignV = ZedGraph.AlignV.Top
},
Text = point.Y.ToString(),
FontSpec = { Angle = 90, Size = 9, Border = { IsVisible = false } }
});
// Add the labels for the XAxis
XAxisLabels.Add(String.Format("P{0}", j));
j++;
}
TestGraph.RenderGraph += delegate(ZedGraphWeb zgw, System.Drawing.Graphics g, ZedGraph.MasterPane mp)
{
ZedGraph.GraphPane gp = mp[0];
gp.XAxis.Type = ZedGraph.AxisType.Text;
gp.XAxis.Scale.TextLabels = XAxisLabels.ToArray();
};
%>
That code will produce this graph:
If the axis type is text, the code below is easier to get x-coordinates of the points ;)
for (int tPoint = 0; tPoint < curve.Points.Count; tPoint++)
{
TextObj text = new TextObj(curve.Points[tPoint].Y.ToString(), curve.Points[tPoint].X, curve.Points[tPoint].Y + 10);
}

Resources