Pane children overlapping the Pane border - javafx

I am trying to generate random circles on click in a Pane, but some of them are appearing outside the Pane border as seen in the pic Pane... this is the code that generates the circle
private void createCircle(){
double r, g, b, o, radius;
Random generator = new Random();
radius =50;
float x = (float)(Math.random()*(700+1));
float y = (float)(Math.random()*(700+1));
cc.setLayoutX(x);
cc.setLayoutY(y);
cc.setRadius(radius);
r = generator.nextDouble();
g = generator.nextDouble();
b = generator.nextDouble();
o = generator.nextDouble();
cc.setFill(new Color(r,g,b,o));
pane.getChildren().addAll(cc);
cc.setOnMouseClicked(e->{
pane.getChildren().remove(cc);
createCircle();
});
}
The pane predWidth is 700 and prefHeight is also 700... I am guessing the cc.setLayoutX() and cc.setLayoutY() are wrong but I couldn't find any other way around it

Related

In JavaFX, How to gradient fill multiple objects on canvas as one object?

I'm trying to draw three separate round rectangles and then fill all three with a linear gradient, but have the gradient traverse all three objects. I can't seem to find any information on drawing objects onto a canvas and linking them together.
I'm very new at using canvas in general.
Here is what I have so far:
final Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
final GraphicsContext gc = canvas.getGraphicsContext2D();
double offset1 = .1;
double offset2 = .9;
Color color1 = Color.rgb(0,0,255);
Color color2 = Color.rgb(0,200,255);
Stop[] stops1 = new Stop[] {new Stop(offset1, color1), new Stop(offset2, color2)};
gc.setFill(new LinearGradient(0, 0, .2, 1.4, true, CycleMethod.NO_CYCLE, stops1));
double third = CANVAS_HEIGHT / 3.0;
double thirdM2 = third - 10;
double h2 = CANVAS_HEIGHT - (2 * third);
double h3 = CANVAS_HEIGHT - third;
gc.fillRoundRect(0,0,CANVAS_WIDTH,thirdM2,thirdM2,thirdM2);
gc.fillRoundRect(0,h2,CANVAS_WIDTH,thirdM2,thirdM2,thirdM2);
gc.fillRoundRect(0,h3,CANVAS_WIDTH,thirdM2,thirdM2,thirdM2);
This makes an image that looks like this
However, I need it to end up looking like this:
Is there any way to accomplish this in JavaFX with canvas?
Thank you,
Mike Sims
Yes. There are a couple ways to do this. You could render all three rounded rectangles as a single path (using path rendering instead of fillRoundedRect, e.g. moveTo, arcTo etc.), or you could change the render blend mode to SRC_ATOP and paint a rectangle over all three rounded rects. That's what I've done in the code below:
final Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
final GraphicsContext gc = canvas.getGraphicsContext2D();
double offset1 = .5;
double offset2 = .9;
Color color1 = Color.rgb(0,0,255);
Color color2 = Color.rgb(0,200,255);
Stop[] stops1 = new Stop[] {new Stop(offset1, color1), new Stop(offset2, color2)};
double third = CANVAS_HEIGHT / 3.0;
double thirdM2 = third - 10;
double h2 = CANVAS_HEIGHT - (2 * third);
double h3 = CANVAS_HEIGHT - third;
gc.fillRoundRect(0,0,CANVAS_WIDTH,thirdM2,thirdM2,thirdM2);
gc.fillRoundRect(0,h2,CANVAS_WIDTH,thirdM2,thirdM2,thirdM2);
gc.fillRoundRect(0,h3,CANVAS_WIDTH,thirdM2,thirdM2,thirdM2);
gc.setGlobalBlendMode(BlendMode.SRC_ATOP); // preserves the alpha channel set above
gc.setFill(new LinearGradient(0, 0, .6, .5, true, CycleMethod.NO_CYCLE, stops1));
gc.fillRect(0, 0, CANVAS_WIDTH, h3+thirdM2);
If you don't want to muck around directly on the canvas (because there may be other elements that get in the way that you can't paint over), you can do this trick to a writeable image and then stamp that onto the canvas.

Generate socket junctions for 3D model / Draw cylinders along edges

I have this Processing sketch in which I'm trying to load a model (.stl or .obj) and build parametric socket junctions for every edge intersection. These will be 3D printed and rods of the appropriate gauge will slot in their holes.
I've been able to draw Spheres at the vertices (in red,on the model), but I can't generate the green sockets or even the rods in pink:
I can get the coordinates of the model's edges:
id: 0 0 {-25.805634,-23.170607,13.6315975} -> 1 {-16.868328,-10.148323,6.785455} f: 2
id: 1 1 {-16.868328,-10.148323,6.785455} -> 2 {-52.833824,-10.148322,16.799314} f: 2
....
and with these I could draw a Line3D(Vec3D a, Vec3D b) (toxi.geom.Line3D)
But I don't want a Line3D, I need to draw a cylinder between them, thereby getting the rods. To sort of extrude or inflate the line to a 3D volume, if you will...
WETriangleMesh whale, redmesh;
[bla bla bla]
Then inside void setup():
for(WingedEdge e : whale.edges.values()) {
edges.add(e);
drawSocket(e);
}
void drawSocket(WingedEdge e) {
// draw size 2 balls at model vertices
Sphere ball = new Sphere(e.a, 2);
// convert to mesh at resolution 6 and add to redmesh
ball.toMesh(redmesh, 6);
}
Then inside void draw():
// draw the mesh with the whale
gfx.mesh(whale);
// color the next mesh red
fill(255,0,0);
// draw the mesh with the spheres
gfx.mesh(redmesh);
I have found no 3D shape class that can be constructed in place from the Vec3D a, Vec3D b arguments. Perhaps creating a class to make use of those two coordinates?
If building a shape in place is too difficult, maybe a transform then? pushMatrix() translate() and popMatrix()?
EDIT: Solved, see below. Thanks!
The trick is to translate the sockets to one vertex in the edge and have them face the opposite vertex. Here's a Processing function that'll take a WETriangleMesh like your whale and return back meshes for the points, sockets and rods. I've written a more complete example here.
float socketLength = 30;
float socketRadius = 6;
float rodRadius = 5;
float pointRadius = 10.0;
int resolution = 10;
WETriangleMesh[] convertMeshToRodSockets(WETriangleMesh inMesh) {
WETriangleMesh[] meshes = new WETriangleMesh[3];
meshes[0] = new WETriangleMesh();
meshes[1] = new WETriangleMesh();
meshes[2] = new WETriangleMesh();
for (Vertex vert : inMesh.getVertices ()) {
//Sphere points
Sphere sphere = new Sphere(vert, pointRadius);
WETriangleMesh sphereMesh = new WETriangleMesh();
sphere.toMesh(sphereMesh, resolution);
meshes[2].addMesh((WETriangleMesh)sphereMesh);
}
for (WingedEdge edge : inMesh.edges.values ()) {
Vec3D pointA = edge.a;
Vec3D pointB = edge.b;
//Meshes to store socket shapes
ZAxisCylinder socket;
ZAxisCylinder rod;
WETriangleMesh socketAMesh = new WETriangleMesh();
WETriangleMesh socketBMesh = new WETriangleMesh();
WETriangleMesh rodMesh = new WETriangleMesh();
float distanceBetweenPoints = pointA.distanceTo(pointB);
//Create sockets and point towards target
socket = new ZAxisCylinder(new Vec3D(0.0, 0.0, 0.0), socketRadius, socketLength);
socket.toMesh(socketAMesh, resolution, 0.0);
socketAMesh.pointTowards(pointB.sub(pointA));
//Translate socket to start from the center of the point
socketAMesh.translate( offsetTranslation(pointA, pointB, socketLength ));
//Create second socket and look in the opposite direction to face the start point
socket.toMesh(socketBMesh, resolution, 0.0);
socketBMesh.pointTowards(pointA.sub(pointB));
socketBMesh.translate( offsetTranslation(pointB, pointA, socketLength ));
//Create rod with a length matching the distance between the two points
rod = new ZAxisCylinder(new Vec3D(0.0, 0.0, 0.0), rodRadius, distanceBetweenPoints);
rod.toMesh(rodMesh, resolution, 0.0);
rodMesh.pointTowards(pointB.sub(pointA));
//Translate the rod to the midpoint of both points
rodMesh.translate(pointA.add(pointB).scale(0.5));
//Combine meshes together
meshes[0].addMesh((WETriangleMesh)rodMesh);
meshes[1].addMesh((WETriangleMesh)socketAMesh);
meshes[1].addMesh((WETriangleMesh)socketBMesh);
}
return meshes;
}
//Function to return a vector that is slightly offset by a length.
Vec3D offsetTranslation(Vec3D a, Vec3D b, float l) {
return a.interpolateTo(b, (l*0.5 / a.distanceTo(b)) );
}

How to draw graph from a list of points?

In this answer to my recent question, there is some code that draws a graph, but I can't manage to edit it into something that accepts any list of points as a parameter.
I'd like the Drawing method to accept these parameters:
List of Vector2, Point or VertexPositionColor, I can work with whichever.
Offset for the whole graph
These optional requirements would be appreciated:
Color that may override VertexPositionColor's color and apply to all points.
Size of the graph, so it can be shrunk or expanded, either as Vector2 as multiplier, or Point as target size. Maybe even combine this with offset in Rectangle.
And if it's possible, I'd like to have it all in a class, so graphs can be used separately from each other, each with its own Effect.world matrix, etc.
Here is that code (by Niko Drašković):
Matrix worldMatrix;
Matrix viewMatrix;
Matrix projectionMatrix;
BasicEffect basicEffect;
VertexPositionColor[] pointList;
short[] lineListIndices;
protected override void Initialize()
{
int n = 300;
//GeneratePoints generates a random graph, implementation irrelevant
pointList = new VertexPositionColor[n];
for (int i = 0; i < n; i++)
pointList[i] = new VertexPositionColor() { Position = new Vector3(i, (float)(Math.Sin((i / 15.0)) * height / 2.0 + height / 2.0 + minY), 0), Color = Color.Blue };
//links the points into a list
lineListIndices = new short[(n * 2) - 2];
for (int i = 0; i < n - 1; i++)
{
lineListIndices[i * 2] = (short)(i);
lineListIndices[(i * 2) + 1] = (short)(i + 1);
}
worldMatrix = Matrix.Identity;
viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up);
projectionMatrix = Matrix.CreateOrthographicOffCenter(0, (float)GraphicsDevice.Viewport.Width, (float)GraphicsDevice.Viewport.Height, 0, 1.0f, 1000.0f);
basicEffect = new BasicEffect(graphics.GraphicsDevice);
basicEffect.World = worldMatrix;
basicEffect.View = viewMatrix;
basicEffect.Projection = projectionMatrix;
basicEffect.VertexColorEnabled = true; //important for color
base.Initialize();
}
And the drawing method:
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
PrimitiveType.LineList,
pointList,
0,
pointList.Length,
lineListIndices,
0,
pointList.Length - 1
);
}
The Graph class that does the requested can be found here.About 200 lines of code seemed too much to paste here.
The Graph is drawn by passing a list of floats (optionally with colors) to its Draw(..) method.
Graph properties are:
Vector2 Position - the bottom left corner of the graph
Point Size - the width (.X) and height (.Y) of the graph. Horizontally, values will be distributed to exactly fit the width. Vertically, all values will be scaled with Size.Y / MaxValue.
float MaxValue - the value which will be at the top of the graph. All off the chart values (greater than MaxValue) will be set to this value.
GraphType Type - with possible values GraphType.Line and GraphType.Fill, determines if the graph will be drawn line only, or bottom filled.
The graph is drawn with a line list / triangle strip.

Quaternion based rotation and pivot position

I can't figure out how to perform matrix rotation using Quaternion while taking into account pivot position in OpenGL.What I am currently getting is rotation of the object around some point in the space and not a local pivot which is what I want.
Here is the code [Using Java]
Quaternion rotation method:
public void rotateTo3(float xr, float yr, float zr) {
_rotation.x = xr;
_rotation.y = yr;
_rotation.z = zr;
Quaternion xrotQ = Glm.angleAxis((xr), Vec3.X_AXIS);
Quaternion yrotQ = Glm.angleAxis((yr), Vec3.Y_AXIS);
Quaternion zrotQ = Glm.angleAxis((zr), Vec3.Z_AXIS);
xrotQ = Glm.normalize(xrotQ);
yrotQ = Glm.normalize(yrotQ);
zrotQ = Glm.normalize(zrotQ);
Quaternion acumQuat;
acumQuat = Quaternion.mul(xrotQ, yrotQ);
acumQuat = Quaternion.mul(acumQuat, zrotQ);
Mat4 rotMat = Glm.matCast(acumQuat);
_model = new Mat4(1);
scaleTo(_scaleX, _scaleY, _scaleZ);
_model = Glm.translate(_model, new Vec3(_pivot.x, _pivot.y, 0));
_model =rotMat.mul(_model);//_model.mul(rotMat); //rotMat.mul(_model);
_model = Glm.translate(_model, new Vec3(-_pivot.x, -_pivot.y, 0));
translateTo(_x, _y, _z);
notifyTranformChange();
}
Model matrix scale method:
public void scaleTo(float x, float y, float z) {
_model.set(0, x);
_model.set(5, y);
_model.set(10, z);
_scaleX = x;
_scaleY = y;
_scaleZ = z;
notifyTranformChange();
}
Translate method:
public void translateTo(float x, float y, float z) {
_x = x - _pivot.x;
_y = y - _pivot.y;
_z = z;
_position.x = _x;
_position.y = _y;
_position.z = _z;
_model.set(12, _x);
_model.set(13, _y);
_model.set(14, _z);
notifyTranformChange();
}
But this method in which I don't use Quaternion works fine:
public void rotate(Vec3 axis, float angleDegr) {
_rotation.add(axis.scale(angleDegr));
// change to GLM:
Mat4 backTr = new Mat4(1.0f);
backTr = Glm.translate(backTr, new Vec3(_pivot.x, _pivot.y, 0));
backTr = Glm.rotate(backTr, angleDegr, axis);
backTr = Glm.translate(backTr, new Vec3(-_pivot.x, -_pivot.y, 0));
_model =_model.mul(backTr);///backTr.mul(_model);
notifyTranformChange();
}
It seems to me you take into account the back and forth translation before and after the rotation already. Why that final call of translateTo?
Besides, when you rotate, a pure rotation is always meant around the origin. So if you want a rotation around your pivot point. I'd exptect to translate your pivot point to the origin, then rotate, then translate back to the pivot would be the right thing to do. Therefore, I'd expect your code to look like this:
_model = Glm.translate(_model, new Vec3(-_pivot.x, -_pivot.y, 0));
_model =rotMat.mul(_model);//_model.mul(rotMat); //rotMat.mul(_model);
_model = Glm.translate(_model, new Vec3(_pivot.x, _pivot.y, 0));
and without the call translateTo(_x, _y, _z);. Also, can you confirm that the rotation part already does what it supposed to? You can check this by comparing rotMat with Glm.rotate(new Mat4(1.0f), angleDegr, axis). They should be the same for the same rotation.
A quaternion describes only a rotation. As a result how do you want to rotate something around a pivot point with only a quaternion?
The minimum that you need is a R3 vector and a quaternion. With only one level of transformation you first roatate the object and then move it there.
If you want to create a matrix you first create the ration matrix and then add the translation unaltered.
If you want to just call glTranslate and glRotate (or glMultMatrix) you would first call glTranslate and then glRoatate.
Edit:
If you are not rendering and just want to know where each vertex is:
Vector3 newVertex = quat.transform(oldVertex) + translation;

Bounding Spheres move farther than sphere object

I have a program that I'm making with others and I ran into a problem. I'm working on adding in polygon models into our scene in an XNA window. I have that part complete. I also have bounding spheres(I know I tagged as bounding-box but there is no bounding sphere tag) drawing around each polygon. My problem is when I move the polygons around the 3D space the bounding spheres move twice as much as the polygons. I imagine its something within my polygon matrices that I use to create the bounding sphere that makes it move twice as much but that is only speculation.
So just to clarify I'll give you an example of my problem. If I hold down D to move a polygon along the X axis. (model.position.X--;) The polygon moves as expected to but the bounding sphere around the polygon moves twice as much. Thanks for the help guys!
Here is how I draw the models and the bounding spheres:
public void Draw(Matrix view, Matrix projection, bool drawBoundingSphere)
{
Matrix translateMatrix = Matrix.CreateTranslation(position);
Matrix worldMatrix = translateMatrix * Matrix.CreateScale(scaleRatio);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = worldMatrix * modelAbsoluteBoneTransforms[mesh.ParentBone.Index];
effect.View = view;
effect.Projection = projection;
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
}
mesh.Draw();
if (drawBoundingSphere)
{
// the mesh's BoundingSphere is stored relative to the mesh itself.
// (Mesh space). We want to get this BoundingSphere in terms of world
// coordinates. To do this, we calculate a matrix that will transform
// from coordinates from mesh space into world space....
Matrix world = modelAbsoluteBoneTransforms[mesh.ParentBone.Index] * worldMatrix;
// ... and then transform the BoundingSphere using that matrix.
BoundingSphere sphere = BoundingSphereRenderer.TransformBoundingSphere(mesh.BoundingSphere, world);
// now draw the sphere with our renderer
BoundingSphereRenderer.Draw(sphere, view, projection);
}
}
And here is the BoundingSphereRenderer Code:
private static VertexBuffer vertexBuffer;
private static BasicEffect effect;
private static int lineCount;
public static void Initialize(GraphicsDevice graphicsDevice, int sphereResolution)
{
// create our effect
effect = new BasicEffect(graphicsDevice);
effect.LightingEnabled = false;
effect.VertexColorEnabled = true;
// calculate the number of lines to draw for all circles
lineCount = (sphereResolution + 1) * 3;
// we need two vertices per line, so we can allocate our vertices
VertexPositionColor[] vertices = new VertexPositionColor[lineCount * 2];
// compute our step around each circle
float step = MathHelper.TwoPi / sphereResolution;
// used to track the index into our vertex array
int index = 0;
//create the loop on the XY plane first
for (float angle = 0f; angle < MathHelper.TwoPi; angle += step)
{
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0f), Color.Blue);
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle + step), (float)Math.Sin(angle + step), 0f), Color.Blue);
}
//next on the XZ plane
for (float angle = 0f; angle < MathHelper.TwoPi; angle += step)
{
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle), 0f, (float)Math.Sin(angle)), Color.Red);
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle + step), 0f, (float)Math.Sin(angle + step)), Color.Red);
}
//finally on the YZ plane
for (float angle = 0f; angle < MathHelper.TwoPi; angle += step)
{
vertices[index++] = new VertexPositionColor(new Vector3(0f, (float)Math.Cos(angle), (float)Math.Sin(angle)), Color.Green);
vertices[index++] = new VertexPositionColor(new Vector3(0f, (float)Math.Cos(angle + step), (float)Math.Sin(angle + step)), Color.Green);
}
// now we create the vertex buffer and put the vertices in it
vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
}
public static void Draw(this BoundingSphere sphere, Matrix view, Matrix projection)
{
if (effect == null)
throw new InvalidOperationException("You must call Initialize before you can render any spheres.");
// set the vertex buffer
effect.GraphicsDevice.SetVertexBuffer(vertexBuffer);
// update our effect matrices
effect.World = Matrix.CreateScale(sphere.Radius) * Matrix.CreateTranslation(sphere.Center);
effect.View = view;
effect.Projection = projection;
// draw the primitives with our effect
effect.CurrentTechnique.Passes[0].Apply();
effect.GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, lineCount);
}
public static BoundingSphere TransformBoundingSphere(BoundingSphere sphere, Matrix transform)
{
BoundingSphere transformedSphere;
// the transform can contain different scales on the x, y, and z components.
// this has the effect of stretching and squishing our bounding sphere along
// different axes. Obviously, this is no good: a bounding sphere has to be a
// SPHERE. so, the transformed sphere's radius must be the maximum of the
// scaled x, y, and z radii.
// to calculate how the transform matrix will affect the x, y, and z
// components of the sphere, we'll create a vector3 with x y and z equal
// to the sphere's radius...
Vector3 scale3 = new Vector3(sphere.Radius, sphere.Radius, sphere.Radius);
// then transform that vector using the transform matrix. we use
// TransformNormal because we don't want to take translation into account.
scale3 = Vector3.TransformNormal(scale3, transform);
// scale3 contains the x, y, and z radii of a squished and stretched sphere.
// we'll set the finished sphere's radius to the maximum of the x y and z
// radii, creating a sphere that is large enough to contain the original
// squished sphere.
transformedSphere.Radius = Math.Max(scale3.X, Math.Max(scale3.Y, scale3.Z));
// transforming the center of the sphere is much easier. we can just use
// Vector3.Transform to transform the center vector. notice that we're using
// Transform instead of TransformNormal because in this case we DO want to
// take translation into account.
transformedSphere.Center = Vector3.Transform(sphere.Center, transform);
return transformedSphere;
}

Resources