Datei:Animation stirling engine.ogv
Originaldatei (Ogg-Theora-Videodatei, Länge: 40 s, 1.000×1.000 Pixel, 996 kbps insgesamt)
Diese Datei stammt aus Wikimedia Commons und kann von anderen Projekten verwendet werden. Die Beschreibung von deren Dateibeschreibungsseite wird unten angezeigt.
Inhaltsverzeichnis
Beschreibung
BeschreibungAnimation stirling engine.ogv |
English: Animation of a stirling engine in alpha configuration running as a motor.A regenerator is included. |
Datum | |
Quelle | Eigenes Werk |
Urheber | Menner |
Lizenz
Diese Datei wird unter der Creative-Commons-Lizenz „CC0 1.0 Verzicht auf das Copyright“ zur Verfügung gestellt. | |
Die Person, die das Werk mit diesem Dokument verbunden hat, übergibt dieses weltweit der Gemeinfreiheit, indem sie alle Urheberrechte und damit verbundenen weiteren Rechte – im Rahmen der jeweils geltenden gesetzlichen Bestimmungen – aufgibt. Das Werk kann – selbst für kommerzielle Zwecke – kopiert, modifiziert und weiterverteilt werden, ohne hierfür um Erlaubnis bitten zu müssen.
http://creativecommons.org/publicdomain/zero/1.0/deed.enCC0Creative Commons Zero, Public Domain Dedicationfalsefalse |
Source code
Recommended tools:
- Java (Java 8 used)
- mjpeg tools (2.1 used)
- inkscape (0.48 used)
- ffmpeg2theora (0.29 used)
- Eclipse (4.4.1 used)
All tools are available for Linux and Windows.
Core tool is Java. Additional helper tools and scripts generate a encoded video from a sequence of svg files. See below
The file File:Stirling template.svg serves as template used by Java code.
Java
Create a Java project with Eclipse. It requires only one file with one class.
package wikipedia.stirling;
import java.io.File;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Locale;
import javax.swing.JFileChooser;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
*
* The StirlingSvgManipulator takes a specially prepared template SVG file and from that it creates a
* sequence of animated SVG files explaining a stirling engine. The template SVG was created with the
* popular Inkscape illustration tool.
*
* StirlingSvgManipulator opens the SVG file a XML based format by using a DOM parser. With DOM specially
* tagged SVG graphic elements can be searched and manipulated. Mostly the "matrix" attribute from SVG
* is used to translate and rotate elements. Further corners of a rectangular path are edited to expand
* and shrink its volume.
*
*/
public class StirlingSvgManipulator {
static final String filename = "stirling";
static final String template = filename + "_template.svg";
static final int duration = 4*10; // duration in seconds
static final int framerate = 30; // frame rate per second
static final double angularSpeed = 1./10.; // rotations per second
static final double Length = 350.;
static final double LengthPiston = 150.;
static final double Excentricity = 100.;
static final int OffsetX = 250;
static final int OffsetY = 250;
/**
* @param args
*
* Opens a file chooser dialog which requires to select the directory where the template SVG is found
* and the resulting SVG files are placed.
*
* @throws Exception
*/
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
Path wspPath = null;
Path templatePath = null;
JFileChooser filechooser = new JFileChooser();
filechooser.setCurrentDirectory(new java.io.File("."));
filechooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
filechooser.setAcceptAllFileFilterUsed(false);
filechooser.setDialogTitle("Select working directory");
int approve = filechooser.showOpenDialog(null);
if(approve == JFileChooser.APPROVE_OPTION) {
System.out.println("You chose to open this file: " +
filechooser.getSelectedFile().getAbsolutePath());
Path path = filechooser.getSelectedFile().toPath();
wspPath = Paths.get(path.toString(), "svg");
templatePath = Paths.get(path.toString(), template);
} else {
System.out.println("Execution canceled!");
return;
}
mkdirSvg(wspPath);
StirlingSvgManipulator template = new StirlingSvgManipulator(templatePath);
template.load();
for (int count = 0 ; count <= (duration * framerate); count++) { // time in seconds
System.out.println("===============================");
System.out.println("Iteration: " + String.valueOf(count));
System.out.println("===============================");
double time = (double) count / (double) framerate;
template.setAngle(2. * Math.PI * angularSpeed * time);
template.applySettings();
Path destination = Paths.get(wspPath.toString(), filename + "-" + String.format("%04d", count) + ".svg");
template.save(destination);
}
long endTime = System.currentTimeMillis();
System.out.println("Execution time: " + String.valueOf((endTime-startTime)/1000) + "s");
System.out.println("Finished");
}
public static void mkdirSvg(Path dir) throws IOException {
boolean success = false;
File directory = dir.toFile();
if (directory.exists()) {
System.out.println("Directory already exists!");
} else {
success = directory.mkdir();
if (success == true) {
System.out.println("Successful");
} else {
throw new IOException("can't make directory for " + dir.toString());
}
}
}
private Path templatePath = null;
private Document document = null;
private double angleRad = 0.;
private double x;
private double y;
private double xStroke;
private double yStroke;
private double alpha1; // Angle between conrod and y axis
private double alpha2; // Angle between conrod and x axis
/**
*
* Konstruktor
*
* @param templatePath
*/
public StirlingSvgManipulator(Path templatePath) {
// TODO Auto-generated constructor stub
this.templatePath = templatePath;
}
/**
*
* Load template with StaXParser
* @throws Exception
*
*/
public void load() throws Exception {
// TODO Auto-generated method stub
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
document = docBuilder.parse(templatePath.toFile());
} catch (IOException | ParserConfigurationException e) {
System.out.print("Error loading " + templatePath.toString() + "\n");
e.printStackTrace();
throw e;
}
}
/**
*
* Write XML file with StaXParser
*
* @param destination
* @throws TransformerException
*/
public void save(Path destination) throws TransformerException {
try {
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer trans = transFactory.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.METHOD, "xml");
trans.transform(new DOMSource(document), new StreamResult(destination.toFile()));
} catch (TransformerConfigurationException e) {
e.printStackTrace();
throw e;
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}
}
/**
*
* @param rad Angular position for the engine
*/
public void setAngle(double rad) {
angleRad = rad;
}
public void applySettings() {
System.out.println( "calcParameters();");
calcParameters();
System.out.println( "applyKolben();");
applyPiston();
System.out.println( "applyHeatexchanger();");
applyHeatexchanger();
System.out.println( "applyVolumen();");
applyVolume();
}
private void calcParameters() {
x = Math.cos(angleRad);
y = Math.sin(angleRad);
alpha1 = Math.acos(x * Excentricity / Length);
alpha2 = Math.acos(y * Excentricity / Length);
xStroke = x * Excentricity + Math.sqrt(Length * Length - (y*Excentricity)*(y*Excentricity)) - Length;
yStroke = y * Excentricity + Math.sqrt(Length * Length - (x*Excentricity)*(x*Excentricity)) - Length; // Pythagoras
}
private void applyVolume() {
NodeList nodes = document.getElementsByTagName("g");
System.out.println( "Gefunden: " + Integer.toString(nodes.getLength()) + " groups");
nodes.item(0);
for (int i = 0; i < nodes.getLength(); ++i) {
Node node = nodes.item(i);
NamedNodeMap attributes = node.getAttributes();
Node id = attributes.getNamedItem("id");
if(id.getNodeValue().equals("gVolume1") == true) {
NodeList childNodes = node.getChildNodes();
Node volumen = childNodes.item(1);
NamedNodeMap childAttributes = volumen.getAttributes();
Node childId = childAttributes.getNamedItem("id");
if(childId.getNodeValue().equals("pVolume1") == true) {
Node d = childAttributes.getNamedItem("d");
System.out.print("Volume path d: " + d.getNodeValue() + "\n");
String[] parameters = d.getNodeValue().split(" ");
if(parameters.length != 6) {
throw new NullPointerException();
}
String[] links = parameters[3].split(",");
String[] rechts = parameters[4].split(",");
links[1] = String.format(Locale.US, "%.3f", yStroke);
rechts[1] = String.format( Locale.US, "%.3f", yStroke);
parameters[3] = links[0] + "," + links[1];
parameters[4] = rechts[0] + "," + rechts[1];
StringBuilder parametersBuild = new StringBuilder();
for(String parameter : parameters) {
parametersBuild.append(parameter + " ");
}
d.setNodeValue(parametersBuild.toString().trim());
}
Node transform = attributes.getNamedItem("transform");
System.out.print("transform: " + transform.getNodeValue() + "\n");
String offset = String.format(Locale.US, "%.3f", (double) OffsetY + Length + LengthPiston);
String matrix = "translate(" + String.valueOf(OffsetX) + "," + offset + ")";
System.out.println(matrix);
transform.setNodeValue(matrix);
}
if(id.getNodeValue().equals("gVolume2") == true) {
NodeList childNodes = node.getChildNodes();
Node volumen = childNodes.item(1);
NamedNodeMap childAttributes = volumen.getAttributes();
Node childId = childAttributes.getNamedItem("id");
if(childId.getNodeValue().equals("pVolume2") == true) {
Node d = childAttributes.getNamedItem("d");
System.out.print("Volume path d: " + d.getNodeValue() + "\n");
String[] parameters = d.getNodeValue().split(" ");
if(parameters.length != 6) {
throw new NullPointerException();
}
String[] links = parameters[3].split(",");
String[] rechts = parameters[4].split(",");
links[0] = String.format(Locale.US, "%.3f", xStroke);
rechts[0] = String.format( Locale.US, "%.3f", xStroke);
parameters[3] = links[0] + "," + links[1];
parameters[4] = rechts[0] + "," + rechts[1];
StringBuilder parametersBuild = new StringBuilder();
for(String parameter : parameters) {
parametersBuild.append(parameter + " ");
}
d.setNodeValue(parametersBuild.toString().trim());
}
Node transform = attributes.getNamedItem("transform");
System.out.print("transform: " + transform.getNodeValue() + "\n");
String offset = String.format(Locale.US, "%.3f", (double) OffsetX + Length + LengthPiston);
String matrix = "translate(" + offset + "," + String.valueOf(OffsetY) + ")";
System.out.println(matrix);
transform.setNodeValue(matrix);
}
}
}
/**
*
* applyHeatexchanter()
*
* This Drawing is not very precise and just for illustration to get an idea about the state of the heat exchanger.
*
*/
private void applyHeatexchanger() {
NodeList nodes = document.getElementsByTagName("linearGradient");
System.out.println( "Gefunden: " + Integer.toString(nodes.getLength()) + " linear Gradient(s)");
nodes.item(0);
double sum = ( x + -1. * y)/Math.sqrt(2.);
double pos = 0.5 + 0.4 * sum; // TODO magic numbers
double delta = 0.1;
System.out.println("");
//double sum =
// V_1 / V_2
// V_1 = x_hub
// V_2 = y_hub
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
NamedNodeMap attributes = node.getAttributes();
Node id = attributes.getNamedItem("id");
System.out.println("Gradient -ID: " + id.getNodeValue());
if(id.getNodeValue().equals("linearGradientHeat") == true) {
NodeList stopNodes = node.getChildNodes();
System.out.println( "Gefunden: " + Integer.toString(stopNodes.getLength()) + " stop(s)");
// stopNodes.item(0);
for (int j = 0; j < stopNodes.getLength(); j++) {
Node stopNode = stopNodes.item(j);
if(stopNode.getNodeName().equals("stop") == true) {
NamedNodeMap stopAttributes = stopNode.getAttributes();
System.out.println( "Gefunden: " + Integer.toString(stopAttributes.getLength()) + " stop attribut(e)");
Node stopId = stopAttributes.getNamedItem("id");
if(stopId.getNodeValue().equals("stopRed") == true) {
System.out.println("Stop ID: " + stopId.getNodeValue());
Node offset = stopAttributes.getNamedItem("offset");
offset.setNodeValue(String.valueOf(pos - delta));
}
if(stopId.getNodeValue().equals("stopBlue1") == true) {
System.out.println("Stop ID: " + stopId.getNodeValue());
Node offset = stopAttributes.getNamedItem("offset");
offset.setNodeValue(String.valueOf(pos + delta));
}
}
}
}
}
}
private void applyPiston() {
NodeList nodes = document.getElementsByTagName("g");
System.out.println( "Found: " + Integer.toString(nodes.getLength()) + " groups");
nodes.item(0);
double alpha_x1 = Math.cos(alpha1);
double alpha_y1 = Math.sin(alpha1);
double alpha_x2 = Math.cos(alpha2);
double alpha_y2 = Math.sin(alpha2);
System.out.println("alpha: " + String.format(Locale.US, "%.3f, alpha_x: ", alpha1) +
String.format(Locale.US, "%.3f, alpha_y: ", alpha_x1) + String.format( Locale.US, "%.3f, ", alpha_y1));
for (int i = 0; i < nodes.getLength(); ++i) {
Node node = nodes.item(i);
NamedNodeMap attributes = node.getAttributes();
Node id = attributes.getNamedItem("id");
System.out.println("Group-ID: " + id.getNodeValue());
if(id.getNodeValue().equals("gCrankShaft") == true) {
Node transform = attributes.getNamedItem("transform");
System.out.print("transform: " + transform.getNodeValue() + "\n");
String matrix = "matrix(" + String.valueOf(-1. * y) + "," + String.valueOf(x) +
"," + String.valueOf(-1. * x) + "," + String.valueOf(-1. * y) + ",0,0)";
System.out.println(matrix);
transform.setNodeValue(matrix);
}
if(id.getNodeValue().equals("gConrod1") == true) { // Pleuel
Node transform = attributes.getNamedItem("transform");
System.out.print("transform: " + transform.getNodeValue() + "\n");
String matrix = "matrix(" + String.valueOf(alpha_y1) + "," + String.valueOf(alpha_x1) +
"," + String.valueOf(-1. * alpha_x1) + "," + String.valueOf(alpha_y1) + "," +
String.valueOf(Excentricity * x) + "," + String.valueOf(Excentricity * y) + ")";
System.out.println(matrix);
transform.setNodeValue(matrix);
}
if(id.getNodeValue().equals("gPiston1") == true) {
Node transform = attributes.getNamedItem("transform");
String yMove = String.format(Locale.US, "%.3f", yStroke + Length);
String translate = "translate(0," + yMove + ")";
transform.setNodeValue(translate);
}
if(id.getNodeValue().equals("gConrod2") == true) { // Pleuel
Node transform = attributes.getNamedItem("transform");
System.out.print("transform: " + transform.getNodeValue() + "\n");
String matrix = "matrix("
+ String.valueOf(alpha_x2) + "," + String.valueOf(alpha_y2) +
"," + String.valueOf(alpha_y2) + "," + String.valueOf(-1. *alpha_x2) + "," +
String.valueOf(Excentricity * x) + "," + String.valueOf(Excentricity * y) + ")";
System.out.println(matrix);
transform.setNodeValue(matrix);
}
if(id.getNodeValue().equals("gPiston2") == true) {
Node transform = attributes.getNamedItem("transform");
String xMove = String.format(Locale.US, "%.3f", xStroke + Length);
String translate = "translate(" + xMove + ",0)";
transform.setNodeValue(translate);
}
if(id.getNodeValue().equals("gCrankDrive") == true) {
Node transform = attributes.getNamedItem("transform");
System.out.print("transform: " + transform.getNodeValue() + "\n");
String matrix = "translate(" + String.valueOf(OffsetX) + "," + String.valueOf(OffsetY) + ")";
System.out.println(matrix);
transform.setNodeValue(matrix);
}
}
}
}
svg_to_png
@echo off
Echo Converting...
set start=%time%
echo %CD%
rmdir png /s /q
mkdir png
cd svg
for %%f in (*.svg) do (
call :convert %%f
)
echo Start time: %start%
echo End time: %time%
timeout /T -1
goto :EOF
:convert
echo %1
set ink="C:\Program Files (x86)\Inkscape\inkscape.exe"
set svg=%1
set png=%svg%
set png=%png:~0,-3%
set png=../png/%png%png
%ink% --file=%svg% --export-png=%png% --export-background=white --without-gui
rem convert %svg% -background white -flatten %png%
echo %png%
goto :EOF
cd ..
png_to_ogv
@echo off
echo Converting...
set start=%time%
echo %CD%
echo %temp%
call :convert
echo Start time: %start%
echo End time: %time%
timeout /T -1
goto :EOF
:convert
set png2yuv="%CD%\mjpeg_tools\bin\png2yuv.exe"
set framerate=30
set filename=stirling
%png2yuv% -j .\png\%filename%-%%04d.png -f %framerate% -I p -b 0 > %temp%\out.yuv
.\ffmpeg2theora-0.29.exe %temp%\out.yuv -F %framerate% -v 9 -o %filename%.ogv
del %temp%\out.yuv /q /s
goto :EOF
In dieser Datei abgebildete Objekte
Motiv
Einige Werte ohne einen Wikidata-Eintrag
10. Dezember 2014
application/ogg
d8f9d8b7e385af3fb929487410258b67a4f74b50
4.986.682 Byte
40,03333333333333 Sekunde
1.000 Pixel
1.000 Pixel
Dateiversionen
Klicke auf einen Zeitpunkt, um diese Version zu laden.
Version vom | Vorschaubild | Maße | Benutzer | Kommentar | |
---|---|---|---|---|---|
aktuell | 16:14, 10. Dez. 2014 | 40 s, 1.000 × 1.000 (4,76 MB) | wikimediacommons>Menner | update |
Dateiverwendung
Die folgende Seite verwendet diese Datei:
Metadaten
Diese Datei enthält weitere Informationen, die in der Regel von der Digitalkamera oder dem verwendeten Scanner stammen. Durch nachträgliche Bearbeitung der Originaldatei können einige Details verändert worden sein.
Software |
|
---|