...
 
Commits (6)
......@@ -36,7 +36,7 @@
While the size of standard spherical and cubic particles is controlled by the <literal>Radius</literal> particle property,
the size and shape of non-spherical and non-cubic particles is determined by the <literal>Aspherical Shape</literal> property.
For OVITO to display non-spherical particles, this property must be defined and the
desired type of shape must be selected in the <link linkend="display_objects.particles">Particle display</link> parameters panels.
desired shape must be selected in the settings of the <link linkend="display_objects.particles">Particles</link> visual element.
</para>
<para>
......@@ -61,7 +61,7 @@
<para>
Both the <literal>Aspherical Shape</literal> and the <literal>Orientation</literal> properties are typically
read from simulation files. The LAMMPS (or LIGGGHTS) simulation code can output this information to dump files using the following LAMMPS script commands:
read from simulation files. The LAMMPS and LIGGGHTS simulation codes can output this information to dump files using the following LAMMPS script commands:
<screen> compute orient all property/atom quati quatj quatk quatw
compute shape all property/atom shapex shapey shapez
dump 1 all custom 100 ellipsoid.dump id type x y z &amp;
......
......@@ -22,8 +22,8 @@
</para>
<para>
You can dynamically filter the displayed list of bonds by entering a Boolean expression in the input field at the top of the table.
Consider, for example, the table shown in the screenshot: Here, the <link linkend="particles.modifiers.compute_bond_lengths">Compute bond lengths</link> modifier
had been used to add the <literal>Length</literal> property to each bond (last table column).
Consider, for example, the table shown in the screenshot: Here, the <link linkend="particles.modifiers.compute_property">Compute property</link> modifier
had been used to compute and assign the <literal>Length</literal> property to each bond (last table column).
To selectively list only those bonds that are very long, let's say longer than 1.5 Angstroms,
we can enter the expression <literal>Length > 1.5</literal> into the filter field.
Multiple criteria can be combined using logical AND and OR operators. For a detailed description of the expression syntax,
......
......@@ -16,7 +16,66 @@
<imagedata fileref="images/display_objects/particles_panel.png" format="PNG" scale="50" />
</imageobject></mediaobject></screenshot></informalfigure>
This <link linkend="display_objects">visual element</link> renders particles as spheres and other geometric shapes.
This <link linkend="display_objects">visual element</link> is responsible for rendering particles in the viewports.
Typically, particles are visualized as simple spheres, but you can switch to other, more complex geometric shapes
if desired.
</para>
<para>
The <emphasis>Particles</emphasis> visual element provides a set of parameters controlling the
visual representation of all particles, which will be described in the section below.
Additionally, the visualization is affected by certain properties, listed in the following table, that particles may optionally
possess. By setting the values of these particle properties, for example using the <link linkend="particles.modifiers.compute_property">
Compute property</link> modifier, you can control the visualization on a per-particle basis.
<informaltable>
<tgroup cols="3">
<colspec colnum="1" colname="name" colwidth="2*" />
<colspec colnum="2" colname="datatype" colwidth="1*" />
<colspec colnum="3" colname="description" colwidth="4*" />
<thead>
<row>
<entry>Particle&#xA0;property</entry>
<entry>Data&#xA0;type / Components</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>Color</literal></entry>
<entry>Real (R,&#xA0;G,&#xA0;B)</entry>
<entry><para>Controls the display color of individual particles. Red, green and blue components are in the range [0,1].</para></entry>
</row>
<row>
<entry><literal>Radius</literal></entry>
<entry>Real</entry>
<entry><para>Controls the display size of individual particles.</para></entry>
</row>
<row>
<entry><literal>Particle&#xA0;Type</literal></entry>
<entry>Integer</entry>
<entry><para>Used to determine size and color if the <emphasis>Radius</emphasis> or <emphasis>Color</emphasis> properties are not present.</para></entry>
</row>
<row>
<entry><literal>Transparency</literal></entry>
<entry>Real</entry>
<entry><para>Controls the transparency of individual particles. Must be in the range [0,1].</para></entry>
</row>
<row>
<entry><literal>Aspherical Shape</literal></entry>
<entry>Real (X,&#xA0;Y,&#xA0;Z)</entry>
<entry><para>Controls the size of particles with a non-symmetric shape. The exact interpretation
of this property depends on the selected <emphasis>Shape</emphasis> setting, see section below.</para></entry>
</row>
<row>
<entry><literal>Orientation</literal></entry>
<entry>Real (X,&#xA0;Y,&#xA0;Z,&#xA0;W)</entry>
<entry><para>Specifies the orientation of particles with non-symmetric shapes.
The rotation of each particle is specified in terms of a <link xlink:href="https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation">quaternion</link>.
See <link linkend="howto.aspherical_particles">this page</link> for more information.
</para></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<simplesect>
......@@ -26,23 +85,52 @@
<varlistentry>
<term>Shape</term>
<listitem>
<para>Selects the visual shape of particles.
Note that spherical particles can be turned into <link linkend="howto.aspherical_particles">ellipsoidal particles</link>
by setting the <literal>Aspherical Shape</literal> particle property. Similarly,
the size of box-shaped particles can be controlled with the same property.
</para>
<para>
The size of cylindrical and spherocylindrical particles is also controlled by the
<literal>Aspherical Shape</literal> property. Here, the component <literal>Aspherical Shape.X</literal>
determines the radius of the cylinder, and <literal>Aspherical Shape.Z</literal> determines its
length. The vector component <literal>Aspherical Shape.Y</literal> is ignored.
</para>
<para>
The orientation of ellipsoidal, box, and cylindrical particles can be controlled
using the <literal>Orientation</literal> particle property. With this property,
a quaternion can be specified for each particle which determines its orientation in space.
If the <literal>Orientation</literal> property is not defined, all particles
will be aligned with the global simulation coordinate axes.
<para>Selects the display shape of particles. The current program version offers the choice between
the following modes:
<variablelist>
<varlistentry>
<term>Sphere/Ellipsoid</term>
<listitem>Particles are visualized as 3d spheres. Unless the <literal>Aspherical Shape</literal> particle property
has been defined; then they are rendered as <link linkend="howto.aspherical_particles">ellipsoidal particles</link>.
In this case, the three components of the <literal>Aspherical Shape</literal> vector property control the
half lengths of the principal axes of each ellipsoid and the scalar <literal>Radius</literal> property is ignored.
</listitem>
</varlistentry>
<varlistentry>
<term>Circle</term>
<listitem>Particles are visualized as flat-shaded circles facing the viewer.
Note that some <link linkend="rendering">rendering engines</link> do not support this mode.</listitem>
</varlistentry>
<varlistentry>
<term>Cube/Box</term>
<listitem>Particles are visualized as cubes if the <literal>Aspherical Shape</literal> particle property
is not present. The <literal>Radius</literal> property can be used to
control the edge half-length of the cubes in this case.
If the <literal>Aspherical Shape</literal> particle property is present, particles are rendered as non-cubic boxes
with the given half-lengths along the three edges.
</listitem>
</varlistentry>
<varlistentry>
<term>Square</term>
<listitem>Particles are visualized as flat-shaded squares facing the viewer.
Note that some <link linkend="rendering">rendering engines</link> do not support this mode.</listitem>
</varlistentry>
<varlistentry>
<term>Cylinder</term>
<listitem>Particles are visualized as cylinders.
The X-component of the <literal>Aspherical Shape</literal> vector property controls the cylinder radius
of particles in this mode, and the Z-component controls the length of the cylindrical particles.
By default, cylinders are aligned along the z-axis. If present, the <literal>Orientation</literal>
particle property rotates the cylinders.
</listitem>
</varlistentry>
<varlistentry>
<term>Spherocylinder</term>
<listitem>Particles are visualized as cylinders with round caps at each end (capsules). The behavior is the
same as for mode <emphasis>Cylinder</emphasis>.
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
......@@ -50,10 +138,10 @@
<term>Default particle radius</term>
<listitem>
<para>Specifies the display size of particles that have an otherwise unspecified size.
This size value is only used for particles for which <emphasis>none</emphasis> of the following applies:
This size value is only used for particles for which none of the following applies:
<itemizedlist>
<listitem><para>The <literal>Radius</literal> property has been set.</para></listitem>
<listitem><para>A non-zero type-specific radius has been set for the particle's type.</para></listitem>
<listitem><para>The <literal>Radius</literal> particle property has a non-zero value.</para></listitem>
<listitem><para>The particle's type, as specified by the <literal>Particle Type</literal>, has a non-zero radius.</para></listitem>
</itemizedlist>
In other words, this parameter provides a fallback value if no display size has been set on a
per-particle basis or on a per-type basis.
......@@ -63,7 +151,7 @@
<varlistentry>
<term>Rendering quality</term>
<listitem>
<para>This parameter controls the method used to render the particles. The following modes are available and affect only the rendering of spherical particles:
<para>This parameter controls the method used for rendering the particles in the interactive viewports. The following modes are available and affect only the rendering of spherical particles:
<variablelist>
<varlistentry>
<term>Low</term>
......
......@@ -88,7 +88,7 @@
</row>
<row>
<entry><link linkend="particles.modifiers.polyhedral_template_matching">Polyhedral&#xA0;template&#xA0;matching</link></entry>
<entry>Identifies common crystal structures using the PTM method.</entry>
<entry>Identifies common crystal structures using the PTM method and computes local crystal orientations.</entry>
</row>
<row>
<entry><link linkend="particles.modifiers.scatter_plot">Scatter&#xA0;plot</link></entry>
......@@ -133,16 +133,12 @@
<entry>Applies an affine transformation to the system.</entry>
</row>
<row>
<entry><link linkend="particles.modifiers.combine_particle_sets">Combine&#xA0;particle&#xA0;sets</link></entry>
<entry>Merges the particles from two separate files into one dataset.</entry>
</row>
<row>
<entry><link linkend="particles.modifiers.compute_bond_lengths">Compute&#xA0;bond&#xA0;lengths</link></entry>
<entry>Computes the length of each bond in the system.</entry>
<entry><link linkend="particles.modifiers.combine_particle_sets">Combine&#xA0;datasets</link></entry>
<entry>Merges the particles and bonds from two separate input files into one dataset.</entry>
</row>
<row>
<entry><link linkend="particles.modifiers.compute_property">Compute&#xA0;property</link></entry>
<entry>Computes a new property for each particle based a user-defined formula.</entry>
<entry>Assigns property values to particles or bonds according to a user-defined formula.</entry>
</row>
<row>
<entry><link linkend="particles.modifiers.delete_selected_particles">Delete&#xA0;selected</link></entry>
......@@ -260,8 +256,6 @@
<xi:include href="particles/common_neighbor_analysis.docbook"/>
<xi:include href="particles/compute_bond_lengths.docbook"/>
<xi:include href="particles/compute_property.docbook"/>
<xi:include href="particles/construct_surface_mesh.docbook"/>
......
......@@ -8,22 +8,22 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ns="http://docbook.org/ns/docbook">
<title>Combine particle sets</title>
<title>Combine datasets</title>
<para>
<informalfigure><screenshot><mediaobject><imageobject>
<imagedata fileref="images/modifiers/combine_particle_sets_panel.png" format="PNG" scale="50" />
<imagedata fileref="images/modifiers/combine_datasets_panel.png" format="PNG" scale="50" />
</imageobject></mediaobject></screenshot></informalfigure>
This modifier loads a set of particles from a second file and merges it into the current dataset
to build a system with both particle sets combined.
to build a system with both sets of particles combined.
</para>
<para>
Note: The simulation cell loaded from the second file is ignored. The modifier does not replace or extend the
Note: The simulation cell loaded from the second input file is ignored. The modifier does not replace or extend the
exiting simulation box. If needed, you can use e.g. the <link linkend="particles.modifiers.affine_transformation">Affine transformation</link> modifier to expand the
simulation cell to accommodate all particles of the merged datasets.
simulation cell and accommodate all particles of the merged datasets.
</para>
<para>
......@@ -41,7 +41,7 @@
<simplesect>
<title>See also</title>
<para>
<link xlink:href="python/modules/ovito_modifiers.html#ovito.modifiers.CombineParticleSetsModifier"><classname>CombineParticleSetsModifier</classname> (Python API)</link>
<link xlink:href="python/modules/ovito_modifiers.html#ovito.modifiers.CombineDatasetsModifier"><classname>CombineDatasetsModifier</classname> (Python API)</link>
</para>
</simplesect>
......
<?xml version="1.0" encoding="utf-8"?>
<section version="5.0"
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd"
xml:id="particles.modifiers.compute_bond_lengths"
xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ns="http://docbook.org/ns/docbook">
<title>Compute bond lengths</title>
<para>
This modifier computes the length of each bond and stores the value in a new bond property named <code>Length</code>.
</para>
<para>
A typical use case of this modifier is in conjunction with the <link linkend="particles.modifiers.color_coding">Color Coding</link>
modifier to visualize the length of each bond. Furthermore, the <link linkend="particles.modifiers.histogram">Histogram</link>
lets you plot the overall distribution of bond lengths in a system computed by this modifier.
</para>
<para>
Note that, depending on the situation, the <link linkend="particles.modifiers.coordination_analysis">Coordination Analysis</link> modifier may provide an
alternative. It computes the distribution of neighbor distances in a system of particles without explicit bonds.
</para>
<simplesect>
<title>See also</title>
<para>
<link xlink:href="python/modules/ovito_modifiers.html#ovito.modifiers.ComputeBondLengthsModifier"><classname>ComputeBondLengthsModifier</classname> (Python API)</link>
</para>
</simplesect>
</section>
......@@ -41,16 +41,12 @@
<imagedata fileref="images/modifiers/create_bonds_panel.png" format="PNG" scale="50" />
</imageobject></mediaobject></screenshot></informalfigure>
This modifier generate bonds between pairs of particles using a distance-based cutoff criterion.
This modifier generate bonds between pairs of particles using a distance-based criterion.
Optionally, the generation can be restricted to one or more pairs of particle types.
</para>
<para>
To visualize the bonds, the modifier automatically creates a new <link linkend="display_objects.bonds">bonds
visual element</link>, which renders the bonds as cylinders in between the particles.
</para>
<para>
The modifier provides two modes of operation:
You can choose between two modes of operation:
<variablelist>
<varlistentry>
<term>Uniform cutoff radius</term>
......@@ -59,13 +55,13 @@
</listitem>
</varlistentry>
<varlistentry>
<term>Pair-wise cutoff radii</term>
<term>Pair-wise cutoffs</term>
<listitem>
<para>
This mode gives you more control over which particle types get connected by bonds.
The table lists all pair-wise combinations of particle types defined in your system.
The table lists all pair-wise combinations of particle types defined for the current system.
Enter a cutoff distance in the third column to create bonds between pairs of particles of the given types.
Note that this mode is only available if particle types have been defined, i.e. if the <literal>Particle Type</literal> particle property
Note that this mode is only available if particle types have been defined, i.e. if the particle property <literal>Particle Type</literal>
exists.
</para>
</listitem>
......@@ -80,18 +76,30 @@
</para>
<para>
The modifier allows you to specify a <emphasis>lower cutoff</emphasis> value. It effectively restricts the generation of bonds to
pairs of particles having a separation within the range given by the lower and the upper cutoff.
The modifier lets you optionally specify a <emphasis>lower cutoff</emphasis> value. It effectively restricts the generation of bonds
to a range with a lower and an upper bound.
</para>
<para>
Visualization of the bonds generated by this modifier is controlled by the <link linkend="display_objects.bonds">bonds
visual element</link>, which is automatically created.
</para>
<para>
Like with particles, OVITO supports the assignment of arbitrary properties to bonds which have been generated by this modifier or read from the input file.
Certain bond properties, which are listed in <link linkend="usage.bond_properties">this section</link>, are used by OVITO
to control the visualization of bonds. By setting the values of these properties, for example using the <link linkend="particles.modifiers.compute_property">Compute property</link> modifier,
you can adjust the visual representation of bonds, even on a per-bond basis.
</para>
<simplesect>
<title>Technical notes</title>
<para>
OVITO stores a periodic shift vector with every generated bond.
This shift vector specifies whether the bond crosses a periodic boundary of the simulation cell.
The shift vector of a bond that does not cross a periodic boundary is (0,0,0). A bond that crosses a
periodic cell boundary in the positive X direction, for instance, has a shift vector of (1,0,0) and
will be visualized as two separate half bonds, one on either side of the cell.
OVITO stores a triplet of integer numbers with every bond in the <literal>Periodic Image</literal> property field.
This triplet specifies whether a bond crosses the periodic boundaries of the simulation cell (if any) and in which direction.
For example, a bond crossing the periodic cell boundary in the positive X direction is associated with the triplet (1,0,0) and
will be visualized as two separate half bonds, one on either end of the cell. Bonds in the interior of the simulation box which do not cross a
periodic boundary have a <literal>Periodic Image</literal> value of (0,0,0).
</para>
</simplesect>
......@@ -99,7 +107,7 @@
<title>See also</title>
<para>
<simplelist>
<member><link linkend="particles.modifiers.compute_bond_lengths">Compute bond lengths modifier</link></member>
<member><link linkend="particles.modifiers.compute_property">Compute property modifier</link></member>
<member><link xlink:href="python/modules/ovito_modifiers.html#ovito.modifiers.CreateBondsModifier"><classname>CreateBondsModifier</classname> (Python API)</link></member>
</simplelist>
</para>
......
......@@ -144,7 +144,7 @@
</para>
</simplesect>
<simplesect>
<simplesect xml:id="usage.bond_properties">
<title>Special bond properties</title>
<para>
<informaltable>
......@@ -160,10 +160,15 @@
</row>
</thead>
<tbody>
<row>
<entry><literal>Topology</literal></entry>
<entry>Integer (A,&#xA0;B)</entry>
<entry><para>This bond property is always present and holds the indices of the two particles connected by a bond.</para></entry>
</row>
<row>
<entry><literal>Bond&#xA0;Type</literal></entry>
<entry>Integer</entry>
<entry><para>Stores the type identifier of each bond. This also determines the bond display color
<entry><para>Stores the type identifier of each bond. The bond type determines the display color
if the <emphasis>Color</emphasis> property is not present.</para></entry>
</row>
<row>
......@@ -171,6 +176,11 @@
<entry>Real (R,&#xA0;G,&#xA0;B)</entry>
<entry><para>If present, this property controls the display color of individual bonds. Red, green and blue components are in the range [0,1].</para></entry>
</row>
<row>
<entry><literal>Transparency</literal></entry>
<entry>Real</entry>
<entry><para>A value in the range [0,1] controlling the bonds's transparency. If not present, bonds are rendered fully opaque.</para></entry>
</row>
<row>
<entry><literal>Selection</literal></entry>
<entry>Integer</entry>
......
from ovito.io import import_file
from ovito.data import BondsEnumerator
from ovito.modifiers import ComputeBondLengthsModifier
from ovito.modifiers import ComputePropertyModifier
# Load a dataset containing atoms and bonds.
pipeline = import_file('input/bonds.data.gz', atom_style='bond')
# For demonstration purposes, let a modifier calculate the length of each bond.
pipeline.modifiers.append(ComputeBondLengthsModifier())
pipeline.modifiers.append(ComputePropertyModifier(operate_on='bonds', output_property='Length', expressions=['BondLength']))
# Obtain pipeline results.
data = pipeline.compute()
......
from ovito.io import import_file
from ovito.data import BondProperty, SimulationCell
from ovito.modifiers import ComputeBondLengthsModifier
from ovito.modifiers import ComputePropertyModifier
from ovito.vis import BondsVis
pipeline = import_file('input/bonds.data.gz', atom_style = 'bond')
pipeline.modifiers.append(ComputeBondLengthsModifier())
pipeline.modifiers.append(ComputePropertyModifier(operate_on = 'bonds', output_property = 'Length', expressions = ['BondLength']))
# snippet begin >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
data = pipeline.compute()
......@@ -14,9 +14,9 @@ print("Number of bonds:", data.bonds.count)
# snippet begin >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
print("Bond property names:")
print(data.bonds.keys())
if 'Lengths' in data.bonds:
lengths_prop = data.bonds['Length']
assert(len(lengths_prop) == data.bonds.count)
if 'Length' in data.bonds:
length_prop = data.bonds['Length']
assert(len(length_prop) == data.bonds.count)
# snippet end <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# snippet begin >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
......
from ovito.io import import_file, export_file
from ovito.modifiers import CombineParticleSetsModifier
from ovito.modifiers import CombineDatasetsModifier
# Load a first set of particles.
pipeline = import_file('input/first_file.dump')
# Insert the particles from a second file into the dataset.
modifier = CombineParticleSetsModifier()
modifier = CombineDatasetsModifier()
modifier.source.load('input/second_file.dump')
pipeline.modifiers.append(modifier)
......
......@@ -187,6 +187,8 @@ The :py:class:`!SelectParticleTypeModifier` has been renamed to :py:class:`~ovit
bonds too. Furthermore, it is now possible to specify the set of particle :py:attr:`~ovito.modifiers.SelectTypeModifier.types` to select
in terms of type *names*. Before, it was only possible to select particles based on *numeric* type IDs.
The :py:class:`!CombineParticleSetsModifier` has been renamed to :py:class:`~ovito.modifiers.CombineDatasetsModifier`.
The following modifier classes have been generalized and gained a new :py:attr:`!operate_on` field that controls what kind(s) of data elements (e.g. particles,
bonds, surfaces, etc.) the modifier should act on:
......@@ -194,7 +196,9 @@ bonds, surfaces, etc.) the modifier should act on:
* :py:class:`~ovito.modifiers.AssignColorModifier`
* :py:class:`~ovito.modifiers.ClearSelectionModifier`
* :py:class:`~ovito.modifiers.ColorCodingModifier`
* :py:class:`~ovito.modifiers.ComputePropertyModifier`
* :py:class:`~ovito.modifiers.DeleteSelectedModifier`
* :py:class:`~ovito.modifiers.ExpressionSelectionModifier`
* :py:class:`~ovito.modifiers.InvertSelectionModifier`
* :py:class:`~ovito.modifiers.HistogramModifier`
* :py:class:`~ovito.modifiers.SelectTypeModifier`
......
......@@ -84,6 +84,7 @@ SET(SourceFiles
dataset/pipeline/ModifierApplication.cpp
dataset/pipeline/ModifierTemplates.cpp
dataset/pipeline/AsynchronousModifierApplication.cpp
dataset/pipeline/AsynchronousDelegatingModifier.cpp
dataset/pipeline/StaticSource.cpp
dataset/pipeline/DelegatingModifier.cpp
utilities/units/UnitsManager.cpp
......
......@@ -129,6 +129,9 @@ namespace Ovito {
class ModifierDelegate;
class DelegatingModifier;
class MultiDelegatingModifier;
class AsynchronousModifier;
class AsynchronousModifierDelegate;
class AsynchronousDelegatingModifier;
OVITO_BEGIN_INLINE_NAMESPACE(StdObj)
class AbstractCameraObject;
OVITO_END_INLINE_NAMESPACE
......
......@@ -297,6 +297,7 @@ SharedFuture<QVector<FileSourceImporter::Frame>> FileSource::requestFrameList(bo
// Intercept future results when they become available and cache them.
_framesListFuture = importer()->discoverFrames(sourceUrls())
.then(executor(), [this, forceReloadOfCurrentFrame](QVector<FileSourceImporter::Frame>&& frameList) {
UndoSuspender noUndo(this);
setListOfFrames(frameList);
// If update was triggered by user, also reload the current frame.
......
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2016) Alexander Stukowski
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
......@@ -19,73 +19,73 @@
//
///////////////////////////////////////////////////////////////////////////////
#include <plugins/particles/Particles.h>
#include <plugins/particles/objects/BondProperty.h>
#include <plugins/particles/modifier/ParticleInputHelper.h>
#include <plugins/particles/modifier/ParticleOutputHelper.h>
#include <core/utilities/concurrent/ParallelFor.h>
#include <plugins/stdobj/simcell/SimulationCellObject.h>
#include "ComputeBondLengthsModifier.h"
#include <core/Core.h>
#include <core/app/PluginManager.h>
#include <core/dataset/DataSet.h>
#include "AsynchronousDelegatingModifier.h"
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Modifiers) OVITO_BEGIN_INLINE_NAMESPACE(Properties)
namespace Ovito { OVITO_BEGIN_INLINE_NAMESPACE(ObjectSystem) OVITO_BEGIN_INLINE_NAMESPACE(Scene)
IMPLEMENT_OVITO_CLASS(ComputeBondLengthsModifier);
IMPLEMENT_OVITO_CLASS(AsynchronousModifierDelegate);
IMPLEMENT_OVITO_CLASS(AsynchronousDelegatingModifier);
DEFINE_REFERENCE_FIELD(AsynchronousDelegatingModifier, delegate);
/******************************************************************************
* Constructs the modifier object.
* Returns the modifier to which this delegate belongs.
******************************************************************************/
ComputeBondLengthsModifier::ComputeBondLengthsModifier(DataSet* dataset) : Modifier(dataset)
AsynchronousDelegatingModifier* AsynchronousModifierDelegate::modifier() const
{
for(RefMaker* dependent : this->dependents()) {
if(AsynchronousDelegatingModifier* modifier = dynamic_object_cast<AsynchronousDelegatingModifier>(dependent)) {
if(modifier->delegate() == this) return modifier;
}
}
return nullptr;
}
/******************************************************************************
* Asks the modifier whether it can be applied to the given input data.
* Constructs the modifier object.
******************************************************************************/
bool ComputeBondLengthsModifier::OOMetaClass::isApplicableTo(const PipelineFlowState& input) const
AsynchronousDelegatingModifier::AsynchronousDelegatingModifier(DataSet* dataset) : AsynchronousModifier(dataset)
{
return input.findObject<BondProperty>() != nullptr;
}
/******************************************************************************
* Modifies the input data in an immediate, preliminary way.
* Creates a default delegate for this modifier.
******************************************************************************/
PipelineFlowState ComputeBondLengthsModifier::evaluatePreliminary(TimePoint time, ModifierApplication* modApp, const PipelineFlowState& input)
void AsynchronousDelegatingModifier::createDefaultModifierDelegate(const OvitoClass& delegateType, const QString& defaultDelegateTypeName)
{
// Inputs:
ParticleInputHelper pih(dataset(), input);
ParticleProperty* posProperty = pih.expectStandardProperty<ParticleProperty>(ParticleProperty::PositionProperty);
BondProperty* bondTopology = pih.expectBonds();
BondProperty* bondPeriodicImages = BondProperty::findInState(input, BondProperty::PeriodicImageProperty);
SimulationCellObject* simCell = input.findObject<SimulationCellObject>();
AffineTransformation cellMatrix = simCell ? simCell->cellMatrix() : AffineTransformation::Identity();
// Outputs:
PipelineFlowState output = input;
ParticleOutputHelper poh(dataset(), output);
BondProperty* lengthProperty = poh.outputStandardProperty<BondProperty>(BondProperty::LengthProperty, false);
OVITO_ASSERT(delegateType.isDerivedFrom(AsynchronousModifierDelegate::OOClass()));
// Perform bond length calculation.
parallelFor(bondTopology->size(), [posProperty, bondTopology, bondPeriodicImages, simCell, &cellMatrix, lengthProperty](size_t bondIndex) {
size_t index1 = bondTopology->getInt64Component(bondIndex, 0);
size_t index2 = bondTopology->getInt64Component(bondIndex, 1);
if(posProperty->size() > index1 && posProperty->size() > index2) {
const Point3& p1 = posProperty->getPoint3(index1);
const Point3& p2 = posProperty->getPoint3(index2);
Vector3 delta = p2 - p1;
if(simCell && bondPeriodicImages) {
if(int dx = bondPeriodicImages->getIntComponent(bondIndex, 0)) delta += cellMatrix.column(0) * (FloatType)dx;
if(int dy = bondPeriodicImages->getIntComponent(bondIndex, 1)) delta += cellMatrix.column(1) * (FloatType)dy;
if(int dz = bondPeriodicImages->getIntComponent(bondIndex, 2)) delta += cellMatrix.column(2) * (FloatType)dz;
}
lengthProperty->setFloat(bondIndex, delta.length());
// Find the delegate type that corresponds to the given name string.
for(OvitoClassPtr clazz : PluginManager::instance().listClasses(delegateType)) {
if(clazz->name() == defaultDelegateTypeName) {
OORef<AsynchronousModifierDelegate> delegate = static_object_cast<AsynchronousModifierDelegate>(clazz->createInstance(dataset()));
setDelegate(delegate);
break;
}
else lengthProperty->setFloat(bondIndex, 0);
});
}
OVITO_ASSERT_MSG(delegate(), "AsynchronousDelegatingModifier::createDefaultModifierDelegate", qPrintable(QStringLiteral("There is no delegate class named '%1' inheriting from %2.").arg(defaultDelegateTypeName).arg(delegateType.name())));
}
/******************************************************************************
* Asks the metaclass whether the modifier can be applied to the given input data.
******************************************************************************/
bool AsynchronousDelegatingModifier::OOMetaClass::isApplicableTo(const PipelineFlowState& input) const
{
if(!AsynchronousModifier::OOMetaClass::isApplicableTo(input)) return false;
return output;
// Check if there is any modifier delegate that could handle the input data.
for(const AsynchronousModifierDelegate::OOMetaClass* clazz : PluginManager::instance().metaclassMembers<AsynchronousModifierDelegate>(delegateMetaclass())) {
if(clazz->isApplicableTo(input))
return true;
}
return false;
}
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <core/Core.h>
#include <core/dataset/pipeline/AsynchronousModifier.h>
namespace Ovito { OVITO_BEGIN_INLINE_NAMESPACE(ObjectSystem) OVITO_BEGIN_INLINE_NAMESPACE(Scene)
/**
* \brief Base class for modifier delegates used by the AsynchronousDelegatingModifier class.
*/
class OVITO_CORE_EXPORT AsynchronousModifierDelegate : public RefTarget
{
public:
/// Give asynchronous modifier delegates their own metaclass.
class AsynchronousModifierDelegateClass : public RefTarget::OOMetaClass
{
public:
/// Inherit constructor from base class.
using RefTarget::OOMetaClass::OOMetaClass;
/// Asks the metaclass whether the modifier delegate can operate on the given input data.
virtual bool isApplicableTo(const PipelineFlowState& input) const {
OVITO_ASSERT_MSG(false, "AsynchronousModifierDelegate::OOMetaClass::isApplicableTo()",
qPrintable(QStringLiteral("Metaclass of modifier delegate class %1 does not override the isApplicableTo() method.").arg(name())));
return false;
}
/// \brief The name by which Python scripts can refer to this modifier delegate.
virtual QString pythonDataName() const {
OVITO_ASSERT_MSG(false, "AsynchronousModifierDelegate::OOMetaClass::pythonDataName()",
qPrintable(QStringLiteral("Metaclass of modifier delegate class %1 does not override the pythonDataName() method.").arg(name())));
return {};
}
};
OVITO_CLASS_META(AsynchronousModifierDelegate, AsynchronousModifierDelegateClass)
Q_OBJECT
protected:
/// \brief Constructor.
using RefTarget::RefTarget;
public:
/// \brief Returns the modifier to which this delegate belongs.
AsynchronousDelegatingModifier* modifier() const;
};
/**
* \brief Base class for modifiers that delegate work to a ModifierDelegate object.
*/
class OVITO_CORE_EXPORT AsynchronousDelegatingModifier : public AsynchronousModifier
{
public:
/// The abstract base class of delegates used by this modifier type.
using DelegateBaseType = AsynchronousModifierDelegate;
/// Give this modifier class its own metaclass.
class DelegatingModifierClass : public ModifierClass
{
public:
/// Inherit constructor from base class.
using ModifierClass::ModifierClass;
/// Asks the metaclass whether the modifier can be applied to the given input data.
virtual bool isApplicableTo(const PipelineFlowState& input) const override;
/// Return the metaclass of delegates for this modifier type.
virtual const AsynchronousModifierDelegate::OOMetaClass& delegateMetaclass() const {
OVITO_ASSERT_MSG(false, "AsynchronousDelegatingModifier::OOMetaClass::delegateMetaclass()",
qPrintable(QStringLiteral("Delegating modifier class %1 does not define a corresponding delegate metaclass. "
"You must override the delegateMetaclass() method in the modifier's metaclass.").arg(name())));
return DelegateBaseType::OOClass();
}
};
OVITO_CLASS_META(AsynchronousDelegatingModifier, DelegatingModifierClass)
Q_OBJECT
public:
/// Constructor.
AsynchronousDelegatingModifier(DataSet* dataset);
protected:
/// Creates a default delegate for this modifier.
/// This should be called from the modifier's constructor.
void createDefaultModifierDelegate(const OvitoClass& delegateType, const QString& defaultDelegateTypeName);
protected:
/// The modifier's delegate.
DECLARE_MODIFIABLE_REFERENCE_FIELD_FLAGS(AsynchronousModifierDelegate, delegate, setDelegate, PROPERTY_FIELD_ALWAYS_CLONE);
};
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
......@@ -34,7 +34,23 @@ IMPLEMENT_OVITO_CLASS(DelegatingModifier);
DEFINE_REFERENCE_FIELD(DelegatingModifier, delegate);
IMPLEMENT_OVITO_CLASS(MultiDelegatingModifier);
DEFINE_REFERENCE_FIELD(MultiDelegatingModifier, delegates);
DEFINE_REFERENCE_FIELD(MultiDelegatingModifier, delegates);
/******************************************************************************
* Returns the modifier to which this delegate belongs.
******************************************************************************/
Modifier* ModifierDelegate::modifier() const
{
for(RefMaker* dependent : this->dependents()) {
if(DelegatingModifier* modifier = dynamic_object_cast<DelegatingModifier>(dependent)) {
if(modifier->delegate() == this) return modifier;
}
else if(MultiDelegatingModifier* modifier = dynamic_object_cast<MultiDelegatingModifier>(dependent)) {
if(modifier->delegates().contains(const_cast<ModifierDelegate*>(this))) return modifier;
}
}
return nullptr;
}
/******************************************************************************
* Constructs the modifier object.
......@@ -92,8 +108,10 @@ PipelineFlowState DelegatingModifier::evaluatePreliminary(TimePoint time, Modifi
/******************************************************************************
* Lets the modifier's delegate operate on a pipeline flow state.
******************************************************************************/
void DelegatingModifier::applyDelegate(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp)
void DelegatingModifier::applyDelegate(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp, const std::vector<std::reference_wrapper<const PipelineFlowState>>& additionalInputs)
{
OVITO_ASSERT(!dataset()->undoStack().isRecording());
if(!delegate() || !delegate()->isEnabled())
return;
......@@ -102,7 +120,7 @@ void DelegatingModifier::applyDelegate(const PipelineFlowState& input, PipelineF
throwException(tr("The modifier input does not contain the expected kind of data."));
// Call the delegate function.
PipelineStatus delegateStatus = delegate()->apply(this, input, output, time, modApp);
PipelineStatus delegateStatus = delegate()->apply(this, input, output, time, modApp, additionalInputs);
// Append status text and code returned by the delegate function to the status returned to our caller.
PipelineStatus status = output.status();
......@@ -168,8 +186,10 @@ PipelineFlowState MultiDelegatingModifier::evaluatePreliminary(TimePoint time, M
/******************************************************************************
* Lets the registered modifier delegates operate on a pipeline flow state.
******************************************************************************/
void MultiDelegatingModifier::applyDelegates(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp)
void MultiDelegatingModifier::applyDelegates(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp, const std::vector<std::reference_wrapper<const PipelineFlowState>>& additionalInputs)
{
OVITO_ASSERT(!dataset()->undoStack().isRecording());
for(ModifierDelegate* delegate : delegates()) {
// Skip function if not applicable.
......@@ -177,7 +197,7 @@ void MultiDelegatingModifier::applyDelegates(const PipelineFlowState& input, Pip
continue;
// Call the delegate function.
PipelineStatus delegateStatus = delegate->apply(this, input, output, time, modApp);
PipelineStatus delegateStatus = delegate->apply(this, input, output, time, modApp, additionalInputs);
// Append status text and code returned by the delegate function to the status returned to our caller.
PipelineStatus status = output.status();
......
......@@ -69,7 +69,10 @@ protected:
public:
/// \brief Applies the modifier operation to the data in a pipeline flow state.
virtual PipelineStatus apply(Modifier* modifier, const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp) = 0;
virtual PipelineStatus apply(Modifier* modifier, const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp, const std::vector<std::reference_wrapper<const PipelineFlowState>>& additionalInputs) = 0;
/// \brief Returns the modifier to which this delegate belongs.
Modifier* modifier() const;
private:
......@@ -84,6 +87,9 @@ class OVITO_CORE_EXPORT DelegatingModifier : public Modifier
{
public:
/// The abstract base class of delegates used by this modifier type.
using DelegateBaseType = ModifierDelegate;
/// Give this modifier class its own metaclass.
class DelegatingModifierClass : public ModifierClass
{
......@@ -100,7 +106,7 @@ public:
OVITO_ASSERT_MSG(false, "DelegatingModifier::OOMetaClass::delegateMetaclass()",
qPrintable(QStringLiteral("Delegating modifier class %1 does not define a corresponding delegate metaclass. "
"You must override the delegateMetaclass() method in the modifier's metaclass.").arg(name())));
return ModifierDelegate::OOClass();
return DelegateBaseType::OOClass();
}
};
......@@ -122,7 +128,7 @@ protected:
void createDefaultModifierDelegate(const OvitoClass& delegateType, const QString& defaultDelegateTypeName);
/// Lets the modifier's delegate operate on a pipeline flow state.
void applyDelegate(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp);
void applyDelegate(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp, const std::vector<std::reference_wrapper<const PipelineFlowState>>& additionalInputs = {});
protected:
......@@ -175,7 +181,7 @@ protected:
void createModifierDelegates(const OvitoClass& delegateType);
/// Lets the registered modifier delegates operate on a pipeline flow state.
void applyDelegates(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp);
void applyDelegates(const PipelineFlowState& input, PipelineFlowState& output, TimePoint time, ModifierApplication* modApp, const std::vector<std::reference_wrapper<const PipelineFlowState>>& additionalInputs = {});
protected:
......
......@@ -124,6 +124,7 @@ SharedFuture<PipelineFlowState> PipelineSceneNode::evaluatePipeline(TimePoint ti
// Evaluate the pipeline and store the obtained results in the cache before returning them to the caller.
return dataProvider()->evaluate(time)
.then(executor(), [this, time](PipelineFlowState state) {
UndoSuspender noUndo(this);
// The pipeline should never return a state without proper validity interval.
OVITO_ASSERT(state.stateValidity().contains(time));
......@@ -154,6 +155,7 @@ SharedFuture<PipelineFlowState> PipelineSceneNode::evaluateRenderingPipeline(Tim
// Evaluate the pipeline and store the obtained results in the cache before returning them to the caller.
return evaluatePipeline(time)
.then(executor(), [this, time](const PipelineFlowState& state) {
UndoSuspender noUndo(this);
// Holds the results to be returned to the caller.
Future<PipelineFlowState> results;
......@@ -169,6 +171,7 @@ SharedFuture<PipelineFlowState> PipelineSceneNode::evaluateRenderingPipeline(Tim
}
else {
results = results.then(transformingVis->executor(), [this, time, transformingVis, dataObj](PipelineFlowState&& state) {
UndoSuspender noUndo(this);
return transformingVis->transformData(time, dataObj, std::move(state), _pipelineRenderingCache.getStaleContents(), this);
});
}
......
......@@ -64,25 +64,25 @@ public:
bool isFinished() const { return sharedState()->isFinished(); }
/// Returns the maximum value for progress reporting.
int progressMaximum() const { return sharedState()->progressMaximum(); }
qlonglong progressMaximum() const { return sharedState()->progressMaximum(); }
/// Sets the current maximum value for progress reporting.
void setProgressMaximum(int maximum) const { sharedState()->setProgressMaximum(maximum); }
void setProgressMaximum(qlonglong maximum) const { sharedState()->setProgressMaximum(maximum); }
/// Returns the current progress value (in the range 0 to progressMaximum()).
int progressValue() const { return sharedState()->progressValue(); }
qlonglong progressValue() const { return sharedState()->progressValue(); }
/// Sets the current progress value (must be in the range 0 to progressMaximum()).
/// Returns false if the promise has been canceled.
bool setProgressValue(int progressValue) const { return sharedState()->setProgressValue(progressValue); }
bool setProgressValue(qlonglong progressValue) const { return sharedState()->setProgressValue(progressValue); }
/// Increments the progress value by 1.
/// Returns false if the promise has been canceled.
bool incrementProgressValue(int increment = 1) const { return sharedState()->incrementProgressValue(increment); }
bool incrementProgressValue(qlonglong increment = 1) const { return sharedState()->incrementProgressValue(increment); }
/// Sets the progress value of the promise but generates an update event only occasionally.
/// Returns false if the promise has been canceled.
bool setProgressValueIntermittent(int progressValue, int updateEvery = 2000) const { return sharedState()->setProgressValueIntermittent(progressValue, updateEvery); }
bool setProgressValueIntermittent(qlonglong progressValue, int updateEvery = 2000) const { return sharedState()->setProgressValueIntermittent(progressValue, updateEvery); }
// Progress reporting for tasks with sub-steps:
......
......@@ -64,25 +64,25 @@ public:
bool isFinished() const { return (_state & Finished); }
/// Returns the maximum value for progress reporting.
virtual int progressMaximum() const { return 0; }
virtual qlonglong progressMaximum() const { return 0; }
/// Sets the current maximum value for progress reporting.
virtual void setProgressMaximum(int maximum) {}
virtual void setProgressMaximum(qlonglong maximum) {}
/// Returns the current progress value (in the range 0 to progressMaximum()).
virtual int progressValue() const { return 0; }
virtual qlonglong progressValue() const { return 0; }
/// Sets the current progress value (must be in the range 0 to progressMaximum()).
/// Returns false if the promise has been canceled.
virtual bool setProgressValue(int progressValue) { return !isCanceled(); }
virtual bool setProgressValue(qlonglong progressValue) { return !isCanceled(); }
/// Increments the progress value by 1.
/// Returns false if the promise has been canceled.
virtual bool incrementProgressValue(int increment = 1) { return !isCanceled(); }
virtual bool incrementProgressValue(qlonglong increment = 1) { return !isCanceled(); }
/// Sets the progress value of the promise but generates an update event only occasionally.
/// Returns false if the promise has been canceled.
virtual bool setProgressValueIntermittent(int progressValue, int updateEvery = 2000) { return !isCanceled(); }
virtual bool setProgressValueIntermittent(qlonglong progressValue, int updateEvery = 2000) { return !isCanceled(); }
/// Return the current status text set for this promise.
virtual QString progressText() const { return QString(); }
......@@ -107,10 +107,10 @@ public:
virtual void endProgressSubSteps() {}
/// Returns the maximum progress value that can be reached (taking into account sub-steps).
virtual int totalProgressMaximum() const { return 0; }
virtual qlonglong totalProgressMaximum() const { return 0; }
/// Returns the current progress value (taking into account sub-steps).
virtual int totalProgressValue() const { return 0; }
virtual qlonglong totalProgressValue() const { return 0; }
/// Cancels this shared state.
virtual void cancel() noexcept;
......
......@@ -30,7 +30,7 @@ enum {
MaxProgressEmitsPerSecond = 20
};
void PromiseStateWithProgress::setProgressMaximum(int maximum)
void PromiseStateWithProgress::setProgressMaximum(qlonglong maximum)
{
if(maximum == _progressMaximum || isCanceled() || isFinished())
return;
......@@ -39,14 +39,14 @@ void PromiseStateWithProgress::setProgressMaximum(int maximum)
computeTotalProgress();
for(PromiseWatcher* watcher = _watchers; watcher != nullptr; watcher = watcher->_nextInList)
QMetaObject::invokeMethod(watcher, "promiseProgressRangeChanged", Qt::QueuedConnection, Q_ARG(int, totalProgressMaximum()));
QMetaObject::invokeMethod(watcher, "promiseProgressRangeChanged", Qt::QueuedConnection, Q_ARG(qlonglong, totalProgressMaximum()));
for(TrackingPromiseState* tracker = _trackers.get(); tracker != nullptr; tracker = tracker->_nextInList.get()) {
for(PromiseWatcher* watcher = tracker->_watchers; watcher != nullptr; watcher = watcher->_nextInList)
QMetaObject::invokeMethod(watcher, "promiseProgressRangeChanged", Qt::QueuedConnection, Q_ARG(int, totalProgressMaximum()));
QMetaObject::invokeMethod(watcher, "promiseProgressRangeChanged", Qt::QueuedConnection, Q_ARG(qlonglong, totalProgressMaximum()));
}
}
bool PromiseStateWithProgress::setProgressValue(int value)
bool PromiseStateWithProgress::setProgressValue(qlonglong value)
{
_intermittentUpdateCounter = 0;
......@@ -60,17 +60,17 @@ bool PromiseStateWithProgress::setProgressValue(int value)
_progressTime.start();
for(PromiseWatcher* watcher = _watchers; watcher != nullptr; watcher = watcher->_nextInList)
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(int, totalProgressValue()));
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(qlonglong, totalProgressValue()));
for(TrackingPromiseState* tracker = _trackers.get(); tracker != nullptr; tracker = tracker->_nextInList.get()) {
for(PromiseWatcher* watcher = tracker->_watchers; watcher != nullptr; watcher = watcher->_nextInList)
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(int, totalProgressValue()));
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(qlonglong, totalProgressValue()));
}
}
return !isCanceled();
}
bool PromiseStateWithProgress::setProgressValueIntermittent(int progressValue, int updateEvery)
bool PromiseStateWithProgress::setProgressValueIntermittent(qlonglong progressValue, int updateEvery)
{
if(_intermittentUpdateCounter == 0 || _intermittentUpdateCounter > updateEvery) {
setProgressValue(progressValue);
......@@ -79,7 +79,7 @@ bool PromiseStateWithProgress::setProgressValueIntermittent(int progressValue, i
return !isCanceled();
}
bool PromiseStateWithProgress::incrementProgressValue(int increment)
bool PromiseStateWithProgress::incrementProgressValue(qlonglong increment)
{
if(isCanceled() || isFinished())
return !isCanceled();
......@@ -91,10 +91,10 @@ bool PromiseStateWithProgress::incrementProgressValue(int increment)
_progressTime.start();
for(PromiseWatcher* watcher = _watchers; watcher != nullptr; watcher = watcher->_nextInList)
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(int, totalProgressValue()));
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(qlonglong, totalProgressValue()));
for(TrackingPromiseState* tracker = _trackers.get(); tracker != nullptr; tracker = tracker->_nextInList.get()) {
for(PromiseWatcher* watcher = tracker->_watchers; watcher != nullptr; watcher = watcher->_nextInList)
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(int, totalProgressValue()));
QMetaObject::invokeMethod(watcher, "promiseProgressValueChanged", Qt::QueuedConnection, Q_ARG(qlonglong, totalProgressValue()));
}
}
......@@ -120,7 +120,7 @@ void PromiseStateWithProgress::computeTotalProgress()
percentage = ((double)weightSum1 + percentage * level->second[level->first]) / (weightSum1 + weightSum2);
}
_totalProgressMaximum = 1000;
_totalProgressValue = int(percentage * 1000.0);
_totalProgressValue = qlonglong(percentage * 1000.0);
}
}
......
......@@ -38,25 +38,25 @@ class OVITO_CORE_EXPORT PromiseStateWithProgress : public PromiseState
public:
/// Returns the maximum value for progress reporting.
virtual int progressMaximum() const override { return _progressMaximum; }
virtual qlonglong progressMaximum() const override { return _progressMaximum; }
/// Sets the current maximum value for progress reporting.
virtual void setProgressMaximum(int maximum) override;
virtual void setProgressMaximum(qlonglong maximum) override;
/// Returns the current progress value (in the range 0 to progressMaximum()).
virtual int progressValue() const override { return _progressValue; }
virtual qlonglong progressValue() const override { return _progressValue; }
/// Sets the current progress value (must be in the range 0 to progressMaximum()).
/// Returns false if the promise has been canceled.
virtual bool setProgressValue(int value) override;
virtual bool setProgressValue(qlonglong value) override;
/// Increments the progress value by 1.
/// Returns false if the promise has been canceled.
virtual bool incrementProgressValue(int increment = 1) override;
virtual bool incrementProgressValue(qlonglong increment = 1) override;
/// Sets the progress value of the promise but generates an update event only occasionally.
/// Returns false if the promise has been canceled.
virtual bool setProgressValueIntermittent(int progressValue, int updateEvery = 2000) override;
virtual bool setProgressValueIntermittent(qlonglong progressValue, int updateEvery = 2000) override;
/// Return the current status text set for this promise.
virtual QString progressText() const override { return _progressText; }
......@@ -78,10 +78,10 @@ public:
virtual void endProgressSubSteps() override;
/// Returns the maximum progress value that can be reached (taking into account sub-steps).
virtual int totalProgressMaximum() const override { return _totalProgressMaximum; }
virtual qlonglong totalProgressMaximum() const override { return _totalProgressMaximum; }
/// Returns the current progress value (taking into account sub-steps).
virtual int totalProgressValue() const override { return _totalProgressValue; }
virtual qlonglong totalProgressValue() const override { return _totalProgressValue; }
protected:
......@@ -91,10 +91,10 @@ protected:
void computeTotalProgress();
int _totalProgressValue = 0;
int _totalProgressMaximum = 0;
int _progressValue = 0;
int _progressMaximum = 0;
qlonglong _totalProgressValue = 0;
qlonglong _totalProgressMaximum = 0;
qlonglong _progressValue = 0;
qlonglong _progressMaximum = 0;
int _intermittentUpdateCounter = 0;
QString _progressText;
QElapsedTimer _progressTime;
......
......@@ -64,13 +64,13 @@ void PromiseWatcher::promiseStarted()
Q_EMIT started();
}
void PromiseWatcher::promiseProgressRangeChanged(int maximum)
void PromiseWatcher::promiseProgressRangeChanged(qlonglong maximum)
{
if(isWatching() && !sharedState()->isCanceled())
Q_EMIT progressRangeChanged(maximum);
}
void PromiseWatcher::promiseProgressValueChanged(int progressValue)
void PromiseWatcher::promiseProgressValueChanged(qlonglong progressValue)
{
if(isWatching() && !sharedState()->isCanceled())
Q_EMIT progressValueChanged(progressValue);
......@@ -92,12 +92,12 @@ bool PromiseWatcher::isFinished() const
return _finished;
}
int PromiseWatcher::progressMaximum() const
qlonglong PromiseWatcher::progressMaximum() const
{
return isWatching() ? sharedState()->totalProgressMaximum() : 0;
}
int PromiseWatcher::progressValue() const
qlonglong PromiseWatcher::progressValue() const
{
return isWatching() ? sharedState()->totalProgressValue() : 0;
}
......
......@@ -63,10 +63,10 @@ public:
bool isFinished() const;
/// Returns the maximum value for the progress of the shared state monitored by this object.
int progressMaximum() const;
qlonglong progressMaximum() const;
/// Returns the current value for the progress of the shared state monitored by this object.
int progressValue() const;
qlonglong progressValue() const;
/// Returns the status text of the shared state monitored by this object.
QString progressText() const;
......@@ -76,8 +76,8 @@ Q_SIGNALS:
void canceled();
void finished();
void started();
void progressRangeChanged(int maximum);
void progressValueChanged(int progressValue);
void progressRangeChanged(qlonglong maximum);
void progressValueChanged(qlonglong progressValue);
void progressTextChanged(const QString& progressText);
private Q_SLOTS:
......@@ -85,8 +85,8 @@ private Q_SLOTS:
void promiseCanceled();
void promiseFinished();
void promiseStarted();
void promiseProgressRangeChanged(int maximum);
void promiseProgressValueChanged(int progressValue);
void promiseProgressRangeChanged(qlonglong maximum);
void promiseProgressValueChanged(qlonglong progressValue);
void promiseProgressTextChanged(const QString& progressText);
private:
......
......@@ -26,7 +26,7 @@
namespace Ovito { OVITO_BEGIN_INLINE_NAMESPACE(Util) OVITO_BEGIN_INLINE_NAMESPACE(Concurrency)
bool SynchronousPromiseState::setProgressValue(int value)
bool SynchronousPromiseState::setProgressValue(qlonglong value)
{
// Yield control to the event loop to process user interface events.
// This is necessary so that the user can interrupt the running opertion.
......@@ -35,7 +35,7 @@ bool SynchronousPromiseState::setProgressValue(int value)
return PromiseStateWithProgress::setProgressValue(value);
}
bool SynchronousPromiseState::incrementProgressValue(int increment)
bool SynchronousPromiseState::incrementProgressValue(qlonglong increment)
{
// Yield control to the event loop to process user interface events.
// This is necessary so that the user can interrupt the running opertion.
......
......@@ -41,11 +41,11 @@ public:
/// Sets the current progress value (must be in the range 0 to progressMaximum()).
/// Returns false if the promise has been canceled.
virtual bool setProgressValue(int value) override;
virtual bool setProgressValue(qlonglong value) override;
/// Increments the progress value by 1.
/// Returns false if the promise has been canceled.
virtual bool incrementProgressValue(int increment = 1) override;
virtual bool incrementProgressValue(qlonglong increment = 1) override;
/// Changes the status text of this promise.
virtual void setProgressText(const QString& progressText) override;
......
......@@ -88,19 +88,19 @@ void ThreadSafePromiseState::addContinuationImpl(std::function<void()>&& cont)
PromiseStateWithProgress::addContinuationImpl(std::move(cont));
}
void ThreadSafePromiseState::setProgressMaximum(int maximum)
void ThreadSafePromiseState::setProgressMaximum(qlonglong maximum)
{
QMutexLocker locker(&_mutex);
PromiseStateWithProgress::setProgressMaximum(maximum);
}
bool ThreadSafePromiseState::setProgressValue(int value)
bool ThreadSafePromiseState::setProgressValue(qlonglong value)
{
QMutexLocker locker(&_mutex);
return PromiseStateWithProgress::setProgressValue(value);
}
bool ThreadSafePromiseState::incrementProgressValue(int increment)
bool ThreadSafePromiseState::incrementProgressValue(qlonglong increment)
{
QMutexLocker locker(&_mutex);
return PromiseStateWithProgress::incrementProgressValue(increment);
......
......@@ -46,15 +46,15 @@ public:
#endif
/// Sets the current maximum value for progress reporting.
virtual void setProgressMaximum(int maximum) override;
virtual void setProgressMaximum(qlonglong maximum) override;
/// Sets the current progress value (must be in the range 0 to progressMaximum()).
/// Returns false if the promise has been canceled.
virtual bool setProgressValue(int value) override;
virtual bool setProgressValue(qlonglong value) override;
/// Increments the progress value by 1.
/// Returns false if the promise has been canceled.
virtual bool incrementProgressValue(int increment = 1) override;
virtual bool incrementProgressValue(qlonglong increment = 1) override;
/// Changes the status text of this promise.
virtual void setProgressText(const QString& text) override;
......
......@@ -44,10 +44,10 @@ public:
#endif
/// Returns the maximum value for progress reporting.
virtual int progressMaximum() const override { return trackedState() ? trackedState()->progressMaximum() : 0; }
virtual qlonglong progressMaximum() const override { return trackedState() ? trackedState()->progressMaximum() : 0; }
/// Returns the current progress value (in the range 0 to progressMaximum()).
virtual int progressValue() const override { return trackedState() ? trackedState()->progressValue() : 0; }
virtual qlonglong progressValue() const override { return trackedState() ? trackedState()->progressValue() : 0; }
/// Return the current status text set for this promise.
virtual QString progressText() const override { return trackedState() ? trackedState()->progressText() : QString(); }
......