use of uk.ac.sussex.gdsc.smlm.ij.ij3d.Shape3DHelper.Rendering in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method getPoints.
/**
* Gets the points.
*
* @param results the results
* @param settings the settings
* @return the points
*/
static LocalList<Point3f> getPoints(MemoryPeakResults results, ImageJ3DResultsViewerSettingsOrBuilder settings) {
final LocalList<Point3f> points = new LocalList<>(results.size());
if (results.is3D()) {
results.forEach(DistanceUnit.NM, (XyzResultProcedure) (x, y, z) -> {
points.push(new Point3f(x, y, z));
});
} else {
results.forEach(DistanceUnit.NM, (XyResultProcedure) (x, y) -> {
points.push(new Point3f(x, y, 0));
});
final double range = settings.getDepthRange();
if (range > 0 && results.size() > 1) {
final DepthMode mode = DepthMode.forNumber(settings.getDepthMode());
final double min = -settings.getDepthRange() / 2;
switch(mode) {
case DITHER:
final SplitMix r = SplitMix.new64(settings.getDitherSeed());
for (int i = points.size(); i-- > 0; ) {
points.unsafeGet(i).z += (min + r.nextDouble() * range);
}
break;
case INTENSITY:
// Rank by intensity, highest first
final StandardResultProcedure p = new StandardResultProcedure(results);
p.getI();
final int[] indices = SimpleArrayUtils.natural(results.size());
SortUtils.sortIndices(indices, p.intensity, true);
final double inc = range / indices.length;
for (int i = 0; i < indices.length; i++) {
// The standard rendering has +z going away so put the highest rank at min
points.unsafeGet(indices[i]).z += (min + i * inc);
}
break;
case NONE:
break;
default:
throw new IllegalStateException("Unknown depth mode: " + mode);
}
}
}
return points;
}
use of uk.ac.sussex.gdsc.smlm.ij.ij3d.Shape3DHelper.Rendering in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method createMesh.
@SuppressWarnings("unused")
private static CustomMesh createMesh(final ImageJ3DResultsViewerSettingsOrBuilder settings, LocalList<Point3f> points, final Point3f[] sphereSize, float transparency, float[] alpha) {
// Coordinates + color
int stride = 3 + 3;
if (alpha != null) {
// add color alpha
stride++;
}
// Support drawing as points ...
if (settings.getRendering() == 0) {
final long arraySize = (long) points.size() * stride;
if (arraySize > CustomContentHelper.MAX_ARRAY_SIZE) {
final double capacity = (double) arraySize / CustomContentHelper.MAX_ARRAY_SIZE;
// @formatter:off
IJ.error(TITLE, TextUtils.wrap(String.format("The results will generate data of %d values. " + "This is amount of data is not supported (%.2fx capacity). " + "Please choose a different dataset with fewer points.", arraySize, capacity), 80));
// @formatter:on
return null;
}
CustomPointMesh mesh;
if (alpha != null) {
final TransparentItemPointMesh mesh2 = new TransparentItemPointMesh(points, null, transparency);
mesh = mesh2;
mesh2.setItemAlpha(alpha);
} else {
mesh = new ItemPointMesh(points, null, transparency);
}
mesh.setPointSize(sphereSize[0].x);
return mesh;
}
final Rendering r = Rendering.forNumber(settings.getRendering());
// Repeated mesh creation is much faster as the normals are cached.
// There does not appear to be a difference in the speed the image responds
// to user interaction between indexed or standard triangles.
// Currently the RepeatedIndexedTriangleMesh computes the normals a different way to
// the super class to preserve the orientation of the normals. So if the coordinates
// are modified through the mesh then the appearance will change. For now just use
// the RepeatedTriangleMesh.
// TODO - check this. It may not be true if the shading mode is flat...
// Also the IndexedTriangleMesh has one normal per vertex and this causes a colour fall-off
// on the triangle plane towards the edges. The TriangleMesh colours the entire surface
// of each triangle the same which looks 'normal'.
final List<Point3f> point = Shape3DHelper.createLocalisationObject(r);
// + normals
stride += 3;
final int singlePointSize = point.size();
final long size = (long) points.size() * singlePointSize;
final long arraySize = size * stride;
if (arraySize > CustomContentHelper.MAX_ARRAY_SIZE) {
final double capacity = (double) arraySize / CustomContentHelper.MAX_ARRAY_SIZE;
// @formatter:off
IJ.error(TITLE, TextUtils.wrap(String.format("The results will generate data of %d values. " + "This is amount of data is not supported (%.2fx capacity). " + "Please choose a different rendering model with fewer vertices.", arraySize, capacity), 80));
// @formatter:on
return null;
}
if (size > 10000000L) {
final ExtendedGenericDialog egd = new ExtendedGenericDialog(TITLE);
egd.addMessage("The results will generate a large mesh of " + size + " vertices.\nThis may take a long time to render and may run out of memory.");
egd.setOKLabel("Continue");
egd.showDialog();
if (egd.wasCanceled()) {
return null;
}
}
IJ.showStatus("Creating 3D mesh ...");
final double creaseAngle = (r.isHighResolution()) ? 44 : 0;
// Used for debugging construction time
final ImageJTrackProgress progress = null;
if (alpha != null) {
final TransparentItemTriangleMesh mesh = new TransparentItemTriangleMesh(point.toArray(new Point3f[singlePointSize]), points.toArray(new Point3f[0]), sphereSize, null, transparency, creaseAngle, progress);
mesh.setItemAlpha(alpha);
return mesh;
}
return new ItemTriangleMesh(point.toArray(new Point3f[singlePointSize]), points.toArray(new Point3f[0]), sphereSize, null, transparency, creaseAngle, progress);
}
use of uk.ac.sussex.gdsc.smlm.ij.ij3d.Shape3DHelper.Rendering in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method createItemMesh.
private static ItemMesh createItemMesh(final ImageJ3DResultsViewerSettingsOrBuilder settings, LocalList<Point3f> points, final Point3f[] sphereSize, float transparency, float[] alpha) {
final Rendering rendering = Rendering.forNumber(settings.getRendering());
final int colorDepth = (alpha != null) ? 4 : 3;
final Shape3D shape = Shape3DHelper.createShape(rendering, colorDepth);
final GeometryArray ga = (GeometryArray) shape.getGeometry();
final Appearance appearance = shape.getAppearance();
// Estimate the largest array required for the data.
// The mesh is created by reference using an array for coords, normals and colors.
final int singlePointVertexSize = ga.getValidVertexCount();
int singlePointIndexSize = 0;
final int stride = Math.max(3, colorDepth);
if (ga instanceof IndexedGeometryArray) {
// Indexed arrays may have much larger index array than the vertex array
singlePointIndexSize = ((IndexedGeometryArray) ga).getIndexCount();
}
final int singlePointSize = Math.max(singlePointIndexSize, stride * singlePointVertexSize);
final long arraySize = (long) points.size() * singlePointSize;
if (arraySize > CustomContentHelper.MAX_ARRAY_SIZE) {
final double capacity = (double) arraySize / CustomContentHelper.MAX_ARRAY_SIZE;
// @formatter:off
IJ.error(TITLE, TextUtils.wrap(String.format("The results will generate data of %d values. " + "This is amount of data is not supported (%.2fx capacity). " + "Please choose a different dataset with fewer points or " + "different rendering model.", arraySize, capacity), 80));
// @formatter:on
return null;
}
// Support drawing as points ...
if (settings.getRendering() == 0) {
final ItemMesh mesh = new ReferenceItemMesh(points.toArray(new Point3f[0]), ga, appearance, null, null, transparency);
if (alpha != null) {
mesh.setItemAlpha(alpha);
}
mesh.getAppearance().getPointAttributes().setPointSize(sphereSize[0].x);
return mesh;
}
final int triangles = Shape3DHelper.getNumberOfTriangles(rendering);
final long size = (long) points.size() * triangles;
if (size > 10000000L) {
final ExtendedGenericDialog egd = new ExtendedGenericDialog(TITLE);
egd.addMessage("The results will generate a large mesh of " + size + " triangles.\nThis may take a long time to render and may run out of memory.");
egd.setOKLabel("Continue");
egd.showDialog();
if (egd.wasCanceled()) {
return null;
}
}
IJ.showStatus("Creating 3D mesh ...");
final ItemMesh mesh = new ReferenceItemMesh(points.toArray(new Point3f[0]), ga, appearance, sphereSize, null, transparency);
if (alpha != null) {
mesh.setItemAlpha(alpha);
}
return mesh;
}
use of uk.ac.sussex.gdsc.smlm.ij.ij3d.Shape3DHelper.Rendering in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method updateAppearance.
private static void updateAppearance(CustomMesh mesh, final ImageJ3DResultsViewerSettingsOrBuilder settings) {
mesh.setShaded(settings.getShaded());
final Appearance appearance = mesh.getAppearance();
final PolygonAttributes pa = appearance.getPolygonAttributes();
// For all 3D polygons we want to support a true face orientation so transparency works
final Rendering r = Rendering.forNumber(settings.getRendering());
if (r.is2D()) {
pa.setCullFace(PolygonAttributes.CULL_NONE);
pa.setBackFaceNormalFlip(true);
} else {
pa.setCullFace(PolygonAttributes.CULL_BACK);
pa.setBackFaceNormalFlip(false);
}
// TransparencyAttributes ta = appearance.getTransparencyAttributes();
// ta.setSrcBlendFunction(TransparencyAttributes.BLEND_SRC_ALPHA);
// ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE);
// ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE_MINUS_SRC_ALPHA); // Default
ItemTriangleMesh.setTransparencyMode(TransparencyAttributes.FASTEST);
// ItemTriangleMesh.setTransparencyMode(TransparencyAttributes.SCREEN_DOOR);
// ItemTriangleMesh.setTransparencyMode(TransparencyAttributes.BLENDED);
final ColoringAttributes ca = appearance.getColoringAttributes();
if (r.isHighResolution() || r.is2D()) {
// Smooth across vertices. Required to show 2D surfaces smoothly
ca.setShadeModel(ColoringAttributes.SHADE_GOURAUD);
} else {
// Faster polygon rendering with flat shading
ca.setShadeModel(ColoringAttributes.SHADE_FLAT);
}
}
use of uk.ac.sussex.gdsc.smlm.ij.ij3d.Shape3DHelper.Rendering in project GDSC-SMLM by aherbert.
the class ImageJ3DResultsViewer method createShape.
@SuppressWarnings("unused")
private static Shape3D createShape(Builder settings) {
final LocalList<Point3f> points = new LocalList<>(1);
points.push(new Point3f());
// We try and match the geometry and appearance of the standard mesh.
// Do this by creating a mesh with a single point and get the Geometry and Appearance.
GeometryArray ga;
CustomMesh mesh;
final float transparency = getTransparency(settings);
// Support drawing as points ...
if (settings.getRendering() == 0) {
mesh = new TransparentItemPointMesh(points, null, transparency);
((ItemPointMesh) mesh).setPointSize((float) settings.getPixelSize());
updateAppearance(mesh, settings);
// Assume the TransparentItemPointMesh sets COLOR_4
ga = (GeometryArray) mesh.getGeometry();
} else {
final Rendering r = Rendering.forNumber(settings.getRendering());
final List<Point3f> point = Shape3DHelper.createLocalisationObject(r);
final Point3f[] vertices = point.toArray(new Point3f[1]);
// Correct the direction
ItemTriangleMesh.checkFacets(vertices);
final double creaseAngle = (r.isHighResolution()) ? 44 : 0;
mesh = new ItemTriangleMesh(vertices, points.toArray(new Point3f[1]), null, null, transparency, creaseAngle, null);
updateAppearance(mesh, settings);
final int nVertices = vertices.length;
ga = new TriangleArray(nVertices, GeometryArray.COORDINATES | GeometryArray.NORMALS);
// Copy the coords and normals. We don't require the vertex colours.
final float[] coords = new float[nVertices * 3];
final float[] normals = new float[nVertices * 3];
final GeometryArray gaToCopy = (GeometryArray) mesh.getGeometry();
gaToCopy.getCoordinates(0, coords);
gaToCopy.getNormals(0, normals);
ga.setCoordinates(0, coords);
ga.setNormals(0, normals);
ga.setValidVertexCount(nVertices);
}
return new Shape3D(ga, mesh.getAppearance());
}
Aggregations