我是一名学生,正在研究过程的物理建模。我是 GUI 新手。我有两个进程。第一个过程将球随机散布到圆柱体的表面上。这是它的代码
public class Generation {
private static final Color[] COLORS = new Color[] { RED, YELLOW, GREEN, BROWN, BLUE, PINK, BLACK };
private final Tube tube;
private final int numberOfParticle;
private final double radius;
public Generation(Tube tube, int numberOfParticle) {
this.tube = tube;
this.numberOfParticle = numberOfParticle;
radius = Math.sqrt(tube.getRadius()*tube.getHeight()/(2*numberOfParticle));
}
private Particle RandomParticle (Color color) {
double phi = 2*Math.PI*Math.random();
double z = GetRandomNumberUsingNextDouble(-tube.getHeight()/2,tube.getHeight()/2);
Particle particle = new Particle(phi,tube.getRadius(),z,radius,color);
return particle;
}
private static double GetRandomNumberUsingNextDouble(double min, double max){
Random r = new Random();
return min + (max - min) * r.nextDouble();
}
public ObservableList<Particle> ParticlesGeneration() {
ObservableList<Particle> particlesList = FXCollections.observableArrayList()
for (int i = 0; i < numberOfParticle; i++) {
Particle particle = RandomParticle(COLORS[i % COLORS.length]);
particlesList.add(particle);
}
return particlesList;
}
}
粒子类
public class Particle {
private final double radius;
private double phi, rho, z;
private final Sphere particle;
public Particle(double phi, double rho, double z, double radius, Color color) {
this.particle = new Sphere(radius);
this.radius = radius;
this.phi = phi;
this.rho = rho;
this.z = z;
particle.setMaterial(new PhongMaterial(color));
particle.setTranslateX(rho * Math.cos(phi));
particle.setTranslateY(z);
particle.setTranslateZ(rho * Math.sin(phi));
}
private static double distance(double x1, double y1, double x2, double y2) {
x2 -= x1;
y2 -= y1;
return Math.sqrt(x2 * x2 + y2 * y2);
}
public double distance(Particle p) { return distance(getPhi()*getRho(), getZ(), p.getPhi()*p.getRho(),p.getZ());}
public double getRadius() { return radius; }
public double getPhi() { return phi; }
public void setPhi(double phi) { this.phi = phi; }
public double getRho() { return rho; }
public void setRho(double rho) { this.rho = rho; }
public double getZ() { return z; }
public void setZ(double z) { this.z = z; }
public Sphere getParticle() { return particle; }
}
气缸类
public class Tube {
private double radius, height;
private final Cylinder tube;
private final Color color;
public Tube(double radius, double height, Color color) {
this.height = height;
this.color = color;
this.radius = radius;
this.tube = new Cylinder(radius,height);
tube.setMaterial(new PhongMaterial(color));
}
public Color getColor() { return color; }
public double getRadius() { return radius; }
public double getHeight() { return height; }
public Cylinder getTube() { return tube; }
public void setRadius(double radius) { this.radius = radius; }
public void setHeight(double height) { this.height = height; }
}
第二个过程是创建随机分散颗粒的致密堆积
public class Minimization {
private double COEFFICIENT_FOR_ANGLE = 1;
private double COEFFICIENT_FOR_Z = 1;
@SuppressWarnings("FieldCanBeLocal")
private final double ACCEPTABLE_COEFFICIENT_VALUE_K_ANGEL = 0.0001;
@SuppressWarnings("FieldCanBeLocal")
private final double ACCEPTABLE_COEFFICIENT_VALUE_K_Z = 0.0001;
@SuppressWarnings("FieldCanBeLocal")
private final double ACCEPTABLE_VALUE_OF_ENERGY_DIFFERENCE = 0.0001;
@SuppressWarnings("FieldCanBeLocal")
public static final double MAX_VALUE = 1.7976931348623157E308;
private final ObservableList<Particle> poissonDiskCoordinatesParticles;
private final int numberOfParticle, degree;
private final double heightTube;
public Minimization(ObservableList<Particle> poissonDiskCoordinatesParticles, int degree, Tube tube) {
this.poissonDiskCoordinatesParticles = poissonDiskCoordinatesParticles;
this.degree = degree;
numberOfParticle = poissonDiskCoordinatesParticles.size();
heightTube = tube.getHeight();
}
public ObservableList<Particle> minimization () {
ObservableList<Particle> list = poissonDiskCoordinatesParticles;
double energyOld = MAX_VALUE;
double energyNew = energyOfSystem(list);
while (COEFFICIENT_FOR_ANGLE > ACCEPTABLE_COEFFICIENT_VALUE_K_ANGEL && COEFFICIENT_FOR_Z > ACCEPTABLE_COEFFICIENT_VALUE_K_Z && energyOld > energyNew) {
if (energyOld - energyNew < ACCEPTABLE_VALUE_OF_ENERGY_DIFFERENCE) {
COEFFICIENT_FOR_Z = COEFFICIENT_FOR_Z/2;
COEFFICIENT_FOR_ANGLE = COEFFICIENT_FOR_ANGLE/2;
}
energyOld = energyNew;
stepOfMinimization(list);
energyNew = energyOfSystem(list);
}
return list;
}
private void stepOfMinimization (ObservableList<Particle> list) {
for (int i = 0; i < numberOfParticle; i++) {
Particle particle = newParticle(list, i);
if (energyOfSystem(list) < energyOfSystem(list,particle,i)) {
list.set(i, particle);
}
}
}
private Particle newParticle(ObservableList<Particle> coordinates, int i) {
Particle particle = coordinates.get(i);
double ForcePhi = 0.0;
double ForceZ = 0.0;
for (int j = 0; j < numberOfParticle; j++) {
Particle jParticle = coordinates.get(j);
if (i != j) {
ForcePhi += (numberOfParticle * particle.getRho() *
(particle.getPhi() - jParticle.getPhi())) / pow(particle.distance(jParticle), degree + 2);
ForceZ += (numberOfParticle *
(particle.getZ() - jParticle.getZ())) / pow(particle.distance(jParticle), degree + 2);
}
}
ForceZ += degree / pow(particle.getZ() - heightTube / 2, degree + 1) + degree / pow(particle.getZ() + heightTube / 2, degree + 1);
particle.setPhi(particle.getPhi() + COEFFICIENT_FOR_ANGLE * ForcePhi);
particle.setZ(particle.getZ() + COEFFICIENT_FOR_Z * ForceZ);
return particle;
}
private double energyOfSystem (ObservableList<Particle> coordinates) {
double Energy = 0;
for (int i = 0; i < numberOfParticle; i++) {
for (int j = 0; j < numberOfParticle; j++) {
if (i != j) {
Energy += 1/pow(coordinates.get(i).distance(coordinates.get(j)),degree);
}
}
Energy += degree / pow(coordinates.get(i).getZ() - heightTube / 2, degree) + degree / pow(coordinates.get(i).getZ() + heightTube / 2, degree);
}
return Energy;
}
private double energyOfSystem (ObservableList<Particle> coordinates, Particle particle, int i) {
coordinates.set(i,particle);
return energyOfSystem(coordinates);
}
}
类绘图粒子
public class Mapping {
private final ObservableList<Particle> list;
private final int numberOfParticle;
private final Group group;
private final Tube tube;
public Mapping(int numberOfParticle, Group group, Tube tube, ObservableList<Particle> list) {
this.numberOfParticle = numberOfParticle;
this.group = group;
this.list = list;
this.tube = tube;
}
public void MappingParticle() {
group.getChildren().clear();
group.getChildren().add(tube.getTube());
for (int i = 0; i < numberOfParticle; i++) {
group.getChildren().add(list.get(i).getParticle());
}
}
}
最后是界面
public class NanoTube extends Application {
private double anchorX, anchorY;
@SuppressWarnings("FieldCanBeLocal")
private final int WIDTH = 800;
@SuppressWarnings("FieldCanBeLocal")
private final int HEIGHT = 670;
private final int RADIUS = 100;
private final Rotate rotateX = new Rotate(0, Rotate.X_AXIS);
private final Rotate rotateY = new Rotate(0, Rotate.Y_AXIS);
@Override
public void start(Stage stage) {
var buttonEnter = new Button("Enter");
var buttonEnergyMinimization = new Button("Minimization");
var buttonEnergyMinimizationStress = new Button("Minimization Stress");
var labelRadius = new Label("Cylinder's radius");
var labelHeight = new Label("Cylinder's height");
var labelNumber = new Label("Number Particle");
var textFieldRadius = new TextField();
var textFieldHeight = new TextField();
var textNumber = new TextField();
GridPane Top = new GridPane();
for (int i : new int[]{120, 100, 70, 90, 60, 140, 150, 65}) {
Top.getColumnConstraints().add(new ColumnConstraints(i));
}
for (int i = 0; i < 3; i++) {
Top.getRowConstraints().add(new RowConstraints(30));
}
Top.getRowConstraints().add(new RowConstraints(560));
Arrays.asList(labelRadius, labelHeight, labelNumber).forEach(label -> {
GridPane.setHalignment(label, HPos.CENTER);
GridPane.setValignment(label, VPos.CENTER);
});
Arrays.asList(buttonEnter, buttonEnergyMinimization).forEach(button -> {
GridPane.setHalignment(button, HPos.CENTER);
GridPane.setValignment(button, VPos.CENTER);
});
Top.add(labelRadius, 0, 0);
Top.add(labelHeight, 0, 1);
Top.add(labelNumber, 0, 2);
Top.add(textFieldRadius, 1, 0);
Top.add(textFieldHeight, 1, 1);
Top.add(textNumber, 1, 2);
Top.add(buttonEnter,2,0,1,3);
Top.add(buttonEnergyMinimization,3,0,1,3);
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setFieldOfView(20);
camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -500));
Tube tube = new Tube(80,80,Color.rgb(225,225,0));
Group group = new Group(tube.getTube());
SubScene subScene = new SubScene(group, 750, 550, true, SceneAntialiasing.BALANCED);
subScene.setFill (Color.rgb (129, 129, 129));
subScene.setCamera(camera);
var root3d = new Group(subScene);
initMouseControl(subScene);
Top.add(root3d,0,3,8,1);
GridPane.setHalignment(root3d, HPos.CENTER);
GridPane.setValignment(root3d, VPos.CENTER);
buttonEnter.setOnAction(e -> {
int n = Integer.parseInt(textNumber.getText());
tube.setHeight(Double.parseDouble(textFieldHeight.getText()));
tube.setRadius(Double.parseDouble(textFieldRadius.getText()));
ObservableList<Particle> particles = new Generation(tube, n).ParticlesGeneration();
new Mapping(n,group,tube,particles).MappingParticle();
buttonEnergyMinimization.setOnAction(actionEvent -> {
ObservableList<Particle> list = new Minimization(particles,2,tube).minimization();
new Mapping(n,group,tube,list).MappingParticle();
});
});
var scene = new Scene(Top, WIDTH,HEIGHT);
stage.setScene(scene);
stage.show();
stage.setTitle("NanoTube Student Project");
}
public static void main(String[] args) {launch();}
private void initMouseControl(SubScene scene) {
scene.setOnMousePressed(event -> {
anchorX = event.getSceneX();
anchorY = event.getSceneY();
});
scene.setOnMouseDragged(event -> {
double dx = (anchorX - event.getSceneX());
double dy = (anchorY - event.getSceneY());
if (event.isPrimaryButtonDown()) {
rotateX.setAngle(rotateX.getAngle() -
(dy /RADIUS * 360) * (Math.PI / 180));
rotateY.setAngle(rotateY.getAngle() -
(dx /RADIUS * -360) * (Math.PI / 180));
}
anchorX = event.getSceneX();
anchorY = event.getSceneY();
});
}
}
如果单击“Enter”按钮,则会绘制粒子,但如果单击“最小化”按钮,图像不会改变。我不明白为什么会这样。
有人建议我尽可能简短地写一个非工作区域的示例。但是这些例子可以工作,但我的程序却不能。我不明白为什么第二个按钮在使用“最小化”类时会忽略绘制粒子。最后,单独来看一切都工作正常。 我使用 javafx 但不使用 fxml。如果您有时间帮助我,我将不胜感激。
代码中的任何内容都不会更新 UI。
您的
Tube
类包含对 UI 对象的引用(Cylinder
)。当您创建 Tube
实例时,您可以根据 Cylinder
的 height
和 radius
设置 Tube
的高度和半径。
但是,如果您稍后通过
Tube
或 setHeight(...)
方法更改 setRadius(...)
的高度或半径,则不会更新 Cylinder
的属性。所以用户界面永远不会改变。
您需要:
public class Tube {
private final Cylinder tube;
// ...
public void setRadius(double radius) {
this.radius = radius;
tube.setRadius(radius);
}
public void setHeight(double height) {
this.height = height;
tube.setHeight(height);
}
}
与
Particle
类类似,如果Particle
的属性发生更改,则需要更新UI对象(Sphere
)的属性:
public class Particle {
private final Sphere particle;
// ...
public void setPhi(double phi) {
this.phi = phi;
particle.setTranslateX(rho * Math.cos(phi));
particle.setTranslateZ(rho * Math.sin(phi));
}
public void setRho(double rho) {
this.rho = rho;
particle.setTranslateX(rho * Math.cos(phi));
particle.setTranslateZ(rho * Math.sin(phi));
}
public void setZ(double z) {
this.z = z;
particle.setTranslateY(z);
}
}
(两个类中都省略了未更改的代码。)
更“JavaFX”的方法是将数据类与数据视图分开,并使用 JavaFX 属性来保持所有内容同步。为了让您对此有一个简单的了解,
Tube
的实现看起来像这样:
public class Tube {
private final DoubleProperty height = new SimpleDoubleProperty();
public DoubleProperty heightProperty() {
return height ;
}
public final double getHeight() {
return heightProperty().get();
}
public final void setHeight(double height) {
heightProperty().set(height);
}
private final DoubleProperty radius = new SimpleDoubleProperty();
public DoubleProperty radiusProperty() {
return radius;
}
public final double getRadius() {
return radiusProperty().get();
}
public final void setRadius(double radius) {
radiusProperty().set(radius);
}
public Tube(double radius, double height) {
setRadius(radius);
setHeight(height);
}
}
public class TubeView {
private final Tube tube ;
private final Cylinder view ;
private Color color;
public TubeView(Tube tube, Color color) {
this.tube = tube;
this.view = new Cylinder();
this.color = color;
view.setMaterial(new PhongMaterial(color));
view.heightProperty().bind(tube.heightProperty());
view.radiusProperty().bind(tube.radiusProperty());
}
public Node asNode() {
return view;
}
}