boofcv.gui.mesh.OrbitAroundPointControl Maven / Gradle / Ivy
/*
* Copyright (c) 2023, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.gui.mesh;
import boofcv.struct.calib.CameraPinhole;
import boofcv.struct.mesh.VertexMesh;
import georegression.struct.point.Point3D_F64;
import georegression.struct.se.Se3_F64;
import org.ddogleg.struct.DogArray;
import org.ddogleg.struct.DogArray_F64;
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
/**
* Camera controls for {@link MeshViewerPanel} where it rotates around a central control point.
* Dragging the mouse will rotate the camera around this point. Using the mouse wheel will zoom in and out.
* This has been designed so that multiple threads can access it at the same time
*
* @author Peter Abeles
*/
public class OrbitAroundPointControl extends MouseAdapter implements Swing3dCameraControl {
public int maxSamplePoints = 1000;
/**
* Called every time the camera has changed
*/
public Runnable handleCameraChanged = () -> {};
// Math for computing the orbit. All read/write must be synchronized for thread safety
final OrbitAroundPoint orbit = new OrbitAroundPoint();
// Previous mouse location
int prevX, prevY;
@Override public void attachControls( JComponent parent ) {
parent.addMouseListener(this);
parent.addMouseMotionListener(this);
parent.addMouseWheelListener(this);
}
@Override public void detachControls( JComponent parent ) {
parent.removeMouseListener(this);
parent.removeMouseMotionListener(this);
parent.removeMouseWheelListener(this);
}
@Override public void reset() {
orbit.resetView();
}
/**
* By default sets the focal point that it rotates around to the medium point
*/
@Override public void selectInitialParameters( VertexMesh mesh ) {
// sub-sample points to keep compute at a reasonable speed.
final int N = Math.min(maxSamplePoints, mesh.vertexes.size());
// Give tell it to look in front of the camera if there is nothing to look at
if (N == 0) {
orbit.targetPoint.setTo(0, 0, 1);
return;
}
var sampled = new DogArray<>(Point3D_F64::new);
sampled.reserve(N);
// evenly sub sample points in the mesh
for (int i = 0; i < N; i++) {
int vertIndex = i*mesh.vertexes.size()/N;
mesh.vertexes.getCopy(vertIndex, sampled.grow());
}
// select the medium point as the focal point
var values = new DogArray_F64();
values.resize(sampled.size);
synchronized (orbit) {
for (int axis = 0; axis < 3; axis++) {
int _axis = axis;
sampled.forIdx(( idx, v ) -> values.set(idx, v.getIdx(_axis)));
values.sort();
orbit.targetPoint.setIdx(axis, values.getFraction(0.5));
}
}
}
@Override public void setCamera( CameraPinhole intrinsics ) {
synchronized (orbit) {
orbit.getCamera().setTo(intrinsics);
}
}
@Override public Se3_F64 getWorldToCamera() {
synchronized (orbit) {
orbit.updateTransform();
return orbit.worldToView.copy();
}
}
@Override public void setChangeHandler( Runnable handler ) {
this.handleCameraChanged = handler;
}
@Override public void mousePressed( MouseEvent e ) {
prevX = e.getX();
prevY = e.getY();
}
@Override public void mouseWheelMoved( MouseWheelEvent e ) {
synchronized (orbit) {
orbit.mouseWheel(e.getPreciseWheelRotation(), 1.0);
}
handleCameraChanged.run();
}
@Override public void mouseDragged( MouseEvent e ) {
synchronized (orbit) {
if (e.isShiftDown() || SwingUtilities.isMiddleMouseButton(e))
orbit.mouseDragTranslate(prevX, prevY, e.getX(), e.getY());
else if (e.isControlDown() || SwingUtilities.isRightMouseButton(e))
orbit.mouseDragZoomRoll(prevX, prevY, e.getX(), e.getY());
else
orbit.mouseDragRotate(prevX, prevY, e.getX(), e.getY());
}
prevX = e.getX();
prevY = e.getY();
handleCameraChanged.run();
}
@Override public String getHelpText() {
return """
Rotates around a single point
Mouse left to rotate around the point
Mouse middle (shift) to translate
Mouse right (ctrl) to zoom and roll
""";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy