我想为 JavaFX/Java 中的 3D 打印切片创建填充图案
I want to create a fill pattern for a slice for 3D printing in JavaFX/Java
我从 STL 文件创建 SVG 切片。 SVG 文件由许多行组成。简短的版本是我不能使用 JavaFX 的内置功能来创建 SVG 的填充图案。原因与未正确创建 SVG 有关,因为代码执行移动然后行然后移动然后行。要使用填充功能,我认为您需要先移动一次,然后再移动多行。太久以前记不起确切的问题了。
所以这就是我现在正在做的来解决这个问题
我将填充图案、蜂窝填充图案存储在一个文件中。这当然可以存储在内存中,但它是为了测试。然后我将空心切片存储在第二个文件中。我需要将两者结合起来,以便仅显示 layer/slice 内的蜂窝部分,其余部分被删除。蜂窝应该是白色的,切片也应该是白色的。计划是在我将蜂窝复制到切片时将其设为白色。
我试了两种方法
我尝试的第一种方法是将像素从填充图案复制到 layer/slice。我试图找到图层的线条位置,然后尝试找出内部和外部的位置。我失败了。代码会附在这个问题的底部。
我尝试的第二种方法是使用混合模式,但是 none 的模式似乎可以满足我的需要。
第一种方法代码
我试着用不同的颜色保存蜂巢和图层,我试着把它们保存在彼此之上,然后移除蜂巢。在这里你可以看到我试图弄清楚里面是什么,外面是什么,但我无法让它工作
package javaapplication3;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javax.imageio.ImageIO;
public class JavaApplication3 {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
File file = new File("C:\Temp\Mandibular\MandibularsolidNOreferencepoints.gizmofill0.gizmoslice.png");
BufferedImage bufImage = ImageIO.read(file);
WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
PixelReader pixelReader = writableImage.getPixelReader();
int width = (int) writableImage.getWidth();
int height = (int) writableImage.getHeight();
WritableImage dest = new WritableImage(width, height);
PixelWriter writer = dest.getPixelWriter();
boolean isOnLine = false;
boolean previousIsOnLine = false;
boolean isInside = false;
for (int x = 0; x < width; x++) {
for (int y = 00; y < height; y++) {
// reading a pixel from src image,
// then writing a pixel to dest image
Color color = pixelReader.getColor(x, y);
double red = color.getRed();
double green = color.getGreen();
double blue = color.getBlue();
if (red == 0 && green == 1 && blue == 0) {
//isInside = !isInside;
isOnLine = true;
} else {
previousIsOnLine = isOnLine;
isOnLine = false;
}
if (previousIsOnLine) {
isInside = !isInside;
}
/*if (isOnLine && red == 1 && green == 0 && blue == 0) {
isInside = true;
isOnLine = false;
}*/
if (isOnLine || isInside) {
writer.setColor(x, y, color);
}
/*if (isOnLine || isInside && (red > 0 && green == 0 && blue == 0)) {
writer.setColor(x, y, Color.WHITE);
}*/
}
}
File outputFile = new File("C:\Temp\Mandibular\test.png");
ImageIO.write(SwingFXUtils.fromFXImage(dest, null), "png", outputFile);
} catch (IOException ex) {
Logger.getLogger(JavaApplication3.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
第二种方法使用混合
我尝试了不同的混合模式并以最后一个结束 layerView.setBlendMode(BlendMode.SRC_ATOP);这显然不能满足我的需要。我刚刚测试了每一个,看看哪些可行
package javafxapplication15;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Button;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class JavaFXApplication15 extends Application {
private void doWork() {
try {
// TODO code application logic here
File file = new File("C:\Temp\Mandibular\MandibularsolidNOreferencepoints.gizmofill0.gizmoslice.png");
BufferedImage layerImage = ImageIO.read(file);
file = new File("C:\Temp\Mandibular\MandibularsolidNOreferencepoints.gizmofill-1.gizmoslice.png");
BufferedImage fillImage = ImageIO.read(file);
WritableImage layerWritableImage = SwingFXUtils.toFXImage(layerImage, null);
WritableImage fillWritableImage = SwingFXUtils.toFXImage(fillImage, null);
WritableImage temp = copyImageOntoFillPattern(fillWritableImage, layerWritableImage);
File outputFile = new File("C:\Temp\Mandibular\test.png");
ImageIO.write(SwingFXUtils.fromFXImage(temp, null), "png", outputFile);
} catch (IOException ex) {
Logger.getLogger(JavaFXApplication15.class.getName()).log(Level.SEVERE, null, ex);
}
}
private WritableImage copyImageOntoFillPattern(final WritableImage fillPatternImage, final WritableImage sourceImage) {
ImageView fillPatternView = new ImageView(fillPatternImage);
ImageView layerView = new ImageView(sourceImage);
layerView.setBlendMode(BlendMode.SRC_ATOP);
Group blend = new Group(fillPatternView, layerView);
blend.snapshot(null, sourceImage);
SnapshotParameters param = new SnapshotParameters();
final WritableImage snapshotCombined = blend.snapshot(param, null);
return snapshotCombined;
}
@Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
doWork();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
我花了大约一个小时来更改 .fxml 文件
这是文件的内容,我需要将它转换成我可以运行的代码,但现在应该不会太难。
需要填充的图层,填充颜色似乎无关紧要。我把它变成了绿色,这样它就可以在网站上看到了,但是当我在我的切片器中创建它时,我可能会把它创建成白色。我还把蜂巢做成了红色,这样更容易看到。我正在展示 SceneBuilder 的工作图像
我现在只需将蜂巢创建为白色,将层创建为纯白色,一切都会很棒
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Group blendMode="HARD_LIGHT">
<children>
<ImageView blendMode="DIFFERENCE" cache="true" fitHeight="418.0" fitWidth="591.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@outline.png" />
</image>
</ImageView>
<ImageView blendMode="SRC_ATOP" fitHeight="451.0" fitWidth="688.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@honeycomb.png" />
</image>
<effect>
<Blend mode="ADD" />
</effect>
</ImageView>
</children>
</Group>
</children>
</AnchorPane>
我从 STL 文件创建 SVG 切片。 SVG 文件由许多行组成。简短的版本是我不能使用 JavaFX 的内置功能来创建 SVG 的填充图案。原因与未正确创建 SVG 有关,因为代码执行移动然后行然后移动然后行。要使用填充功能,我认为您需要先移动一次,然后再移动多行。太久以前记不起确切的问题了。
所以这就是我现在正在做的来解决这个问题 我将填充图案、蜂窝填充图案存储在一个文件中。这当然可以存储在内存中,但它是为了测试。然后我将空心切片存储在第二个文件中。我需要将两者结合起来,以便仅显示 layer/slice 内的蜂窝部分,其余部分被删除。蜂窝应该是白色的,切片也应该是白色的。计划是在我将蜂窝复制到切片时将其设为白色。
我试了两种方法
我尝试的第一种方法是将像素从填充图案复制到 layer/slice。我试图找到图层的线条位置,然后尝试找出内部和外部的位置。我失败了。代码会附在这个问题的底部。
我尝试的第二种方法是使用混合模式,但是 none 的模式似乎可以满足我的需要。
第一种方法代码 我试着用不同的颜色保存蜂巢和图层,我试着把它们保存在彼此之上,然后移除蜂巢。在这里你可以看到我试图弄清楚里面是什么,外面是什么,但我无法让它工作
package javaapplication3;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javax.imageio.ImageIO;
public class JavaApplication3 {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
File file = new File("C:\Temp\Mandibular\MandibularsolidNOreferencepoints.gizmofill0.gizmoslice.png");
BufferedImage bufImage = ImageIO.read(file);
WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
PixelReader pixelReader = writableImage.getPixelReader();
int width = (int) writableImage.getWidth();
int height = (int) writableImage.getHeight();
WritableImage dest = new WritableImage(width, height);
PixelWriter writer = dest.getPixelWriter();
boolean isOnLine = false;
boolean previousIsOnLine = false;
boolean isInside = false;
for (int x = 0; x < width; x++) {
for (int y = 00; y < height; y++) {
// reading a pixel from src image,
// then writing a pixel to dest image
Color color = pixelReader.getColor(x, y);
double red = color.getRed();
double green = color.getGreen();
double blue = color.getBlue();
if (red == 0 && green == 1 && blue == 0) {
//isInside = !isInside;
isOnLine = true;
} else {
previousIsOnLine = isOnLine;
isOnLine = false;
}
if (previousIsOnLine) {
isInside = !isInside;
}
/*if (isOnLine && red == 1 && green == 0 && blue == 0) {
isInside = true;
isOnLine = false;
}*/
if (isOnLine || isInside) {
writer.setColor(x, y, color);
}
/*if (isOnLine || isInside && (red > 0 && green == 0 && blue == 0)) {
writer.setColor(x, y, Color.WHITE);
}*/
}
}
File outputFile = new File("C:\Temp\Mandibular\test.png");
ImageIO.write(SwingFXUtils.fromFXImage(dest, null), "png", outputFile);
} catch (IOException ex) {
Logger.getLogger(JavaApplication3.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
第二种方法使用混合 我尝试了不同的混合模式并以最后一个结束 layerView.setBlendMode(BlendMode.SRC_ATOP);这显然不能满足我的需要。我刚刚测试了每一个,看看哪些可行
package javafxapplication15;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Button;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class JavaFXApplication15 extends Application {
private void doWork() {
try {
// TODO code application logic here
File file = new File("C:\Temp\Mandibular\MandibularsolidNOreferencepoints.gizmofill0.gizmoslice.png");
BufferedImage layerImage = ImageIO.read(file);
file = new File("C:\Temp\Mandibular\MandibularsolidNOreferencepoints.gizmofill-1.gizmoslice.png");
BufferedImage fillImage = ImageIO.read(file);
WritableImage layerWritableImage = SwingFXUtils.toFXImage(layerImage, null);
WritableImage fillWritableImage = SwingFXUtils.toFXImage(fillImage, null);
WritableImage temp = copyImageOntoFillPattern(fillWritableImage, layerWritableImage);
File outputFile = new File("C:\Temp\Mandibular\test.png");
ImageIO.write(SwingFXUtils.fromFXImage(temp, null), "png", outputFile);
} catch (IOException ex) {
Logger.getLogger(JavaFXApplication15.class.getName()).log(Level.SEVERE, null, ex);
}
}
private WritableImage copyImageOntoFillPattern(final WritableImage fillPatternImage, final WritableImage sourceImage) {
ImageView fillPatternView = new ImageView(fillPatternImage);
ImageView layerView = new ImageView(sourceImage);
layerView.setBlendMode(BlendMode.SRC_ATOP);
Group blend = new Group(fillPatternView, layerView);
blend.snapshot(null, sourceImage);
SnapshotParameters param = new SnapshotParameters();
final WritableImage snapshotCombined = blend.snapshot(param, null);
return snapshotCombined;
}
@Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
doWork();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
我花了大约一个小时来更改 .fxml 文件
这是文件的内容,我需要将它转换成我可以运行的代码,但现在应该不会太难。
需要填充的图层,填充颜色似乎无关紧要。我把它变成了绿色,这样它就可以在网站上看到了,但是当我在我的切片器中创建它时,我可能会把它创建成白色。我还把蜂巢做成了红色,这样更容易看到。我正在展示 SceneBuilder 的工作图像
我现在只需将蜂巢创建为白色,将层创建为纯白色,一切都会很棒
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Group blendMode="HARD_LIGHT">
<children>
<ImageView blendMode="DIFFERENCE" cache="true" fitHeight="418.0" fitWidth="591.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@outline.png" />
</image>
</ImageView>
<ImageView blendMode="SRC_ATOP" fitHeight="451.0" fitWidth="688.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@honeycomb.png" />
</image>
<effect>
<Blend mode="ADD" />
</effect>
</ImageView>
</children>
</Group>
</children>
</AnchorPane>