Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Bioimage Analysis
3D Mesh ROI
Commits
3458c2aa
Commit
3458c2aa
authored
Aug 25, 2020
by
Amandine TOURNAY
Browse files
Initial commit
parents
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
.gitignore
0 → 100644
View file @
3458c2aa
.idea/
.settings/
build/
target/
*.iml
.classpath
.project
\ No newline at end of file
pom.xml
0 → 100644
View file @
3458c2aa
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.bioimageanalysis.icy
</groupId>
<artifactId>
icy-3d-mesh-roi
</artifactId>
<version>
1.4.7
</version>
<name>
3D Mesh ROI
</name>
<description>
SDK for 3D ROI creation and manipulation using polygonal (surface) and polyhedral (volume) meshes.
</description>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<jdk.version>
1.8
</jdk.version>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
<outputJar>
${project.build.outputDirectory}/../plugin
</outputJar>
</properties>
<build>
<finalName>
${project.artifactId}
</finalName>
<plugins>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-jar-plugin
</artifactId>
<version>
3.1.2
</version>
<configuration>
<outputDirectory>
${outputJar}
</outputDirectory>
<archive>
<manifest>
<addClasspath>
true
</addClasspath>
<mainClass>
plugins.adufour.roi.mesh.ROI3DMeshPlugin
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
org.bioimageanalysis.icy
</groupId>
<artifactId>
icy-kernel
</artifactId>
<version>
2.1.0
</version>
</dependency>
<dependency>
<groupId>
org.bioimageanalysis.icy
</groupId>
<artifactId>
icy-quickhull
</artifactId>
<version>
1.0.0
</version>
</dependency>
<dependency>
<groupId>
org.bioimageanalysis.icy
</groupId>
<artifactId>
icy-vecmath
</artifactId>
<version>
1.6.0
</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>
icy
</id>
<url>
https://icy-nexus.pasteur.fr/repository/Icy/
</url>
</repository>
</repositories>
<distributionManagement>
<snapshotRepository>
<id>
icy-dev
</id>
<name>
icy-dev
</name>
<url>
https://icy-nexus-dev.pasteur.cloud/repository/icy-core/
</url>
</snapshotRepository>
<repository>
<id>
icy-prod
</id>
<name>
icy-prod
</name>
<url>
https://icy-nexus.pasteur.fr/repository/icy-core/
</url>
</repository>
</distributionManagement>
</project>
\ No newline at end of file
src/main/java/plugins/adufour/roi/mesh/Cell3D.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh
;
import
plugins.adufour.roi.mesh.polygon.Polygon3D
;
import
plugins.adufour.roi.mesh.polyhedron.Polyhedron3D
;
/**
* Structural element of a generic {@link ROI3DMesh 3D mesh}.
*
* @see Polygon3D
* @see Polyhedron3D
* @author Alexandre Dufour
*/
public
abstract
class
Cell3D
{
/**
* The indices of the vertex forming this cell, in arbitrary order (it is up to the overriding
* classes to define how vertices should be ordered)
*/
public
final
int
[]
vertexIndices
;
/**
* The number of vertices in this face (point: 1, edge: 2, triangle: 3, quad: 4, etc.)
*/
public
final
int
size
;
/**
* Creates a new mesh cell from the specified vertex indices
*
* @param vertexIndices
*/
protected
Cell3D
(
int
...
vertexIndices
)
{
this
.
vertexIndices
=
new
int
[
vertexIndices
.
length
];
System
.
arraycopy
(
vertexIndices
,
0
,
this
.
vertexIndices
,
0
,
vertexIndices
.
length
);
size
=
vertexIndices
.
length
;
}
/**
* Creates a copy of this cell.
*/
public
abstract
Cell3D
clone
();
/**
* Indicates whether the specified vertex index belongs to this face
*
* @param index
* the vertex index to look for
* @return <code>true</code> if the index is present in this face, <code>false</code> otherwise
*/
public
boolean
contains
(
int
index
)
{
for
(
int
i
:
vertexIndices
)
if
(
i
==
index
)
return
true
;
return
false
;
}
/**
* @param vertexIndex
* @return a zero-based index where the specified vertex index has been found, or
* <code>-1</code> if the specified vertex index was not found
*/
public
int
indexOf
(
int
vertexIndex
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
if
(
vertexIndices
[
i
]
==
vertexIndex
)
return
i
;
return
-
1
;
}
/**
* Replaces a vertex index by another (or simply returns if the index to replace is not found in
* this cell)
*
* @param oldIndex
* the index of the old vertex
* @param newIndex
* the index of the new vertex
*/
public
void
replace
(
int
oldIndex
,
int
newIndex
)
{
int
position
=
indexOf
(
oldIndex
);
if
(
position
>=
0
)
vertexIndices
[
position
]
=
newIndex
;
}
/**
* Replaces the vertex indices with the specified indexes
*
* @param vertexIndices
* @throws IllegalArgumentException
* if the size of the specified list is different from the size of this cell
*/
public
void
setIndices
(
int
...
vertexIndices
)
throws
IllegalArgumentException
{
if
(
vertexIndices
.
length
!=
size
)
throw
new
IllegalArgumentException
(
"Invalid cell size: "
+
vertexIndices
.
length
);
System
.
arraycopy
(
vertexIndices
,
0
,
this
.
vertexIndices
,
0
,
size
);
}
}
src/main/java/plugins/adufour/roi/mesh/MeshTopologyException.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh
;
import
plugins.adufour.roi.mesh.polygon.ROI3DTriangularMesh
;
/**
* Exception that occurs when the topology of a {@link ROI3DMesh} is inconsistent. A typical example
* is when a {@link ROI3DTriangularMesh} is splitting as a result of a resampling operation, giving
* rise to two new meshes.
*
* @see ROI3DTriangularMesh#reSampleToAverageDistance(double, double)
* @author Alexandre Dufour
*/
public
class
MeshTopologyException
extends
Exception
{
private
static
final
long
serialVersionUID
=
1L
;
public
final
ROI3DMesh
<?>
source
;
public
final
ROI3DMesh
<?>[]
children
;
/**
* Creates a new Topology exception for the specified contour
*
* @param contour
* the contour undergoing a topology break
* @param children
* an array containing zero or more contours that should replace the contour raising
* the exception (typically when a mesh vanishes or splits as a result of a
* resampling operation)
*/
public
<
C
extends
Cell3D
>
MeshTopologyException
(
ROI3DMesh
<
C
>
contour
,
ROI3DMesh
<
C
>[]
children
)
{
super
(
"Topology break detected in contour "
+
contour
.
hashCode
());
this
.
source
=
contour
;
this
.
children
=
children
;
}
}
src/main/java/plugins/adufour/roi/mesh/ROI3DMesh.java
0 → 100644
View file @
3458c2aa
This diff is collapsed.
Click to expand it.
src/main/java/plugins/adufour/roi/mesh/ROI3DMeshPlugin.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh
;
import
icy.plugin.abstract_.Plugin
;
import
icy.plugin.interface_.PluginLibrary
;
/**
* Marks the entire package as an Icy plugin
*
* @author Alexandre Dufour
*/
public
class
ROI3DMeshPlugin
extends
Plugin
implements
PluginLibrary
{
}
src/main/java/plugins/adufour/roi/mesh/VTKMeshImporter.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.List
;
import
javax.swing.filechooser.FileFilter
;
import
icy.common.exception.UnsupportedFormatException
;
import
icy.file.FileUtil
;
import
icy.gui.frame.progress.FileFrame
;
import
icy.gui.viewer.Viewer
;
import
icy.image.IcyBufferedImage
;
import
icy.plugin.abstract_.PluginFileImporter
;
import
icy.sequence.Sequence
;
import
icy.system.thread.ThreadUtil
;
import
icy.type.DataType
;
import
icy.type.rectangle.Rectangle3D
;
import
plugins.adufour.roi.mesh.polygon.ROI3DPolygonalMesh
;
import
plugins.kernel.canvas.VtkCanvasPlugin
;
public
class
VTKMeshImporter
extends
PluginFileImporter
{
@Override
public
boolean
acceptFile
(
String
path
)
{
if
(
FileUtil
.
isDirectory
(
path
))
return
false
;
return
path
.
endsWith
(
"vtk"
)
||
path
.
endsWith
(
"vtk.txt"
);
}
@Override
public
List
<
FileFilter
>
getFileFilters
()
{
FileFilter
vtkFilter
=
new
FileFilter
()
{
@Override
public
String
getDescription
()
{
return
"VTK mesh files"
;
}
@Override
public
boolean
accept
(
File
f
)
{
return
f
.
isDirectory
()
||
acceptFile
(
f
.
getPath
());
}
};
return
Arrays
.
asList
(
vtkFilter
);
}
@Override
public
boolean
load
(
String
path
,
FileFrame
loadingFrame
)
throws
UnsupportedFormatException
,
IOException
{
Sequence
sequence
=
getActiveSequence
();
boolean
newSequence
=
false
;
if
(
sequence
==
null
)
{
// Create a fake Sequence
sequence
=
new
Sequence
(
FileUtil
.
getFileName
(
path
,
false
));
addSequence
(
sequence
);
newSequence
=
true
;
}
if
(
loadingFrame
!=
null
)
loadingFrame
.
setTitle
(
"Importing "
+
FileUtil
.
getFileName
(
path
)
+
"..."
);
final
ROI3DMesh
<?>
mesh
=
new
ROI3DPolygonalMesh
();
// mesh.setPixelSize(new Point3d(sequence.getPixelSizeX(), sequence.getPixelSizeY(), sequence.getPixelSizeZ()));
mesh
.
loadFromVTK
(
new
File
(
path
));
if
(
newSequence
)
{
Rectangle3D
.
Integer
bounds
=
mesh
.
getBounds
();
// Add a fake image
sequence
.
addImage
(
new
IcyBufferedImage
(
bounds
.
sizeX
,
bounds
.
sizeY
,
1
,
DataType
.
UBYTE
));
final
Sequence
theSequence
=
sequence
;
ThreadUtil
.
invokeLater
(
new
Runnable
()
{
@Override
public
void
run
()
{
Viewer
viewer
=
theSequence
.
getFirstViewer
();
if
(
viewer
!=
null
)
viewer
.
setCanvas
(
VtkCanvasPlugin
.
class
.
getName
());
}
},
true
);
}
sequence
.
addROI
(
mesh
);
return
true
;
}
}
src/main/java/plugins/adufour/roi/mesh/Vertex3D.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh
;
import
java.util.HashSet
;
import
java.util.Set
;
import
javax.vecmath.Point3d
;
import
javax.vecmath.Vector3d
;
/**
* Structural element of a {@link ROI3DMesh 3D mesh}, representing a position in 3D space. This
* class can be overridden to provide additional functionalities, under the condition that
* subclasses also override the {@link #clone()} method accordingly.
*
* @author Alexandre Dufour
*/
public
class
Vertex3D
{
public
final
Point3d
position
=
new
Point3d
();
public
final
Vector3d
normal
=
new
Vector3d
();
public
final
Set
<
Integer
>
neighbors
;
protected
Vertex3D
(
Vertex3D
v
)
{
this
(
v
.
position
,
v
.
neighbors
);
}
protected
Vertex3D
(
Point3d
position
)
{
this
(
position
,
0
);
}
protected
Vertex3D
(
Point3d
position
,
int
nbNeighbors
)
{
// if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
// {
// System.out.println("oups !");
// }
this
.
position
.
set
(
position
);
this
.
neighbors
=
new
HashSet
<
Integer
>(
nbNeighbors
);
}
public
Vertex3D
(
Point3d
position
,
Set
<
Integer
>
neighbors
)
{
this
(
position
,
neighbors
.
size
());
for
(
Integer
i
:
neighbors
)
this
.
neighbors
.
add
(
i
.
intValue
());
}
public
Vertex3D
clone
()
{
return
new
Vertex3D
(
this
);
}
public
double
distanceTo
(
Vertex3D
v
)
{
return
position
.
distance
(
v
.
position
);
}
public
double
distanceSqTo
(
Vertex3D
v
)
{
return
position
.
distanceSquared
(
v
.
position
);
}
public
String
toString
()
{
return
"Vertex {"
+
position
.
x
+
","
+
position
.
y
+
","
+
position
.
z
+
"} ("
+
neighbors
.
size
()
+
" neighbors)"
;
}
}
src/main/java/plugins/adufour/roi/mesh/polygon/Polygon3D.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh.polygon
;
import
java.util.List
;
import
javax.vecmath.Point3d
;
import
javax.vecmath.Vector3d
;
import
plugins.adufour.roi.mesh.Cell3D
;
import
plugins.adufour.roi.mesh.Vertex3D
;
/**
* Structural element of a {@link ROI3DPolygonalMesh 3D polygonal mesh}, representing a flat polygon
* in 3D space. A polygon does not store the vertex locations <i>per se</i>, but rather stores their
* indices in the vertex buffer of the corresponding mesh. By convention, polygon vertices are
* stored in counter-clockwise order when looking at the front of the face
*
* @author Alexandre Dufour
*/
public
class
Polygon3D
extends
Cell3D
{
/**
* Creates a new polygon from the specified vertex indices. This constructor is protected as it
* should not be used directly by client code. Client code should use
* {@link ROI3DPolygonalMesh#createCell(int[])} instead
*
* @param vertexIndices
* the vertex indices, in counter-clockwise order
*/
protected
Polygon3D
(
int
...
vertexIndices
)
{
super
(
vertexIndices
);
}
@Override
public
Polygon3D
clone
()
{
return
new
Polygon3D
(
this
.
vertexIndices
);
}
/**
* Indicates whether the edge formed by the specified vertex indices belongs to this face
*
* @param vertexIndex1
* the index of the edge's first vertex
* @param vertexIndex2
* the index of the edge's second vertex
* @param inThatOrder
* <code>true</code> if the two indices must be found in the specified order
* (suggesting counter-clockwise ordering by convention), or <code>false</code> if
* the order is unimportant
* @return
*/
public
boolean
containsEdge
(
int
vertexIndex1
,
int
vertexIndex2
,
boolean
inThatOrder
)
{
int
i1
=
indexOf
(
vertexIndex1
);
int
i2
=
indexOf
(
vertexIndex2
);
if
(
i1
==
-
1
||
i2
==
-
1
)
return
false
;
return
!
inThatOrder
||
((
i1
+
1
)
%
size
==
i2
);
}
/**
* Calculate the surface of this polygon, using the specified vertex list to fetch the vertex
* positions
*
* @param vertices
* the vertex list where to fetch the positions from
* @return the surface of this polygon
*/
public
double
getArea
(
List
<
Vertex3D
>
vertices
)
{
Vector3d
v12
=
new
Vector3d
();
Vector3d
v13
=
new
Vector3d
();
Vector3d
cross
=
new
Vector3d
();
// if the face has more than 3 vertices,
// split it into a triangle fan
// the first vertex of the fan never changes
// => has to be a vector for the final cross product
Vector3d
v1
=
new
Vector3d
(
vertices
.
get
(
vertexIndices
[
0
]).
position
);
double
surface
=
0
;
for
(
int
i
=
1
;
i
<
size
-
1
;
i
++)
{
Point3d
v2
=
vertices
.
get
(
vertexIndices
[
i
]).
position
;
Point3d
v3
=
vertices
.
get
(
vertexIndices
[
i
+
1
]).
position
;
v12
.
sub
(
v2
,
v1
);
v13
.
sub
(
v3
,
v1
);
cross
.
cross
(
v12
,
v13
);
double
surf
=
cross
.
length
()
*
0.5f
;
surface
+=
surf
;
}
return
surface
;
}
/**
* Indicates whether the specified edge follows the ordering convention of this cell (this is
* implementation dependent)
*
* @param v1
* the first vertex index
* @param v2
* the second vertex index
* @return <code>true</code> if <code>v1</code> and <code>v2</code> are ordered following the
* convention in this cell (counter-clockwise in the present case), and
* <code>false</code> otherwise
* @throws IllegalArgumentException
* if one of the given indices does not belong to this cell
*/
public
boolean
isEdgeOrdered
(
int
v1
,
int
v2
)
throws
IllegalArgumentException
{
int
i1
=
indexOf
(
v1
);
if
(
i1
==
-
1
)
throw
new
IllegalArgumentException
(
"Vertex index "
+
i1
+
" does not belong to this face"
);
int
i2
=
indexOf
(
v2
);
if
(
i2
==
-
1
)
throw
new
IllegalArgumentException
(
"Vertex index "
+
i2
+
" does not belong to this face"
);
return
(
i1
+
1
)
%
size
==
i2
;
}
}
src/main/java/plugins/adufour/roi/mesh/polygon/ROI3DPolygonalMesh.java
0 → 100644
View file @
3458c2aa
This diff is collapsed.
Click to expand it.
src/main/java/plugins/adufour/roi/mesh/polygon/ROI3DTriangularMesh.java
0 → 100644
View file @
3458c2aa
This diff is collapsed.
Click to expand it.
src/main/java/plugins/adufour/roi/mesh/polyhedron/Polyhedron3D.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh.polyhedron
;
import
java.util.List
;
import
javax.vecmath.Point3d
;
import
plugins.adufour.roi.mesh.Cell3D
;
import
plugins.adufour.roi.mesh.ROI3DMesh
;
import
plugins.adufour.roi.mesh.Vertex3D
;
import
vtk.vtkCell3D
;
/**
* Generic structural element of a {@link ROI3DPolyhedralMesh 3D polyhedral mesh}
*
* @see Tetrahedron3D
* @author Alexandre Dufour
*/
public
abstract
class
Polyhedron3D
extends
Cell3D
{
/**
* Creates a new polygon from the specified vertex indices. This constructor is protected as it
* should not be used directly by client code. Client code should use
* {@link ROI3DPolyhedralMesh#createCell(int[])} instead
*
* @param vertexIndices
* the vertex indices, in an order allowed by the local convention
*/
protected
Polyhedron3D
(
int
...
vertexIndices
)
{
super
(
vertexIndices
);
}
/**
* @return a VTK representation of this polyhedron
*/
public
abstract
vtkCell3D
createVTKCell
();
}
src/main/java/plugins/adufour/roi/mesh/polyhedron/Pyramid3D.java
0 → 100644
View file @
3458c2aa
package
plugins.adufour.roi.mesh.polyhedron
;
import
vtk.vtkCell3D
;