Skip to content
Snippets Groups Projects
Commit 6412ac23 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch 'issue121' into 'master'

cross section visitor optimised

See merge request grp-fidentis/analyst2!135
parents 86d571d4 1160ce6f
No related branches found
No related tags found
No related merge requests found
Showing
with 508 additions and 103 deletions
...@@ -2,12 +2,14 @@ package cz.fidentis.analyst.symmetry; ...@@ -2,12 +2,14 @@ package cz.fidentis.analyst.symmetry;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d; import javax.vecmath.Vector3d;
/** /**
* Symmetry plane. * Symmetry plane.
* *
* @author Natalia Bebjakova * @author Natalia Bebjakova
* @author Dominik Racek
*/ */
public class Plane implements Serializable { public class Plane implements Serializable {
...@@ -103,12 +105,21 @@ public class Plane implements Serializable { ...@@ -103,12 +105,21 @@ public class Plane implements Serializable {
} }
public Vector3d getNormal() { public Vector3d getNormal() {
return normal; return new Vector3d(normal);
} }
public double getDistance() { public double getDistance() {
return distance; return distance;
} }
/**
* Translate the plane along its normal
*
* @param value
*/
public void translate(double value) {
this.distance += value;
}
protected void setNormal(Vector3d normal) { protected void setNormal(Vector3d normal) {
this.normal = normal; this.normal = normal;
...@@ -117,4 +128,32 @@ public class Plane implements Serializable { ...@@ -117,4 +128,32 @@ public class Plane implements Serializable {
protected void setDistance(double dist) { protected void setDistance(double dist) {
this.distance = dist; this.distance = dist;
} }
/**
* Calculates an intersection of a plane and a line given by two points
*
* @param p1 first point of the line
* @param p2 second point of the line
* @return The point of intersection of null if no point found
*/
public Point3d getIntersectionWithLine(Point3d p1, Point3d p2) {
double distance1 = ((normal.x * p1.x) + (normal.y * p1.y) + (normal.z * p1.z) + distance)
/ Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
double distance2 = ((normal.x * p2.x) + (normal.y * p2.y) + (normal.z * p2.z) + distance)
/ Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
double t = distance1 / (distance1 - distance2);
if (distance1 * distance2 > 0) {
return null;
}
Point3d output = new Point3d(p2);
output.sub(p1);
output.scale(t);
output.add(p1);
return output;
}
} }
package cz.fidentis.analyst.visitors.mesh; package cz.fidentis.analyst.visitors.mesh;
import cz.fidentis.analyst.Logger;
import cz.fidentis.analyst.mesh.MeshVisitor; import cz.fidentis.analyst.mesh.MeshVisitor;
import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshTriangle; import cz.fidentis.analyst.mesh.core.MeshTriangle;
import cz.fidentis.analyst.symmetry.Plane;
import javax.vecmath.Point3d; import javax.vecmath.Point3d;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* A visitor that calculates the cross-section of a face and a cutting plane. * A visitor that calculates the cross-section of a face and a cutting plane using the triangles.
* <p> * <p>
* This visitor is thread-safe. * This visitor is thread-safe.
* </p> * </p>
...@@ -18,39 +22,142 @@ import java.util.List; ...@@ -18,39 +22,142 @@ import java.util.List;
*/ */
public class CrossSection extends MeshVisitor { public class CrossSection extends MeshVisitor {
private List<Point3d> points; private List<Point3d> points;
private MeshFacet plane; private Set<Point3d> usedPoints;
private Plane plane;
private Set<MeshTriangle> visited;
/** /**
* Constructor * Constructor
* @param plane the cutting plane * @param plane the cutting plane
*/ */
public CrossSection(MeshFacet plane) { public CrossSection(Plane plane) {
this.plane = plane; this.plane = plane;
this.points = new ArrayList<>(); this.points = new ArrayList<>();
this.usedPoints = new HashSet<>();
}
private List<MeshTriangle> getValidNeighboringTriangles(MeshFacet facet, MeshTriangle tri) {
List<MeshTriangle> output = facet.getNeighboringTriangles(tri);
output.removeIf(n -> ((visited.contains(n))
|| (!n.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance()))));
return output;
}
private List<MeshTriangle> getValidAdjacentTriangles(MeshFacet facet, MeshTriangle tri) {
List<MeshTriangle> output = facet.getAdjacentTriangles(tri);
output.removeIf(n -> ((visited.contains(n))
|| (!n.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance()))));
return output;
}
private void addPoint(MeshTriangle tri, MeshTriangle previous, boolean direction) {
List<Point3d> commonEdge = tri.getCommonPoints(previous);
if (commonEdge.size() == 2) {
Point3d p = plane.getIntersectionWithLine(commonEdge.get(0), commonEdge.get(1));
if (p == null) {
return;
}
if (!usedPoints.contains(p)) {
usedPoints.add(p);
if (direction) {
points.add(p);
} else {
points.add(0, p);
}
}
}
}
private void visitMeshFacetRec(MeshFacet facet, MeshTriangle tri, MeshTriangle previous, boolean direction) {
visited.add(tri);
// Depending on the direction, add the point to the start or to the end of points
addPoint(tri, previous, direction);
// Recursively call to the end
// Get all neighbors that have not been visited and are intercepted
List<MeshTriangle> neighbors = getValidNeighboringTriangles(facet, tri);
// If no valid neighbours are found, try to look further
if (neighbors.size() == 0) {
neighbors = getValidAdjacentTriangles(facet, tri);
}
if (neighbors.size() == 1) {
//Only one neighbor - go there
visitMeshFacetRec(facet, neighbors.get(0), tri, direction);
} else if (neighbors.size() == 2) {
//Two neighbors - they are valid to each other, but one of them has another valid neighbor.
// Select the one that only has the other as a neighbor so the route is linear.
List<MeshTriangle> valid = getValidNeighboringTriangles(facet, neighbors.get(0));
if (valid.size() == 1) {
visitMeshFacetRec(facet, neighbors.get(0), tri, direction);
} else {
visitMeshFacetRec(facet, neighbors.get(1), tri, direction);
}
}
} }
@Override @Override
public void visitMeshFacet(MeshFacet facet) { public void visitMeshFacet(MeshFacet facet) {
//TODO Dont check every triangle, find first and then check it's neighbors and new neighbors and so on Logger out = Logger.measureTime();
this.visited = new HashSet<>();
synchronized (this) { synchronized (this) {
Point3d last = null;
// Find the first triangle
MeshTriangle first = null;
for (MeshTriangle tri : facet) { for (MeshTriangle tri : facet) {
if (tri.checkIntersectionWithPlane(plane)) { if (tri.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance())) {
Point3d p = tri.getVertex1(); first = tri;
break;
// Check for duplicates }
if (last != null) { }
if (last == p) {
continue;
}
}
points.add(p); if (first == null) {
last = p; return;
}
// Set found and visited and add to points
visited.add(first);
// Find the valid neighboring triangles and act based on the amount
List<MeshTriangle> neighbors = getValidNeighboringTriangles(facet, first);
if (neighbors.size() == 1) {
//Only one neighbor - go there
visitMeshFacetRec(facet, neighbors.get(0), first, true);
} else if (neighbors.size() == 2) {
//Two neighbors - one on each side
visitMeshFacetRec(facet, neighbors.get(0), first, true);
visitMeshFacetRec(facet, neighbors.get(1), first, false);
} else if (neighbors.size() == 3) {
//Three neighbors - select the two with only one valid neighbor
List<MeshTriangle> valid = getValidNeighboringTriangles(facet, neighbors.get(0));
if (valid.size() == 1) {
//Index 0 is one of the correct ones, find the other
visitMeshFacetRec(facet, neighbors.get(0), first, true);
List<MeshTriangle> valid1 = getValidNeighboringTriangles(facet, neighbors.get(1));
if (valid1.size() == 1) {
visitMeshFacetRec(facet, neighbors.get(1), first, false);
} else {
visitMeshFacetRec(facet, neighbors.get(2), first, false);
}
} else {
//Index 0 is not one of the correct ones, 1 and 2 are
visitMeshFacetRec(facet, neighbors.get(1), first, true);
visitMeshFacetRec(facet, neighbors.get(2), first, false);
} }
} }
} }
out.printDuration("Cross section with triangle method");
} }
public List<Point3d> getPoints() { public List<Point3d> getPoints() {
......
package cz.fidentis.analyst.visitors.mesh;
import cz.fidentis.analyst.Logger;
import cz.fidentis.analyst.mesh.MeshVisitor;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshTriangle;
import cz.fidentis.analyst.symmetry.Plane;
import javax.vecmath.Point3d;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* A visitor that calculates the cross-section of a face and a cutting plane using the edges between triangles.
* <p>
* This visitor is thread-safe.
* </p>
*
* @author Dominik Racek
*/
public class CrossSectionZigZag extends MeshVisitor {
private List<Point3d> points;
private Set<Point3d> usedPoints;
private Set<MeshTriangle> visited;
private Plane plane;
public CrossSectionZigZag(Plane plane) {
this.plane = plane;
this.points = new ArrayList<>();
this.usedPoints = new HashSet<>();
}
private void addPoint(Point3d p, boolean direction) {
if (!usedPoints.contains(p)) {
usedPoints.add(p);
if (direction) {
points.add(p);
} else {
points.add(0, p);
}
}
}
private void visitMeshFacetRec(MeshFacet facet, int p1, int p2, MeshTriangle previous, boolean direction) {
List<MeshTriangle> triangles = facet.getAdjacentTriangles(p1, p2);
triangles.remove(previous);
if (triangles.isEmpty()) {
return;
}
//Find the next intersected edge
MeshTriangle current = triangles.get(0);
if (visited.contains(current)) {
return;
}
visited.add(current);
//Find the index of the last vertex of current (first ones being p1 and p2)
int p3;
if (current.index1 != p1 && current.index1 != p2) {
p3 = current.index1;
} else if (current.index2 != p1 && current.index2 != p2) {
p3 = current.index2;
} else {
p3 = current.index3;
}
//Next intersected edge will be between p1-p3 or p2-p3
Point3d intersection = plane.getIntersectionWithLine(facet.getVertex(p1).getPosition(),
facet.getVertex(p3).getPosition());
if (intersection == null) {
intersection = plane.getIntersectionWithLine(facet.getVertex(p2).getPosition(),
facet.getVertex(p3).getPosition());
addPoint(intersection, direction);
visitMeshFacetRec(facet, p2, p3, current, direction);
} else {
addPoint(intersection, direction);
visitMeshFacetRec(facet, p1, p3, current, direction);
}
}
@Override
public void visitMeshFacet(MeshFacet facet) {
Logger out = Logger.measureTime();
visited = new HashSet<>();
synchronized (this) {
// Find the first triangle
MeshTriangle first = null;
for (MeshTriangle tri : facet) {
if (tri.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance())) {
first = tri;
break;
}
}
if (first == null) {
return;
}
visited.add(first);
//Figure out which lines are intersected
Point3d intersection1 = plane.getIntersectionWithLine(first.getVertex1(), first.getVertex2());
Point3d intersection2 = plane.getIntersectionWithLine(first.getVertex2(), first.getVertex3());
Point3d intersection3 = plane.getIntersectionWithLine(first.getVertex3(), first.getVertex1());
if (intersection1 != null) {
//Intersection 1
visitMeshFacetRec(facet, first.index1, first.index2, first, true);
if (intersection2 != null) {
//Intersection 1 and 2
visitMeshFacetRec(facet, first.index2, first.index3, first, false);
} else if (intersection3 != null) {
//Intersection 1 and 3
visitMeshFacetRec(facet, first.index3, first.index1, first, false);
}
} else if (intersection2 != null) {
//Intersection 2
visitMeshFacetRec(facet, first.index2, first.index3, first, true);
if (intersection3 != null) {
//Intersection 2 and 3
visitMeshFacetRec(facet, first.index3, first.index1, first, false);
}
} else if (intersection3 != null) {
//Intersection 3 only
visitMeshFacetRec(facet, first.index3, first.index1, first, true);
}
//No intersection
}
out.printDuration("Cross section with zigzag method");
}
public List<Point3d> getPoints() {
return points;
}
}
...@@ -4,6 +4,8 @@ import cz.fidentis.analyst.mesh.core.MeshFacet; ...@@ -4,6 +4,8 @@ import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.symmetry.Plane; import cz.fidentis.analyst.symmetry.Plane;
import javax.vecmath.Vector3d;
/** /**
* A cutting plane. * A cutting plane.
* *
...@@ -36,6 +38,30 @@ public class DrawablePlane extends DrawableMesh { ...@@ -36,6 +38,30 @@ public class DrawablePlane extends DrawableMesh {
if (plane == null) { if (plane == null) {
throw new IllegalArgumentException("plane"); throw new IllegalArgumentException("plane");
} }
this.plane = plane; this.plane = new Plane(plane);
}
public Plane getPlane() {
return plane;
}
/**
* Translate the plane along its normal
*
* @param value
*/
public void translatePlane(double value) {
// Move real plane
this.plane.translate(value);
// Move Drawable plane
Vector3d move = this.plane.getNormal();
move.x *= value;
move.y *= value;
move.z *= value;
for (int i = 0; i < 4; ++i) {
getFacets().get(0).getVertex(i).getPosition().sub(move);
}
} }
} }
...@@ -7,8 +7,6 @@ import java.awt.Graphics; ...@@ -7,8 +7,6 @@ import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Stroke; import java.awt.Stroke;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.vecmath.Point3d; import javax.vecmath.Point3d;
...@@ -38,33 +36,11 @@ public class PolylinePanel extends JPanel { ...@@ -38,33 +36,11 @@ public class PolylinePanel extends JPanel {
private double scale = Double.POSITIVE_INFINITY; private double scale = Double.POSITIVE_INFINITY;
/**
* Comparator for Point3d based on Y value
*
* @author Dominik Racek
*/
public class CompareY implements Comparator<Point3d> {
/**
* Compare two Points3d objects
*/
public int compare(final Point3d a, final Point3d b) {
if (a.y < b.y) {
return -1;
} else if (a.y > b.y) {
return 1;
} else {
return 0;
}
}
}
/** /**
* Constructor for one face * Constructor for one face
*/ */
public PolylinePanel(List<Point3d> values) { public PolylinePanel(List<Point3d> values) {
this.primaryPoints = values; this.primaryPoints = values;
Collections.sort(this.primaryPoints, new CompareY());
} }
/** /**
...@@ -73,8 +49,6 @@ public class PolylinePanel extends JPanel { ...@@ -73,8 +49,6 @@ public class PolylinePanel extends JPanel {
public PolylinePanel(List<Point3d> primaryPoints, List<Point3d> secondaryPoints) { public PolylinePanel(List<Point3d> primaryPoints, List<Point3d> secondaryPoints) {
this.primaryPoints = primaryPoints; this.primaryPoints = primaryPoints;
this.secondaryPoints = secondaryPoints; this.secondaryPoints = secondaryPoints;
Collections.sort(this.primaryPoints, new CompareY());
Collections.sort(this.secondaryPoints, new CompareY());
} }
protected void drawFace(Graphics2D g2, List<Point3d> values, Color faceColor, boolean isPrimary) { protected void drawFace(Graphics2D g2, List<Point3d> values, Color faceColor, boolean isPrimary) {
...@@ -168,7 +142,6 @@ public class PolylinePanel extends JPanel { ...@@ -168,7 +142,6 @@ public class PolylinePanel extends JPanel {
*/ */
public void setPrimaryPoints(List<Point3d> points) { public void setPrimaryPoints(List<Point3d> points) {
this.primaryPoints = points; this.primaryPoints = points;
Collections.sort(this.primaryPoints, new CompareY());
repaint(); repaint();
} }
...@@ -180,7 +153,6 @@ public class PolylinePanel extends JPanel { ...@@ -180,7 +153,6 @@ public class PolylinePanel extends JPanel {
*/ */
public void setPrimaryMirrorPoints(List<Point3d> points) { public void setPrimaryMirrorPoints(List<Point3d> points) {
this.primaryMirrorPoints = points; this.primaryMirrorPoints = points;
Collections.sort(this.primaryMirrorPoints, new CompareY());
repaint(); repaint();
} }
...@@ -191,7 +163,6 @@ public class PolylinePanel extends JPanel { ...@@ -191,7 +163,6 @@ public class PolylinePanel extends JPanel {
*/ */
public void setSecondaryPoints(List<Point3d> points) { public void setSecondaryPoints(List<Point3d> points) {
this.secondaryPoints = points; this.secondaryPoints = points;
Collections.sort(this.secondaryPoints, new CompareY());
repaint(); repaint();
} }
...@@ -203,7 +174,6 @@ public class PolylinePanel extends JPanel { ...@@ -203,7 +174,6 @@ public class PolylinePanel extends JPanel {
*/ */
public void setSecondaryMirrorPoints(List<Point3d> points) { public void setSecondaryMirrorPoints(List<Point3d> points) {
this.secondaryMirrorPoints = points; this.secondaryMirrorPoints = points;
Collections.sort(this.secondaryMirrorPoints, new CompareY());
repaint(); repaint();
} }
......
...@@ -3,6 +3,7 @@ package cz.fidentis.analyst.symmetry; ...@@ -3,6 +3,7 @@ package cz.fidentis.analyst.symmetry;
import cz.fidentis.analyst.canvas.Canvas; import cz.fidentis.analyst.canvas.Canvas;
import cz.fidentis.analyst.core.ControlPanelAction; import cz.fidentis.analyst.core.ControlPanelAction;
import cz.fidentis.analyst.visitors.mesh.CrossSection; import cz.fidentis.analyst.visitors.mesh.CrossSection;
import cz.fidentis.analyst.visitors.mesh.CrossSectionZigZag;
import org.openide.filesystems.FileChooserBuilder; import org.openide.filesystems.FileChooserBuilder;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
...@@ -36,6 +37,8 @@ public class ProfilesAction extends ControlPanelAction { ...@@ -36,6 +37,8 @@ public class ProfilesAction extends ControlPanelAction {
private List<Point3d> primaryMirrorPoints; private List<Point3d> primaryMirrorPoints;
private List<Point3d> secondaryMirrorPoints; private List<Point3d> secondaryMirrorPoints;
private double lastSliderValue = 0.5;
/** /**
* Constructor. * Constructor.
* *
...@@ -119,24 +122,24 @@ public class ProfilesAction extends ControlPanelAction { ...@@ -119,24 +122,24 @@ public class ProfilesAction extends ControlPanelAction {
private void recomputePrimaryProfile() { private void recomputePrimaryProfile() {
//Main profile //Main profile
CrossSection cs = new CrossSection(getScene().getDrawableCuttingPlane(0).getFacets().get(0)); CrossSectionZigZag cs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(0).getPlane());
getPrimaryDrawableFace().getModel().compute(cs); getPrimaryDrawableFace().getModel().compute(cs);
this.primaryPoints = cs.getPoints(); this.primaryPoints = cs.getPoints();
//Mirror profile //Mirror profile
CrossSection mcs = new CrossSection(getScene().getDrawableMirrorPlane(0).getFacets().get(0)); CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(0).getPlane());
getPrimaryDrawableFace().getModel().compute(mcs); getPrimaryDrawableFace().getModel().compute(mcs);
this.primaryMirrorPoints = mcs.getPoints(); this.primaryMirrorPoints = mcs.getPoints();
} }
private void recomputeSecondaryProfile() { private void recomputeSecondaryProfile() {
//Main profile //Main profile
CrossSection cs = new CrossSection(getScene().getDrawableCuttingPlane(1).getFacets().get(0)); CrossSectionZigZag cs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(1).getPlane());
getSecondaryDrawableFace().getModel().compute(cs); getSecondaryDrawableFace().getModel().compute(cs);
this.secondaryPoints = cs.getPoints(); this.secondaryPoints = cs.getPoints();
//Mirror profile //Mirror profile
CrossSection mcs = new CrossSection(getScene().getDrawableMirrorPlane(1).getFacets().get(0)); CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(1).getPlane());
getSecondaryDrawableFace().getModel().compute(mcs); getSecondaryDrawableFace().getModel().compute(mcs);
this.secondaryMirrorPoints = mcs.getPoints(); this.secondaryMirrorPoints = mcs.getPoints();
} }
...@@ -154,9 +157,18 @@ public class ProfilesAction extends ControlPanelAction { ...@@ -154,9 +157,18 @@ public class ProfilesAction extends ControlPanelAction {
} }
private void setCuttingPlaneOffset(int index, double value) { private void setCuttingPlaneOffset(int index, double value) {
for (int i = 0; i < 4; ++i) { //Move cutting planes left and mirror planes right
getScene().getDrawableCuttingPlane(index).getFacets().get(0).getVertex(i).getPosition().x = value; //If normal is negative, need to negate value
getScene().getDrawableMirrorPlane(index).getFacets().get(0).getVertex(i).getPosition().x = value * -1.0; if (getScene().getDrawableCuttingPlane(index).getPlane().getNormal().x < 0) {
getScene().getDrawableCuttingPlane(index).translatePlane(-value);
} else {
getScene().getDrawableCuttingPlane(index).translatePlane(value);
}
if (getScene().getDrawableMirrorPlane(index).getPlane().getNormal().x < 0) {
getScene().getDrawableMirrorPlane(index).translatePlane(value);
} else {
getScene().getDrawableMirrorPlane(index).translatePlane(-value);
} }
} }
...@@ -176,20 +188,28 @@ public class ProfilesAction extends ControlPanelAction { ...@@ -176,20 +188,28 @@ public class ProfilesAction extends ControlPanelAction {
break; break;
case ProfilesPanel.ACTION_COMMAND_EXPORT: case ProfilesPanel.ACTION_COMMAND_EXPORT:
exportProfile(this.primaryPoints, "Export primary face profile to file"); exportProfile(this.primaryPoints, "Export primary face profile to file");
if (controlPanel.isMirrorCutsChecked()) {
exportProfile(this.primaryMirrorPoints, "Export primary face mirror profile to file");
}
if (getSecondaryDrawableFace() != null) { if (getSecondaryDrawableFace() != null) {
exportProfile(this.secondaryPoints, "Export secondary face profile to file"); exportProfile(this.secondaryPoints, "Export secondary face profile to file");
if (controlPanel.isMirrorCutsChecked()) {
exportProfile(this.secondaryMirrorPoints, "Export secondary face mirror profile to file");
}
} }
break; break;
case ProfilesPanel.ACTION_OFFSET_CUTTING_PLANE: case ProfilesPanel.ACTION_OFFSET_CUTTING_PLANE:
double value = controlPanel.getOffsetValue(); double value = controlPanel.getOffsetValue() - lastSliderValue;
double multiplier = 150; double multiplier = -150;
setCuttingPlaneOffset(0, multiplier * (value - 0.5)); setCuttingPlaneOffset(0, multiplier * value);
if (getSecondaryDrawableFace() != null) { if (getSecondaryDrawableFace() != null) {
setCuttingPlaneOffset(1, multiplier * (value - 0.5)); setCuttingPlaneOffset(1, multiplier * value);
} }
recomputeProfiles(); recomputeProfiles();
lastSliderValue = controlPanel.getOffsetValue();
break; break;
case ProfilesPanel.ACTION_COMMAND_RECOMPUTE: case ProfilesPanel.ACTION_COMMAND_RECOMPUTE:
recomputeProfiles(); recomputeProfiles();
......
...@@ -117,26 +117,15 @@ public class ProfilesPanel extends ControlPanel { ...@@ -117,26 +117,15 @@ public class ProfilesPanel extends ControlPanel {
); );
builder.addLine(); builder.addLine();
builder.addButtons( builder.addButton(
List.of("Recompute", "Export Profile(s)",
"Export Profile(s)"), (ActionEvent e) -> {
List.of( action.actionPerformed(new ActionEvent(
(ActionEvent e) -> { e.getSource(),
action.actionPerformed(new ActionEvent( ActionEvent.ACTION_PERFORMED,
e.getSource(), ACTION_COMMAND_EXPORT
ActionEvent.ACTION_PERFORMED, ));
ACTION_COMMAND_RECOMPUTE });
));
},
(ActionEvent e) -> {
action.actionPerformed(new ActionEvent(
e.getSource(),
ActionEvent.ACTION_PERFORMED,
ACTION_COMMAND_EXPORT
));
}
)
);
} }
@Override @Override
......
...@@ -84,6 +84,33 @@ public interface MeshFacet extends Iterable<MeshTriangle>, Serializable { ...@@ -84,6 +84,33 @@ public interface MeshFacet extends Iterable<MeshTriangle>, Serializable {
* @return Triangles sharing the mesh vertex * @return Triangles sharing the mesh vertex
*/ */
List<MeshTriangle> getAdjacentTriangles(int vertexIndex); List<MeshTriangle> getAdjacentTriangles(int vertexIndex);
/**
* Returns triangles sharing the given edge.
*
* @param index1 Index of the first point of the edge
* @param index2 Index of the second point of the edge
* @return Triangles sharing the edge
*/
List<MeshTriangle> getAdjacentTriangles(int index1, int index2);
/**
* Returns adjacent triangles, i.e., triangles sharing an edge or a vertex with the given triangle
*
* @param triangle The triangle
* @return Unique adjacent triangles
*/
List<MeshTriangle> getAdjacentTriangles(MeshTriangle triangle);
/**
* Returns neighboring triangles, i.e., triangles sharing an edge with the given triangle.
* In contrast to the {@link #getAdjacentTriangles(cz.fidentis.analyst.mesh.core.MeshTriangle)},
* triangles sharing only a vertex are omitted.
*
* @param triangle The triangle
* @return Unique neighboring triangles
*/
List<MeshTriangle> getNeighboringTriangles(MeshTriangle triangle);
/** /**
* Finds and returns a point lying at triangles around (sharing) the given mesh vertex * Finds and returns a point lying at triangles around (sharing) the given mesh vertex
......
...@@ -3,10 +3,12 @@ package cz.fidentis.analyst.mesh.core; ...@@ -3,10 +3,12 @@ package cz.fidentis.analyst.mesh.core;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
import javax.vecmath.Vector3d; import javax.vecmath.Vector3d;
import cz.fidentis.analyst.mesh.MeshVisitor; import cz.fidentis.analyst.mesh.MeshVisitor;
import javax.vecmath.Point3d; import javax.vecmath.Point3d;
...@@ -15,6 +17,7 @@ import javax.vecmath.Point3d; ...@@ -15,6 +17,7 @@ import javax.vecmath.Point3d;
* Mash facet is a compact triangular mesh without duplicated vertices. * Mash facet is a compact triangular mesh without duplicated vertices.
* *
* @author Matej Lukes * @author Matej Lukes
* @author Dominik Racek
*/ */
public class MeshFacetImpl implements MeshFacet { public class MeshFacetImpl implements MeshFacet {
...@@ -149,6 +152,52 @@ public class MeshFacetImpl implements MeshFacet { ...@@ -149,6 +152,52 @@ public class MeshFacetImpl implements MeshFacet {
return ret; return ret;
} }
@Override
public List<MeshTriangle> getAdjacentTriangles(int index1, int index2) {
List<MeshTriangle> output = getAdjacentTriangles(index1);
List<MeshTriangle> other = getAdjacentTriangles(index2);
output.retainAll(other);
return output;
}
@Override
public List<MeshTriangle> getAdjacentTriangles(MeshTriangle tri) {
Set<MeshTriangle> output = new HashSet<>();
output.addAll(getAdjacentTriangles(tri.index1));
output.addAll(getAdjacentTriangles(tri.index2));
output.addAll(getAdjacentTriangles(tri.index3));
output.remove(tri);
return new ArrayList<>(output);
}
@Override
public List<MeshTriangle> getNeighboringTriangles(MeshTriangle tri) {
Set<MeshTriangle> output = new HashSet<>();
//Find only the three triangles sharing edges with tri
List<MeshTriangle> l1 = getAdjacentTriangles(tri.index1);
List<MeshTriangle> l2 = getAdjacentTriangles(tri.index2);
List<MeshTriangle> l3 = getAdjacentTriangles(tri.index3);
//Calculate the three intersections
List<MeshTriangle> i1 = new ArrayList<>(l1);
i1.retainAll(l2);
List<MeshTriangle> i2 = new ArrayList<>(l2);
i2.retainAll(l3);
List<MeshTriangle> i3 = new ArrayList<>(l3);
i3.retainAll(l1);
output.addAll(i1);
output.addAll(i2);
output.addAll(i3);
output.remove(tri);
return new ArrayList<>(output);
}
@Override @Override
public Point3d getClosestAdjacentPoint(Point3d point, int vertexIndex) { public Point3d getClosestAdjacentPoint(Point3d point, int vertexIndex) {
......
...@@ -4,6 +4,7 @@ import java.util.ArrayList; ...@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Objects;
import javax.vecmath.Point3d; import javax.vecmath.Point3d;
import javax.vecmath.Vector3d; import javax.vecmath.Vector3d;
...@@ -11,6 +12,7 @@ import javax.vecmath.Vector3d; ...@@ -11,6 +12,7 @@ import javax.vecmath.Vector3d;
* Adapter for the corner table representing a single triangle of {@code MeshFacet}. * Adapter for the corner table representing a single triangle of {@code MeshFacet}.
* *
* @author Natalia Bebjakova * @author Natalia Bebjakova
* @author Dominik Racek
*/ */
public class MeshTriangle implements Iterable<MeshPoint> { public class MeshTriangle implements Iterable<MeshPoint> {
...@@ -69,6 +71,28 @@ public class MeshTriangle implements Iterable<MeshPoint> { ...@@ -69,6 +71,28 @@ public class MeshTriangle implements Iterable<MeshPoint> {
public MeshPoint getPoint3() { public MeshPoint getPoint3() {
return facet.getVertex(index3); return facet.getVertex(index3);
} }
@Override
public boolean equals(Object obj)
{
if(this == obj)
return true;
if(obj == null || obj.getClass()!= this.getClass())
return false;
MeshTriangle mt = (MeshTriangle) obj;
return ((index1 == mt.index1 || index1 == mt.index2 || index1 == mt.index3)
&& (index2 == mt.index1 || index2 == mt.index2 || index2 == mt.index3)
&& (index3 == mt.index1 || index3 == mt.index2 || index3 == mt.index3));
}
@Override
public int hashCode() {
return Objects.hash(index1, index2, index3);
}
/** /**
* Computes and returns normalized normal vector from the vertices. * Computes and returns normalized normal vector from the vertices.
...@@ -364,7 +388,7 @@ public class MeshTriangle implements Iterable<MeshPoint> { ...@@ -364,7 +388,7 @@ public class MeshTriangle implements Iterable<MeshPoint> {
ab.sub(v1); ab.sub(v1);
Vector3d ap = new Vector3d(point); Vector3d ap = new Vector3d(point);
ap.sub(v1); ap.sub(v1);
double abLenSquared = ab.lengthSquared(); double abLenSquared = ab.lengthSquared();
double t = ab.dot(ap) / abLenSquared; double t = ab.dot(ap) / abLenSquared;
...@@ -401,39 +425,43 @@ public class MeshTriangle implements Iterable<MeshPoint> { ...@@ -401,39 +425,43 @@ public class MeshTriangle implements Iterable<MeshPoint> {
/** /**
* Checks whether the triangle is intersected by a cutting plane * Checks whether the triangle is intersected by a cutting plane
* *
* @param plane cutting plane * @param normal normal defining the plane
* @param d distance defining the plane
* @return true if the triangle is intersected by the plane * @return true if the triangle is intersected by the plane
*/ */
public boolean checkIntersectionWithPlane(MeshFacet plane) { public boolean checkIntersectionWithPlane(Vector3d normal, double d) {
Point3d min = getVertex1(), max = getVertex1(); double p1 = (normal.x * getVertex1().x) + (normal.y * getVertex1().y) + (normal.z * getVertex1().z) + d;
double p2 = (normal.x * getVertex2().x) + (normal.y * getVertex2().y) + (normal.z * getVertex2().z) + d;
if (getVertex2().x < min.x) { double p3 = (normal.x * getVertex3().x) + (normal.y * getVertex3().y) + (normal.z * getVertex3().z) + d;
min = getVertex2();
}
if (getVertex3().x < min.x) { //If one point is on one side of the plane and the other on the other side
min = getVertex3(); return ((p1 <= 0 || p2 <= 0 || p3 <= 0) && (p1 >= 0 || p2 >= 0 || p3 >= 0));
} }
if (getVertex2().x > max.x) { /**
max = getVertex2(); * Selects the common points between two triangles
} *
* @param other The other triangle
* @return the common points of two triangles
*/
public List<Point3d> getCommonPoints(MeshTriangle other) {
List<Point3d> output = new ArrayList<>();
if (getVertex3().x > max.x) { if (getVertex1().equals(other.getVertex1()) || getVertex1().equals(other.getVertex2())
max = getVertex3(); || getVertex1().equals(other.getVertex3())) {
output.add(getVertex1());
} }
Point3d projMin = plane.getTriangles().get(0).getProjectionToTrianglePlane(min); if (getVertex2().equals(other.getVertex1()) || getVertex2().equals(other.getVertex2())
Point3d projMax = plane.getTriangles().get(0).getProjectionToTrianglePlane(max); || getVertex2().equals(other.getVertex3())) {
output.add(getVertex2());
if (projMin == null) {
projMin = plane.getTriangles().get(1).getProjectionToTrianglePlane(min);
} }
if (projMax == null) { if (getVertex3().equals(other.getVertex1()) || getVertex3().equals(other.getVertex2())
projMax = plane.getTriangles().get(1).getProjectionToTrianglePlane(max); || getVertex3().equals(other.getVertex3())) {
output.add(getVertex3());
} }
return (min.x < projMin.x && max.x > projMax.x); return output;
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment