下面列出了javafx.scene.input.PickResult#javafx.geometry.Point3D 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static String getRightRotation(Point3D p, String selFaces){
double radius = p.magnitude();
double angle = Math.atan2(p.getY(), p.getX());
String face="";
if (radius >= RAD_MINIMUM && selFaces.contains("-") && selFaces.split("-").length == 2) {
String[] faces = selFaces.split("-");
// select rotation if p.getX>p.getY
if (-Math.PI / 4d <= angle && angle < Math.PI / 4d ){ // X
face = faces[0];
} else if (Math.PI / 4d <= angle && angle < 3d * Math.PI / 4d) { // Y
face = faces[1];
} else if ((3d * Math.PI / 4d <= angle && angle <= Math.PI) ||
(-Math.PI <= angle && angle < -3d * Math.PI / 4d)) { // -X
face = reverseRotation(faces[0]);
} else { //-Y
face = reverseRotation(faces[1]);
}
// System.out.println("face: "+face);
} else if (!face.isEmpty() && radius < RAD_MINIMUM) { // reset previous face
face = "";
}
return face;
}
/**
* Constructs new DockEvent event..
*
* @param source the source of the event. Can be null.
* @param target the target of the event. Can be null.
* @param eventType The type of the event.
* @param x The x with respect to the source. Should be in scene coordinates if source == null or
* source is not a Node.
* @param y The y with respect to the source. Should be in scene coordinates if source == null or
* source is not a Node.
* @param screenX The x coordinate relative to screen.
* @param screenY The y coordinate relative to screen.
* @param pickResult pick result. Can be null, in this case a 2D pick result without any further
* values is constructed based on the scene coordinates
* @param contents The contents being dragged during this event.
*/
public DockEvent(Object source, EventTarget target, EventType<? extends DockEvent> eventType,
double x, double y, double screenX, double screenY, PickResult pickResult, Node contents) {
super(source, target, eventType);
this.x = x;
this.y = y;
this.screenX = screenX;
this.screenY = screenY;
this.sceneX = x;
this.sceneY = y;
this.pickResult = pickResult != null ? pickResult : new PickResult(target, x, y);
final Point3D p = InputEventUtils.recomputeCoordinates(this.pickResult, null);
this.x = p.getX();
this.y = p.getY();
this.z = p.getZ();
this.contents = contents;
}
public static void matrixRotateNode(Node n, double alf, double bet, double gam){
alf = alf*Math.PI/180.0;
bet = bet*Math.PI/180.0;
gam = gam*Math.PI/180.0;
double A11=Math.cos(alf)*Math.cos(gam);
double A12=Math.cos(bet)*Math.sin(alf)+Math.cos(alf)*Math.sin(bet)*Math.sin(gam);
double A13=Math.sin(alf)*Math.sin(bet)-Math.cos(alf)*Math.cos(bet)*Math.sin(gam);
double A21=-Math.cos(gam)*Math.sin(alf);
double A22=Math.cos(alf)*Math.cos(bet)-Math.sin(alf)*Math.sin(bet)*Math.sin(gam);
double A23=Math.cos(alf)*Math.sin(bet)+Math.cos(bet)*Math.sin(alf)*Math.sin(gam);
double A31=Math.sin(gam);
double A32=-Math.cos(gam)*Math.sin(bet);
double A33=Math.cos(bet)*Math.cos(gam);
double d = Math.acos((A11+A22+A33-1d)/2d);
if(d!=0d){
double den=2d*Math.sin(d);
Point3D p= new Point3D((A32-A23)/den,(A13-A31)/den,(A21-A12)/den);
n.setRotationAxis(p);
n.setRotate(Math.toDegrees(d));
}
}
public static String getRightRotation(Point3D p, String selFaces){
double radius=p.magnitude();
double angle=Math.atan2(p.getY(),p.getX());
String face="";
if(radius>=radMinimum && selFaces.contains("-") && selFaces.split("-").length==2){
String[] faces=selFaces.split("-");
// select rotation if p.getX>p.getY
if(-Math.PI/4d<=angle && angle<Math.PI/4d){ // X
face=faces[0];
} else if(Math.PI/4d<=angle && angle<3d*Math.PI/4d){ // Y
face=faces[1];
} else if((3d*Math.PI/4d<=angle && angle<=Math.PI) ||
(-Math.PI<=angle && angle<-3d*Math.PI/4d)){ // -X
face=reverseRotation(faces[0]);
} else { //-Y
face=reverseRotation(faces[1]);
}
System.out.println("face: "+face);
} else if(!face.isEmpty() && radius<radMinimum){ // reset previous face
face="";
}
return face;
}
private void configureMovePointBinding() {
nodeBinder()
.usingInteraction(DnD::new)
.toProduce(i -> new MovePointShape((ModifiablePointsShape) canvas.getDrawing().getSelection().getShapeAt(0).orElseThrow(),
i.getSrcObject().filter(o -> o instanceof MovePtHandler).map(o -> ((MovePtHandler) o).getPoint()).orElseThrow()))
.on(mvPtHandlers)
.then((i, c) -> {
i.getSrcObject().ifPresent(node -> {
final Point3D startPt = node.localToParent(i.getSrcLocalPoint());
final Point3D endPt = node.localToParent(i.getTgtLocalPoint());
final Point ptToMove = ((MovePtHandler) node).getPoint();
final double x = ptToMove.getX() + endPt.getX() - startPt.getX();
final double y = ptToMove.getY() + endPt.getY() - startPt.getY();
c.setNewCoord(grid.getTransformedPointToGrid(new Point3D(x, y, 0d)));
});
canvas.update();
})
.continuousExecution()
.when(i -> i.getSrcLocalPoint() != null && i.getTgtLocalPoint() != null && i.getSrcObject().orElse(null) instanceof MovePtHandler &&
canvas.getDrawing().getSelection().size() == 1 && canvas.getDrawing().getSelection().getShapeAt(0).filter(s -> s instanceof ModifiablePointsShape).isPresent())
.end(() -> coordDimCustomiser.update())
.bind();
}
@Override
protected void configureBindings() {
buttonBinder()
.toProduce(() -> new UpdateTemplates(templatePane, svgGen, true))
.on(updateTemplates)
.bind();
nodeBinder()
.usingInteraction(DnD::new)
.toProduce(i -> new LoadTemplate(svgGen, drawing, new File((String) i.getSrcObject().orElseThrow().getUserData()),
statusController.getProgressBar(), statusController.getLabel(), app))
.on(templatePane)
.first(c -> templatePane.setCursor(Cursor.CLOSED_HAND))
.then((i, c) -> {
final Node srcObj = i.getSrcObject().orElseThrow();
final Point3D pt3d = i.getTgtObject().orElseThrow().sceneToLocal(srcObj.localToScene(i.getTgtLocalPoint())).
subtract(Canvas.ORIGIN.getX() + srcObj.getLayoutX(), Canvas.ORIGIN.getY() + srcObj.getLayoutY(), 0d);
c.setPosition(ShapeFactory.INST.createPoint(pt3d));
})
.when(i -> i.getSrcObject().orElse(null) instanceof ImageView &&
i.getSrcObject().get().getUserData() instanceof String &&
i.getTgtObject().orElse(null) instanceof Canvas)
.endOrCancel(i -> templatePane.setCursor(Cursor.MOVE))
.bind();
}
@Override
protected Stream<Runnable> canDoFixtures() {
return Stream.of(() -> {
shape = ShapeFactory.INST.createGroup();
s0 = ShapeFactory.INST.createRectangle(ShapeFactory.INST.createPoint(1, 2), 3, 4);
s1 = ShapeFactory.INST.createRectangle(ShapeFactory.INST.createPoint(10, 20), 30, 40);
shape.addShape(s0);
shape.addShape(s1);
grid = Mockito.mock(MagneticGrid.class);
Mockito.when(grid.getTransformedPointToGrid(new Point3D(1, 2, 0))).thenReturn(ShapeFactory.INST.createPoint(5, 6));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(4, 2, 0))).thenReturn(ShapeFactory.INST.createPoint(7, 8));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(4, 6, 0))).thenReturn(ShapeFactory.INST.createPoint(9, 10));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(1, 6, 0))).thenReturn(ShapeFactory.INST.createPoint(11, 12));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(10, 20, 0))).thenReturn(ShapeFactory.INST.createPoint(50, 60));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(40, 20, 0))).thenReturn(ShapeFactory.INST.createPoint(70, 80));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(40, 60, 0))).thenReturn(ShapeFactory.INST.createPoint(90, 100));
Mockito.when(grid.getTransformedPointToGrid(new Point3D(10, 60, 0))).thenReturn(ShapeFactory.INST.createPoint(110, 120));
cmd = new UpdateToGrid(grid, shape);
});
}
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
RotateTransition transition = new RotateTransition(Duration.seconds(5), arc1);
transition.setAxis(new Point3D(50, 50, 0));
transition.setByAngle(200);
transition.play();
}
@Override
public ObjectProperty<Point3D> rotationAxisProperty() {
if (rotationAxis == null) {
rotationAxis = new SimpleObjectProperty<>(this, "rotationAxis", Rotate.Z_AXIS);
rotationAxis.addListener((v, o, n) -> forwardShapeProperty(s -> s.setRotationAxis(n)));
}
return rotationAxis;
}
private static Point3D getMeshNormal(MeshView mesh){
TriangleMesh tm = (TriangleMesh) mesh.getMesh();
float[] fPoints = new float[tm.getPoints().size()];
tm.getPoints().toArray(fPoints);
Point3D BA = new Point3D(fPoints[3] - fPoints[0], fPoints[4] - fPoints[1], fPoints[5] - fPoints[2]);
Point3D CA = new Point3D(fPoints[6] - fPoints[0], fPoints[7] - fPoints[1], fPoints[8] - fPoints[2]);
Point3D normal = BA.crossProduct(CA);
Affine a = new Affine(mesh.getTransforms().get(0));
return a.transform(normal.normalize());
}
private void placeCube(Point3D point) {
Random random = new Random();
Cube cube = new Cube(1, Color.rgb(random.nextInt(150) + 100, random.nextInt(150) + 100, random.nextInt(250)));
cube.setTranslateX(point.getX());
cube.setTranslateY(point.getY());
cube.setTranslateZ(point.getZ());
worldRoot.getChildren().add(cube);
}
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createContent());
placeCube(new Point3D(10, 0, 0));
placeCube(new Point3D(-10, 0, 0));
placeCube(new Point3D(0, 0, -20));
scene.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.W) {
translate.setZ(translate.getZ() + 1);
} else if (event.getCode() == KeyCode.S) {
translate.setZ(translate.getZ() - 1);
} else if (event.getCode() == KeyCode.A) {
//rotate.setAngle(rotate.getAngle() - 5);
translate.setX(translate.getX() - 1);
} else if (event.getCode() == KeyCode.D) {
//rotate.setAngle(rotate.getAngle() + 5);
translate.setX(translate.getX() + 1);
}
if (event.getCode() == KeyCode.UP) {
} else if (event.getCode() == KeyCode.DOWN) {
} else if (event.getCode() == KeyCode.LEFT) {
rotate.setAngle(rotate.getAngle() - 5);
} else if (event.getCode() == KeyCode.RIGHT) {
rotate.setAngle(rotate.getAngle() + 5);
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
@Override
public void run() {
try {
if (!webCam.isOpen())
webCam.open();
isRunning = true;
Result result;
BufferedImage bufferedImage;
while (isRunning) {
bufferedImage = webCam.getImage();
if (bufferedImage != null) {
WritableImage writableImage = SwingFXUtils.toFXImage(bufferedImage, null);
imageView.setImage(writableImage);
imageView.setRotationAxis(new Point3D(0.0, 1.0, 0.0));
imageView.setRotate(180.0);
LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
result = new MultiFormatReader().decode(bitmap);
isRunning = false;
String qrCode = result.getText();
UserThread.execute(() -> resultHandler.accept(qrCode));
} catch (NotFoundException ignore) {
// No qr code in image...
}
}
}
} catch (Throwable t) {
log.error(t.toString());
} finally {
webCam.close();
}
}
/**
* Projects the Ray from new <code>origin</code> along <code>direction</code> by <code>distance</code>
* @param orig the new origin point
* @param dir the new direction of travel
* @param dist distance to project ray
* @return sets origin and returns projected position
*/
public Point3D setProject(Point3D orig, Point3D dir, double dist){
setOrigin(orig);
setDirection(dir);
setPosition(getOrigin().add((getDirection().normalize().multiply(dist))));
return getPosition();
}
public Vec3d localToScene(Vec3d pt, Vec3d result) {
Point3D res = camera.localToParentTransformProperty().get().transform(pt.x, pt.y, pt.z);
if (camera.getParent() != null) {
res = camera.getParent().localToSceneTransformProperty().get().transform(res);
}
result.set(res.getX(), res.getY(), res.getZ());
return result;
}
private static Point3D getMeshNormal(MeshView mesh){
TriangleMesh tm=(TriangleMesh)mesh.getMesh();
float[] fPoints=new float[tm.getPoints().size()];
tm.getPoints().toArray(fPoints);
Point3D BA=new Point3D(fPoints[3]-fPoints[0],fPoints[4]-fPoints[1],fPoints[5]-fPoints[2]);
Point3D CA=new Point3D(fPoints[6]-fPoints[0],fPoints[7]-fPoints[1],fPoints[8]-fPoints[2]);
Point3D normal=BA.crossProduct(CA);
Affine a=new Affine(mesh.getTransforms().get(0));
return a.transform(normal.normalize());
}
/**
* Companion function to the bindMultiClic2AddShape binding.
* It initialises the first two points of the given shape.
*/
private Shape setInitialPtsShape(final Shape sh, final Point3D firstPt) {
if(sh instanceof ModifiablePointsShape) {
final ModifiablePointsShape modShape = (ModifiablePointsShape) sh;
final Point pt = getAdaptedPoint(firstPt);
modShape.setPoint(pt.getX(), pt.getY(), 0);
modShape.setPoint(pt.getX() + 1d, pt.getY() + 1d, 1);
}
return sh;
}
/**
* Transform a point to another that sticks the magnetic grid.
* @param pt The point to transform.
* @return The transformed point or a clone of the given point if there is no magnetic grid.
*/
public @NotNull Point getTransformedPointToGrid(final @NotNull Point3D pt) {
if(!prefs.isMagneticGrid() || prefs.gridStyleProperty().get() == GridStyle.NONE) {
return ShapeFactory.INST.createPoint(pt.getX(), pt.getY());
}
final double modulo = getMagneticGridGap();
return ShapeFactory.INST.createPoint(MathUtils.INST.getClosestModuloValue(pt.getX(), modulo), MathUtils.INST.getClosestModuloValue(pt.getY(), modulo));
}
@ParameterizedTest
@CsvSource(value = {"9, 8, 0, 0",
"11, 8, 20, 0",
"4, 11, 0, 20",
"30, 55, 40, 60",
"-29, -55, -20, -60"})
void testGetTransformedPointToGridCustomGrid(final double x1, final double y1, final double x2, final double y2) {
prefs.gridStyleProperty().setValue(GridStyle.CUSTOMISED);
prefs.gridGapProperty().setValue(20);
prefs.magneticGridProperty().set(true);
assertThat(grid.getTransformedPointToGrid(new Point3D(x1, y1, 11))).isEqualTo(ShapeFactory.INST.createPoint(x2, y2));
}
@ParameterizedTest
@CsvSource(value = {"2, 1, 0, 0",
"3, 2, 5, 0",
"1, 3, 0, 5",
"3, 8, 5, 10",
"-6, -8, -5, -10"})
void testGetTransformedPointToGridStdGridCM(final double x1, final double y1, final double x2, final double y2) {
prefs.gridStyleProperty().setValue(GridStyle.STANDARD);
prefs.unitProperty().setValue(Unit.CM);
prefs.magneticGridProperty().set(true);
assertThat(grid.getTransformedPointToGrid(new Point3D(x1, y1, 11))).isEqualTo(ShapeFactory.INST.createPoint(x2, y2));
}
@ParameterizedTest
@CsvSource(value = {"2, 1, 0, 0",
"7, 2, 13, 0",
"6, 6.6, 0, 13",
"13, 20, 13, 26",
"-8, -20, -13, -26"})
void testGetTransformedPointToGridStdGridINCH(final double x1, final double y1, final double x2, final double y2) {
prefs.gridStyleProperty().setValue(GridStyle.STANDARD);
prefs.unitProperty().setValue(Unit.INCH);
prefs.magneticGridProperty().set(true);
assertThat(grid.getTransformedPointToGrid(new Point3D(x1, y1, 11))).isEqualTo(ShapeFactory.INST.createPoint(x2, y2));
}
@Test
public void testToPoint3D() {
pt.setPoint(10d, 11d);
final Point3D p = pt.toPoint3D();
assertThat(p.getX()).isEqualTo(10d, within(0.00001d));
assertThat(p.getY()).isEqualTo(11d, within(0.00001d));
assertThat(p.getZ()).isZero();
}
public Point3D getPoint3D(Node v) {
return node2point3D.get(v);
}
default Point3D getRotationAxis() {
return rotationAxisProperty().get();
}
default void setRotationAxis(Point3D rotationAxis) {
rotationAxisProperty().set(rotationAxis);
}
public static String getPickedRotation(int cubie, MeshView mesh){
Point3D normal = getMeshNormal(mesh);
String rots = ""; // Rx-Ry
switch(cubie){
case 0: rots = (normal.getZ() > 0.99) ? "Ui-Li" : ((normal.getX() < -0.99) ? "Ui-F" : ((normal.getY() > 0.99) ? "Ui-Li" : ""));
break;
case 1: rots = (normal.getZ() > 0.99) ? "F-Mi" : ((normal.getY() > 0.99) ? "Ui-Mi" : ""); // between L and R, as L
break;
case 2: rots = (normal.getZ() > 0.99) ? "Ui-R" : ((normal.getX() > 0.99) ? "Ui-Fi" : ((normal.getY() > 0.99) ? "Ui-R" : ""));
break;
case 3: rots = (normal.getZ() > 0.99) ? "E-F" : ((normal.getX() < -0.99) ? "E-Li" : ""); // between U and D, as D
break;
case 4: rots = (normal.getZ() > 0.99) ? "Yi-X" : "";
break;
case 5: rots = (normal.getZ() > 0.99) ? "E-Fi" : ((normal.getX() > 0.99) ? "E-R" : ""); // between U and D, as D
break;
case 6: rots = (normal.getZ() > 0.99) ? "D-Li" : ((normal.getX() < -0.99) ? "D-F" : ((normal.getY() < -0.99) ? "D-Li" : ""));
break;
case 7: rots = (normal.getZ() > 0.99) ? "Fi-Mi" : ((normal.getY() < -0.99) ? "Fi-Mi" : ""); // between L and R, as L
break;
case 8: rots = (normal.getZ() > 0.99) ? "D-R" : ((normal.getX() > 0.99) ? "D-Fi" : ((normal.getY() < -0.99) ? "D-R" : ""));
break;
case 9: rots = (normal.getY() > 0.99) ? "S-U" : ((normal.getX() < -0.99) ? "L-S" : ""); // between U and D, as D
break;
case 10: rots = (normal.getY() > 0.99) ? "Z-X" : "";
break;
case 11: rots = (normal.getY() > 0.99) ? "S-Ui" : ((normal.getX() > 0.99) ? "R-Si" : ""); // between U and D, as D
break;
case 12: rots = (normal.getX() < -0.99) ? "Yi-Z" : "";
break;
case 14: rots = (normal.getX() > 0.99) ? "Yi-Zi" : "";
break;
case 15: rots = (normal.getY() < -0.99) ? "D-S" : ((normal.getX() < -0.99) ? "Li-S" : ""); // between U and D, as D
break;
case 16: rots = (normal.getY() < -0.99) ? "Zi-X" : "";
break;
case 17: rots = (normal.getY() < -0.99) ? "D-S" : ((normal.getX() > 0.99) ? "Ri-Si" : ""); // between U and D, as D
break;
case 18: rots = (normal.getZ() < -0.99) ? "Ui-L" : ((normal.getX() < -0.99) ? "Ui-Bi" : ((normal.getY() > 0.99) ? "Ui-L" : ""));
break;
case 19: rots = (normal.getZ() < -0.99) ? "B-M" : ((normal.getY() > 0.99) ? "U-M" : ""); // between L and R, as L
break;
case 20: rots = (normal.getZ() < -0.99) ? "Ui-Ri" : ((normal.getX() > 0.99) ? "Ui-B" : ((normal.getY() > 0.99) ? "Ui-Ri" : ""));
break;
case 21: rots = (normal.getZ() < -0.99) ? "E-Bi" : ((normal.getX() < -0.99) ? "E-L" : ""); // between U and D, as D
break;
case 22: rots = (normal.getZ() < -0.99) ? "Yi-Xi" : "";
break;
case 23: rots = (normal.getZ() < -0.99) ? "E-B" : ((normal.getX() > 0.99) ? "E-Ri" : ""); // between U and D, as D
break;
case 24: rots = (normal.getZ() < -0.99) ? "D-L" : ((normal.getX() < -0.99) ? "D-Bi" : ((normal.getY() < -0.99) ? "D-L" : ""));
break;
case 25: rots = (normal.getZ() < -0.99) ? "Bi-M" : ((normal.getY() < -0.99) ? "Bi-M" : ""); // between L and R, as L
break;
case 26: rots = (normal.getZ() < -0.99) ? "D-Ri" : ((normal.getX() > 0.99) ? "D-B" : ((normal.getY() < -0.99) ? "D-B" : ""));
break;
}
return rots;
}
private Parent createContent() {
Cube c = new Cube(1, Color.GREEN);
c.setTranslateX(-1);
c.setRotationAxis(Rotate.Y_AXIS);
c.setRotate(45);
Cube c2 = new Cube(1, Color.BLUE);
c2.setTranslateX(1);
c2.setRotationAxis(Rotate.Y_AXIS);
c2.setRotate(45);
Cube c3 = new Cube(1, Color.RED);
c3.setRotationAxis(Rotate.Y_AXIS);
c3.setRotate(45);
camera = new PerspectiveCamera(true);
translate = new Translate(0, 0, -10);
rotate = new Rotate(0, new Point3D(0, 1, 0));
camera.getTransforms().addAll(translate, rotate);
PointLight light = new PointLight(Color.WHITE);
light.setTranslateX(3);
light.setTranslateZ(-5);
TranslateTransition tt = new TranslateTransition(Duration.seconds(2), light);
tt.setFromX(-3);
tt.setToX(3);
tt.setAutoReverse(true);
tt.setCycleCount(Animation.INDEFINITE);
AmbientLight globalLight = new AmbientLight(Color.WHITE.deriveColor(0, 1, 0.2, 1));
worldRoot.getChildren().addAll(c, c2, c3, globalLight, light);
SubScene subScene = new SubScene(worldRoot, 800, 600, true, SceneAntialiasing.BALANCED);
subScene.setCamera(camera);
tt.play();
return new Group(new Rectangle(800, 600), subScene);
}
public void set(Point3D p) {
setTranslateX(p.getX());
setTranslateY(p.getY());
setTranslateZ(p.getZ());
}
/**
* @param radius radius of the sphere segment
* @param color The sphere segment color.
* @param phimin The starting azimutal angle [rad], 0-2*pi.
* @param phimax The ending azimutal angle [rad], 0-2*pi, phimax >
* phimin.
* @param thetamin The starting polar angle [rad], -pi/2-pi/2.
* @param thetamax The ending polar angle [rad], -pi/2-pi/2, thetamax >
* thetamin.
* @param granularity The number of segments of curves approximations,
* granulariy > 2.
* @param ambient Whether to have an ambient light or not
* @param fill whether to show filled with the color param or as wire mesh
*/
public SphereSegment(double radius, Color color,
double phimin, double phimax, double thetamin, double thetamax,
int granularity, boolean ambient, boolean fill) {
this.radius = radius;
this.color = color;
this.phimin = phimin;
this.phimax = phimax;
this.thetamin = thetamin;
this.thetamax = thetamax;
this.granularity = granularity;
this.ambient = ambient;
this.fill = fill;
setDepthTest(DepthTest.ENABLE);
mesh = new TriangleMesh();
// Fill Points
double phi = phimin;
double theta;
PhongMaterial maxPhong = new PhongMaterial();
maxPhong.setSpecularColor(color);
maxPhong.setDiffuseColor(color);
for (int i = 0; i < granularity + 1; i++) {
theta = thetamin;
for (int j = 0; j < granularity + 1; j++) {
Point3D p3D = new Point3D((float) (radius * Math.cos(theta) * Math.sin(phi)),
(float) (radius * Math.cos(theta) * Math.cos(phi)),
(float) (radius * Math.sin(theta)));
mesh.getPoints().addAll(new Float(p3D.getX()), new Float(p3D.getY()), new Float(p3D.getZ()));
theta += (thetamax - thetamin) / granularity;
}
phi += (phimax - phimin) / granularity;
}
//for now we'll just make an empty texCoordinate group
mesh.getTexCoords().addAll(0, 0);
//Add the faces "winding" the points generally counter clock wise
for (int i = 0; i < granularity; i++) {
int multiplier = (i * granularity) + i;
//Up the Outside
for (int j = multiplier; j < granularity + multiplier; j++) {
mesh.getFaces().addAll(j, 0, j + 1, 0, j + granularity + 1, 0); //lower triangle
mesh.getFaces().addAll(j + granularity + 1, 0, j + 1, 0, j + granularity + 2, 0); //upper triangle
}
//Down the Inside
for (int j = granularity + multiplier; j > multiplier; j--) {
mesh.getFaces().addAll(j, 0, j - 1, 0, j + granularity + 1, 0); //lower triangle
mesh.getFaces().addAll(j - 1, 0, j + granularity, 0, j + granularity + 1, 0); //upper triangle
}
}
//Create a viewable MeshView to be added to the scene
//To add a TriangleMesh to a 3D scene you need a MeshView container object
meshView = new MeshView(mesh);
//The MeshView allows you to control how the TriangleMesh is rendered
if (fill) {
meshView.setDrawMode(DrawMode.FILL);
} else {
meshView.setDrawMode(DrawMode.LINE); //show lines only by default
}
meshView.setCullFace(CullFace.BACK); //Removing culling to show back lines
getChildren().add(meshView);
meshView.setMaterial(maxPhong);
if (ambient) {
AmbientLight light = new AmbientLight(Color.WHITE);
light.getScope().add(meshView);
getChildren().add(light);
}
}
public static void mesh2STL(String fileName, Mesh mesh) throws IOException{
if(!(mesh instanceof TriangleMesh)){
return;
}
// Get faces
ObservableFaceArray faces = ((TriangleMesh)mesh).getFaces();
int[] f=new int[faces.size()];
faces.toArray(f);
// Get vertices
ObservableFloatArray points = ((TriangleMesh)mesh).getPoints();
float[] p = new float[points.size()];
points.toArray(p);
StringBuilder sb = new StringBuilder();
sb.append("solid meshFX\n");
// convert faces to polygons
for(int i=0; i<faces.size()/6; i++){
int i0=f[6*i], i1=f[6*i+2], i2=f[6*i+4];
Point3D pA=new Point3D(p[3*i0], p[3*i0+1], p[3*i0+2]);
Point3D pB=new Point3D(p[3*i1], p[3*i1+1], p[3*i1+2]);
Point3D pC=new Point3D(p[3*i2], p[3*i2+1], p[3*i2+2]);
Point3D pN=pB.subtract(pA).crossProduct(pC.subtract(pA)).normalize();
sb.append(" facet normal ").append(pN.getX()).append(" ").append(pN.getY()).append(" ").append(pN.getZ()).append("\n");
sb.append(" outer loop\n");
sb.append(" vertex ").append(pA.getX()).append(" ").append(pA.getY()).append(" ").append(pA.getZ()).append("\n");
sb.append(" vertex ").append(pB.getX()).append(" ").append(pB.getY()).append(" ").append(pB.getZ()).append("\n");
sb.append(" vertex ").append(pC.getX()).append(" ").append(pC.getY()).append(" ").append(pC.getZ()).append("\n");
sb.append(" endloop\n");
sb.append(" endfacet\n");
}
sb.append("endsolid meshFX\n");
// write file
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(fileName), Charset.forName("UTF-8"),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
writer.write(sb.toString());
}
}