mirror of
https://github.com/xibyte/jsketcher
synced 2026-01-10 18:03:06 +01:00
BIG CLEAN-UP
This commit is contained in:
parent
4cefadffd6
commit
471680ff13
137 changed files with 19 additions and 15678 deletions
BIN
misc/octave-core
BIN
misc/octave-core
Binary file not shown.
27
misc/perp
27
misc/perp
|
|
@ -1,27 +0,0 @@
|
|||
pkg load optim;
|
||||
|
||||
function y = f (x)
|
||||
|
||||
y = [
|
||||
(
|
||||
(x(3) - x(1)) * (x(7) - x(5)) +
|
||||
(x(4) - x(2)) * (x(8) - x(6))
|
||||
) ^ 2,
|
||||
(
|
||||
(x(11) - x(9)) * (x(7) - x(5)) +
|
||||
(x(12) - x(10)) * (x(8) - x(6))
|
||||
) ^ 2];
|
||||
y(3) = 0;y(4) = 0;y(5) = 0;y(6) = 0;y(7) = 0;y(8) = 0;
|
||||
y(9) = 0;y(10) = 0;y(11) = 0;y(12) = 0;
|
||||
endfunction
|
||||
|
||||
x0 = [100, 100, 600, 600, 700, 600, 900, 100, 1100, 100, 1600, 600];
|
||||
#x = fminunc(@f, reshape(x0, 12,1));
|
||||
x = fsolve(@f, x0); #WORKS!
|
||||
|
||||
#x = x0;
|
||||
l1 = [x(1), x(2); x(3), x(4)];
|
||||
l2 = [x(5), x(6); x(7), x(8)];
|
||||
l3 = [x(9), x(10); x(11), x(12)];
|
||||
|
||||
plot(l1(:,1), l1(:,2), l2(:,1), l2(:,2), l3(:,1), l3(:,2),'-');
|
||||
72
misc/proto.m
72
misc/proto.m
|
|
@ -1,72 +0,0 @@
|
|||
pkg load optim;
|
||||
|
||||
l1p1x = 1;
|
||||
l1p1y = 2;
|
||||
l1p2x = 3;
|
||||
l1p2y = 4;
|
||||
l2p1x = 5;
|
||||
l2p1y = 6;
|
||||
l2p2x = 7;
|
||||
l2p2y = 8;
|
||||
|
||||
function out = g (x)
|
||||
|
||||
l1p1x = 1;
|
||||
l1p1y = 2;
|
||||
l1p2x = 3;
|
||||
l1p2y = 4;
|
||||
l2p1x = 5;
|
||||
l2p1y = 6;
|
||||
l2p2x = 7;
|
||||
l2p2y = 8;
|
||||
p = x{1};
|
||||
out = [
|
||||
(p(l2p1y) - p(l2p2y));
|
||||
-(p(l2p1y) - p(l2p2y));
|
||||
(p(l2p1x) - p(l2p2x));
|
||||
-(p(l2p1x) - p(l2p2x));
|
||||
(p(l1p1y) - p(l1p2y));
|
||||
-(p(l1p1y) - p(l1p2y));
|
||||
(p(l1p1x) - p(l1p2x));
|
||||
-(p(l1p1x) - p(l1p2x));
|
||||
];
|
||||
|
||||
endfunction
|
||||
|
||||
function out = phi (x)
|
||||
|
||||
l1p1x = 1;
|
||||
l1p1y = 2;
|
||||
l1p2x = 3;
|
||||
l1p2y = 4;
|
||||
l2p1x = 5;
|
||||
l2p1y = 6;
|
||||
l2p2x = 7;
|
||||
l2p2y = 8;
|
||||
p = x{1};
|
||||
dx1 = (p(l1p1x) - p(l1p2x));
|
||||
dy1 = (p(l1p1y) - p(l1p2y));
|
||||
dx2 = (p(l2p1x) - p(l2p2x));
|
||||
dy2 = (p(l2p1y) - p(l2p2y));
|
||||
#dot product shows how the lines off to be perpendicular
|
||||
off = dx1 * dx2 + dy1 * dy2;
|
||||
out = off * off;
|
||||
endfunction
|
||||
|
||||
|
||||
|
||||
l1 = [100, 100; 300, 600];
|
||||
l2 = [400, 600; 600, 100];
|
||||
|
||||
|
||||
x0 = [l1(1,1);l1(1,2);l1(2,1);l1(2,2); l2(1,1);l2(1,2);l2(2,1);l2(2,2)];
|
||||
|
||||
#[x, obj, info, iter, nf, lambda] = sqp (x0, @phi, @g, []);
|
||||
|
||||
[a,b,c] = cg_min (@phi, @g, x0);
|
||||
|
||||
|
||||
#plot([l1(1), l1(2)], [l1(3), l1(4)], '-');
|
||||
#plot(reshape(l2, 2, 2));
|
||||
plot(l1(:,1), l1(:,2), l2(:,1), l2(:,2), '-');
|
||||
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
function y = angle (x)
|
||||
|
||||
a = [x(3) - x(1); x(4) - x(2)];
|
||||
b = [x(7) - x(5); x(8) - x(6)];
|
||||
|
||||
y = acos(dot(a, b) / (norm(a) * norm(b))) / pi * 180;
|
||||
|
||||
endfunction
|
||||
|
||||
function y = f (x)
|
||||
y(1) = (
|
||||
(x(3) - x(1)) * (x(7) - x(5)) +
|
||||
(x(4) - x(2)) * (x(8) - x(6))
|
||||
) ^ 2;
|
||||
endfunction
|
||||
|
||||
x0 = [100, 100, 600, 600, 700, 600, 900, 100];
|
||||
x = sqp(x0, @f);
|
||||
|
||||
#pkg load optim;
|
||||
#x = bfgsmin('f', {reshape(x0, 8,1)}); #WORKS!
|
||||
|
||||
|
||||
l1 = [x(1), x(2); x(3), x(4)];
|
||||
l2 = [x(5), x(6); x(7), x(8)];
|
||||
|
||||
plot(l1(:,1), l1(:,2), l2(:,1), l2(:,2), '-');
|
||||
|
||||
|
||||
#d = (x(3) - x(1)) * (x(7) - x(5)) + (x(4) - x(2)) * (x(8) - x(6)) ;
|
||||
disp("Angle: "), disp(angle(x));
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
cd build_oce/
|
||||
cmake -D OCE_VISUALISATION:BOOLEAN=FALSE -D OCE_DISABLE_X11:BOOLEAN=TRUE -D OCE_USE_PCH:BOOLEAN=TRUE ../oce
|
||||
make -j 4
|
||||
|
||||
export DESTDIR=/home/xibyte/git/build_oce/out && make -j4 install
|
||||
|
||||
export LD_LIBRARY_PATH=/home/xibyte/git/build_oce/out/usr/local/lib/
|
||||
|
||||
official/6.7.0
|
||||
|
||||
1071 sudo apt-get install g++
|
||||
1073 sudo apt-get install tcl
|
||||
1074 sudo apt-get install tclsudo
|
||||
1075 sudo apt-get install cmake cmake-curses-gui g++ build-essential
|
||||
1078 sudo apt-get install tcl-dev
|
||||
1084 sudo apt-get install automake
|
||||
1090 sudo apt-get install libtool
|
||||
|
||||
1085 ./build_configure
|
||||
1092 ./configure
|
||||
1093 make
|
||||
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
package cad;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.GlobalSolver;
|
||||
import cad.gcs.Param;
|
||||
import cad.gcs.Solver;
|
||||
import cad.gcs.constr.Equal;
|
||||
import cad.gcs.constr.EqualsTo;
|
||||
import cad.gcs.constr.P2LDistance;
|
||||
import cad.gcs.constr.P2PDistance;
|
||||
import cad.gcs.constr.Parallel;
|
||||
import cad.gcs.constr.Perpendicular;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class SolveServer {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Server server = new Server(8080);
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.addHandler(new SolveHandler());
|
||||
|
||||
ResourceHandler rh = new ResourceHandler();
|
||||
rh.setDirectoriesListed(true);
|
||||
rh.setResourceBase("/home/xibyte/Dropbox/project/cadit/web");
|
||||
handlers.addHandler(rh);
|
||||
|
||||
server.setHandler(handlers);
|
||||
server.start();
|
||||
// server.dumpStdErr();
|
||||
server.join();
|
||||
}
|
||||
}
|
||||
|
||||
class SolveHandler extends AbstractHandler {
|
||||
|
||||
volatile boolean busy = false;
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
|
||||
if (!request.getRequestURI().startsWith("/solve")) {
|
||||
return;
|
||||
}
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
if (busy) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (busy) return;
|
||||
busy = true;
|
||||
try {
|
||||
BufferedReader reader = request.getReader();
|
||||
String jsonStr = new Scanner(reader).useDelimiter("\\A").next();
|
||||
System.out.println("REQUEST: " + jsonStr);
|
||||
|
||||
JSONObject json = new JSONObject(jsonStr);
|
||||
|
||||
JSONObject solved = solve(json);
|
||||
System.out.println("RESPONSE: " + solved);
|
||||
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
response.getWriter().println(solved.toString());
|
||||
} finally {
|
||||
busy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject solve(JSONObject req) {
|
||||
List<Constraint> constraints = new ArrayList<>();
|
||||
JSONObject system = req.getJSONObject("system");
|
||||
JSONArray params = system.getJSONArray("params");
|
||||
JSONArray constrs = system.getJSONArray("constraints");
|
||||
JSONArray locked = system.getJSONArray("locked");
|
||||
|
||||
// TIntObjectMap<Param> paramsDict = new TIntObjectHashMap();
|
||||
List<Param> paramsDict = new ArrayList<>(params.length());
|
||||
for (int i = 0; i < params.length(); i++) {
|
||||
paramsDict.add(null);
|
||||
}
|
||||
class ParamHelper {
|
||||
private JSONArray refs;
|
||||
public Param get(int pos) {
|
||||
int ref = refs.getInt(pos);
|
||||
Param param = paramsDict.get(ref);
|
||||
if (param == null) {
|
||||
param = new Param(params.getDouble(ref));
|
||||
paramsDict.set(ref, param);
|
||||
}
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
ParamHelper h = new ParamHelper();
|
||||
|
||||
for (int i = 0; i < constrs.length(); i++) {
|
||||
JSONArray constr = constrs.getJSONArray(i);
|
||||
String functional = constr.getString(0);
|
||||
h.refs = constr.getJSONArray(1);
|
||||
JSONArray constants = constr.getJSONArray(2);
|
||||
|
||||
switch (functional) {
|
||||
case "equal":
|
||||
constraints.add(new Equal(h.get(0), h.get(1)));
|
||||
break;
|
||||
case "perpendicular":
|
||||
constraints.add(new Perpendicular(h.get(0), h.get(1), h.get(2), h.get(3), h.get(4), h.get(5), h.get(6), h.get(7)));
|
||||
break;
|
||||
case "parallel":
|
||||
constraints.add(new Parallel(h.get(0), h.get(1), h.get(2), h.get(3), h.get(4), h.get(5), h.get(6), h.get(7)));
|
||||
break;
|
||||
case "P2LDistance":
|
||||
constraints.add(new P2LDistance(constants.getDouble(0), h.get(0), h.get(1), h.get(2), h.get(3), h.get(4), h.get(5)));
|
||||
break;
|
||||
case "P2PDistance":
|
||||
constraints.add(new P2PDistance(h.get(0), h.get(1), h.get(2), h.get(3), constants.getDouble(0)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < locked.length(); i++) {
|
||||
Param param = paramsDict.get(locked.getInt(i));
|
||||
// param.setLocked(true);
|
||||
constraints.add(new EqualsTo(param, param.get()));
|
||||
}
|
||||
|
||||
Solver.SubSystem subSystem = new Solver.SubSystem(constraints);
|
||||
GlobalSolver.globalSolve(subSystem, () -> {});
|
||||
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("reqId", req.getInt("reqId"));
|
||||
JSONArray paramsJson = new JSONArray();
|
||||
response.put("params", paramsJson);
|
||||
for (Param param : paramsDict) {
|
||||
paramsJson.put(param.get());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class App extends Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("prism.dirtyopts", "false");
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Scene scene = new Scene(FXMLLoader.load(AppCtrl.class.getResource("app.fxml")), 1024, 1100);
|
||||
primaryStage.setTitle("Solid CAD");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class App2D extends Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("prism.dirtyopts", "false");
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Scene scene = new Scene(FXMLLoader.load(AppCtrl.class.getResource("app2d.fxml")), 1024, 1100);
|
||||
primaryStage.setTitle("Sketch");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Figures;
|
||||
import cad.gcs.GlobalSolver;
|
||||
import cad.gcs.Param;
|
||||
import cad.gcs.Solver;
|
||||
import cad.gcs.constr.P2LDistance;
|
||||
import cad.gcs.constr.Parallel;
|
||||
import cad.gcs.constr.Perpendicular;
|
||||
import cad.gcs.constr.Reconcilable;
|
||||
import cad.math.Vector;
|
||||
import gnu.trove.list.TDoubleList;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.shape.Line;
|
||||
import org.apache.commons.math3.analysis.MultivariateFunction;
|
||||
import org.apache.commons.math3.exception.MathIllegalStateException;
|
||||
import org.apache.commons.math3.optim.ConvergenceChecker;
|
||||
import org.apache.commons.math3.optim.InitialGuess;
|
||||
import org.apache.commons.math3.optim.MaxEval;
|
||||
import org.apache.commons.math3.optim.MaxIter;
|
||||
import org.apache.commons.math3.optim.PointValuePair;
|
||||
import org.apache.commons.math3.optim.PointVectorValuePair;
|
||||
import org.apache.commons.math3.optim.SimpleBounds;
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType;
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction;
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient;
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.ModelFunction;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.ModelFunctionJacobian;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.Target;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.Weight;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.jacobian.LevenbergMarquardtOptimizer;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES;
|
||||
|
||||
public class App2DCtrl implements Initializable {
|
||||
|
||||
private final CadContext cadContext = new CadContext();
|
||||
|
||||
public Pane viewer;
|
||||
public Button solve;
|
||||
public Button square;
|
||||
private Group content;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
content = new Group();
|
||||
setInitObject(content);
|
||||
viewer.getChildren().setAll(content);
|
||||
|
||||
|
||||
Line l1 = new Line(100, 100, 300, 600);
|
||||
Line l2 = new Line(400, 600, 600, 100);
|
||||
Line l3 = new Line(650, 100, 800, 600);
|
||||
|
||||
content.getChildren().addAll(l1, l2, l3);
|
||||
|
||||
square.setOnAction(event -> {
|
||||
solveFigure(Figures.square(100));
|
||||
});
|
||||
|
||||
|
||||
solve.setOnAction(event -> {
|
||||
|
||||
Vector as = new Vector(l1.getStartX(), l1.getStartY());
|
||||
Vector ae = new Vector(l1.getEndX(), l1.getEndY());
|
||||
Vector bs = new Vector(l2.getStartX(), l2.getStartY());
|
||||
Vector be = new Vector(l2.getEndX(), l2.getEndY());
|
||||
|
||||
|
||||
Param l1p1x = new Param(l1.getStartX());
|
||||
Param l1p1y = new Param(l1.getStartY());
|
||||
Param l1p2x = new Param(l1.getEndX());
|
||||
Param l1p2y = new Param(l1.getEndY());
|
||||
|
||||
Param l2p1x = new Param(l2.getStartX());
|
||||
Param l2p1y = new Param(l2.getStartY());
|
||||
Param l2p2x = new Param(l2.getEndX());
|
||||
Param l2p2y = new Param(l2.getEndY());
|
||||
|
||||
Param l3p1x = new Param(l3.getStartX());
|
||||
Param l3p1y = new Param(l3.getStartY());
|
||||
Param l3p2x = new Param(l3.getEndX());
|
||||
Param l3p2y = new Param(l3.getEndY());
|
||||
|
||||
// l2p2x.setLocked(true);
|
||||
// l2p2y.setLocked(true);
|
||||
// l2p1x.setLocked(true);
|
||||
// l2p1y.setLocked(true);
|
||||
|
||||
|
||||
Perpendicular perpendicular = new Perpendicular(
|
||||
l1p1x,
|
||||
l1p1y,
|
||||
l1p2x,
|
||||
l1p2y,
|
||||
l2p1x,
|
||||
l2p1y,
|
||||
l2p2x,
|
||||
l2p2y
|
||||
);
|
||||
|
||||
Parallel parallel = new Parallel(
|
||||
l3p1x,
|
||||
l3p1y,
|
||||
l3p2x,
|
||||
l3p2y,
|
||||
l2p1x,
|
||||
l2p1y,
|
||||
l2p2x,
|
||||
l2p2y
|
||||
);
|
||||
|
||||
P2LDistance p2l1 = new P2LDistance(
|
||||
10,
|
||||
l3p1x, l3p1y,
|
||||
l2p1x, l2p1y,
|
||||
l2p2x, l2p2y
|
||||
);
|
||||
|
||||
P2LDistance p2l2 = new P2LDistance(
|
||||
10,
|
||||
l1p2x, l1p2y,
|
||||
l2p1x, l2p1y,
|
||||
l2p2x, l2p2y
|
||||
);
|
||||
|
||||
|
||||
Runnable update = () -> {
|
||||
System.out.println("ANGLE |- : " + perpendicular.angle());
|
||||
System.out.println("ANGLE || : " + parallel.angle());
|
||||
System.out.println("DISTANCE : " + p2l1.error());
|
||||
|
||||
// Constraint2 constr = xy;
|
||||
|
||||
// Constraint constr = perpendicular;
|
||||
// GradientDescent.solve(constr);
|
||||
// perpendicular.out(a1, b1, a2, b2);
|
||||
|
||||
// GradientDescent2.solve(constr);
|
||||
|
||||
|
||||
// l1.setStartX(as.x);
|
||||
// l1.setStartY(as.y);
|
||||
// l1.setEndX(ae.x);
|
||||
// l1.setEndY(ae.y);
|
||||
//
|
||||
// l2.setStartX(bs.x);
|
||||
// l2.setStartY(bs.y);
|
||||
// l2.setEndX(be.x);
|
||||
// l2.setEndY(be.y);
|
||||
|
||||
l1.setStartX(l1p1x.get());
|
||||
l1.setStartY(l1p1y.get());
|
||||
l1.setEndX(l1p2x.get());
|
||||
l1.setEndY(l1p2y.get());
|
||||
|
||||
l2.setStartX(l2p1x.get());
|
||||
l2.setStartY(l2p1y.get());
|
||||
l2.setEndX(l2p2x.get());
|
||||
l2.setEndY(l2p2y.get());
|
||||
|
||||
l3.setStartX(l3p1x.get());
|
||||
l3.setStartY(l3p1y.get());
|
||||
l3.setEndX(l3p2x.get());
|
||||
l3.setEndY(l3p2y.get());
|
||||
|
||||
// scale(l1);
|
||||
// scale(l2);
|
||||
// scale(l3);
|
||||
};
|
||||
|
||||
|
||||
List<Constraint> constrs = Arrays.<Constraint>asList(p2l2, parallel, perpendicular, p2l1);
|
||||
// List<Constraint> constrs = Arrays.<Constraint>asList(p2l1);
|
||||
Solver.SubSystem subSystem = new Solver.SubSystem(constrs);
|
||||
// Solver.optimize(subSystem);
|
||||
//
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
executor.execute(() -> {
|
||||
GlobalSolver.globalSolve(subSystem, () -> Platform.runLater(update));
|
||||
if (true) return;
|
||||
while (subSystem.errorSquared() > 0.0001) {
|
||||
// Solver.solve_LM(subSystem);
|
||||
GlobalSolver.solveLM_COMMONS(subSystem);
|
||||
// Solver.solve_DL(subSystem);
|
||||
// Solver.solve_BFGS(subSystem, true);
|
||||
Platform.runLater(update);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void solveFigure(Figures.Figure square) {
|
||||
|
||||
Solver.SubSystem subSystem = new Solver.SubSystem(square.constraints);
|
||||
|
||||
List<Line> lines = new ArrayList<>();
|
||||
|
||||
for (Param[] line : square.lines) {
|
||||
Line fxLine = new Line();
|
||||
fxLine.setStartX(line[0].get());
|
||||
fxLine.setStartY(line[1].get());
|
||||
fxLine.setEndX(line[2].get());
|
||||
fxLine.setEndY(line[3].get());
|
||||
|
||||
lines.add(fxLine);
|
||||
}
|
||||
|
||||
content.getChildren().addAll(lines);
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
executor.execute(() -> {
|
||||
GlobalSolver.globalSolve(subSystem, () -> Platform.runLater(() -> {
|
||||
for (int i = 0; i < square.lines.length; i++) {
|
||||
Param[] line = square.lines[i];
|
||||
Line fxLine = lines.get(i);
|
||||
fxLine.setStartX(line[0].get());
|
||||
fxLine.setStartY(line[1].get());
|
||||
fxLine.setEndX(line[2].get());
|
||||
fxLine.setEndY(line[3].get());
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void solveWorse(Solver.SubSystem subSystem, double eps) {
|
||||
TDoubleList residuals = subSystem.calcResidual();
|
||||
double worseValue = residuals.max();
|
||||
if (Math.abs(worseValue) > eps) {
|
||||
int worseId = residuals.indexOf(worseValue);
|
||||
Constraint worseConstr = subSystem.constraints.get(worseId);
|
||||
if (worseConstr instanceof Reconcilable) {
|
||||
((Reconcilable) worseConstr).reconcile();
|
||||
} else {
|
||||
Solver.SubSystem worse = new Solver.SubSystem(asList(worseConstr));
|
||||
GlobalSolver.solveLM_COMMONS(worse);
|
||||
// Solver.solve_LM(worse);
|
||||
|
||||
}
|
||||
|
||||
System.out.println("WORSE FIXED ERROR:" + worseConstr.error());
|
||||
}
|
||||
}
|
||||
|
||||
double xxx = 100;
|
||||
|
||||
private void scale(Line l) {
|
||||
|
||||
Vector v = new Vector(l.getEndX() - l.getStartX(), l.getEndY() - l.getStartY());
|
||||
v = v.normalize().multi(200);
|
||||
l.setStartX(xxx += 100.);
|
||||
l.setStartY(500.);
|
||||
|
||||
l.setEndX(l.getStartX() + v.x);
|
||||
l.setEndY(l.getStartY() + v.y);
|
||||
}
|
||||
|
||||
private void solveScalarFunc(final Solver.SubSystem subSystem) {
|
||||
double eps = 1e-10;
|
||||
ConvergenceChecker<PointValuePair> convergenceChecker = new ConvergenceChecker<PointValuePair>() {
|
||||
@Override
|
||||
public boolean converged(int iteration, PointValuePair previous, PointValuePair current) {
|
||||
return previous.getValue() < eps;
|
||||
}
|
||||
};
|
||||
NonLinearConjugateGradientOptimizer optimizer = new NonLinearConjugateGradientOptimizer(FLETCHER_REEVES, convergenceChecker);
|
||||
double[] lb = new double[subSystem.pSize()];
|
||||
double[] ub = new double[subSystem.pSize()];
|
||||
|
||||
Arrays.fill(lb, -1000);
|
||||
Arrays.fill(ub, 1000);
|
||||
|
||||
optimizer.optimize(
|
||||
new MaxEval(10000),
|
||||
new InitialGuess(subSystem.getParams().toArray()),
|
||||
GoalType.MINIMIZE,
|
||||
new SimpleBounds(lb, ub),
|
||||
// new NonLinearConjugateGradientOptimizer.BracketingStep( 100 ),
|
||||
getGradient(subSystem),
|
||||
getScalarFunction(subSystem));
|
||||
}
|
||||
|
||||
private ObjectiveFunction getScalarFunction(Solver.SubSystem system) {
|
||||
return new ObjectiveFunction(point -> {
|
||||
system.setParams(point);
|
||||
return system.value();
|
||||
});
|
||||
}
|
||||
|
||||
private ObjectiveFunctionGradient getGradient(Solver.SubSystem subSystem) {
|
||||
return new ObjectiveFunctionGradient(point -> {
|
||||
subSystem.setParams(point);
|
||||
Constraint constraint = subSystem.constraints.get(0);
|
||||
double[] out = new double[constraint.pSize()];
|
||||
constraint.gradient(out);
|
||||
return out;
|
||||
});
|
||||
}
|
||||
|
||||
private void solve(ActionEvent e) {
|
||||
|
||||
// UnconstrainedLeastSquares opt = FactoryOptimization.leastSquaresTrustRegion(100, RegionStepType.DOG_LEG_FTF, false);
|
||||
|
||||
}
|
||||
|
||||
private void setInitObject(Group parent) {
|
||||
// CSG init = new Cube(100).toCSG().difference(new Cylinder(30, 100, 10).toCSG());
|
||||
// return new CSGNode(Utils3D.getFXMesh(init), cadContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.fx.viewer.Viewer3D;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.control.Button;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class AppCtrl implements Initializable {
|
||||
|
||||
private final CadContext cadContext = new CadContext();
|
||||
|
||||
public Viewer3D viewer;
|
||||
public Button beginSketching;
|
||||
public Button endSketching;
|
||||
public Button pad;
|
||||
public Button cut;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
Group content = new Group();
|
||||
setInitObject(content);
|
||||
viewer.setContent(content);
|
||||
beginSketching.setOnAction(event -> {
|
||||
cadContext.beginSketching();
|
||||
});
|
||||
endSketching.setOnAction(event -> {
|
||||
cadContext.endSketching();
|
||||
});
|
||||
pad.setOnAction(event -> {
|
||||
cadContext.pad(50);
|
||||
});
|
||||
}
|
||||
|
||||
private void setInitObject(Group parent) {
|
||||
List<Polygon> cube = Utils3D.createCube(100);
|
||||
parent.getChildren().addAll(cadContext.toNodes(cube));
|
||||
//
|
||||
// CSG init = new Cube(100).toCSG().difference(new Cylinder(30, 100, 10).toCSG());
|
||||
// return new CSGNode(Utils3D.getFXMesh(init), cadContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import javafx.scene.shape.TriangleMesh;
|
||||
|
||||
public class CSGMesh extends TriangleMesh {
|
||||
|
||||
public final TIntObjectMap<Polygon> polygons = new TIntObjectHashMap<>();
|
||||
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.shape.MeshView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CSGNode extends MeshView {
|
||||
|
||||
private final CadContext context;
|
||||
|
||||
public CSGNode(CSGMesh mesh, CadContext context) {
|
||||
super(mesh);
|
||||
this.context = context;
|
||||
setMaterial(Utils3D.DEFAULT_MATERIAL);
|
||||
setOnMouseEntered(e -> {
|
||||
context.highlightManger.selectExclusively(this);
|
||||
});
|
||||
setOnMouseExited(e -> {
|
||||
context.highlightManger.getSelection().clear();
|
||||
});
|
||||
setOnMouseClicked(e -> {
|
||||
context.clickOnNode(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
private void highlight(eu.mihosoft.vrl.v3d.Polygon poly) {
|
||||
System.out.println(poly);
|
||||
}
|
||||
|
||||
private void select(eu.mihosoft.vrl.v3d.Polygon poly) {
|
||||
System.out.println(poly);
|
||||
}
|
||||
|
||||
public final Map<Polygon, Sketch> sketches = new HashMap<>();
|
||||
|
||||
public Sketch getSketch(Polygon poly) {
|
||||
Sketch sketch = sketches.get(poly);
|
||||
if (sketch == null) {
|
||||
sketch = new Sketch(poly);
|
||||
((Group) getParent()).getChildren().add(sketch.drawLayer);
|
||||
sketches.put(poly, sketch);
|
||||
}
|
||||
return sketch;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.math.Vector;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.input.PickResult;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.MeshView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class CadContext {
|
||||
|
||||
public Sketcher sketcher;
|
||||
public Selection selection;
|
||||
public final SelectionManager selectionManger = new SelectionManager();
|
||||
public final SelectionManager highlightManger = new SelectionManager();
|
||||
|
||||
|
||||
class MaterialChangeListener implements SelectionManager.Listener {
|
||||
|
||||
public final PhongMaterial onSelect;
|
||||
public final PhongMaterial onDeselect;
|
||||
private SelectionManager dependency;
|
||||
|
||||
MaterialChangeListener(PhongMaterial onSelect, PhongMaterial onDeselect, SelectionManager dependency) {
|
||||
this.onSelect = onSelect;
|
||||
this.onDeselect = onDeselect;
|
||||
this.dependency = dependency;
|
||||
}
|
||||
|
||||
public void added(List<Node> nodes) {
|
||||
if (dependency != null) {
|
||||
nodes = filter(nodes, dependency);
|
||||
}
|
||||
setMaterial(nodes, onSelect);
|
||||
}
|
||||
|
||||
public void removed(List<Node> nodes) {
|
||||
if (dependency != null) {
|
||||
nodes = filter(nodes, dependency);
|
||||
}
|
||||
setMaterial(nodes, onDeselect);
|
||||
}
|
||||
|
||||
private List<Node> filter(List<Node> nodes, SelectionManager dependency) {
|
||||
nodes = new ArrayList<>(nodes);
|
||||
nodes.removeAll(selectionManger.getSelection());
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
selectionManger.addListener(new MaterialChangeListener(Utils3D.SELECTED_MATERIAL, Utils3D.DEFAULT_MATERIAL, null));
|
||||
highlightManger.addListener(new MaterialChangeListener(Utils3D.HIGHLIGHTED_MATERIAL, Utils3D.DEFAULT_MATERIAL, selectionManger));
|
||||
}
|
||||
|
||||
private void setMaterial(List<Node> nodes, PhongMaterial material) {
|
||||
for (Node node : nodes) {
|
||||
if (node instanceof MeshView) {
|
||||
((MeshView) node).setMaterial(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clickOnNode(CSGNode csgNode, MouseEvent e) {
|
||||
selectionManger.selectExclusively(csgNode);
|
||||
PickResult pickResult = e.getPickResult();
|
||||
int face = pickResult.getIntersectedFace();
|
||||
CSGMesh csgMesh = (CSGMesh) csgNode.getMesh();
|
||||
Polygon poly = csgMesh.polygons.get(face);
|
||||
System.out.println(poly);
|
||||
if (poly != null) {
|
||||
if (selection != null) {
|
||||
boolean isSameNode = selection.sameTo(csgNode, poly);
|
||||
if (sketcher == null && !isSameNode) {
|
||||
selection = new Selection(csgNode, poly);
|
||||
}
|
||||
if (sketcher != null && isSameNode) {
|
||||
sketcher.addPoint(pickResult.getIntersectedPoint());
|
||||
}
|
||||
} else {
|
||||
if (sketcher == null) {
|
||||
selection = new Selection(csgNode, poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void beginSketching() {
|
||||
if (sketcher != null || selection == null) {
|
||||
return;
|
||||
}
|
||||
sketcher = new Sketcher(selection.csgNode.getSketch(selection.poly));
|
||||
}
|
||||
|
||||
public void endSketching() {
|
||||
if (sketcher == null) {
|
||||
return;
|
||||
}
|
||||
sketcher.commitOperation();
|
||||
sketcher = null;
|
||||
}
|
||||
|
||||
public void pad(double height) {
|
||||
if (selection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sketch sketch = selection.csgNode.getSketch(selection.poly);
|
||||
Vector dir = sketch.owner.normal.multi(height);
|
||||
for (List<Vector> polygon : sketch.polygons) {
|
||||
if (polygon.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Polygon poly = new Polygon(sketch.owner.normal, polygon, Collections.emptyList());
|
||||
List<Polygon> extruded = Polygon.extrude(poly, dir);
|
||||
|
||||
for (Polygon s : extruded) {
|
||||
sketch.drawLayer.getChildren().addAll(toNodes(extruded));// fixme
|
||||
}
|
||||
// CSG pad = Extrude.points(dir, polygon);
|
||||
}
|
||||
}
|
||||
|
||||
public List<CSGNode> toNodes(List<Polygon> extruded) {
|
||||
return extruded.stream().map(this::toNode).collect(toList());
|
||||
}
|
||||
|
||||
public CSGNode toNode(Polygon poly) {
|
||||
return new CSGNode(Utils3D.getMesh(Collections.singletonList(poly)), this);
|
||||
}
|
||||
|
||||
public static class Selection {
|
||||
|
||||
public final CSGNode csgNode;
|
||||
public final Polygon poly;
|
||||
|
||||
public Selection(CSGNode csgNode, Polygon poly) {
|
||||
this.csgNode = csgNode;
|
||||
this.poly = poly;
|
||||
}
|
||||
|
||||
public boolean sameTo(CSGNode csgNode, Polygon poly) {
|
||||
return this.csgNode.equals(csgNode) && this.poly.equals(poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.math.HMath;
|
||||
import cad.math.Matrix;
|
||||
import cad.math.Vector;
|
||||
import org.poly2tri.Poly2Tri;
|
||||
import org.poly2tri.geometry.polygon.PolygonPoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class Polygon {
|
||||
|
||||
public final Vector normal;
|
||||
public final List<Vector> shell;
|
||||
public final List<List<Vector>> holes;
|
||||
|
||||
private List<Vector[]> triangles;
|
||||
|
||||
public Polygon(List<Vector> shell) {
|
||||
this(shell, Collections.emptyList());
|
||||
}
|
||||
|
||||
public Polygon(List<Vector> shell, List<List<Vector>> holes) {
|
||||
this(normalOfCCWSeq(shell.get(0), shell.get(1), shell.get(2)), shell, holes);
|
||||
}
|
||||
|
||||
public Polygon(Vector normal, List<Vector> shell, List<List<Vector>> holes) {
|
||||
this.normal = normal.normalize();
|
||||
this.shell = shell;
|
||||
this.holes = holes;
|
||||
checkPolygon(shell);
|
||||
for (List<Vector> hole : holes) {
|
||||
checkPolygon(hole);
|
||||
}
|
||||
}
|
||||
|
||||
public Polygon fixCCW() {
|
||||
if (!normal.slightlyEqualTo(normalOfCCWSeq(shell.get(0), shell.get(1), shell.get(2)))) {
|
||||
List<Vector> shell = new ArrayList<>(this.shell);
|
||||
Collections.reverse(shell);
|
||||
return new Polygon(normal, shell, holes);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Vector[] someBasis() {
|
||||
Vector x = shell.get(1).minus(shell.get(0)).normalize();
|
||||
Vector y = normal.cross(x).normalize();
|
||||
return new Vector[] {x, y, normal};
|
||||
}
|
||||
|
||||
private void checkPolygon(List<Vector> points) {
|
||||
if (points.size() < 3) {
|
||||
throw new IllegalArgumentException("Polygon should contain at least 3 point");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Vector[]> getTriangles() {
|
||||
if (triangles == null) {
|
||||
triangulate();
|
||||
}
|
||||
return triangles;
|
||||
}
|
||||
|
||||
private void triangulate() {
|
||||
|
||||
Matrix _3dTransformation = new Matrix(someBasis());
|
||||
Matrix _2dTransformation = _3dTransformation.invert();
|
||||
|
||||
List<PolygonPoint> shellPoints = shell.stream()
|
||||
.map(vector -> HMath.cross(_2dTransformation, vector))
|
||||
.map(vector -> new PolygonPoint(vector.x, vector.y, vector.z))
|
||||
.collect(toList());
|
||||
|
||||
org.poly2tri.geometry.polygon.Polygon polygon = new org.poly2tri.geometry.polygon.Polygon(shellPoints);
|
||||
|
||||
for (List<Vector> hole : holes) {
|
||||
|
||||
List<PolygonPoint> holePoints = hole.stream()
|
||||
.map(vector -> HMath.cross(_2dTransformation, vector))
|
||||
.map(vector -> new PolygonPoint(vector.x, vector.y, vector.z))
|
||||
.collect(toList());
|
||||
|
||||
polygon.addHole(new org.poly2tri.geometry.polygon.Polygon(holePoints));
|
||||
}
|
||||
|
||||
Poly2Tri.triangulate(polygon);
|
||||
|
||||
triangles = polygon.getTriangles().stream()
|
||||
.map(tr ->
|
||||
new Vector[]{
|
||||
HMath.cross(_3dTransformation, new Vector(tr.points[0].getX(), tr.points[0].getY(), tr.points[0].getZ())),
|
||||
HMath.cross(_3dTransformation, new Vector(tr.points[1].getX(), tr.points[1].getY(), tr.points[1].getZ())),
|
||||
HMath.cross(_3dTransformation, new Vector(tr.points[2].getX(), tr.points[2].getY(), tr.points[2].getZ()))
|
||||
})
|
||||
.collect(Collectors.<Vector[]>toList());
|
||||
|
||||
setupNormal(triangles, normal);
|
||||
}
|
||||
|
||||
public static void setupNormal(List<Vector[]> triangles, Vector normal) {
|
||||
|
||||
for (Vector[] triangle : triangles) {
|
||||
if (!normalOfCCWSeq(triangle[0], triangle[1], triangle[2]).slightlyEqualTo(normal)) {
|
||||
reverse(triangle);
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector normalOfCCWSeq(Vector v0, Vector v1, Vector v2) {
|
||||
return v1.minus(v0).cross(v2.minus(v0)).normalize();
|
||||
}
|
||||
|
||||
private static void reverse(Vector[] triangle) {
|
||||
Vector first = triangle[0];
|
||||
triangle[0] = triangle[2];
|
||||
triangle[2] = first;
|
||||
}
|
||||
|
||||
public Polygon flip() {
|
||||
return new Polygon(normal.negate(), shell, holes);
|
||||
}
|
||||
|
||||
public static List<Polygon> extrude(Polygon source, Vector target) {
|
||||
|
||||
double dotProduct = target.normalize().dot(source.normal);
|
||||
if (dotProduct == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (dotProduct > 0) {
|
||||
source = source.flip();
|
||||
}
|
||||
source = source.fixCCW();
|
||||
|
||||
List<Polygon> poly = new ArrayList<>();
|
||||
poly.add(source);
|
||||
|
||||
Polygon lid = source.shift(target).flip();
|
||||
poly.add(lid);
|
||||
|
||||
for (int i = 0; i < source.shell.size(); i++) {
|
||||
Polygon face = new Polygon(Arrays.asList(
|
||||
get(source.shell, i - 1),
|
||||
get(lid.shell, i - 1),
|
||||
get(lid.shell, i),
|
||||
get(source.shell, i)
|
||||
));
|
||||
poly.add(face);
|
||||
}
|
||||
return poly;
|
||||
}
|
||||
|
||||
public static <T> T get(List<T> list, int i) {
|
||||
i = i % list.size();
|
||||
if (i < 0) {
|
||||
i = list.size() + i;
|
||||
}
|
||||
return list.get(i);
|
||||
}
|
||||
|
||||
public Polygon shift(Vector target) {
|
||||
List<Vector> shell = this.shell.stream().map(vector -> vector.plus(target)).collect(toList());
|
||||
List<List<Vector>> holes = new ArrayList<>();
|
||||
for (List<Vector> hole : this.holes) {
|
||||
holes.add(hole.stream().map(vector -> vector.plus(target)).collect(toList()));
|
||||
}
|
||||
return new Polygon(normal, shell, holes);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import com.sun.javafx.collections.TrackableObservableList;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SelectionManager {
|
||||
|
||||
private final List<Listener> listeners = new ArrayList<>();
|
||||
|
||||
public void addListener(Listener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
private final ObservableList<Node> selection = new TrackableObservableList<Node>() {
|
||||
|
||||
protected void onChanged(ListChangeListener.Change<Node> c) {
|
||||
while (c.next()) {
|
||||
if (c.wasAdded()) {
|
||||
List<Node> added = c.getAddedSubList();
|
||||
added.forEach((n) -> {
|
||||
ObservableList<String> styleClass = n.getStyleClass();
|
||||
if (!styleClass.contains("selected")) {
|
||||
styleClass.add("selected");
|
||||
}
|
||||
});
|
||||
fireSelected(added);
|
||||
} else if (c.wasRemoved()) {
|
||||
List<Node> removed = c.getRemoved();
|
||||
removed.forEach((n) -> n.getStyleClass().removeAll("selected"));
|
||||
fireRemoved(removed);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void fireRemoved(List<Node> removed) {
|
||||
for (Listener l : listeners) {
|
||||
l.removed(removed);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireSelected(List<Node> added) {
|
||||
for (Listener l : listeners) {
|
||||
l.added(added);
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableList<Node> getSelection() {
|
||||
return selection;
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void added(List<Node> nodes);
|
||||
void removed(List<Node> nodes);
|
||||
}
|
||||
|
||||
public void selectExclusively(Node node) {
|
||||
selection.clear();
|
||||
selection.add(node);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.math.Vector;
|
||||
import javafx.scene.Group;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Sketch {
|
||||
|
||||
public final Polygon owner;
|
||||
public final List<List<Vector>> polygons = new ArrayList<>();
|
||||
public final Group drawLayer = new Group();
|
||||
|
||||
public Sketch(Polygon owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.math.Vector;
|
||||
import eu.mihosoft.vrl.v3d.Vector3d;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.scene.shape.Sphere;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Sketcher {
|
||||
|
||||
public final Sketch sketch;
|
||||
|
||||
public Sketcher(Sketch sketch) {
|
||||
this.sketch = sketch;
|
||||
if (sketch.polygons.isEmpty()) {
|
||||
sketch.polygons.add(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
public void addPoint(Point3D point) {
|
||||
List<Vector> poly = sketch.polygons.get(sketch.polygons.size() - 1);
|
||||
poly.add(new Vector(point.getX(), point.getY(), point.getZ()));
|
||||
Sphere pt = new Sphere(1);
|
||||
pt.setTranslateX(point.getX());
|
||||
pt.setTranslateY(point.getY());
|
||||
pt.setTranslateZ(point.getZ());
|
||||
sketch.drawLayer.getChildren().addAll(pt);
|
||||
}
|
||||
|
||||
public void commitOperation() {
|
||||
sketch.polygons.add(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.scene.transform.Translate;
|
||||
import javafx.stage.Stage;
|
||||
import org.poly2tri.Poly2Tri;
|
||||
import org.poly2tri.geometry.polygon.Polygon;
|
||||
import org.poly2tri.geometry.polygon.PolygonPoint;
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Test extends Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("prism.dirtyopts", "false");
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Pane pane = new Pane();
|
||||
Scene scene = new Scene(pane, 600, 600);
|
||||
|
||||
|
||||
|
||||
|
||||
Polygon polygon = new Polygon(Arrays.asList(
|
||||
new PolygonPoint(0, 0),
|
||||
// new PolygonPoint(200, 100),
|
||||
new PolygonPoint(400, 0),
|
||||
new PolygonPoint(400, 400),
|
||||
new PolygonPoint(0, 400)
|
||||
));
|
||||
|
||||
Polygon hole = new Polygon(Arrays.asList(
|
||||
new PolygonPoint(50, 50),
|
||||
new PolygonPoint(50, 100),
|
||||
new PolygonPoint(100, 100),
|
||||
new PolygonPoint(100, 50)
|
||||
));
|
||||
|
||||
polygon.addHole(hole);
|
||||
|
||||
Poly2Tri.triangulate(polygon);
|
||||
|
||||
|
||||
for (DelaunayTriangle triangle : polygon.getTriangles()) {
|
||||
show(pane, Arrays.asList(triangle.points));
|
||||
}
|
||||
|
||||
pane.getTransforms().add(new Translate(10, 10));
|
||||
show(pane, polygon);
|
||||
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private void show(Pane pane, Polygon polygon) {
|
||||
show(pane, polygon.getPoints());
|
||||
}
|
||||
|
||||
private void show(Pane pane, List<TriangulationPoint> points) {
|
||||
|
||||
TriangulationPoint first = points.get(0);
|
||||
TriangulationPoint prev = first;
|
||||
for (TriangulationPoint point : points.subList(1, points.size())) {
|
||||
pane.getChildren().addAll(new Line(prev.getX(), prev.getY(), point.getX(), point.getY()));
|
||||
prev = point;
|
||||
}
|
||||
pane.getChildren().addAll(new Line(prev.getX(), prev.getY(), first.getX(), first.getY()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
package cad.fx;
|
||||
|
||||
import cad.math.Vector;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Utils3D {
|
||||
|
||||
public static final PhongMaterial DEFAULT_MATERIAL = new PhongMaterial();
|
||||
public static final PhongMaterial SELECTED_MATERIAL = new PhongMaterial();
|
||||
public static final PhongMaterial HIGHLIGHTED_MATERIAL = new PhongMaterial();
|
||||
|
||||
static {
|
||||
// DEFAULT_MATERIAL.setDiffuseColor(Color.LIGHTBLUE);
|
||||
// DEFAULT_MATERIAL.setSpecularColor(Color.WHITE);
|
||||
|
||||
DEFAULT_MATERIAL.setDiffuseColor(Color.LIGHTSTEELBLUE);
|
||||
// DEFAULT_MATERIAL.setSpecularColor(Color.LIGHTBLUE);
|
||||
|
||||
SELECTED_MATERIAL.setDiffuseColor(Color.AZURE);
|
||||
// SELECTED_MATERIAL.setSpecularColor(Color.SEAGREEN); //disable reflection
|
||||
|
||||
HIGHLIGHTED_MATERIAL.setDiffuseColor(Color.LIGHTGOLDENRODYELLOW);
|
||||
// HIGHLIGHTED_MATERIAL.setSpecularColor(Color.GOLD);
|
||||
|
||||
// DEFAULT_MATERIAL.setDiffuseMap(new Image(Utils3D.class.getResource("tex.png").toExternalForm()));
|
||||
}
|
||||
|
||||
|
||||
public static CSGMesh getMesh(List<Polygon> polygons) {
|
||||
|
||||
CSGMesh mesh = new CSGMesh();
|
||||
|
||||
int faceCounter = 0;
|
||||
|
||||
for (Polygon poly : polygons) {
|
||||
|
||||
|
||||
for (Vector[] triangle : poly.getTriangles()) {
|
||||
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
(float) triangle[0].x,
|
||||
(float) triangle[0].y,
|
||||
(float) triangle[0].z
|
||||
);
|
||||
|
||||
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||
mesh.getTexCoords().addAll(0);
|
||||
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
(float) triangle[1].x,
|
||||
(float) triangle[1].y,
|
||||
(float) triangle[1].z
|
||||
);
|
||||
|
||||
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||
mesh.getTexCoords().addAll(0);
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
(float) triangle[2].x,
|
||||
(float) triangle[2].y,
|
||||
(float) triangle[2].z
|
||||
);
|
||||
|
||||
|
||||
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||
mesh.getTexCoords().addAll(0);
|
||||
|
||||
int counter = faceCounter * 3;
|
||||
mesh.getFaces().addAll(
|
||||
counter, // first vertex
|
||||
0, // texture (not covered)
|
||||
counter + 1, // second vertex
|
||||
0, // texture (not covered)
|
||||
counter + 2, // third vertex
|
||||
0 // texture (not covered)
|
||||
);
|
||||
mesh.polygons.put(faceCounter, poly);
|
||||
++faceCounter;
|
||||
|
||||
} // end if #verts >= 3
|
||||
|
||||
} // end for polygon
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static CSGMesh getFXMesh(List<DelaunayTriangle> triangles) {
|
||||
|
||||
CSGMesh mesh = new CSGMesh();
|
||||
|
||||
int faceCounter = 0;
|
||||
|
||||
for (DelaunayTriangle p : triangles) {
|
||||
|
||||
|
||||
TriangulationPoint firstVertex = p.points[0];
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
p.points[2].getXf(),
|
||||
p.points[2].getYf(),
|
||||
p.points[2].getZf()
|
||||
);
|
||||
|
||||
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||
mesh.getTexCoords().addAll(0);
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
p.points[1].getXf(),
|
||||
p.points[1].getYf(),
|
||||
p.points[1].getZf()
|
||||
);
|
||||
|
||||
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||
mesh.getTexCoords().addAll(0);
|
||||
|
||||
mesh.getPoints().addAll(
|
||||
p.points[0].getXf(),
|
||||
p.points[0].getYf(),
|
||||
p.points[0].getZf()
|
||||
);
|
||||
|
||||
mesh.getTexCoords().addAll(0); // texture (not covered)
|
||||
mesh.getTexCoords().addAll(0);
|
||||
|
||||
int counter = faceCounter * 3;
|
||||
mesh.getFaces().addAll(
|
||||
counter, // first vertex
|
||||
0, // texture (not covered)
|
||||
counter + 1, // second vertex
|
||||
0, // texture (not covered)
|
||||
counter + 2, // third vertex
|
||||
0 // texture (not covered)
|
||||
);
|
||||
// mesh.polygons.put(faceCounter, p);
|
||||
++faceCounter;
|
||||
|
||||
} // end for polygon
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static List<Polygon> createCube(double width) {
|
||||
Polygon square = createSquare(width);
|
||||
return Polygon.extrude(square, square.normal.multi(width));
|
||||
}
|
||||
|
||||
public static Polygon createSquare(double width) {
|
||||
|
||||
width /= 2;
|
||||
|
||||
List<Vector> shell = Arrays.asList(
|
||||
new Vector(-width, -width),
|
||||
new Vector(width, -width),
|
||||
new Vector(width, width, 0),
|
||||
new Vector(-width, width, 0)
|
||||
);
|
||||
|
||||
// width /= 3;
|
||||
// org.poly2tri.geometry.polygon.Polygon hole = new org.poly2tri.geometry.polygon.Polygon(Arrays.asList(
|
||||
// new PolygonPoint(-width, -width),
|
||||
// new PolygonPoint(width, -width),
|
||||
// new PolygonPoint(width, width, 100),
|
||||
// new PolygonPoint(-width, width, 100)
|
||||
// ));
|
||||
//
|
||||
// polygon.addHole(hole);
|
||||
|
||||
return new Polygon(shell);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import cad.fx.viewer.* ?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<?import javafx.scene.control.ToolBar?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox xmlns:fx="fx" fx:controller="cad.fx.AppCtrl">
|
||||
|
||||
<ToolBar>
|
||||
<Region styleClass="spacer"/>
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button text="Begin" fx:id="beginSketching"/>
|
||||
<Button text="End" fx:id="endSketching"/>
|
||||
<Button text="Pad" fx:id="pad"/>
|
||||
<Button text="Cut" fx:id="cut"/>
|
||||
</HBox>
|
||||
</ToolBar>
|
||||
|
||||
<Viewer3D fx:id="viewer"/>
|
||||
|
||||
</VBox>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import cad.fx.viewer.* ?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<?import javafx.scene.control.ToolBar?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<VBox xmlns:fx="fx" fx:controller="cad.fx.App2DCtrl">
|
||||
|
||||
<ToolBar>
|
||||
<Region styleClass="spacer"/>
|
||||
<HBox styleClass="segmented-button-bar">
|
||||
<Button text="solve" fx:id="solve"/>
|
||||
<Button text="square" fx:id="square"/>
|
||||
</HBox>
|
||||
</ToolBar>
|
||||
|
||||
<Pane fx:id="viewer">
|
||||
|
||||
</Pane>
|
||||
|
||||
</VBox>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 172 B |
|
|
@ -1,303 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2013 Oracle and/or its affiliates.
|
||||
* All rights reserved. Use is subject to license terms.
|
||||
*
|
||||
* This file is available and licensed under the following license:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the distribution.
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package cad.fx.viewer;
|
||||
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.*;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.Box;
|
||||
import javafx.scene.shape.Sphere;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.util.Duration;
|
||||
|
||||
public class Viewer3D extends SubScene {
|
||||
|
||||
final Group root = new Group();
|
||||
final Group axisGroup = new Group();
|
||||
public final Xform world = new Xform();
|
||||
final PerspectiveCamera camera = new PerspectiveCamera(true);
|
||||
final Xform cameraXform = new Xform();
|
||||
final Xform cameraXform2 = new Xform();
|
||||
final Xform cameraXform3 = new Xform();
|
||||
final double cameraDistance = 450;
|
||||
final Xform modelGroup = new Xform();
|
||||
public final Xform modelXform = new Xform();
|
||||
private Timeline timeline;
|
||||
boolean timelinePlaying = false;
|
||||
double ONE_FRAME = 1.0 / 24.0;
|
||||
double DELTA_MULTIPLIER = 200.0;
|
||||
double CONTROL_MULTIPLIER = 0.1;
|
||||
double SHIFT_MULTIPLIER = 0.1;
|
||||
double ALT_MULTIPLIER = 0.5;
|
||||
double mousePosX;
|
||||
double mousePosY;
|
||||
double mouseOldX;
|
||||
double mouseOldY;
|
||||
double mouseDeltaX;
|
||||
double mouseDeltaY;
|
||||
|
||||
public Viewer3D() {
|
||||
super(new Group(), 1024, 768, true, SceneAntialiasing.DISABLED);
|
||||
((Group)getRoot()).getChildren().add(world);
|
||||
buildCamera();
|
||||
buildAxes();
|
||||
modelGroup.getChildren().add(modelXform);
|
||||
world.getChildren().addAll(modelGroup);
|
||||
world.getTransforms().add(new Rotate(180, new Point3D(1,0,0))); //fix Y-axis
|
||||
// scene = new SubScene();
|
||||
setFill(Color.GREY);
|
||||
handleKeyboard(this, world);
|
||||
handleMouse(this, world);
|
||||
setCamera(camera);
|
||||
}
|
||||
|
||||
public void setContent(Node content) {
|
||||
modelXform.getChildren().setAll(content);
|
||||
}
|
||||
|
||||
private void buildCamera() {
|
||||
root.getChildren().add(cameraXform);
|
||||
cameraXform.getChildren().add(cameraXform2);
|
||||
cameraXform2.getChildren().add(cameraXform3);
|
||||
cameraXform3.getChildren().add(camera);
|
||||
// cameraXform3.setRotateZ(180.0);
|
||||
|
||||
camera.setNearClip(0.1);
|
||||
camera.setFarClip(10000.0);
|
||||
camera.setTranslateZ(-cameraDistance);
|
||||
cameraXform.ry.setAngle(315.0);
|
||||
cameraXform.rx.setAngle(-25);
|
||||
}
|
||||
|
||||
private void buildAxes() {
|
||||
final PhongMaterial redMaterial = new PhongMaterial();
|
||||
redMaterial.setDiffuseColor(Color.DARKRED);
|
||||
redMaterial.setSpecularColor(Color.RED);
|
||||
|
||||
final PhongMaterial greenMaterial = new PhongMaterial();
|
||||
greenMaterial.setDiffuseColor(Color.DARKGREEN);
|
||||
greenMaterial.setSpecularColor(Color.GREEN);
|
||||
|
||||
final PhongMaterial blueMaterial = new PhongMaterial();
|
||||
blueMaterial.setDiffuseColor(Color.DARKBLUE);
|
||||
blueMaterial.setSpecularColor(Color.BLUE);
|
||||
|
||||
|
||||
Sphere xArrow = new Sphere(1);
|
||||
Sphere yArrow = new Sphere(1);
|
||||
Sphere zArrow = new Sphere(1);
|
||||
|
||||
xArrow.setTranslateX(120);
|
||||
yArrow.setTranslateY(120);
|
||||
zArrow.setTranslateZ(120);
|
||||
|
||||
double axisWidth = 0.5;
|
||||
final Box xAxis = new Box(240.0, axisWidth, axisWidth);
|
||||
final Box yAxis = new Box(axisWidth, 240.0, axisWidth);
|
||||
final Box zAxis = new Box(axisWidth, axisWidth, 240.0);
|
||||
|
||||
xAxis.setMaterial(redMaterial);
|
||||
yAxis.setMaterial(greenMaterial);
|
||||
zAxis.setMaterial(blueMaterial);
|
||||
|
||||
axisGroup.getChildren().addAll(xAxis, yAxis, zAxis, xArrow, yArrow, zArrow);
|
||||
world.getChildren().addAll(axisGroup);
|
||||
}
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
private void handleMouse(SubScene scene, final Node root) {
|
||||
scene.setOnScroll(new EventHandler<ScrollEvent>() {
|
||||
public void handle(ScrollEvent event) {
|
||||
event.consume();
|
||||
if (event.getDeltaY() == 0) {
|
||||
return;
|
||||
}
|
||||
//
|
||||
double scaleFactor = event.getDeltaY() > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||
cameraXform.setScale(scaleFactor * cameraXform.s.getX());
|
||||
}
|
||||
});
|
||||
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent me) {
|
||||
mousePosX = me.getSceneX();
|
||||
mousePosY = me.getSceneY();
|
||||
mouseOldX = me.getSceneX();
|
||||
mouseOldY = me.getSceneY();
|
||||
}
|
||||
});
|
||||
scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent me) {
|
||||
mouseOldX = mousePosX;
|
||||
mouseOldY = mousePosY;
|
||||
mousePosX = me.getSceneX();
|
||||
mousePosY = me.getSceneY();
|
||||
mouseDeltaX = (mousePosX - mouseOldX);
|
||||
mouseDeltaY = (mousePosY - mouseOldY);
|
||||
|
||||
double modifierFactor = 0.1;
|
||||
|
||||
if (me.isPrimaryButtonDown()) {
|
||||
double modifier = 1.0;
|
||||
if (me.isControlDown()) modifier = 0.1;
|
||||
if (me.isShiftDown()) modifier = 10.0;
|
||||
|
||||
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0); // +
|
||||
cameraXform.rx.setAngle(cameraXform.rx.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0); // -
|
||||
// System.out.println(cameraXform.ry.getAngle() + ":" + cameraXform.rx.getAngle());
|
||||
} else if (me.isSecondaryButtonDown()) {
|
||||
double modifier = 1.0;
|
||||
if (me.isControlDown()) modifier = 0.1;
|
||||
if (me.isShiftDown()) modifier = 10.0;
|
||||
|
||||
double z = camera.getTranslateZ();
|
||||
double newZ = z + mouseDeltaX * modifierFactor * modifier;
|
||||
camera.setTranslateZ(newZ);
|
||||
} else if (me.isMiddleButtonDown()) {
|
||||
double modifier = 10.0;
|
||||
if (me.isControlDown()) modifier = 0.1;
|
||||
|
||||
cameraXform2.t.setX(cameraXform2.t.getX() - mouseDeltaX * modifierFactor * modifier * 0.3); // -
|
||||
cameraXform2.t.setY(cameraXform2.t.getY() - mouseDeltaY * modifierFactor * modifier * 0.3); // -
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleKeyboard(SubScene scene, final Node root) {
|
||||
final boolean moveCamera = true;
|
||||
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
||||
@Override
|
||||
public void handle(KeyEvent event) {
|
||||
Duration currentTime;
|
||||
switch (event.getCode()) {
|
||||
case Z:
|
||||
if (event.isShiftDown()) {
|
||||
cameraXform.ry.setAngle(0.0);
|
||||
cameraXform.rx.setAngle(0.0);
|
||||
camera.setTranslateZ(-300.0);
|
||||
}
|
||||
cameraXform2.t.setX(0.0);
|
||||
cameraXform2.t.setY(0.0);
|
||||
break;
|
||||
case X:
|
||||
if (event.isControlDown()) {
|
||||
if (axisGroup.isVisible()) {
|
||||
axisGroup.setVisible(false);
|
||||
} else {
|
||||
axisGroup.setVisible(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case S:
|
||||
if (event.isControlDown()) {
|
||||
if (modelGroup.isVisible()) {
|
||||
modelGroup.setVisible(false);
|
||||
} else {
|
||||
modelGroup.setVisible(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPACE:
|
||||
if (timelinePlaying) {
|
||||
timeline.pause();
|
||||
timelinePlaying = false;
|
||||
} else {
|
||||
timeline.play();
|
||||
timelinePlaying = true;
|
||||
}
|
||||
break;
|
||||
case UP:
|
||||
if (event.isControlDown() && event.isShiftDown()) {
|
||||
cameraXform2.t.setY(cameraXform2.t.getY() - 10.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||
cameraXform.rx.setAngle(cameraXform.rx.getAngle() - 10.0 * ALT_MULTIPLIER);
|
||||
} else if (event.isControlDown()) {
|
||||
cameraXform2.t.setY(cameraXform2.t.getY() - 1.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown()) {
|
||||
cameraXform.rx.setAngle(cameraXform.rx.getAngle() - 2.0 * ALT_MULTIPLIER);
|
||||
} else if (event.isShiftDown()) {
|
||||
double z = camera.getTranslateZ();
|
||||
double newZ = z + 5.0 * SHIFT_MULTIPLIER;
|
||||
camera.setTranslateZ(newZ);
|
||||
}
|
||||
break;
|
||||
case DOWN:
|
||||
if (event.isControlDown() && event.isShiftDown()) {
|
||||
cameraXform2.t.setY(cameraXform2.t.getY() + 10.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||
cameraXform.rx.setAngle(cameraXform.rx.getAngle() + 10.0 * ALT_MULTIPLIER);
|
||||
} else if (event.isControlDown()) {
|
||||
cameraXform2.t.setY(cameraXform2.t.getY() + 1.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown()) {
|
||||
cameraXform.rx.setAngle(cameraXform.rx.getAngle() + 2.0 * ALT_MULTIPLIER);
|
||||
} else if (event.isShiftDown()) {
|
||||
double z = camera.getTranslateZ();
|
||||
double newZ = z - 5.0 * SHIFT_MULTIPLIER;
|
||||
camera.setTranslateZ(newZ);
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
if (event.isControlDown() && event.isShiftDown()) {
|
||||
cameraXform2.t.setX(cameraXform2.t.getX() + 10.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||
cameraXform.ry.setAngle(cameraXform.ry.getAngle() - 10.0 * ALT_MULTIPLIER);
|
||||
} else if (event.isControlDown()) {
|
||||
cameraXform2.t.setX(cameraXform2.t.getX() + 1.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown()) {
|
||||
cameraXform.ry.setAngle(cameraXform.ry.getAngle() - 2.0 * ALT_MULTIPLIER);
|
||||
}
|
||||
break;
|
||||
case LEFT:
|
||||
if (event.isControlDown() && event.isShiftDown()) {
|
||||
cameraXform2.t.setX(cameraXform2.t.getX() - 10.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown() && event.isShiftDown()) {
|
||||
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + 10.0 * ALT_MULTIPLIER); // -
|
||||
} else if (event.isControlDown()) {
|
||||
cameraXform2.t.setX(cameraXform2.t.getX() - 1.0 * CONTROL_MULTIPLIER);
|
||||
} else if (event.isAltDown()) {
|
||||
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + 2.0 * ALT_MULTIPLIER); // -
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2013 Oracle and/or its affiliates.
|
||||
* All rights reserved. Use is subject to license terms.
|
||||
*
|
||||
* This file is available and licensed under the following license:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the distribution.
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package cad.fx.viewer;
|
||||
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
import javafx.scene.transform.Translate;
|
||||
|
||||
public class Xform extends Group {
|
||||
|
||||
public enum RotateOrder {
|
||||
XYZ, XZY, YXZ, YZX, ZXY, ZYX
|
||||
}
|
||||
|
||||
public Translate t = new Translate();
|
||||
public Translate p = new Translate();
|
||||
public Translate ip = new Translate();
|
||||
public Rotate rx = new Rotate();
|
||||
|
||||
{
|
||||
rx.setAxis(Rotate.X_AXIS);
|
||||
}
|
||||
|
||||
public Rotate ry = new Rotate();
|
||||
|
||||
{
|
||||
ry.setAxis(Rotate.Y_AXIS);
|
||||
}
|
||||
|
||||
public Rotate rz = new Rotate();
|
||||
|
||||
{
|
||||
rz.setAxis(Rotate.Z_AXIS);
|
||||
}
|
||||
|
||||
public Scale s = new Scale();
|
||||
|
||||
public Xform() {
|
||||
super();
|
||||
getTransforms().addAll(t, rz, ry, rx, s);
|
||||
}
|
||||
|
||||
public Xform(RotateOrder rotateOrder) {
|
||||
super();
|
||||
// choose the order of rotations based on the rotateOrder
|
||||
switch (rotateOrder) {
|
||||
case XYZ:
|
||||
getTransforms().addAll(t, p, rz, ry, rx, s, ip);
|
||||
break;
|
||||
case XZY:
|
||||
getTransforms().addAll(t, p, ry, rz, rx, s, ip);
|
||||
break;
|
||||
case YXZ:
|
||||
getTransforms().addAll(t, p, rz, rx, ry, s, ip);
|
||||
break;
|
||||
case YZX:
|
||||
getTransforms().addAll(t, p, rx, rz, ry, s, ip); // For Camera
|
||||
break;
|
||||
case ZXY:
|
||||
getTransforms().addAll(t, p, ry, rx, rz, s, ip);
|
||||
break;
|
||||
case ZYX:
|
||||
getTransforms().addAll(t, p, rx, ry, rz, s, ip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTranslate(double x, double y, double z) {
|
||||
t.setX(x);
|
||||
t.setY(y);
|
||||
t.setZ(z);
|
||||
}
|
||||
|
||||
public void setTranslate(double x, double y) {
|
||||
t.setX(x);
|
||||
t.setY(y);
|
||||
}
|
||||
|
||||
// Cannot override these methods as they are final:
|
||||
// public void setTranslateX(double x) { t.setX(x); }
|
||||
// public void setTranslateY(double y) { t.setY(y); }
|
||||
// public void setTranslateZ(double z) { t.setZ(z); }
|
||||
// Use these methods instead:
|
||||
public void setTx(double x) {
|
||||
t.setX(x);
|
||||
}
|
||||
|
||||
public void setTy(double y) {
|
||||
t.setY(y);
|
||||
}
|
||||
|
||||
public void setTz(double z) {
|
||||
t.setZ(z);
|
||||
}
|
||||
|
||||
public void setRotate(double x, double y, double z) {
|
||||
rx.setAngle(x);
|
||||
ry.setAngle(y);
|
||||
rz.setAngle(z);
|
||||
}
|
||||
|
||||
public void setRotateX(double x) {
|
||||
rx.setAngle(x);
|
||||
}
|
||||
|
||||
public void setRotateY(double y) {
|
||||
ry.setAngle(y);
|
||||
}
|
||||
|
||||
public void setRotateZ(double z) {
|
||||
rz.setAngle(z);
|
||||
}
|
||||
|
||||
public void setRx(double x) {
|
||||
rx.setAngle(x);
|
||||
}
|
||||
|
||||
public void setRy(double y) {
|
||||
ry.setAngle(y);
|
||||
}
|
||||
|
||||
public void setRz(double z) {
|
||||
rz.setAngle(z);
|
||||
}
|
||||
|
||||
public void setScale(double scaleFactor) {
|
||||
s.setX(scaleFactor);
|
||||
s.setY(scaleFactor);
|
||||
s.setZ(scaleFactor);
|
||||
}
|
||||
|
||||
public void setScale(double x, double y, double z) {
|
||||
s.setX(x);
|
||||
s.setY(y);
|
||||
s.setZ(z);
|
||||
}
|
||||
|
||||
// Cannot override these methods as they are final:
|
||||
// public void setScaleX(double x) { s.setX(x); }
|
||||
// public void setScaleY(double y) { s.setY(y); }
|
||||
// public void setScaleZ(double z) { s.setZ(z); }
|
||||
// Use these methods instead:
|
||||
public void setSx(double x) {
|
||||
s.setX(x);
|
||||
}
|
||||
|
||||
public void setSy(double y) {
|
||||
s.setY(y);
|
||||
}
|
||||
|
||||
public void setSz(double z) {
|
||||
s.setZ(z);
|
||||
}
|
||||
|
||||
public void setPivot(double x, double y, double z) {
|
||||
p.setX(x);
|
||||
p.setY(y);
|
||||
p.setZ(z);
|
||||
ip.setX(-x);
|
||||
ip.setY(-y);
|
||||
ip.setZ(-z);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
t.setX(0.0);
|
||||
t.setY(0.0);
|
||||
t.setZ(0.0);
|
||||
rx.setAngle(0.0);
|
||||
ry.setAngle(0.0);
|
||||
rz.setAngle(0.0);
|
||||
s.setX(1.0);
|
||||
s.setY(1.0);
|
||||
s.setZ(1.0);
|
||||
p.setX(0.0);
|
||||
p.setY(0.0);
|
||||
p.setZ(0.0);
|
||||
ip.setX(0.0);
|
||||
ip.setY(0.0);
|
||||
ip.setZ(0.0);
|
||||
}
|
||||
|
||||
public void resetTSP() {
|
||||
t.setX(0.0);
|
||||
t.setY(0.0);
|
||||
t.setZ(0.0);
|
||||
s.setX(1.0);
|
||||
s.setY(1.0);
|
||||
s.setZ(1.0);
|
||||
p.setX(0.0);
|
||||
p.setY(0.0);
|
||||
p.setZ(0.0);
|
||||
ip.setX(0.0);
|
||||
ip.setY(0.0);
|
||||
ip.setZ(0.0);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
public interface Constraint extends System {
|
||||
|
||||
double error();
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import cad.gcs.constr.Equal;
|
||||
import cad.gcs.constr.P2LDistance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Figures {
|
||||
|
||||
public static final int X1 = 0;
|
||||
public static final int Y1 = 1;
|
||||
public static final int X2 = 2;
|
||||
public static final int Y2 = 3;
|
||||
public static final int X3 = 4;
|
||||
public static final int Y3 = 5;
|
||||
public static final int X4 = 6;
|
||||
public static final int Y4 = 7;
|
||||
|
||||
public static Figure square(double size) {
|
||||
|
||||
List<Constraint> constrs = new ArrayList<>();
|
||||
|
||||
Param[] l1 = line();
|
||||
Param[] l2 = line();
|
||||
Param[] l3 = line();
|
||||
Param[] l4 = line();
|
||||
|
||||
constrs.add(new Equal(l1[X1], l4[X2]));
|
||||
constrs.add(new Equal(l1[Y1], l4[Y2]));
|
||||
constrs.add(new Equal(l2[X1], l1[X2]));
|
||||
constrs.add(new Equal(l2[Y1], l1[Y2]));
|
||||
constrs.add(new Equal(l3[X1], l2[X2]));
|
||||
constrs.add(new Equal(l3[Y1], l2[Y2]));
|
||||
constrs.add(new Equal(l4[X1], l3[X2]));
|
||||
constrs.add(new Equal(l4[Y1], l3[Y2]));
|
||||
|
||||
constrs.add(new Equal(l1[Y1], l1[Y2]));
|
||||
constrs.add(new Equal(l3[Y1], l3[Y2]));
|
||||
constrs.add(new Equal(l2[X1], l2[X2]));
|
||||
constrs.add(new Equal(l4[X1], l4[X2]));
|
||||
|
||||
constrs.add(new P2LDistance(100, l1[X1], l1[Y1], l2[X1], l2[Y1], l2[X2], l2[Y2]));
|
||||
constrs.add(new P2LDistance(100, l1[X1], l1[Y1], l3[X1], l3[Y1], l3[X2], l3[Y2]));
|
||||
|
||||
return new Figure(new Param[][]{l1, l2, l3, l4}, constrs);
|
||||
}
|
||||
|
||||
private static Param[] line() {
|
||||
return new Param[]{new Param(200), new Param(200), new Param(500), new Param(500)};
|
||||
}
|
||||
|
||||
public static class Figure {
|
||||
|
||||
public final Param[][] lines;
|
||||
public final List<Constraint> constraints;
|
||||
|
||||
public Figure(Param[][] lines, List<Constraint> constraints) {
|
||||
this.lines = lines;
|
||||
this.constraints = constraints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import cad.gcs.constr.Equal;
|
||||
import cad.gcs.constr.EqualsTo;
|
||||
import gnu.trove.list.TDoubleList;
|
||||
import org.apache.commons.math3.optim.InitialGuess;
|
||||
import org.apache.commons.math3.optim.MaxEval;
|
||||
import org.apache.commons.math3.optim.MaxIter;
|
||||
import org.apache.commons.math3.optim.PointVectorValuePair;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.ModelFunction;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.ModelFunctionJacobian;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.Target;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.Weight;
|
||||
import org.apache.commons.math3.optim.nonlinear.vector.jacobian.LevenbergMarquardtOptimizer;
|
||||
|
||||
import java.lang.*;
|
||||
import java.lang.System;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class GlobalSolver {
|
||||
|
||||
public static void globalSolve(Solver.SubSystem subSystem, Runnable linearSolvedCallback) {
|
||||
|
||||
// for (Constraint c : subSystem.constraints) {
|
||||
// if (c instanceof Reconcilable) {
|
||||
// ((Reconcilable) c).reconcile();
|
||||
// }
|
||||
// }
|
||||
|
||||
double eps = 0.0001;
|
||||
java.lang.System.out.println(String.format("Solve system with error: %.4f", + subSystem.value()));
|
||||
int count = 0;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
solveLM_COMMONS(subSystem);
|
||||
|
||||
// if (subSystem.valueSquared() > eps) Solver.solve_BFGS(subSystem, false);
|
||||
// if (subSystem.valueSquared() > eps) Solver.solve_DL(subSystem);
|
||||
// if (subSystem.valueSquared() > eps) Solver.solve_LM(subSystem);
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
java.lang.System.out.println(String.format("Solved with error: %.4f", + subSystem.value()));
|
||||
java.lang.System.out.println("TOOK: " + (end - start) / 1000f);
|
||||
linearSolvedCallback.run();
|
||||
}
|
||||
|
||||
public static void globalSolve2(Solver.SubSystem subSystem, Runnable linearSolvedCallback) {
|
||||
|
||||
|
||||
double eps = 0.0001;
|
||||
java.lang.System.out.println("Solve system with error: " + subSystem.value());
|
||||
int count = 0;
|
||||
|
||||
List<Solver.SubSystem> subSystems = subSystem.splitUp();
|
||||
for (Solver.SubSystem system : subSystems) {
|
||||
java.lang.System.out.println("Solve subsystem: " + subSystem.value());
|
||||
solveLM_COMMONS(system);
|
||||
// Solver.solve_BFGS(system, false);
|
||||
// Solver.solve_LM(system);
|
||||
java.lang.System.out.println("Subsystem solved: " + subSystem.value());
|
||||
linearSolvedCallback.run();
|
||||
}
|
||||
linearSolvedCallback.run();
|
||||
|
||||
// globalSolve2(subSystem, linearSolvedCallback);
|
||||
}
|
||||
|
||||
|
||||
public static void solveLM_COMMONS(final Solver.SubSystem subSystem) {
|
||||
double fine = 0.00000001;
|
||||
double rough = 0.0001;
|
||||
double eps = rough;
|
||||
|
||||
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer(eps,eps,eps);
|
||||
|
||||
double[] wieght = new double[subSystem.cSize()];
|
||||
Arrays.fill(wieght, 1);
|
||||
setUpWeight(subSystem, wieght);
|
||||
PointVectorValuePair result = optimizer.optimize(
|
||||
new MaxEval(100000),
|
||||
new MaxIter(100000),
|
||||
new InitialGuess(subSystem.getParams().toArray()),
|
||||
new Target(new double[subSystem.cSize()]),
|
||||
new Weight(wieght),
|
||||
getJacobian(subSystem),
|
||||
getFunction(subSystem)
|
||||
);
|
||||
|
||||
subSystem.setParams(result.getPoint());
|
||||
}
|
||||
|
||||
private static void setUpWeight(Solver.SubSystem subSystem, double[] wieght) {
|
||||
for (int i = 0; i < subSystem.constraints.size(); i++) {
|
||||
Constraint constraint = subSystem.constraints.get(i);
|
||||
if ((constraint instanceof Equal) || (constraint instanceof EqualsTo)) {
|
||||
// wieght[i] = 0.9;
|
||||
} else {
|
||||
// wieght[i] = 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ModelFunction getFunction(Solver.SubSystem subSystem) {
|
||||
return new ModelFunction(point -> {
|
||||
subSystem.setParams(point);
|
||||
return subSystem.getValues().toArray();
|
||||
});
|
||||
}
|
||||
|
||||
private static ModelFunctionJacobian getJacobian(Solver.SubSystem subSystem) {
|
||||
return new ModelFunctionJacobian(point -> {
|
||||
subSystem.setParams(point);
|
||||
return subSystem.makeJacobi().getData();
|
||||
});
|
||||
}
|
||||
|
||||
private static Solver.SubSystem shrink(Solver.SubSystem system) {
|
||||
TDoubleList residuals = system.calcResidual();
|
||||
int minIdx = residuals.indexOf(residuals.min());
|
||||
ArrayList<Constraint> constrs = new ArrayList<>(system.constraints);
|
||||
constrs.remove(minIdx);
|
||||
return new Solver.SubSystem(constrs);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import cad.gcs.constr.Perpendicular;
|
||||
import org.apache.commons.math3.linear.ArrayRealVector;
|
||||
import org.apache.commons.math3.linear.RealVector;
|
||||
|
||||
public class GradientDescent {
|
||||
|
||||
static double EPS = 0.0000001;
|
||||
|
||||
public static void solve(Constraint constr) {
|
||||
|
||||
//
|
||||
// double last = value(constr);
|
||||
//
|
||||
// double alpha = 10;
|
||||
// int pSize = constr.pSize();
|
||||
//
|
||||
// RealVector steps = new ArrayRealVector(pSize);
|
||||
// steps.set(10);
|
||||
//
|
||||
// for (int i = 0; i < 1000000; i++) {
|
||||
//
|
||||
//
|
||||
// double[] gradData = new double[pSize];
|
||||
// constr.gradient(gradData);
|
||||
// ArrayRealVector grad = new ArrayRealVector(gradData);
|
||||
//
|
||||
// RealVector dir = grad.mapDivide(grad.getNorm());
|
||||
// dir = dir.mapMultiply( alpha);
|
||||
// java.lang.System.out.println(dir.getNorm());
|
||||
//
|
||||
//
|
||||
// ArrayRealVector params = new ArrayRealVector(constr.params());
|
||||
// params = params.add(dir);
|
||||
// constr.set(params.toArray());
|
||||
// java.lang.System.out.println(((Perpendicular) constr).angle());
|
||||
//// constr.step(alpha);
|
||||
// double err = value(constr);
|
||||
//
|
||||
// if (err < last) {
|
||||
//
|
||||
// } else if (alpha < EPS) {
|
||||
// return;
|
||||
// } else {
|
||||
// alpha /= 3;
|
||||
// }
|
||||
// last = err;
|
||||
// }
|
||||
}
|
||||
|
||||
private static double value(Constraint constr) {
|
||||
double err = constr.error();
|
||||
return err * err;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import cad.gcs.constr.Constraint2;
|
||||
import cad.gcs.constr.Perpendicular2;
|
||||
import cad.math.Vector;
|
||||
|
||||
import java.lang.*;
|
||||
import java.util.List;
|
||||
|
||||
public class GradientDescent2 {
|
||||
|
||||
private static final double DBL_EPSILON = Double.MIN_VALUE;
|
||||
|
||||
static double EPS = 0.0000000001;
|
||||
|
||||
public static void solve(Constraint2 constr) {
|
||||
|
||||
|
||||
double last = value(constr);
|
||||
|
||||
double alpha = .01;
|
||||
|
||||
List<Vector> params = constr.params();
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
|
||||
|
||||
List<Vector> grad = constr.gradient();
|
||||
for (int j = 0; j < grad.size(); j++) {
|
||||
Vector gr = grad.get(j);
|
||||
Vector param = params.get(j);
|
||||
Vector step = gr.normalize().multi(alpha);
|
||||
param._plus(step);
|
||||
}
|
||||
double err = value(constr);
|
||||
|
||||
java.lang.System.out.println(constr.debug() + "===" + err + "====>" + alpha );
|
||||
if (err < last) {
|
||||
|
||||
} else {
|
||||
if (alpha < EPS) {
|
||||
return;
|
||||
} else {
|
||||
alpha /= 3;
|
||||
}
|
||||
}
|
||||
last = err;
|
||||
}
|
||||
}
|
||||
|
||||
private static double value(Constraint2 constr) {
|
||||
double err = constr.error();
|
||||
return Math.abs(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import cad.gcs.constr.Constraint2;
|
||||
import cad.gcs.constr.Perpendicular2;
|
||||
import cad.math.Vector;
|
||||
import gnu.trove.list.TDoubleList;
|
||||
import gnu.trove.list.array.TDoubleArrayList;
|
||||
import gnu.trove.map.hash.TObjectDoubleHashMap;
|
||||
|
||||
import java.lang.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class GradientDescent3 {
|
||||
|
||||
private static final double DBL_EPSILON = Double.MIN_VALUE;
|
||||
|
||||
static double EPS = 0.0000001;
|
||||
|
||||
public static void solve(Constraint2... constrs) {
|
||||
|
||||
TObjectDoubleHashMap<Vector> alphas = new TObjectDoubleHashMap<>();
|
||||
double[] values = new double[constrs.length];
|
||||
double[] calphas = new double[constrs.length];
|
||||
|
||||
for (int k = 0; k < constrs.length; k++) {
|
||||
Constraint2 constr = constrs[k];
|
||||
for (Vector p : constr.params()) {
|
||||
alphas.put(p, 1);
|
||||
}
|
||||
values[k] = (value(constr));
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
for (int k = 0; k < constrs.length; k++) {
|
||||
Constraint2 constr = constrs[k];
|
||||
List<Vector> params = constr.params();
|
||||
double calpha = calphas[k];
|
||||
List<Vector> grad = constr.gradient();
|
||||
for (int j = 0; j < grad.size(); j++) {
|
||||
Vector gr = grad.get(j);
|
||||
Vector param = params.get(j);
|
||||
double alpha = alphas.get(param);
|
||||
Vector step = gr.normalize().multi(alpha);
|
||||
param._plus(step);
|
||||
}
|
||||
double err = value(constr);
|
||||
double last = values[k];
|
||||
// java.lang.System.out.println(constr.debug() + "===" + err + "====>" + alpha );
|
||||
if (err < last) {
|
||||
} else {
|
||||
boolean divergence = true;
|
||||
for (double a : calphas) {
|
||||
if (a >= EPS) {
|
||||
divergence = false;
|
||||
}
|
||||
}
|
||||
if (divergence) {
|
||||
return;
|
||||
} else {
|
||||
calpha /= 3;
|
||||
calphas[k] = calpha;
|
||||
for (Vector param : params) {
|
||||
alphas.put(param, Math.min(alphas.get(param), calpha));
|
||||
}
|
||||
}
|
||||
}
|
||||
values[k] = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double value(Constraint2 constr) {
|
||||
double err = constr.error();
|
||||
return Math.abs(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
// levenberg-marquardt in java
|
||||
//
|
||||
// To use this, implement the functions in the LMfunc interface.
|
||||
//
|
||||
// This library uses simple matrix routines from the JAMA java matrix package,
|
||||
// which is in the public domain. Reference:
|
||||
// http://math.nist.gov/javanumerics/jama/
|
||||
// (JAMA has a matrix object class. An earlier library JNL, which is no longer
|
||||
// available, represented matrices as low-level arrays. Several years
|
||||
// ago the performance of JNL matrix code was better than that of JAMA,
|
||||
// though improvements in java compilers may have fixed this by now.)
|
||||
//
|
||||
// One further recommendation would be to use an inverse based
|
||||
// on Choleski decomposition, which is easy to implement and
|
||||
// suitable for the symmetric inverse required here. There is a choleski
|
||||
// routine at idiom.com/~zilla.
|
||||
//
|
||||
// If you make an improved version, please consider adding your
|
||||
// name to it ("modified by ...") and send it back to me
|
||||
// (and put it on the web).
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the
|
||||
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
// Boston, MA 02111-1307, USA.
|
||||
//
|
||||
// initial author contact info:
|
||||
// jplewis www.idiom.com/~zilla zilla # computer.org, #=at
|
||||
//
|
||||
// Improvements by:
|
||||
// dscherba www.ncsa.uiuc.edu/~dscherba
|
||||
// Jonathan Jackson j.jackson # ucl.ac.uk
|
||||
|
||||
|
||||
package cad.gcs;
|
||||
|
||||
// see comment above
|
||||
|
||||
import Jama.*;
|
||||
|
||||
/**
|
||||
* Levenberg-Marquardt, implemented from the general description
|
||||
* in Numerical Recipes (NR), then tweaked slightly to mostly
|
||||
* match the results of their code.
|
||||
* Use for nonlinear least squares assuming Gaussian errors.
|
||||
* <p>
|
||||
* TODO this holds some parameters fixed by simply not updating them.
|
||||
* this may be ok if the number if fixed parameters is small,
|
||||
* but if the number of varying parameters is larger it would
|
||||
* be more efficient to make a smaller hessian involving only
|
||||
* the variables.
|
||||
* <p>
|
||||
* The NR code assumes a statistical context, e.g. returns
|
||||
* covariance of parameter errors; we do not do this.
|
||||
*/
|
||||
public final class LM {
|
||||
|
||||
/**
|
||||
* calculate the current sum-squared-error
|
||||
* (Chi-squared is the distribution of squared Gaussian errors,
|
||||
* thus the name)
|
||||
*/
|
||||
static double chiSquared(double[] a, double[] y, double[] s,
|
||||
LMfunc f) {
|
||||
int npts = y.length;
|
||||
double sum = 0.;
|
||||
|
||||
double[] val = f.val(a);
|
||||
for (int i = 0; i < npts; i++) {
|
||||
double d = y[i] - val[i];
|
||||
d = d / s[i];
|
||||
sum = sum + (d * d);
|
||||
}
|
||||
|
||||
return sum;
|
||||
} //chiSquared
|
||||
|
||||
|
||||
/**
|
||||
* Minimize E = sum {(y[k] - f(x[k],a)) / s[k]}^2
|
||||
* The individual errors are optionally scaled by s[k].
|
||||
* Note that LMfunc implements the value and gradient of f(x,a),
|
||||
* NOT the value and gradient of E with respect to a!
|
||||
*
|
||||
* @param y corresponding array of values
|
||||
* @param a the parameters/state of the model
|
||||
* @param vary false to indicate the corresponding a[k] is to be held fixed
|
||||
* @param s sigma^2 for point i
|
||||
* @param lambda blend between steepest descent (lambda high) and
|
||||
* jump to bottom of quadratic (lambda zero).
|
||||
* Start with 0.001.
|
||||
* @param termepsilon termination accuracy (0.01)
|
||||
* @param maxiter stop and return after this many iterations if not done
|
||||
* @param verbose set to zero (no prints), 1, 2
|
||||
* @return the new lambda for future iterations.
|
||||
* Can use this and maxiter to interleave the LM descent with some other
|
||||
* task, setting maxiter to something small.
|
||||
*/
|
||||
public static double solve(double[] a, double[] y, double[] s,
|
||||
boolean[] vary, LMfunc f,
|
||||
double lambda, double termepsilon, int maxiter,
|
||||
int verbose)
|
||||
throws Exception {
|
||||
int npts = y.length;
|
||||
int nparm = a.length;
|
||||
assert s.length == npts;
|
||||
if (verbose > 0) {
|
||||
out().print(" a[" + a.length + "]");
|
||||
out().println(" y[" + y.length + "]");
|
||||
}
|
||||
|
||||
double e0 = chiSquared(a, y, s, f);
|
||||
//double lambda = 0.001;
|
||||
boolean done = false;
|
||||
|
||||
// g = gradient, H = hessian, d = step to minimum
|
||||
// H d = -g, solve for d
|
||||
double[][] H = new double[nparm][nparm];
|
||||
double[] g = new double[nparm];
|
||||
//double[] d = new double[nparm];
|
||||
|
||||
double[] oos2 = new double[s.length];
|
||||
for (int i = 0; i < npts; i++) {
|
||||
oos2[i] = 1. / (s[i] * s[i]);
|
||||
}
|
||||
|
||||
int iter = 0;
|
||||
int term = 0; // termination count test
|
||||
|
||||
do {
|
||||
++iter;
|
||||
|
||||
// hessian approximation
|
||||
for (int r = 0; r < nparm; r++) {
|
||||
for (int c = 0; c < nparm; c++) {
|
||||
for (int i = 0; i < npts; i++) {
|
||||
if (i == 0) {
|
||||
H[r][c] = 0.;
|
||||
}
|
||||
double[] grad = f.grad(a);
|
||||
H[r][c] += (oos2[i] * grad[r] * grad[c]);
|
||||
} //npts
|
||||
} //c
|
||||
} //r
|
||||
|
||||
// boost diagonal towards gradient descent
|
||||
for (int r = 0; r < nparm; r++) {
|
||||
H[r][r] *= (1. + lambda);
|
||||
}
|
||||
|
||||
// gradient
|
||||
for (int r = 0; r < nparm; r++) {
|
||||
for (int i = 0; i < npts; i++) {
|
||||
if (i == 0) {
|
||||
g[r] = 0.;
|
||||
}
|
||||
double[] grad = f.grad(a);
|
||||
double[] val = f.val(a);
|
||||
g[r] += (oos2[i] * (y[i] - val[i]) * grad[r]);
|
||||
}
|
||||
} //npts
|
||||
|
||||
// scale (for consistency with NR, not necessary)
|
||||
if (false) {
|
||||
for (int r = 0; r < nparm; r++) {
|
||||
g[r] = -0.5 * g[r];
|
||||
for (int c = 0; c < nparm; c++) {
|
||||
H[r][c] *= 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// solve H d = -g, evaluate error at new location
|
||||
//double[] d = DoubleMatrix.solve(H, g);
|
||||
double[] d = (new Matrix(H)).lu().solve(new Matrix(g, nparm)).getRowPackedCopy();
|
||||
//double[] na = DoubleVector.add(a, d);
|
||||
double[] na = (new Matrix(a, nparm)).plus(new Matrix(d, nparm)).getRowPackedCopy();
|
||||
double e1 = chiSquared(na, y, s, f);
|
||||
|
||||
if (verbose > 0) {
|
||||
out().println("\n\niteration " + iter + " lambda = " + lambda);
|
||||
out().print("a = ");
|
||||
(new Matrix(a, nparm)).print(10, 2);
|
||||
if (verbose > 1) {
|
||||
out().print("H = ");
|
||||
(new Matrix(H)).print(10, 2);
|
||||
out().print("g = ");
|
||||
(new Matrix(g, nparm)).print(10, 2);
|
||||
out().print("d = ");
|
||||
(new Matrix(d, nparm)).print(10, 2);
|
||||
}
|
||||
out().print("e0 = " + e0 + ": ");
|
||||
out().print("moved from ");
|
||||
(new Matrix(a, nparm)).print(10, 2);
|
||||
out().print("e1 = " + e1 + ": ");
|
||||
if (e1 < e0) {
|
||||
out().print("to ");
|
||||
(new Matrix(na, nparm)).print(10, 2);
|
||||
} else {
|
||||
out().println("move rejected");
|
||||
}
|
||||
}
|
||||
|
||||
// termination test (slightly different than NR)
|
||||
if (Math.abs(e1 - e0) > termepsilon) {
|
||||
term = 0;
|
||||
} else {
|
||||
term++;
|
||||
if (term == 4) {
|
||||
out().println("terminating after " + iter + " iterations");
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (iter >= maxiter) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
// in the C++ version, found that changing this to e1 >= e0
|
||||
// was not a good idea. See comment there.
|
||||
//
|
||||
if (e1 > e0 || Double.isNaN(e1)) { // new location worse than before
|
||||
lambda *= 10.;
|
||||
} else { // new location better, accept new parameters
|
||||
lambda *= 0.1;
|
||||
e0 = e1;
|
||||
// simply assigning a = na will not get results copied back to caller
|
||||
for (int i = 0; i < nparm; i++) {
|
||||
if (vary[i]) {
|
||||
a[i] = na[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
|
||||
return lambda;
|
||||
} //solve
|
||||
|
||||
private static java.io.PrintStream out() {
|
||||
return java.lang.System.out;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
} //LM
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
// LMfunc.java
|
||||
|
||||
package cad.gcs;
|
||||
|
||||
/**
|
||||
* Caller implement this interface to specify the
|
||||
* function to be minimized and its gradient.
|
||||
*
|
||||
* Optionally return an initial guess and some test data,
|
||||
* though the LM.java only uses this in its optional main() test program.
|
||||
* Return null if these are not needed.
|
||||
*/
|
||||
public interface LMfunc
|
||||
{
|
||||
|
||||
/**
|
||||
* x is a single point, but domain may be mulidimensional
|
||||
*/
|
||||
double[] val(double[] a);
|
||||
|
||||
/**
|
||||
* return the kth component of the gradient df(x,a)/da_k
|
||||
*/
|
||||
double[] grad(double[] a);
|
||||
|
||||
} //LMfunc
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2007-2009, OpenMaLi Project Group all rights reserved.
|
||||
*
|
||||
* Portions based on the Sun's javax.vecmath interface, Copyright by Sun
|
||||
* Microsystems or Kenji Hiranabe's alternative GC-cheap implementation.
|
||||
* Many thanks to the developers.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the 'OpenMaLi Project Group' nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
|
||||
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE
|
||||
*/
|
||||
package cad.gcs;
|
||||
|
||||
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
|
||||
import org.apache.commons.math3.linear.RealMatrix;
|
||||
|
||||
/**
|
||||
* LU Decomposition.
|
||||
* <p>
|
||||
* For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
|
||||
* unit lower triangular matrix L, an n-by-n upper triangular matrix U,
|
||||
* and a permutation vector piv of length m so that A(piv,:) = L*U.
|
||||
* If m < n, then L is m-by-m and U is m-by-n.
|
||||
* </p>
|
||||
* <p>
|
||||
* The LU decompostion with pivoting always exists, even if the matrix is
|
||||
* singular, so the constructor will never fail. The primary use of the
|
||||
* LU decomposition is in the solution of square systems of simultaneous
|
||||
* linear equations. This will fail if isNonsingular() returns false.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a>
|
||||
*/
|
||||
public class LUDecomposition {
|
||||
/**
|
||||
* Array for internal storage of decomposition.
|
||||
*
|
||||
* @serial internal array storage.
|
||||
*/
|
||||
private final RealMatrix LU;
|
||||
|
||||
/**
|
||||
* Row and column dimensions, and pivot sign.
|
||||
*
|
||||
* @serial column dimension.
|
||||
* @serial row dimension.
|
||||
* @serial pivot sign.
|
||||
*/
|
||||
private int m, n, pivsign;
|
||||
|
||||
/**
|
||||
* Internal storage of pivot vector.
|
||||
*
|
||||
* @serial pivot vector.
|
||||
*/
|
||||
private final int[] piv;
|
||||
|
||||
/**
|
||||
* LU Decomposition.
|
||||
*
|
||||
* @param A Rectangular matrix
|
||||
*/
|
||||
public LUDecomposition(RealMatrix A) {
|
||||
|
||||
// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
|
||||
|
||||
this.LU = new Array2DRowRealMatrix(A.getData());
|
||||
this.m = A.getRowDimension();
|
||||
this.n = A.getColumnDimension();
|
||||
this.piv = new int[m];
|
||||
|
||||
for (int i = 0; i < m; i++) {
|
||||
piv[i] = i;
|
||||
}
|
||||
|
||||
this.pivsign = 1;
|
||||
double[] LUrowi;
|
||||
double[] LUcolj;
|
||||
|
||||
// Outer loop.
|
||||
for (int j = 0; j < n; j++) {
|
||||
// Make a copy of the j-th column to localize references.
|
||||
LUcolj = LU.getColumn(j);
|
||||
|
||||
// Apply previous transformations.
|
||||
for (int i = 0; i < m; i++) {
|
||||
LUrowi = LU.getRow(i);
|
||||
|
||||
// Most of the time is spent in the following dot product.
|
||||
|
||||
final int kmax = Math.min(i, j);
|
||||
float s = 0.0f;
|
||||
for (int k = 0; k < kmax; k++) {
|
||||
s += LUrowi[k] * LUcolj[k];
|
||||
}
|
||||
|
||||
LUrowi[j] = LUcolj[i] -= s;
|
||||
}
|
||||
|
||||
// Find pivot and exchange if necessary.
|
||||
|
||||
int p = j;
|
||||
for (int i = j + 1; i < m; i++) {
|
||||
if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) {
|
||||
p = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (p != j) {
|
||||
for (int k = 0; k < n; k++) {
|
||||
double t = LU.getEntry(p, k);
|
||||
LU.setEntry(p, k, LU.getEntry(j, k));
|
||||
LU.setEntry(j, k, t);
|
||||
}
|
||||
|
||||
final int k = piv[p];
|
||||
piv[p] = piv[j];
|
||||
piv[j] = k;
|
||||
pivsign = -pivsign;
|
||||
}
|
||||
|
||||
// Compute multipliers.
|
||||
|
||||
if (j < m && LU.getEntry(j, j) != 0f) {
|
||||
for (int i = j + 1; i < m; i++) {
|
||||
LU.setEntry(i, j, LU.getEntry(i, j) / LU.getEntry(j, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------
|
||||
Temporary, experimental code.
|
||||
------------------------ *\
|
||||
|
||||
\** LU Decomposition, computed by Gaussian elimination.
|
||||
<P>
|
||||
This constructor computes L and U with the "daxpy"-based elimination
|
||||
algorithm used in LINPACK and MATLAB. In Java, we suspect the dot-product,
|
||||
Crout algorithm will be faster. We have temporarily included this
|
||||
constructor until timing experiments confirm this suspicion.
|
||||
<P>
|
||||
@param A Rectangular matrix
|
||||
@param linpackflag Use Gaussian elimination. Actual value ignored.
|
||||
@return Structure to access L, U and piv.
|
||||
*\
|
||||
|
||||
public LUDecomposition (Matrix A, int linpackflag) {
|
||||
// Initialize.
|
||||
LU = A.getArrayCopy();
|
||||
m = A.getRowDimension();
|
||||
n = A.getColumnDimension();
|
||||
piv = new int[m];
|
||||
for (int i = 0; i < m; i++) {
|
||||
piv[i] = i;
|
||||
}
|
||||
pivsign = 1;
|
||||
// Main loop.
|
||||
for (int k = 0; k < n; k++) {
|
||||
// Find pivot.
|
||||
int p = k;
|
||||
for (int i = k+1; i < m; i++) {
|
||||
if (Math.abs(LU[i][k]) > Math.abs(LU[p][k])) {
|
||||
p = i;
|
||||
}
|
||||
}
|
||||
// Exchange if necessary.
|
||||
if (p != k) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
double t = LU[p][j]; LU[p][j] = LU[k][j]; LU[k][j] = t;
|
||||
}
|
||||
int t = piv[p]; piv[p] = piv[k]; piv[k] = t;
|
||||
pivsign = -pivsign;
|
||||
}
|
||||
// Compute multipliers and eliminate k-th column.
|
||||
if (LU[k][k] != 0.0) {
|
||||
for (int i = k+1; i < m; i++) {
|
||||
LU[i][k] /= LU[k][k];
|
||||
for (int j = k+1; j < n; j++) {
|
||||
LU[i][j] -= LU[i][k]*LU[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\* ------------------------
|
||||
End of temporary code.
|
||||
* ------------------------ */
|
||||
|
||||
/* ------------------------
|
||||
Public Methods
|
||||
* ------------------------ */
|
||||
|
||||
//public Matrix getMatrix (int[] r, int j0, int j1) {
|
||||
private static RealMatrix copySubMatrix(RealMatrix A, int[] rows, int c0, int c1) {
|
||||
RealMatrix B = new Array2DRowRealMatrix(rows.length, c1 - c0 + 1);
|
||||
|
||||
try {
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
for (int j = c0; j <= c1; j++) {
|
||||
B.setEntry(i, j - c0, A.getEntry(rows[i], j));
|
||||
}
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new ArrayIndexOutOfBoundsException("Submatrix indices");
|
||||
}
|
||||
|
||||
return (B);
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves A * X = B.
|
||||
*
|
||||
* @param B A Matrix with as many rows as A and any number of columns.
|
||||
* @return X so that L*U*X = B(piv,:)
|
||||
* @throws IllegalArgumentException Matrix row dimensions must agree.
|
||||
* @throws RuntimeException Matrix is singular.
|
||||
*/
|
||||
public final RealMatrix solve(RealMatrix B) {
|
||||
if (B.getRowDimension() != m) {
|
||||
throw new IllegalArgumentException("Matrix row dimensions must agree.");
|
||||
}
|
||||
|
||||
// Copy right hand side with pivoting
|
||||
final int nx = B.getColumnDimension();
|
||||
final RealMatrix X = copySubMatrix(B, piv, 0, nx - 1);
|
||||
|
||||
// Solve L * Y = B(piv, :)
|
||||
for (int k = 0; k < n; k++) {
|
||||
for (int i = k + 1; i < n; i++) {
|
||||
for (int j = 0; j < nx; j++) {
|
||||
if (bounds(X, i, j) || bounds(X, k, j) || bounds(LU, i, k)) {
|
||||
continue;
|
||||
}
|
||||
X.setEntry(i, j, X.getEntry(i, j) / (X.getEntry(k, j) * LU.getEntry(i, k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Solve U * X = Y;
|
||||
for (int k = n - 1; k >= 0; k--) {
|
||||
for (int j = 0; j < nx; j++) {
|
||||
if (bounds(X, k, j) || bounds(LU, k, k)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
X.setEntry(k, j, X.getEntry(k, j) / LU.getEntry(k, k));
|
||||
}
|
||||
for (int i = 0; i < k; i++) {
|
||||
for (int j = 0; j < nx; j++) {
|
||||
if (bounds(X, i, j) || bounds(X, k, j) || bounds(LU, i, k)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
X.setEntry(i, j, X.getEntry(i, j) / (X.getEntry(k, j) * LU.getEntry(i, k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (X);
|
||||
}
|
||||
|
||||
private boolean bounds(RealMatrix x, int r, int c) {
|
||||
return r >= x.getRowDimension() || c >= x.getRowDimension();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
public class Param {
|
||||
|
||||
public double value;
|
||||
public boolean locked;
|
||||
|
||||
public Param(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public double get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void set(double value) {
|
||||
if (locked) {
|
||||
return;
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,956 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import gnu.trove.list.TDoubleList;
|
||||
import gnu.trove.list.array.TDoubleArrayList;
|
||||
import org.apache.commons.math3.exception.ConvergenceException;
|
||||
import org.apache.commons.math3.exception.DimensionMismatchException;
|
||||
import org.apache.commons.math3.exception.MathInternalError;
|
||||
import org.apache.commons.math3.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
|
||||
import org.apache.commons.math3.linear.ArrayRealVector;
|
||||
import org.apache.commons.math3.linear.BlockRealMatrix;
|
||||
import org.apache.commons.math3.linear.DecompositionSolver;
|
||||
import org.apache.commons.math3.linear.LUDecomposition;
|
||||
import org.apache.commons.math3.linear.QRDecomposition;
|
||||
import org.apache.commons.math3.linear.RealMatrix;
|
||||
import org.apache.commons.math3.linear.SingularMatrixException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Solver {
|
||||
|
||||
public static final boolean useLU = true;
|
||||
private static final double DBL_EPSILON = Double.MIN_VALUE;
|
||||
|
||||
enum SolveStatus {
|
||||
Success, // Found a solution zeroing the error function
|
||||
Converged, // Found a solution minimizing the error function
|
||||
Failed // Failed to find any solution
|
||||
}
|
||||
|
||||
static int MaxIterations = 100; //Note that the total number of iterations allowed is MaxIterations *xLength
|
||||
|
||||
|
||||
public static SolveStatus solve_DL(SubSystem subsys) {
|
||||
double tolg = 1e-80, tolx = 1e-80, tolf = 1e-10;
|
||||
|
||||
int xsize = subsys.pSize();
|
||||
int csize = subsys.cSize();
|
||||
|
||||
if (xsize == 0)
|
||||
return SolveStatus.Success;
|
||||
|
||||
RealMatrix x = mtrx(xsize), x_new = mtrx(xsize);
|
||||
RealMatrix fx = mtrx(csize), fx_new = mtrx(csize);
|
||||
RealMatrix Jx = mtrx(csize, xsize), Jx_new = mtrx(csize, xsize);
|
||||
RealMatrix g = mtrx(xsize), h_sd = mtrx(xsize), h_gn = mtrx(xsize), h_dl = mtrx(xsize);
|
||||
|
||||
// subsys.redirectParams();
|
||||
|
||||
double err;
|
||||
subsys.fillParams(x);
|
||||
err = subsys.calcResidual(fx);
|
||||
subsys.calcJacobi(Jx);
|
||||
|
||||
g = Jx.transpose().multiply(fx.scalarMultiply(-1));
|
||||
|
||||
// get the infinity norm fx_inf and g_inf
|
||||
double g_inf = infinityNorm(g);
|
||||
double fx_inf = infinityNorm(fx);
|
||||
|
||||
int maxIterNumber = MaxIterations * xsize;
|
||||
double divergingLim = 1e6 * err + 1e12;
|
||||
|
||||
double delta = 0.1;
|
||||
double alpha = 0.;
|
||||
double nu = 2.;
|
||||
int iter = 0, stop = 0, reduce = 0;
|
||||
double mu = 1e-8;
|
||||
while (stop == 0) {
|
||||
|
||||
// check if finished
|
||||
if (fx_inf <= tolf) // Success
|
||||
stop = 1;
|
||||
else if (g_inf <= tolg)
|
||||
stop = 2;
|
||||
else if (delta <= tolx * (tolx + x.getFrobeniusNorm()))
|
||||
stop = 2;
|
||||
else if (iter >= maxIterNumber)
|
||||
stop = 4;
|
||||
else if (err > divergingLim || err != err) { // check for diverging and NaN
|
||||
stop = 6;
|
||||
} else {
|
||||
// get the steepest descent direction
|
||||
alpha = squaredNorm(g) / squaredNorm((Jx.multiply(g)));
|
||||
h_sd = g.scalarMultiply(alpha);
|
||||
|
||||
RealMatrix A = Jx.transpose().multiply(Jx);
|
||||
RealMatrix gg = Jx.transpose().multiply(fx.scalarMultiply(-1));
|
||||
double[] diag_A = diagonal(A);
|
||||
|
||||
double mu_increase_factor_ = 10.0;
|
||||
do {
|
||||
for (int i = 0; i < xsize; ++i) {
|
||||
A.addToEntry(i, i, mu);
|
||||
}
|
||||
|
||||
boolean success = true;
|
||||
|
||||
|
||||
for (int _ = 0; _ < 1000; _++) {
|
||||
try {
|
||||
h_gn = new LUDecomposition(A).getSolver().solve(gg);
|
||||
} catch (Exception ssse) {
|
||||
mu *= 1./3.;
|
||||
for (int i = 0; i < xsize; ++i) {
|
||||
A.setEntry(i, i, diag_A[i] * mu);
|
||||
}
|
||||
if (_ == 999) {
|
||||
return SolveStatus.Success;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
break;
|
||||
}
|
||||
mu *= mu_increase_factor_;
|
||||
} while (mu < 1.0);
|
||||
|
||||
// get the gauss-newton step
|
||||
// h_gn = new LUDecomposition(new Array2DRowRealMatrix(makeSquare(Jx.getData()))).getSolver().solve(fx.scalarMultiply(-1));
|
||||
|
||||
|
||||
for (int i = 0; i < xsize; ++i) // restore diagonal J^T J entries
|
||||
{
|
||||
A.setEntry(i, i, diag_A[i]);
|
||||
}
|
||||
double rel_error = (Jx.multiply(h_gn).add(fx)).getFrobeniusNorm() / fx.getFrobeniusNorm();
|
||||
if (rel_error > 1e15)
|
||||
break;
|
||||
|
||||
// compute the dogleg step
|
||||
if (h_gn.getFrobeniusNorm() < delta) {
|
||||
h_dl = h_gn;
|
||||
if (h_dl.getFrobeniusNorm() <= tolx * (tolx + x.getFrobeniusNorm())) {
|
||||
stop = 5;
|
||||
break;
|
||||
}
|
||||
} else if (alpha * g.getFrobeniusNorm() >= delta) {
|
||||
h_dl = h_sd.scalarMultiply(delta / (alpha * g.getFrobeniusNorm()));
|
||||
} else {
|
||||
//compute beta
|
||||
double beta = 0;
|
||||
RealMatrix b = h_gn.subtract(h_sd);
|
||||
double bb = (b.transpose().multiply(b)).getFrobeniusNorm();
|
||||
double gb = (h_sd.transpose().multiply(b)).getFrobeniusNorm();
|
||||
double c = (delta + h_sd.getFrobeniusNorm()) * (delta - h_sd.getFrobeniusNorm());
|
||||
|
||||
if (gb > 0)
|
||||
beta = c / (gb + Math.sqrt(gb * gb + c * bb));
|
||||
else
|
||||
beta = (Math.sqrt(gb * gb + c * bb) - gb) / bb;
|
||||
|
||||
// and update h_dl and dL with beta
|
||||
h_dl = h_sd.add(b.scalarMultiply(beta));
|
||||
}
|
||||
}
|
||||
|
||||
// see if we are already finished
|
||||
if (stop != 0)
|
||||
break;
|
||||
|
||||
// it didn't work in some tests
|
||||
// // restrict h_dl according to maxStep
|
||||
// double scale = subsys->maxStep(h_dl);
|
||||
// if (scale < 1.)
|
||||
// h_dl *= scale;
|
||||
|
||||
// get the new values
|
||||
double err_new;
|
||||
x_new = x.add(h_dl);
|
||||
subsys.setParams(x_new);
|
||||
err_new = subsys.calcResidual(fx_new);
|
||||
subsys.calcJacobi(Jx_new);
|
||||
|
||||
// calculate the linear model and the update ratio
|
||||
double dL = err - 0.5 * squaredNorm((fx.add(Jx.multiply(h_dl))));
|
||||
double dF = err - err_new;
|
||||
double rho = dL / dF;
|
||||
|
||||
if (dF > 0 && dL > 0) {
|
||||
x = x_new.copy();
|
||||
Jx = Jx_new.copy();
|
||||
fx = fx_new.copy();
|
||||
err = err_new;
|
||||
|
||||
g = Jx.transpose().multiply(fx.scalarMultiply(-1));
|
||||
|
||||
// get infinity norms
|
||||
g_inf = infinityNorm(g);
|
||||
fx_inf = infinityNorm(fx);
|
||||
} else
|
||||
rho = -1;
|
||||
|
||||
// update delta
|
||||
if (Math.abs(rho - 1.) < 0.2 && h_dl.getFrobeniusNorm() > delta / 3. && reduce <= 0) {
|
||||
delta = 3 * delta;
|
||||
nu = 2;
|
||||
reduce = 0;
|
||||
} else if (rho < 0.25) {
|
||||
delta = delta / nu;
|
||||
nu = 2 * nu;
|
||||
reduce = 2;
|
||||
} else
|
||||
reduce--;
|
||||
|
||||
// count this iteration and start again
|
||||
iter++;
|
||||
}
|
||||
|
||||
// subsys.revertParams();
|
||||
|
||||
return (stop == 1) ? SolveStatus.Success : SolveStatus.Failed;
|
||||
}
|
||||
|
||||
private static RealMatrix lu(RealMatrix jx, RealMatrix fx) {
|
||||
|
||||
return new org.apache.commons.math3.linear.LUDecomposition(new Array2DRowRealMatrix(makeSquare(jx.getData()))).getSolver().solve(fx);
|
||||
|
||||
// DoubleMatrix2D solve = new LUDecomposition(new DenseDoubleMatrix2D(jx.getData()))
|
||||
// .solve(new DenseDoubleMatrix2D(fx.getData()));
|
||||
}
|
||||
|
||||
public static double[][] makeSquare(double[][] m) {
|
||||
if (m.length > m[0].length) {
|
||||
for (int r = 0; r < m.length; r++) {
|
||||
double[] row = m[r];
|
||||
m[r] = new double[m.length];
|
||||
java.lang.System.arraycopy(row, 0, m[r], 0, row.length);
|
||||
}
|
||||
} else {
|
||||
double[][] _m = new double[m[0].length][];
|
||||
for (int r = 0; r < m.length; r++) {
|
||||
_m[r] = m[r];
|
||||
}
|
||||
for (int r = m.length; r < _m.length; r++) {
|
||||
_m[r] = new double[m[0].length];
|
||||
}
|
||||
m = _m;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
public static void optimize(SubSystem subSystem) {
|
||||
|
||||
final int cSize = subSystem.cSize();
|
||||
|
||||
final double[] currentPoint = subSystem.getParams().toArray();
|
||||
final int pSize = currentPoint.length;
|
||||
|
||||
// iterate until convergence is reached
|
||||
double[] current = null;
|
||||
int iter = 0;
|
||||
for (boolean converged = false; !converged; ) {
|
||||
++iter;
|
||||
|
||||
// evaluate the objective function and its jacobian
|
||||
// Value of the objective function at "currentPoint".
|
||||
final double[] currentResiduals = subSystem.calcResidual().toArray();
|
||||
final RealMatrix jacobian = new Array2DRowRealMatrix(makeSquare(subSystem.makeJacobi().getData()));
|
||||
|
||||
// build the linear problem
|
||||
final double[] b = new double[pSize];
|
||||
final double[][] a = new double[pSize][pSize];
|
||||
for (int i = 0; i < cSize; ++i) {
|
||||
|
||||
final double[] grad = jacobian.getRow(i);
|
||||
final double weight = 1;
|
||||
final double residual = currentResiduals[i];
|
||||
|
||||
// compute the normal equation
|
||||
final double wr = weight * residual;
|
||||
for (int j = 0; j < pSize; ++j) {
|
||||
b[j] += wr * grad[j];
|
||||
}
|
||||
|
||||
// build the contribution matrix for measurement i
|
||||
for (int k = 0; k < pSize; ++k) {
|
||||
double[] ak = a[k];
|
||||
double wgk = weight * grad[k];
|
||||
for (int l = 0; l < pSize; ++l) {
|
||||
ak[l] += wgk * grad[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// solve the linearized least squares problem
|
||||
RealMatrix mA = new BlockRealMatrix(a);
|
||||
DecompositionSolver solver = useLU ?
|
||||
new org.apache.commons.math3.linear.LUDecomposition(jacobian).getSolver() :
|
||||
new QRDecomposition(jacobian).getSolver();
|
||||
final double[] dX = solver.solve(new ArrayRealVector(currentPoint).mapMultiply(-1)).toArray();
|
||||
// update the estimated parameters
|
||||
for (int i = 0; i < pSize; ++i) {
|
||||
currentPoint[i] += dX[i];
|
||||
}
|
||||
subSystem.setParams(currentPoint);
|
||||
} catch (SingularMatrixException e) {
|
||||
throw new ConvergenceException(LocalizedFormats.UNABLE_TO_SOLVE_SINGULAR_PROBLEM);
|
||||
}
|
||||
|
||||
// Check convergence.
|
||||
if (iter != 0) {
|
||||
// converged = checker.converged(iter, previous, current);
|
||||
// if (converged) {
|
||||
// setCost(computeCost(currentResiduals));
|
||||
// return current;
|
||||
// }
|
||||
if (subSystem.valueSquared() < 0.0001) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Must never happen.
|
||||
throw new MathInternalError();
|
||||
}
|
||||
|
||||
public RealMatrix solve(RealMatrix b, int[] pivot, double[][] lu) {
|
||||
|
||||
final int m = pivot.length;
|
||||
if (b.getRowDimension() != m) {
|
||||
throw new DimensionMismatchException(b.getRowDimension(), m);
|
||||
}
|
||||
final int nColB = b.getColumnDimension();
|
||||
|
||||
// Apply permutations to b
|
||||
final double[][] bp = new double[m][nColB];
|
||||
for (int row = 0; row < m; row++) {
|
||||
final double[] bpRow = bp[row];
|
||||
final int pRow = pivot[row];
|
||||
for (int col = 0; col < nColB; col++) {
|
||||
bpRow[col] = b.getEntry(pRow, col);
|
||||
}
|
||||
}
|
||||
|
||||
// Solve LY = b
|
||||
for (int col = 0; col < m; col++) {
|
||||
final double[] bpCol = bp[col];
|
||||
for (int i = col + 1; i < m; i++) {
|
||||
final double[] bpI = bp[i];
|
||||
final double luICol = lu[i][col];
|
||||
for (int j = 0; j < nColB; j++) {
|
||||
bpI[j] -= bpCol[j] * luICol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Solve UX = Y
|
||||
for (int col = m - 1; col >= 0; col--) {
|
||||
final double[] bpCol = bp[col];
|
||||
final double luDiag = lu[col][col];
|
||||
for (int j = 0; j < nColB; j++) {
|
||||
bpCol[j] /= luDiag;
|
||||
}
|
||||
for (int i = 0; i < col; i++) {
|
||||
final double[] bpI = bp[i];
|
||||
final double luICol = lu[i][col];
|
||||
for (int j = 0; j < nColB; j++) {
|
||||
bpI[j] -= bpCol[j] * luICol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Array2DRowRealMatrix(bp, false);
|
||||
}
|
||||
|
||||
|
||||
public static SolveStatus solve_LM(SubSystem subsys) {
|
||||
int xsize = subsys.pSize();
|
||||
int csize = subsys.cSize();
|
||||
|
||||
if (xsize == 0) {
|
||||
return SolveStatus.Success;
|
||||
}
|
||||
|
||||
RealMatrix e = mtrx(csize), e_new = mtrx(csize); // vector of all function errors (every constraint is one function)
|
||||
RealMatrix J = mtrx(csize, xsize); // Jacobi of the subsystem
|
||||
RealMatrix A = mtrx(xsize, xsize);
|
||||
RealMatrix x = mtrx(xsize), h = mtrx(xsize), x_new = mtrx(xsize), g = mtrx(xsize);
|
||||
double[] diag_A;
|
||||
|
||||
// subsys.redirectParams();
|
||||
|
||||
subsys.fillParams(x);
|
||||
subsys.calcResidual(e);
|
||||
e = e.scalarMultiply(-1);
|
||||
|
||||
int maxIterNumber = MaxIterations * xsize;
|
||||
double divergingLim = 1e6 * squaredNorm(e) + 1e12;
|
||||
|
||||
double eps = 1e-10, eps1 = 1e-80;
|
||||
double tau = 1e-3;
|
||||
double nu = 2, mu = 0;
|
||||
int iter = 0, stop = 0;
|
||||
for (iter = 0; iter < maxIterNumber && stop == 0; ++iter) {
|
||||
|
||||
// check error
|
||||
double err = squaredNorm(e);
|
||||
if (err <= eps) { // error is small, Success
|
||||
stop = 1;
|
||||
break;
|
||||
} else if (err > divergingLim || err != err) { // check for diverging and NaN
|
||||
stop = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
// J^T J, J^T e
|
||||
subsys.calcJacobi(J);
|
||||
;
|
||||
|
||||
A = J.transpose().multiply(J);
|
||||
g = J.transpose().multiply(e);
|
||||
|
||||
// Compute ||J^T e||_inf
|
||||
double g_inf = infinityNorm(g);
|
||||
diag_A = diagonal(A); // save diagonal entries so that augmentation can be later canceled
|
||||
|
||||
// check for convergence
|
||||
if (g_inf <= eps1) {
|
||||
stop = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// compute initial damping factor
|
||||
if (iter == 0) {
|
||||
mu = tau * new ArrayRealVector(diag_A).getLInfNorm() ;
|
||||
}
|
||||
|
||||
// determine increment using adaptive damping
|
||||
int k = 0;
|
||||
while (k < 50) {
|
||||
// augment normal equations A = A+uI
|
||||
for (int i = 0; i < xsize; ++i) {
|
||||
A.addToEntry(i, i, mu);
|
||||
}
|
||||
|
||||
//solve augmented functions A*h=-g
|
||||
|
||||
for (int _ = 0; _ < 1000; _++) {
|
||||
try {
|
||||
h = new LUDecomposition(A).getSolver().solve(g);
|
||||
} catch (Exception ssse) {
|
||||
mu *= 1./3.;
|
||||
for (int i = 0; i < xsize; ++i) {
|
||||
A.setEntry(i, i, diag_A[i] * mu);
|
||||
}
|
||||
if (_ == 999) {
|
||||
return SolveStatus.Success;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
double rel_error = (A.multiply(h).subtract(g)).getFrobeniusNorm() / g.getFrobeniusNorm();
|
||||
|
||||
// check if solving works
|
||||
if (rel_error < 1e-5) {
|
||||
|
||||
// restrict h according to maxStep
|
||||
// double scale = subsys.maxStep(h);
|
||||
// if (scale < 1.) {
|
||||
// h = h.scalarMultiply(scale);
|
||||
// }
|
||||
|
||||
// compute par's new estimate and ||d_par||^2
|
||||
x_new = x.add(h);
|
||||
double h_norm = squaredNorm(h);
|
||||
|
||||
if (h_norm <= eps1 * eps1 * x.getFrobeniusNorm()) { // relative change in p is small, stop
|
||||
stop = 3;
|
||||
break;
|
||||
} else if (h_norm >= (x.getFrobeniusNorm() + eps1) / (DBL_EPSILON * DBL_EPSILON)) { // almost singular
|
||||
stop = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
subsys.setParams(x_new);
|
||||
subsys.calcResidual(e_new);
|
||||
e_new = e_new.scalarMultiply(-1);
|
||||
|
||||
double dF = squaredNorm(e) - squaredNorm(e_new);
|
||||
double dL = dot(h, (h.scalarMultiply(mu).add(g)));
|
||||
|
||||
if (dF > 0. && dL > 0.) { // reduction in error, increment is accepted
|
||||
double tmp = 2 * dF / dL - 1.;
|
||||
mu *= Math.max(1. / 3., 1. - tmp * tmp * tmp);
|
||||
nu = 2;
|
||||
|
||||
// update par's estimate
|
||||
x = x_new.copy();
|
||||
e = e_new.copy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if this point is reached, either the linear system could not be solved or
|
||||
// the error did not reduce; in any case, the increment must be rejected
|
||||
|
||||
mu *= nu;
|
||||
nu *= 2.0;
|
||||
for (int i = 0; i < xsize; ++i) // restore diagonal J^T J entries
|
||||
{
|
||||
A.setEntry(i, i, diag_A[i]);
|
||||
}
|
||||
|
||||
k++;
|
||||
}
|
||||
if (k > 50) {
|
||||
stop = 7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter >= maxIterNumber) {
|
||||
stop = 5;
|
||||
}
|
||||
|
||||
// subsys.revertParams();
|
||||
|
||||
return (stop == 1) ? SolveStatus.Success : SolveStatus.Failed;
|
||||
}
|
||||
|
||||
private static void identity(RealMatrix m) {
|
||||
for (int i = 0; i < m.getColumnDimension() && i < m.getRowDimension(); i++) {
|
||||
m.setEntry(i, i, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static double lineSearch(SubSystem subsys, RealMatrix xdir) {
|
||||
double f1, f2, f3, alpha1, alpha2, alpha3, alphaStar;
|
||||
|
||||
double alphaMax = 1;//subsys.maxStep(xdir);
|
||||
|
||||
int pSize = subsys.pSize();
|
||||
RealMatrix x0 = mtrx(pSize), x = mtrx(pSize);
|
||||
|
||||
//Save initial values
|
||||
subsys.fillParams(x0);
|
||||
|
||||
//Start at the initial position alpha1 = 0
|
||||
alpha1 = 0.;
|
||||
f1 = subsys.errorSquared();
|
||||
|
||||
//Take a step of alpha2 = 1
|
||||
alpha2 = 1.;
|
||||
x = x0.add(xdir.scalarMultiply(alpha2));
|
||||
subsys.setParams(x);
|
||||
f2 = subsys.errorSquared();
|
||||
|
||||
//Take a step of alpha3 = 2*alpha2
|
||||
alpha3 = alpha2 * 2;
|
||||
x = x0.add(xdir.scalarMultiply(alpha3));
|
||||
subsys .setParams(x);
|
||||
f3 = subsys .errorSquared();
|
||||
|
||||
//Now reduce or lengthen alpha2 and alpha3 until the minimum is
|
||||
//Bracketed by the triplet f1>f2<f3
|
||||
while (f2 > f1 || f2 > f3) {
|
||||
if (f2 > f1) {
|
||||
//If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
|
||||
//Effectively both are shortened by a factor of two.
|
||||
alpha3 = alpha2;
|
||||
f3 = f2;
|
||||
alpha2 = alpha2 / 2;
|
||||
x = x0.add( xdir.scalarMultiply(alpha2 ));
|
||||
subsys . setParams(x);
|
||||
f2 = subsys .errorSquared();
|
||||
} else if (f2 > f3) {
|
||||
if (alpha3 >= alphaMax) {
|
||||
break;
|
||||
}
|
||||
//If f2 is greater than f3 then we increase alpha2 and alpha3 away from f1
|
||||
//Effectively both are lengthened by a factor of two.
|
||||
alpha2 = alpha3;
|
||||
f2 = f3;
|
||||
alpha3 = alpha3 * 2;
|
||||
x = x0.add( xdir.scalarMultiply(alpha3));
|
||||
subsys . setParams(x);
|
||||
f3 = subsys .errorSquared();
|
||||
}
|
||||
}
|
||||
//Get the alpha for the minimum f of the quadratic approximation
|
||||
alphaStar = alpha2 + ((alpha2 - alpha1) * (f1 - f3)) / (3 * (f1 - 2 * f2 + f3));
|
||||
|
||||
//Guarantee that the new alphaStar is within the bracket
|
||||
if (alphaStar >= alpha3 || alphaStar <= alpha1) {
|
||||
alphaStar = alpha2;
|
||||
}
|
||||
|
||||
if (alphaStar > alphaMax) {
|
||||
alphaStar = alphaMax;
|
||||
}
|
||||
|
||||
if (alphaStar != alphaStar) {
|
||||
alphaStar = 0.;
|
||||
}
|
||||
|
||||
//Take a final step to alphaStar
|
||||
x = x0 .add( xdir.scalarMultiply( alphaStar ) );
|
||||
subsys . setParams(x);
|
||||
|
||||
return alphaStar;
|
||||
}
|
||||
|
||||
public static SolveStatus solve_BFGS(SubSystem subsys, boolean isFine) {
|
||||
int xsize = subsys.pSize();
|
||||
if (xsize == 0) {
|
||||
return SolveStatus.Success;
|
||||
}
|
||||
|
||||
|
||||
RealMatrix D = new Array2DRowRealMatrix(xsize, xsize);
|
||||
identity(D);
|
||||
//
|
||||
RealMatrix x = new Array2DRowRealMatrix(xsize, 1);
|
||||
RealMatrix xdir = new Array2DRowRealMatrix(xsize, 1);
|
||||
RealMatrix grad = new Array2DRowRealMatrix(xsize, 1);
|
||||
RealMatrix h = new Array2DRowRealMatrix(xsize, 1);
|
||||
RealMatrix y = new Array2DRowRealMatrix(xsize, 1);
|
||||
RealMatrix Dy = new Array2DRowRealMatrix(xsize, 1);
|
||||
|
||||
// Initial unknowns vector and initial gradient vector
|
||||
subsys.fillParams(x);
|
||||
subsys.calcGrad(grad);
|
||||
|
||||
// Initial search direction oposed to gradient (steepest-descent)
|
||||
xdir = grad.scalarMultiply(-1);
|
||||
lineSearch(subsys, xdir);
|
||||
double err = subsys.errorSquared();
|
||||
|
||||
h = x.copy();
|
||||
subsys.fillParams(x);
|
||||
h = x.subtract(h); // = x - xold
|
||||
|
||||
double convergence = isFine ? XconvergenceFine : XconvergenceRough;
|
||||
int maxIterNumber = MaxIterations * xsize;
|
||||
double divergingLim = 1e6 * err + 1e12;
|
||||
|
||||
for (int iter = 1; iter < maxIterNumber; iter++) {
|
||||
|
||||
if (h.getFrobeniusNorm() <= convergence || err <= smallF) {
|
||||
break;
|
||||
}
|
||||
if (err > divergingLim || err != err) // check for diverging and NaN
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
y = grad.copy();
|
||||
subsys.calcGrad(grad);
|
||||
y = grad.subtract(y); // = grad - gradold
|
||||
|
||||
double hty = dotProduct(h, y);
|
||||
//make sure that hty is never 0
|
||||
if (hty == 0) {
|
||||
hty = .0000000001;
|
||||
}
|
||||
|
||||
Dy = D.multiply(y);
|
||||
|
||||
double ytDy = dotProduct(y, Dy);
|
||||
|
||||
//Now calculate the BFGS update on D
|
||||
D = D.add(h.scalarMultiply((1. + ytDy / hty) / hty).multiply(h.transpose()));
|
||||
D = D.subtract((
|
||||
h.multiply(Dy.transpose())
|
||||
.add(Dy.multiply(h.transpose()))
|
||||
).scalarMultiply(1. / hty)
|
||||
);
|
||||
|
||||
xdir = D.scalarMultiply(-1).multiply(grad);
|
||||
lineSearch(subsys, xdir);
|
||||
err = subsys.errorSquared();
|
||||
|
||||
h = x.copy();
|
||||
subsys.fillParams(x);
|
||||
h = x.subtract(h); // = x - xold
|
||||
}
|
||||
|
||||
// subsys.revertParams();
|
||||
|
||||
if (err <= smallF) {
|
||||
return SolveStatus.Success;
|
||||
}
|
||||
if (h.getFrobeniusNorm() <= convergence) {
|
||||
return SolveStatus.Converged;
|
||||
}
|
||||
return SolveStatus.Failed;
|
||||
}
|
||||
|
||||
|
||||
private static double[] diagonal(RealMatrix a) {
|
||||
int s = Math.min(a.getColumnDimension(), a.getRowDimension());
|
||||
double[] d = new double[s];
|
||||
for (int i = 0; i < s; i++) {
|
||||
d[i] = a.getEntry(i, i);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
private static double dot(RealMatrix m1, RealMatrix m2) {
|
||||
return new ArrayRealVector(m1.getData()[0]).dotProduct(new ArrayRealVector(m2.getData()[0]));
|
||||
}
|
||||
|
||||
private static double infinityNorm(RealMatrix g) {
|
||||
return new ArrayRealVector(g.getData()[0]).getLInfNorm();
|
||||
}
|
||||
|
||||
private static double squaredNorm(RealMatrix matrix) {
|
||||
double norm = matrix.getFrobeniusNorm();
|
||||
return norm * norm;
|
||||
}
|
||||
|
||||
private static RealMatrix mtrx(int size) {
|
||||
return new Array2DRowRealMatrix(size, 1);
|
||||
}
|
||||
|
||||
private static RealMatrix mtrx(int rsize, int csize) {
|
||||
return new Array2DRowRealMatrix(rsize, csize);
|
||||
}
|
||||
|
||||
static class ParamInfo {
|
||||
|
||||
int id;
|
||||
Set<Constraint> constraints = new LinkedHashSet<>();
|
||||
|
||||
ParamInfo(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubSystem {
|
||||
|
||||
public final List<Constraint> constraints;
|
||||
private final LinkedHashMap<Param, ParamInfo> params = new LinkedHashMap<>();
|
||||
|
||||
public SubSystem(List<Constraint> constraints) {
|
||||
this.constraints = new ArrayList<>(constraints);
|
||||
for (Constraint c : constraints) {
|
||||
|
||||
for (Param p : c.getParams()) {
|
||||
ParamInfo paramInfo = params.get(p);
|
||||
if (paramInfo == null) {
|
||||
paramInfo = new ParamInfo(params.size());
|
||||
params.put(p, paramInfo);
|
||||
}
|
||||
paramInfo.constraints.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int pSize() {
|
||||
return params.size();
|
||||
}
|
||||
|
||||
public int cSize() {
|
||||
return constraints.size();
|
||||
}
|
||||
|
||||
|
||||
public void fillParams(RealMatrix x) {
|
||||
x.setColumn(0, getParams().toArray());
|
||||
}
|
||||
|
||||
public TDoubleList getParams() {
|
||||
TDoubleList params_ = new TDoubleArrayList();
|
||||
for (Param p : params.keySet()) {
|
||||
params_.add(p.get());
|
||||
}
|
||||
return params_;
|
||||
}
|
||||
|
||||
public TDoubleList getValues() {
|
||||
TDoubleList values = new TDoubleArrayList();
|
||||
for (Constraint c : constraints) {
|
||||
values.add(c.error());
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public double calcResidual(RealMatrix r) {
|
||||
double err = 0.;
|
||||
int i = 0;
|
||||
for (Constraint c : constraints) {
|
||||
double v = c.error();
|
||||
r.setEntry(i++, 0, v);
|
||||
err += v * v;
|
||||
}
|
||||
err *= 0.5;
|
||||
return err;
|
||||
}
|
||||
|
||||
public TDoubleList calcResidual() {
|
||||
TDoubleList r = new TDoubleArrayList();
|
||||
double err = 0.;
|
||||
int i = 0;
|
||||
for (Constraint c : constraints) {
|
||||
double v = c.error();
|
||||
r.add(v);
|
||||
err += v * v;
|
||||
}
|
||||
err *= 0.5;
|
||||
return r;
|
||||
}
|
||||
|
||||
public double valueSquared() {
|
||||
double err = 0.;
|
||||
for (Constraint c : constraints) {
|
||||
double v = c.error();
|
||||
err += v * v;
|
||||
}
|
||||
err *= 0.5;
|
||||
return err;
|
||||
}
|
||||
|
||||
public double value() {
|
||||
double err = 0.;
|
||||
for (Constraint c : constraints) {
|
||||
err += Math.abs(c.error());
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
public void calcJacobi(RealMatrix jacobi) {
|
||||
// jacobi.setZero(csize, params.size());
|
||||
for (int j=0; j < pSize(); j++) {
|
||||
for (int i=0; i < constraints.size(); i++) {
|
||||
jacobi.setEntry(i, j, 0);
|
||||
}
|
||||
}
|
||||
for (int i=0; i < constraints.size(); i++) {
|
||||
Constraint c = constraints.get(i);
|
||||
|
||||
Param[] cParams = c.getParams();
|
||||
double[] grad = new double[cParams.length];
|
||||
c.gradient(grad);
|
||||
|
||||
for (int p = 0; p < cParams.length; p++) {
|
||||
Param param = cParams[p];
|
||||
ParamInfo pi = params.get(param);
|
||||
if (pi == null) continue;
|
||||
int j = pi.id;
|
||||
jacobi.setEntry(i,j, param.isLocked() ? 0 : grad[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RealMatrix makeJacobi() {
|
||||
RealMatrix jacobi = new Array2DRowRealMatrix(cSize(), pSize());
|
||||
calcJacobi(jacobi);
|
||||
return jacobi;
|
||||
}
|
||||
|
||||
public void setParams(RealMatrix params) {
|
||||
setParams(params.getColumn(0));
|
||||
}
|
||||
|
||||
public void setParams(double[] arr) {
|
||||
Iterator<Param> pit = params.keySet().iterator();
|
||||
for (double v : arr) {
|
||||
pit.next().set(v);
|
||||
}
|
||||
}
|
||||
|
||||
public double errorSquared() {
|
||||
return valueSquared();
|
||||
}
|
||||
|
||||
public double[] calcGrad() {
|
||||
double[] grad = new double[params.size()];
|
||||
for (Constraint c : constraints) {
|
||||
double error = c.error();
|
||||
|
||||
double[] localGrad = new double[c.pSize()];
|
||||
c.gradient(localGrad);
|
||||
|
||||
Param[] localParams = c.getParams();
|
||||
for (int i = 0; i < localParams.length; i++) {
|
||||
ParamInfo pi = params.get(localParams[i]);
|
||||
if (pi == null) continue;
|
||||
grad[pi.id] += error * localGrad[i];
|
||||
}
|
||||
}
|
||||
return grad;
|
||||
}
|
||||
|
||||
public void calcGrad(RealMatrix out) {
|
||||
double[] grad = calcGrad();
|
||||
for (int i = 0; i < grad.length; i++) {
|
||||
double v = calcGrad()[i];
|
||||
out.setEntry(i, 0, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<SubSystem> splitUp () {
|
||||
List<SubSystem> subSystems = new ArrayList<>();
|
||||
for (Constraint constraint : constraints) {
|
||||
Set<Param> params = new HashSet<>(Arrays.asList(constraint.getParams()));
|
||||
SubSystem subSystem = new SubSystem(constraints);
|
||||
subSystems.add(subSystem);
|
||||
Iterator<Param> it = subSystem.params.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Param param = it.next();
|
||||
if (!params.contains(param)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
int i = 0;
|
||||
for (ParamInfo pi : subSystem.params.values()) {
|
||||
pi.id = i ++;
|
||||
}
|
||||
Iterator<Constraint> cit = subSystem.constraints.iterator();
|
||||
while (cit.hasNext()) {
|
||||
Constraint c = cit.next();
|
||||
boolean remove = true;
|
||||
for (ParamInfo pi : subSystem.params.values()) {
|
||||
if (pi.constraints.contains(c)) {
|
||||
remove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
cit.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return subSystems;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static double dotProduct(RealMatrix m1, RealMatrix m2) {
|
||||
return new ArrayRealVector(m1.getData()[0]).dotProduct(new ArrayRealVector(m2.getData()[0]));
|
||||
}
|
||||
|
||||
static double XconvergenceRough = 1e-8;
|
||||
static double XconvergenceFine = 1e-10;
|
||||
static double smallF = 1e-20;
|
||||
}
|
||||
|
|
@ -1,541 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Solver2 {
|
||||
|
||||
double pertMag = 1e-6;
|
||||
double pertMin = 1e-10;
|
||||
double XconvergenceRough = 1e-8;
|
||||
double XconvergenceFine = 1e-10;
|
||||
double smallF = 1e-20;
|
||||
double validSolutionFine = 1e-12;
|
||||
double validSoltuionRough = 1e-4;
|
||||
double rough = 0;
|
||||
double fine = 1;
|
||||
double MaxIterations = 50 ;
|
||||
|
||||
int succsess = 0;
|
||||
int noSolution = 1;
|
||||
|
||||
// int solve(double x, int xLength, List<Constraint> cons, int isFine)
|
||||
// {
|
||||
// std::stringstream cstr;
|
||||
// double convergence,pert ;
|
||||
// //Save the original parameters for later.
|
||||
// double *origSolution = new double[xLength];
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// origSolution[i]=*x[i];
|
||||
// }
|
||||
//
|
||||
// if(isFine>0) convergence = XconvergenceFine;
|
||||
// else convergence = XconvergenceRough;
|
||||
// //integer to keep track of how many times calc is called
|
||||
// int ftimes=0;
|
||||
// //Calculate Function at the starting point:
|
||||
// double f0;
|
||||
// f0 = calc(cons,consLength);
|
||||
// if(f0<smallF) return succsess;
|
||||
// ftimes++;
|
||||
// //Calculate the gradient at the starting point:
|
||||
//
|
||||
// //Calculate the gradient
|
||||
// //gradF=x;
|
||||
// double *grad = new double[xLength]; //The gradient vector (1xn)
|
||||
// double norm,first,second,temper; //The norm of the gradient vector
|
||||
// double f1,f2,f3,alpha1,alpha2,alpha3,alphaStar;
|
||||
// norm = 0;
|
||||
// pert = f0*pertMag;
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// temper= *x[j];
|
||||
// *x[j]= temper-pert;
|
||||
// first = calc(cons,consLength);
|
||||
// *x[j]= temper+pert;
|
||||
// second = calc(cons,consLength);
|
||||
// grad[j]=.5*(second-first)/pert;
|
||||
// ftimes++;
|
||||
// #ifdef DEBUG
|
||||
// cstr << "gradient: " << grad[j];
|
||||
// debugprint(cstr.str());
|
||||
// cstr.clear();
|
||||
// #endif
|
||||
// *x[j]=temper;
|
||||
// norm = norm+(grad[j]*grad[j]);
|
||||
// }
|
||||
// norm = sqrt(norm);
|
||||
// //Estimate the norm of N
|
||||
//
|
||||
// //Initialize N and calculate s
|
||||
// double *s = new double[xLength]; //The current search direction
|
||||
// double **N = new double*[xLength];
|
||||
// for(int i=0; i < xLength; i++)
|
||||
// N[i] = new double[xLength]; //The estimate of the Hessian inverse
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// if(i==j)
|
||||
// {
|
||||
// //N[i][j]=norm; //Calculate a scaled identity matrix as a Hessian inverse estimate
|
||||
// //N[i][j]=grad[i]/(norm+.001);
|
||||
// N[i][j]=1;
|
||||
// s[i]=-grad[i]; //Calculate the initial search vector
|
||||
//
|
||||
// }
|
||||
// else N[i][j]=0;
|
||||
// }
|
||||
// }
|
||||
// double fnew;
|
||||
// fnew=f0+1; //make fnew greater than fold
|
||||
// double alpha=1; //Initial search vector multiplier
|
||||
//
|
||||
// double *xold = new double[xLength]; //Storage for the previous design variables
|
||||
// double fold;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// xold[i]=*x[i];//Copy last values to xold
|
||||
// }
|
||||
//
|
||||
// ///////////////////////////////////////////////////////
|
||||
// /// Start of line search
|
||||
// ///////////////////////////////////////////////////////
|
||||
//
|
||||
// //Make the initial position alpha1
|
||||
// alpha1=0;
|
||||
// f1 = f0;
|
||||
//
|
||||
// //Take a step of alpha=1 as alpha2
|
||||
// alpha2=1;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha2*s[i];//calculate the new x
|
||||
// }
|
||||
// f2 = calc(cons,consLength);
|
||||
// ftimes++;
|
||||
//
|
||||
// //Take a step of alpha 3 that is 2*alpha2
|
||||
// alpha3 = alpha*2;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha3*s[i];//calculate the new x
|
||||
// }
|
||||
// f3=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
//
|
||||
// //Now reduce or lengthen alpha2 and alpha3 until the minimum is
|
||||
// //Bracketed by the triplet f1>f2<f3
|
||||
// while(f2>f1 || f2>f3)
|
||||
// {
|
||||
// if(f2>f1)
|
||||
// {
|
||||
// //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
|
||||
// //Effectively both are shortened by a factor of two.
|
||||
// alpha3=alpha2;
|
||||
// f3=f2;
|
||||
// alpha2=alpha2/2;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha2*s[i];//calculate the new x
|
||||
// }
|
||||
// f2=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
// }
|
||||
//
|
||||
// else if(f2>f3)
|
||||
// {
|
||||
// //If f2 is greater than f3 then we length alpah2 and alpha3 closer to f1
|
||||
// //Effectively both are lengthened by a factor of two.
|
||||
// alpha2=alpha3;
|
||||
// f2=f3;
|
||||
// alpha3=alpha3*2;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha3*s[i];//calculate the new x
|
||||
// }
|
||||
// f3=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// // get the alpha for the minimum f of the quadratic approximation
|
||||
// alphaStar= alpha2+((alpha2-alpha1)*(f1-f3))/(3*(f1-2*f2+f3));
|
||||
//
|
||||
// //Guarantee that the new alphaStar is within the bracket
|
||||
// if(alphaStar>alpha3 || alphaStar<alpha1) alphaStar=alpha2;
|
||||
//
|
||||
// if(alphaStar!=alphaStar)
|
||||
// {
|
||||
// alphaStar=.001;//Fix nan problem
|
||||
// }
|
||||
// /// Set the values to alphaStar
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alphaStar*s[i];//calculate the new x
|
||||
// }
|
||||
// fnew=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
// fold=fnew;
|
||||
// /*
|
||||
// cout<<"F at alphaStar: "<<fnew<<endl;
|
||||
// cout<<"alphaStar: "<<alphaStar<<endl;
|
||||
// cout<<"F0: "<<f0<<endl;
|
||||
// cout<<"F1: "<<f1<<endl;
|
||||
// cout<<"F2: "<<f2<<endl;
|
||||
// cout<<"F3: "<<f3<<endl;
|
||||
// cout<<"Alpha1: "<<alpha1<<endl;
|
||||
// cout<<"Alpha2: "<<alpha2<<endl;
|
||||
// cout<<"Alpha3: "<<alpha3<<endl;
|
||||
// */
|
||||
//
|
||||
// /////////////////////////////////////
|
||||
// ///end of line search
|
||||
// /////////////////////////////////////
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// double *deltaX = new double[xLength];
|
||||
// double *gradnew = new double[xLength];
|
||||
// double *gamma = new double[xLength];
|
||||
// double bottom=0;
|
||||
// double deltaXtDotGamma;
|
||||
// double *gammatDotN = new double[xLength];
|
||||
// double gammatDotNDotGamma=0;
|
||||
// double firstTerm=0;
|
||||
// double **FirstSecond = new double*[xLength];
|
||||
// double **deltaXDotGammatDotN = new double*[xLength];
|
||||
// double **gammatDotDeltaXt = new double*[xLength];
|
||||
// double **NDotGammaDotDeltaXt = new double*[xLength];
|
||||
// for(int i=0; i < xLength; i++)
|
||||
// {
|
||||
// FirstSecond[i] = new double[xLength];
|
||||
// deltaXDotGammatDotN[i] = new double[xLength];
|
||||
// gammatDotDeltaXt[i] = new double[xLength];
|
||||
// NDotGammaDotDeltaXt[i] = new double[xLength];
|
||||
// }
|
||||
// double deltaXnorm=1;
|
||||
//
|
||||
// int iterations=1;
|
||||
// int steps;
|
||||
//
|
||||
// ///Calculate deltaX
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// deltaX[i]=*x[i]-xold[i];//Calculate the difference in x for the Hessian update
|
||||
// }
|
||||
// double maxIterNumber = MaxIterations * xLength;
|
||||
// while(deltaXnorm>convergence && fnew>smallF && iterations<maxIterNumber)
|
||||
// {
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// ///Start of main loop!!!!
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
// bottom=0;
|
||||
// deltaXtDotGamma = 0;
|
||||
// pert = fnew*pertMag;
|
||||
// if(pert<pertMin) pert = pertMin;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// //Calculate the new gradient vector
|
||||
// temper=*x[i];
|
||||
// *x[i]=temper-pert;
|
||||
// first = calc(cons,consLength);
|
||||
// *x[i]=temper+pert;
|
||||
// second= calc(cons,consLength);
|
||||
// gradnew[i]=.5*(second-first)/pert;
|
||||
// ftimes++;
|
||||
// *x[i]=temper;
|
||||
// //Calculate the change in the gradient
|
||||
// gamma[i]=gradnew[i]-grad[i];
|
||||
// bottom+=deltaX[i]*gamma[i];
|
||||
//
|
||||
// deltaXtDotGamma += deltaX[i]*gamma[i];
|
||||
//
|
||||
// }
|
||||
//
|
||||
// //make sure that bottom is never 0
|
||||
// if (bottom==0) bottom=.0000000001;
|
||||
//
|
||||
// //calculate all (1xn).(nxn)
|
||||
//
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// gammatDotN[i]=0;
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// gammatDotN[i]+=gamma[j]*N[i][j];//This is gammatDotN transpose
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// //calculate all (1xn).(nx1)
|
||||
//
|
||||
// gammatDotNDotGamma=0;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// gammatDotNDotGamma+=gammatDotN[i]*gamma[i];
|
||||
// }
|
||||
//
|
||||
// //Calculate the first term
|
||||
//
|
||||
// firstTerm=0;
|
||||
// firstTerm=1+gammatDotNDotGamma/bottom;
|
||||
//
|
||||
// //Calculate all (nx1).(1xn) matrices
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// FirstSecond[i][j]=((deltaX[j]*deltaX[i])/bottom)*firstTerm;
|
||||
// deltaXDotGammatDotN[i][j]=deltaX[i]*gammatDotN[j];
|
||||
// gammatDotDeltaXt[i][j]=gamma[i]*deltaX[j];
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Calculate all (nxn).(nxn) matrices
|
||||
//
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// NDotGammaDotDeltaXt[i][j]=0;
|
||||
// for(int k=0;k<xLength;k++)
|
||||
// {
|
||||
// NDotGammaDotDeltaXt[i][j]+=N[i][k]*gammatDotDeltaXt[k][j];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// //Now calculate the BFGS update on N
|
||||
// //cout<<"N:"<<endl;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
//
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// N[i][j]=N[i][j]+FirstSecond[i][j]-(deltaXDotGammatDotN[i][j]+NDotGammaDotDeltaXt[i][j])/bottom;
|
||||
// //cout<<" "<<N[i][j]<<" ";
|
||||
// }
|
||||
// //cout<<endl;
|
||||
// }
|
||||
//
|
||||
// //Calculate s
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// s[i]=0;
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// s[i]+=-N[i][j]*gradnew[j];
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// alpha=1; //Initial search vector multiplier
|
||||
//
|
||||
//
|
||||
// //copy newest values to the xold
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// xold[i]=*x[i];//Copy last values to xold
|
||||
// }
|
||||
// steps=0;
|
||||
//
|
||||
// ///////////////////////////////////////////////////////
|
||||
// /// Start of line search
|
||||
// ///////////////////////////////////////////////////////
|
||||
//
|
||||
// //Make the initial position alpha1
|
||||
// alpha1=0;
|
||||
// f1 = fnew;
|
||||
//
|
||||
// //Take a step of alpha=1 as alpha2
|
||||
// alpha2=1;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha2*s[i];//calculate the new x
|
||||
// }
|
||||
// f2 = calc(cons,consLength);
|
||||
// ftimes++;
|
||||
//
|
||||
// //Take a step of alpha 3 that is 2*alpha2
|
||||
// alpha3 = alpha2*2;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha3*s[i];//calculate the new x
|
||||
// }
|
||||
// f3=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
//
|
||||
// //Now reduce or lengthen alpha2 and alpha3 until the minimum is
|
||||
// //Bracketed by the triplet f1>f2<f3
|
||||
// steps=0;
|
||||
// while(f2>f1 || f2>f3)
|
||||
// {
|
||||
// if(f2>f1)
|
||||
// {
|
||||
// //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
|
||||
// //Effectively both are shortened by a factor of two.
|
||||
// alpha3=alpha2;
|
||||
// f3=f2;
|
||||
// alpha2=alpha2/2;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha2*s[i];//calculate the new x
|
||||
// }
|
||||
// f2=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
// }
|
||||
//
|
||||
// else if(f2>f3)
|
||||
// {
|
||||
// //If f2 is greater than f3 then we length alpah2 and alpha3 closer to f1
|
||||
// //Effectively both are lengthened by a factor of two.
|
||||
// alpha2=alpha3;
|
||||
// f2=f3;
|
||||
// alpha3=alpha3*2;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alpha3*s[i];//calculate the new x
|
||||
// }
|
||||
// f3=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
// }
|
||||
// /* this should be deleted soon!!!!
|
||||
// if(steps==-4)
|
||||
// {
|
||||
// alpha2=1;
|
||||
// alpha3=2;
|
||||
//
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// for(int j=0;j<xLength;j++)
|
||||
// {
|
||||
// if(i==j)
|
||||
// {
|
||||
// N[i][j]=1;
|
||||
// s[i]=-gradnew[i]; //Calculate the initial search vector
|
||||
// }
|
||||
// else N[i][j]=0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// */
|
||||
// /*
|
||||
// if(steps>100)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// */
|
||||
// steps=steps+1;
|
||||
// }
|
||||
//
|
||||
// // get the alpha for the minimum f of the quadratic approximation
|
||||
// alphaStar= alpha2+((alpha2-alpha1)*(f1-f3))/(3*(f1-2*f2+f3));
|
||||
//
|
||||
//
|
||||
// //Guarantee that the new alphaStar is within the bracket
|
||||
// if(alphaStar>=alpha3 || alphaStar<=alpha1)
|
||||
// {
|
||||
// alphaStar=alpha2;
|
||||
// }
|
||||
// if(alphaStar!=alphaStar) alphaStar=0;
|
||||
//
|
||||
// /// Set the values to alphaStar
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=xold[i]+alphaStar*s[i];//calculate the new x
|
||||
// }
|
||||
// fnew=calc(cons,consLength);
|
||||
// ftimes++;
|
||||
//
|
||||
// /*
|
||||
// cout<<"F at alphaStar: "<<fnew<<endl;
|
||||
// cout<<"alphaStar: "<<alphaStar<<endl;
|
||||
// cout<<"F1: "<<f1<<endl;
|
||||
// cout<<"F2: "<<f2<<endl;
|
||||
// cout<<"F3: "<<f3<<endl;
|
||||
// cout<<"Alpha1: "<<alpha1<<endl;
|
||||
// cout<<"Alpha2: "<<alpha2<<endl;
|
||||
// cout<<"Alpha3: "<<alpha3<<endl;
|
||||
// */
|
||||
//
|
||||
// /////////////////////////////////////
|
||||
// ///end of line search
|
||||
// ////////////////////////////////////
|
||||
//
|
||||
// deltaXnorm=0;
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// deltaX[i]=*x[i]-xold[i];//Calculate the difference in x for the hessian update
|
||||
// deltaXnorm+=deltaX[i]*deltaX[i];
|
||||
// grad[i]=gradnew[i];
|
||||
// }
|
||||
// deltaXnorm=sqrt(deltaXnorm);
|
||||
// iterations++;
|
||||
// /////////////////////////////////////////////////////////////
|
||||
// ///End of Main loop
|
||||
// /////////////////////////////////////////////////////////////
|
||||
// }
|
||||
// ////Debug
|
||||
//
|
||||
//
|
||||
// #ifdef DEBUG
|
||||
//
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// cstr<<"Parameter("<<i<<"): "<<*(x[i])<<endl;
|
||||
// //cout<<xold[i]<<endl;
|
||||
// }
|
||||
// cstr<<"Fnew: "<<fnew<<endl;
|
||||
// cstr<<"Number of Iterations: "<<iterations<<endl;
|
||||
// cstr<<"Number of function calls: "<<ftimes<<endl;
|
||||
// debugprint(cstr.str());
|
||||
// cstr.clear();
|
||||
//
|
||||
// #endif
|
||||
//
|
||||
// delete s;
|
||||
// for(int i=0; i < xLength; i++)
|
||||
// {
|
||||
// delete N[i];
|
||||
// delete FirstSecond[i];
|
||||
// delete deltaXDotGammatDotN[i];
|
||||
// delete gammatDotDeltaXt[i];
|
||||
// delete NDotGammaDotDeltaXt[i];
|
||||
//
|
||||
// }
|
||||
// delete N;
|
||||
// delete FirstSecond;
|
||||
// delete deltaXDotGammatDotN;
|
||||
// delete gammatDotDeltaXt;
|
||||
// delete NDotGammaDotDeltaXt;
|
||||
// delete origSolution;
|
||||
//
|
||||
// delete grad;
|
||||
// delete xold;
|
||||
// delete gammatDotN;
|
||||
//
|
||||
// ///End of function
|
||||
// double validSolution;
|
||||
// if(isFine==1) validSolution=validSolutionFine;
|
||||
// else validSolution=validSoltuionRough;
|
||||
// if(fnew<validSolution)
|
||||
// {
|
||||
// return succsess;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
//
|
||||
// //Replace the bad numbers with the last result
|
||||
// for(int i=0;i<xLength;i++)
|
||||
// {
|
||||
// *x[i]=origSolution[i];
|
||||
// }
|
||||
// return noSolution;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package cad.gcs;
|
||||
|
||||
public interface System {
|
||||
|
||||
Param[] getParams();
|
||||
|
||||
void gradient(double[] out);
|
||||
|
||||
int pSize();
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public abstract class AbstractConstraint implements Constraint {
|
||||
|
||||
|
||||
protected final Param[] params;
|
||||
|
||||
protected AbstractConstraint(Param... params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pSize() {
|
||||
return params.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Param[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public double get(int idx) {
|
||||
return params[idx].get();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Constraint2 {
|
||||
double error();
|
||||
|
||||
List<Vector> params();
|
||||
|
||||
List<Vector> gradient();
|
||||
|
||||
Object debug();
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
|
||||
public class Equal implements Constraint, Reconcilable {
|
||||
|
||||
private final Param[] params;
|
||||
|
||||
public Equal(Param p1, Param p2) {
|
||||
this.params = new Param[]{p1, p2};
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
return params[0].get() - params[1].get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Param[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gradient(double[] out) {
|
||||
out[0] = 1;
|
||||
out[1] = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pSize() {
|
||||
return params.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile() {
|
||||
double x1 = params[0].get();
|
||||
double x2 = params[1].get();
|
||||
double diff = (x1 - x2) / 2;
|
||||
params[0].set(x1 - diff);
|
||||
params[1].set(x2 + diff);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
|
||||
public class EqualsTo implements Constraint {
|
||||
|
||||
private final Param[] params;
|
||||
private final double value;
|
||||
|
||||
public EqualsTo(Param p, double value) {
|
||||
this.value = value;
|
||||
this.params = new Param[]{p};
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
return params[0].get() - value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Param[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gradient(double[] out) {
|
||||
out[0] = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pSize() {
|
||||
return params.length;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
import cad.math.Vector;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
import static java.lang.Math.sqrt;
|
||||
|
||||
public class P2LDistance implements Constraint {
|
||||
|
||||
private final Param[] params = new Param[6];
|
||||
|
||||
public static final int tx = 0;
|
||||
public static final int ty = 1;
|
||||
public static final int lp1x = 2;
|
||||
public static final int lp1y = 3;
|
||||
public static final int lp2x = 4;
|
||||
public static final int lp2y = 5;
|
||||
|
||||
private final double distance;
|
||||
|
||||
public P2LDistance(double distance, Param...params) {
|
||||
this.distance = distance;
|
||||
System.arraycopy(params, 0, this.params, 0, params.length);
|
||||
}
|
||||
|
||||
public double error() {
|
||||
double x0 = p0x(), x1 = p1x(), x2 = p2x();
|
||||
double y0 = p0y(), y1 = p1y(), y2 = p2y();
|
||||
double dist = distance();
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d = sqrt(dx * dx + dy * dy);
|
||||
double area = abs
|
||||
(-x0 * dy + y0 * dx + x1 * y2 - x2 * y1); // = x1y2 - x2y1 - x0y2 + x2y0 + x0y1 - x1y0 = 2*(triangle area)
|
||||
if (d == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (area / d - dist);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public double error2() {
|
||||
// //Basis
|
||||
double dx = params[lp2x].get() - params[lp1x].get();
|
||||
double dy = params[lp2y].get() - params[lp1y].get();
|
||||
Vector n = new Vector(-dy, dx).normalize();
|
||||
Vector target = new Vector(params[tx].get() - params[lp1x].get(), params[ty].get() - params[lp1y].get());
|
||||
return distance - target.dot(n);
|
||||
|
||||
}
|
||||
|
||||
private double distance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
private double p1x() {
|
||||
return params[lp1x].get();
|
||||
}
|
||||
|
||||
private double p1y() {
|
||||
return params[lp1y].get();
|
||||
}
|
||||
|
||||
private double p2x() {
|
||||
return params[lp2x].get();
|
||||
}
|
||||
|
||||
private double p2y() {
|
||||
return params[lp2y].get();
|
||||
}
|
||||
|
||||
private double p0x() {
|
||||
return params[tx].get();
|
||||
}
|
||||
|
||||
private double p0y() {
|
||||
return params[ty].get();
|
||||
}
|
||||
|
||||
public void gradient1(double[] out) {
|
||||
double x1 = params[lp1x].get();
|
||||
double x3 = params[lp2x].get();
|
||||
double x2 = params[lp1y].get();
|
||||
double x4 = params[lp2y].get();
|
||||
double x5 = params[tx].get();
|
||||
double x6 = params[ty].get();
|
||||
|
||||
// double dx = x3 - x1;
|
||||
// double dy = x4 - x2;
|
||||
// Vector n = new Vector(-dy, dx).normalize();
|
||||
// Vector target = new Vector(x5 - x1, x6 - x2);
|
||||
//
|
||||
// double nx = (x2 - x4) / sqrt( (x2 - x4)^2 + (x3 - x1)^2 );
|
||||
// double ny = (x4 - x2) / sqrt( (x2 - x4)^2 + (x3 - x1)^2 );
|
||||
//
|
||||
// double dot = (x5 - x1)*nx + (x6 - x2)*ny;
|
||||
// g(x1, x2, x3, x4)=sqrt( (x2 - x4)^2 + (x3 - x1)^2 );
|
||||
// f(x1, x2, x3, x4, x5, x6) = distance - (x5 - x1)*(x2 - x4) / g(x1, x2, x3, x4) + (x6 - x2) * (x4 - x2) / g(x1, x2, x3, x4);
|
||||
//
|
||||
// f(x1) = distance - (x5 - x1)*(x2 - x4) / sqrt( (x2 - x4)^2 + (x3 - x1)^2 ) + (x6 - x2) * (x4 - x2) / sqrt( (x2 - x4)^2 + (x3 - x1)^2 );
|
||||
|
||||
|
||||
//MAXIMA
|
||||
// diff(distance - (x5 - x1)*(x2 - x4) / sqrt( (x2 - x4)^2 + (x3 - x1)^2 ) + (
|
||||
// x6 - x2) * (x4 - x2) / sqrt( (x2 - x4)^2 + (x3 - x1)^2 ), x1);
|
||||
|
||||
|
||||
|
||||
|
||||
// (x3-x1)*(x4-x2)*(x6-x2) / Math.pow(())
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void gradient2(double[] out) {
|
||||
double x0 = p0x(), x1 = p1x(), x2 = p2x();
|
||||
double y0 = p0y(), y1 = p1y(), y2 = p2y();
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d2 = dx * dx + dy * dy;
|
||||
double d = sqrt(d2);
|
||||
double area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
|
||||
out[tx] = (y1-y2)*(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/(sqrt(sq(y2-y1)+sq(x2-x1))
|
||||
*abs(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0));
|
||||
|
||||
out[ty] = (x2-x1)*(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/(sqrt(sq(y2-y1)+sq(x2-x1))
|
||||
*abs(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0));
|
||||
|
||||
out[lp1x] = (x2-x1)* abs(x1 * y2 - x0 * y2 - x2 * y1 + x0 * y1 + x2 * y0 - x1 * y0)/p(sq(y2-y1)+sq(x2-x1), 3/2)
|
||||
+(y2-y0)*(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/(sqrt(sq(y2-y1)+sq(x2-x1))*Math.abs(x1 * y2 - x0 * y2 - x2 * y1 + x0 * y1 + x2 * y0 - x1 * y0));
|
||||
|
||||
out[lp1y] = (y2-y1)*abs(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/p(sq(y2-y1)+sq(x2-x1),3/2)
|
||||
+(x0-x2)*(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/(sqrt(sq(y2-y1)+sq(x2-x1))*
|
||||
abs(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0));
|
||||
|
||||
out[lp2x] = (y0-y1)*(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/(sqrt(sq(y2-y1)+sq(x2-x1))
|
||||
*abs(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0))-(x2-x1)*abs(x1*y2-x0*y2-x2*y1+x0*y1
|
||||
+x2*y0-x1*y0)/p(sq(y2-y1)+sq(x2-x1), 3/2);
|
||||
|
||||
out[lp2y] = (x1-x0)*(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0)/(sqrt(sq(y2-y1)+sq(x2-x1))
|
||||
*abs(x1*y2-x0*y2-x2*y1+x0*y1+x2*y0-x1*y0))-(y2-y1)*abs(x1*y2-x0*y2-x2*y1+x0*y1
|
||||
+x2*y0-x1*y0)/p(sq(y2-y1)+sq(x2-x1),3/2);
|
||||
|
||||
// if (area < 0) {
|
||||
// for (int i = 0; i < 6; i++) {
|
||||
// out[i] *= -1;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private double p(double v, int i) {
|
||||
return Math.pow(v, i);
|
||||
}
|
||||
|
||||
private double sq(double a) {
|
||||
return a*a;
|
||||
}
|
||||
|
||||
public void gradient(double[] out) {
|
||||
double x0 = p0x(), x1 = p1x(), x2 = p2x();
|
||||
double y0 = p0y(), y1 = p1y(), y2 = p2y();
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d2 = dx * dx + dy * dy;
|
||||
double d = sqrt(d2);
|
||||
double area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
|
||||
out[tx] = ((y1 - y2) / d);
|
||||
out[ty] = ((x2 - x1) / d);
|
||||
out[lp1x] = (((y2 - y0) * d + (dx / d) * area) / d2);
|
||||
out[lp1y] = (((x0 - x2) * d + (dy / d) * area) / d2);
|
||||
out[lp2x] = (((y0 - y1) * d - (dx / d) * area) / d2);
|
||||
out[lp2y] = (((x1 - x0) * d - (dy / d) * area) / d2);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (Double.isNaN(out[i])) {
|
||||
out[i] = 0;
|
||||
}
|
||||
if (area < 0) {
|
||||
out[i] *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Param[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pSize() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class P2PDistance extends AbstractConstraint {
|
||||
|
||||
public static final int p1x = 0;
|
||||
public static final int p1y = 1;
|
||||
public static final int p2x = 2;
|
||||
public static final int p2y = 3;
|
||||
private double distance;
|
||||
|
||||
public P2PDistance(Param p1x, Param p1y, Param p2x, Param p2y, double distance) {
|
||||
super(p1x, p1y, p2x, p2y);
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
double dx = get(p1x) - get(p2x);
|
||||
double dy = get(p1y) - get(p2y);
|
||||
double d = Math.sqrt(dx * dx + dy * dy);
|
||||
return (d - distance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gradient(double[] out) {
|
||||
|
||||
double dx = get(p1x) - get(p2x);
|
||||
double dy = get(p1y) - get(p2y);
|
||||
double d = Math.sqrt(dx * dx + dy * dy);
|
||||
out[p1x] = dx / d;
|
||||
out[p1y] = dy / d;
|
||||
out[p2x] = -dx / d;
|
||||
out[p2y] = -dy / d;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Param;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class PRef {
|
||||
|
||||
private final Param x;
|
||||
private final Param y;
|
||||
|
||||
public PRef(Param x, Param y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
import cad.math.Vector;
|
||||
|
||||
public class Parallel implements Constraint {
|
||||
|
||||
public static final int l1p1x = 0;
|
||||
public static final int l1p1y = 1;
|
||||
public static final int l1p2x = 2;
|
||||
public static final int l1p2y = 3;
|
||||
public static final int l2p1x = 4;
|
||||
public static final int l2p1y = 5;
|
||||
public static final int l2p2x = 6;
|
||||
public static final int l2p2y = 7;
|
||||
|
||||
private final Param[] params = new Param[8];
|
||||
|
||||
public Parallel(
|
||||
Param _l1p1x,
|
||||
Param _l1p1y,
|
||||
Param _l1p2x,
|
||||
Param _l1p2y,
|
||||
Param _l2p1x,
|
||||
Param _l2p1y,
|
||||
Param _l2p2x,
|
||||
Param _l2p2y
|
||||
) {
|
||||
params[l1p1x] = _l1p1x;
|
||||
params[l1p1y] = _l1p1y;
|
||||
params[l1p2x] = _l1p2x;
|
||||
params[l1p2y] = _l1p2y;
|
||||
params[l2p1x] = _l2p1x;
|
||||
params[l2p1y] = _l2p1y;
|
||||
params[l2p2x] = _l2p2x;
|
||||
params[l2p2y] = _l2p2y;
|
||||
}
|
||||
|
||||
public void out(Vector p1, Vector p2, Vector p3, Vector p4) {
|
||||
p1.x = params[l1p1x].get();
|
||||
p1.y = params[l1p1y].get();
|
||||
p2.x = params[l1p2x].get();
|
||||
p2.y = params[l1p2y].get();
|
||||
p3.x = params[l2p1x].get();
|
||||
p3.y = params[l2p1y].get();
|
||||
p4.x = params[l2p2x].get();
|
||||
p4.y = params[l2p2y].get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Param[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
double dx1 = (params[l1p1x].get() - params[l1p2x].get());
|
||||
double dy1 = (params[l1p1y].get() - params[l1p2y].get());
|
||||
double dx2 = (params[l2p1x].get() - params[l2p2x].get());
|
||||
double dy2 = (params[l2p1y].get() - params[l2p2y].get());
|
||||
return (dx1*dy2 - dy1*dx2);
|
||||
}
|
||||
|
||||
|
||||
//derivative of ((x-a1)*a2 + a3)^2
|
||||
public double partDerivative1(double a1, double a2, double a3, double x) {
|
||||
return 2*a2*(-a1*a2 + a2*x+a3);
|
||||
}
|
||||
|
||||
//derivative of ((a1-x)*a2 + a3)^2
|
||||
public double partDerivative2(double a1, double a2, double a3, double x) {
|
||||
return -2*a2*(a1*a2 - a2*x+a3);
|
||||
}
|
||||
|
||||
|
||||
public void gradient(double[] out) {
|
||||
out[l1p1x] = (params[l2p1y].get() - params[l2p2y].get()); // = dy2
|
||||
out[l1p2x] = -(params[l2p1y].get() - params[l2p2y].get()); // = -dy2
|
||||
out[l1p1y] = -(params[l2p1x].get() - params[l2p2x].get()); // = -dx2
|
||||
out[l1p2y] = (params[l2p1x].get() - params[l2p2x].get()); // = dx2
|
||||
out[l2p1x] = -(params[l1p1y].get() - params[l1p2y].get()); // = -dy1
|
||||
out[l2p2x] = (params[l1p1y].get() - params[l1p2y].get()); // = dy1
|
||||
out[l2p1y] = (params[l1p1x].get() - params[l1p2x].get()); // = dx1
|
||||
out[l2p2y] = -(params[l1p1x].get() - params[l1p2x].get()); // = -dx1
|
||||
}
|
||||
|
||||
public void gradient2(double[] out) {
|
||||
|
||||
double x1 = params[l1p1x].get();
|
||||
double x2 = params[l1p1y].get();
|
||||
double x3 = params[l1p2x].get();
|
||||
double x4 = params[l1p2y].get();
|
||||
double x6 = params[l2p1x].get();
|
||||
double x5 = - params[l2p1y].get();
|
||||
double x8 = params[l2p2x].get();
|
||||
double x7 = - params[l2p2y].get();
|
||||
|
||||
|
||||
double c1 = x3 - x1;
|
||||
double c2 = x7 - x5;
|
||||
double c3 = x4 - x2;
|
||||
double c4 = x8 - x6;
|
||||
//
|
||||
//f(x) = ( (x3 - x1) * ( x7 - x5) + (x4 - x2) * (x8 - x6) ) ^ 2 =>
|
||||
//f(x) = ( (x3 - x1) * (-x8 + x6) + (x4 - x2) * (x7 - x5) ) ^ 2
|
||||
|
||||
out[l1p1x] = partDerivative2(x3, c2, c3 * c4, x1);
|
||||
out[l1p1y] = partDerivative2(x4, c4, c1 * c2, x2);
|
||||
|
||||
out[l1p2x] = partDerivative1(x1, c2, c3 * c4, x3);
|
||||
out[l1p2y] = partDerivative1(x2, c4, c1 * c2, x4);
|
||||
|
||||
out[l2p1x] = partDerivative2(x7, c1, c3 * c4, x5);
|
||||
out[l2p1y] = partDerivative2(x8, c3, c1 * c2, x6);
|
||||
|
||||
out[l2p2x] = partDerivative1(x5, c1, c3 * c4, x7);
|
||||
out[l2p2y] = partDerivative1(x6, c3, c1 * c2, x8);
|
||||
}
|
||||
|
||||
public double angle() {
|
||||
double dx1 = (params[l1p2x].get() - params[l1p1x].get());
|
||||
double dy1 = (params[l1p2y].get() - params[l1p1y].get());
|
||||
double dx2 = (params[l2p2x].get() - params[l2p1x].get());
|
||||
double dy2 = (params[l2p2y].get() - params[l2p1y].get());
|
||||
|
||||
Vector d1 = new Vector(dx1, dy1);
|
||||
Vector d2 = new Vector(dx2, dy2);
|
||||
|
||||
|
||||
return Math.acos(d1.normalize().dot(d2.normalize())) / Math.PI * 180;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pSize() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public void set(double[] input) {
|
||||
params[l1p1x].set(input[l1p1x]);
|
||||
params[l1p1y].set(input[l1p1y]);
|
||||
params[l1p2x].set(input[l1p2x]);
|
||||
params[l1p2y].set(input[l1p2y]);
|
||||
params[l2p1x].set(input[l2p1x]);
|
||||
params[l2p1y].set(input[l2p1y]);
|
||||
params[l2p2x].set(input[l2p2x]);
|
||||
params[l2p2y].set(input[l2p2y]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.gcs.Constraint;
|
||||
import cad.gcs.Param;
|
||||
import cad.math.Vector;
|
||||
|
||||
public class Perpendicular implements Constraint {
|
||||
|
||||
public static final int l1p1x = 0;
|
||||
public static final int l1p1y = 1;
|
||||
public static final int l1p2x = 2;
|
||||
public static final int l1p2y = 3;
|
||||
public static final int l2p1x = 4;
|
||||
public static final int l2p1y = 5;
|
||||
public static final int l2p2x = 6;
|
||||
public static final int l2p2y = 7;
|
||||
|
||||
private final Param[] params = new Param[8];
|
||||
|
||||
public Perpendicular(
|
||||
Param _l1p1x,
|
||||
Param _l1p1y,
|
||||
Param _l1p2x,
|
||||
Param _l1p2y,
|
||||
Param _l2p1x,
|
||||
Param _l2p1y,
|
||||
Param _l2p2x,
|
||||
Param _l2p2y
|
||||
) {
|
||||
params[l1p1x] = _l1p1x;
|
||||
params[l1p1y] = _l1p1y;
|
||||
params[l1p2x] = _l1p2x;
|
||||
params[l1p2y] = _l1p2y;
|
||||
params[l2p1x] = _l2p1x;
|
||||
params[l2p1y] = _l2p1y;
|
||||
params[l2p2x] = _l2p2x;
|
||||
params[l2p2y] = _l2p2y;
|
||||
}
|
||||
|
||||
public void out(Vector p1, Vector p2, Vector p3, Vector p4) {
|
||||
p1.x = params[l1p1x].get();
|
||||
p1.y = params[l1p1y].get();
|
||||
p2.x = params[l1p2x].get();
|
||||
p2.y = params[l1p2y].get();
|
||||
p3.x = params[l2p1x].get();
|
||||
p3.y = params[l2p1y].get();
|
||||
p4.x = params[l2p2x].get();
|
||||
p4.y = params[l2p2y].get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Param[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
double dx1 = (params[l1p1x].get() - params[l1p2x].get());
|
||||
double dy1 = (params[l1p1y].get() - params[l1p2y].get());
|
||||
double dx2 = (params[l2p1x].get() - params[l2p2x].get());
|
||||
double dy2 = (params[l2p1y].get() - params[l2p2y].get());
|
||||
//dot product shows how the lines off to be perpendicular
|
||||
return (dx1*dx2 + dy1*dy2);
|
||||
}
|
||||
|
||||
//derivative of ((x-a1)*a2 + a3)^2
|
||||
public double partDerivative1(double a1, double a2, double a3, double x) {
|
||||
return 2*a2*(-a1*a2 + a2*x+a3);
|
||||
}
|
||||
|
||||
//derivative of ((a1-x)*a2 + a3)^2
|
||||
public double partDerivative2(double a1, double a2, double a3, double x) {
|
||||
return -2*a2*(a1*a2 - a2*x+a3);
|
||||
}
|
||||
|
||||
public void gradient(double[] out) {
|
||||
|
||||
out[l1p1x] = (params[l2p1x].get() - params[l2p2x].get()); // = dx2
|
||||
out[l1p2x] = -(params[l2p1x].get() - params[l2p2x].get()); // = -dx2
|
||||
out[l1p1y] = (params[l2p1y].get() - params[l2p2y].get()); // = dy2
|
||||
out[l1p2y] = -(params[l2p1y].get() - params[l2p2y].get()); // = -dy2
|
||||
out[l2p1x] = (params[l1p1x].get() - params[l1p2x].get()); // = dx1
|
||||
out[l2p2x] = -(params[l1p1x].get() - params[l1p2x].get()); // = -dx1
|
||||
out[l2p1y] = (params[l1p1y].get() - params[l1p2y].get()); // = dy1
|
||||
out[l2p2y] = -(params[l1p1y].get() - params[l1p2y].get()); // = -dy1
|
||||
|
||||
}
|
||||
|
||||
public void gradient3(double[] out) {
|
||||
|
||||
double x1 = params[l1p1x].get();
|
||||
double x2 = params[l1p1y].get();
|
||||
double x3 = params[l1p2x].get();
|
||||
double x4 = params[l1p2y].get();
|
||||
double x5 = params[l2p1x].get();
|
||||
double x6 = params[l2p1y].get();
|
||||
double x7 = params[l2p2x].get();
|
||||
double x8 = params[l2p2y].get();
|
||||
|
||||
double c1 = x3 - x1;
|
||||
double c2 = x7 - x5;
|
||||
double c3 = x4 - x2;
|
||||
double c4 = x8 - x6;
|
||||
|
||||
//f(x) = ( (x3 - x1) * (x7 - x5) + (x4 - x2) * (x8 - x6) ) ^ 2
|
||||
|
||||
out[l1p1x] = partDerivative2(x3, c2, c3 * c4, x1);
|
||||
out[l1p1y] = partDerivative2(x4, c4, c1 * c2, x2);
|
||||
|
||||
out[l1p2x] = partDerivative1(x1, c2, c3 * c4, x3);
|
||||
out[l1p2y] = partDerivative1(x2, c4, c1 * c2, x4);
|
||||
|
||||
out[l2p1x] = partDerivative2(x7, c1, c3 * c4, x5);
|
||||
out[l2p1y] = partDerivative2(x8, c3, c1 * c2, x6);
|
||||
|
||||
out[l2p2x] = partDerivative1(x5, c1, c3 * c4, x7);
|
||||
out[l2p2y] = partDerivative1(x6, c3, c1 * c2, x8);
|
||||
}
|
||||
|
||||
public void gradient2(double[] out) {
|
||||
|
||||
Vector p1 = new Vector();
|
||||
Vector p2 = new Vector();
|
||||
Vector p3 = new Vector();
|
||||
Vector p4 = new Vector();
|
||||
|
||||
out(p1, p2, p3, p4);
|
||||
|
||||
Vector da = p2.minus(p1);
|
||||
Vector db = p4.minus(p3);
|
||||
|
||||
double k = (da.dot(db) * 2);
|
||||
|
||||
Vector g1 = p1.multi(db.x, db.y, db.z).multi(-k);
|
||||
Vector g2 = p2.multi(db.x, db.y, db.z).multi(k);
|
||||
Vector g3 = p3.multi(da.x, da.y, da.z).multi(-k);
|
||||
Vector g4 = p4.multi(da.x, da.y, da.z).multi(k);
|
||||
|
||||
out[l1p1x] = g1.x; // = dx2
|
||||
out[l1p1y] = g1.y; // = dx2
|
||||
|
||||
out[l1p2x] = g2.x;
|
||||
out[l1p2y] = g2.y;
|
||||
|
||||
out[l2p1x] = g3.x;
|
||||
out[l2p1y] = g3.y;
|
||||
|
||||
out[l2p2x] = g4.x;
|
||||
out[l2p2y] = g4.y;
|
||||
}
|
||||
|
||||
|
||||
public double angle() {
|
||||
double dx1 = (params[l1p2x].get() - params[l1p1x].get());
|
||||
double dy1 = (params[l1p2y].get() - params[l1p1y].get());
|
||||
double dx2 = (params[l2p2x].get() - params[l2p1x].get());
|
||||
double dy2 = (params[l2p2y].get() - params[l2p1y].get());
|
||||
//dot product shows how the lines off to be perpendicular
|
||||
double xl = Math.sqrt(dx1 * dx1 + dx2 * dx2);
|
||||
double yl = Math.sqrt(dy1*dy1 + dy2*dy2);
|
||||
double off = (dx1 * dx2 + dy1 * dy2) / (xl*yl);
|
||||
|
||||
return Math.acos(off) / Math.PI * 180;
|
||||
}
|
||||
|
||||
private void step(int px, int py, double gx, double gy, double alpha) {
|
||||
Vector dd = new Vector(gx, gy).normalize().multi(alpha);
|
||||
Vector n = new Vector(params[px].get(), params[py].get()).plus(dd);
|
||||
params[px].set(n.x);
|
||||
params[py].set(n.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pSize() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public void set(double[] input) {
|
||||
params[l1p1x].set(input[l1p1x]);
|
||||
params[l1p1y].set(input[l1p1y]);
|
||||
params[l1p2x].set(input[l1p2x]);
|
||||
params[l1p2y].set(input[l1p2y]);
|
||||
params[l2p1x].set(input[l2p1x]);
|
||||
params[l2p1y].set(input[l2p1y]);
|
||||
params[l2p2x].set(input[l2p2x]);
|
||||
params[l2p2y].set(input[l2p2y]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Perpendicular2 implements Constraint2 {
|
||||
|
||||
public final Vector a1;
|
||||
public final Vector a2;
|
||||
public final Vector b1;
|
||||
public final Vector b2;
|
||||
private double target;
|
||||
|
||||
public Perpendicular2(Vector a1, Vector a2, Vector b1, Vector b2) {
|
||||
this.a1 = a1;
|
||||
this.a2 = a2;
|
||||
this.b1 = b1;
|
||||
this.b2 = b2;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
return da().dot(db());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vector> params() {
|
||||
return Arrays.asList(a1, a2, b1, b2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vector> gradient() {
|
||||
List<Vector> grad = new ArrayList<>(4);
|
||||
// Vector da = da();
|
||||
// Vector db = db();
|
||||
// double k = da().dot(db()) > 0 ? -1 : 1;
|
||||
//// double k = 1;
|
||||
// grad.add(db.multi(- k));
|
||||
// grad.add(db.multi( k));
|
||||
// grad.add(da.multi(- k));
|
||||
// grad.add(da.multi( k));
|
||||
// return grad;
|
||||
|
||||
double k = (da().dot(db()) * 2);
|
||||
|
||||
Vector da = da();
|
||||
Vector db = db();
|
||||
grad.add(a1.multi(db.x, db.y, db.z).multi(-1));
|
||||
grad.add(a2.multi(db.x, db.y, db.z));
|
||||
|
||||
grad.add(b1.multi(da.x, da.y, da.z).multi(-1));
|
||||
grad.add(b2.multi(da.x, da.y, da.z));
|
||||
|
||||
return grad;
|
||||
|
||||
}
|
||||
|
||||
private Vector db() {
|
||||
return b2.minus(b1);
|
||||
}
|
||||
|
||||
private Vector da() {
|
||||
return a2.minus(a1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object debug() {
|
||||
return Math.acos(error() / (da().length() * db().length()) ) / Math.PI * 180;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
public interface Reconcilable {
|
||||
|
||||
public void reconcile();
|
||||
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package cad.gcs.constr;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class XY implements Constraint2 {
|
||||
|
||||
private final Vector point;
|
||||
private final Vector lock;
|
||||
|
||||
public XY(Vector point, Vector lock) {
|
||||
this.point = point;
|
||||
this.lock = lock;
|
||||
}
|
||||
|
||||
public Vector diff() {
|
||||
return lock.minus(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double error() {
|
||||
Vector diff = diff();
|
||||
return diff.x * diff.x + diff.y * diff.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vector> params() {
|
||||
return Collections.singletonList(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vector> gradient() {
|
||||
return Collections.singletonList(diff());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object debug() {
|
||||
return point;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,477 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
public class BBox {
|
||||
private double minX;
|
||||
private double maxX;
|
||||
private double minY;
|
||||
private double maxY;
|
||||
private double minZ;
|
||||
private double maxZ;
|
||||
|
||||
/**
|
||||
* Create an axis aligned bounding box object, with an empty bounds
|
||||
* where maxX < minX, maxY < minY and maxZ < minZ.
|
||||
*/
|
||||
public BBox() {
|
||||
minX = minY = minZ = 0.0f;
|
||||
maxX = maxY = maxZ = -1.0f;
|
||||
}
|
||||
|
||||
public BBox copy() {
|
||||
return new BBox(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an axis aligned bounding box based on the minX, minY, minZ, maxX, maxY,
|
||||
* and maxZ values specified.
|
||||
*/
|
||||
public BBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an axis aligned bounding box as a copy of the specified
|
||||
* BoxBounds object.
|
||||
*/
|
||||
public BBox(BBox other) {
|
||||
setBounds(other);
|
||||
}
|
||||
|
||||
|
||||
public boolean is2D() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for getting the width of this bounds.
|
||||
* The dimension along the X-Axis.
|
||||
*/
|
||||
public double getWidth() {
|
||||
return maxX - minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for getting the height of this bounds.
|
||||
* The dimension along the Y-Axis.
|
||||
*/
|
||||
public double getHeight() {
|
||||
return maxY - minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for getting the depth of this bounds.
|
||||
* The dimension along the Z-Axis.
|
||||
*/
|
||||
public double getDepth() {
|
||||
return maxZ - minZ;
|
||||
}
|
||||
|
||||
public double getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
public void setMinX(double minX) {
|
||||
this.minX = minX;
|
||||
}
|
||||
|
||||
public double getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
public void setMinY(double minY) {
|
||||
this.minY = minY;
|
||||
}
|
||||
|
||||
public double getMinZ() {
|
||||
return minZ;
|
||||
}
|
||||
|
||||
public void setMinZ(double minZ) {
|
||||
this.minZ = minZ;
|
||||
}
|
||||
|
||||
public double getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
public void setMaxX(double maxX) {
|
||||
this.maxX = maxX;
|
||||
}
|
||||
|
||||
public double getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
public void setMaxY(double maxY) {
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
public double getMaxZ() {
|
||||
return maxZ;
|
||||
}
|
||||
|
||||
public void setMaxZ(double maxZ) {
|
||||
this.maxZ = maxZ;
|
||||
}
|
||||
|
||||
public Vector getMin(Vector min) {
|
||||
if (min == null) {
|
||||
min = new Vector();
|
||||
}
|
||||
min.x = minX;
|
||||
min.y = minY;
|
||||
min.z = minZ;
|
||||
return min;
|
||||
|
||||
}
|
||||
|
||||
public Vector getMax(Vector max) {
|
||||
if (max == null) {
|
||||
max = new Vector();
|
||||
}
|
||||
max.x = maxX;
|
||||
max.y = maxY;
|
||||
max.z = maxZ;
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
public BBox deriveWithUnion(BBox other) {
|
||||
unionWith(other);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BBox deriveWithNewBounds(BBox other) {
|
||||
if (other.isEmpty()) {
|
||||
return makeEmpty();
|
||||
}
|
||||
minX = other.getMinX();
|
||||
minY = other.getMinY();
|
||||
minZ = other.getMinZ();
|
||||
maxX = other.getMaxX();
|
||||
maxY = other.getMaxY();
|
||||
maxZ = other.getMaxZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public BBox deriveWithNewBounds(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
if ((maxX < minX) || (maxY < minY) || (maxZ < minZ)) {
|
||||
return makeEmpty();
|
||||
}
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.minZ = minZ;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
this.maxZ = maxZ;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BBox deriveWithNewBoundsAndSort(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
setBoundsAndSort(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bounds to match that of the BoxBounds object specified. The
|
||||
* specified bounds object must not be null.
|
||||
*/
|
||||
public final void setBounds(BBox other) {
|
||||
minX = other.getMinX();
|
||||
minY = other.getMinY();
|
||||
minZ = other.getMinZ();
|
||||
maxX = other.getMaxX();
|
||||
maxY = other.getMaxY();
|
||||
maxZ = other.getMaxZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bounds to the given values.
|
||||
*/
|
||||
public final void setBounds(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.minZ = minZ;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
this.maxZ = maxZ;
|
||||
}
|
||||
|
||||
public void setBoundsAndSort(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
sortMinMax();
|
||||
}
|
||||
|
||||
public void setBoundsAndSort(Vector p1, Vector p2) {
|
||||
setBoundsAndSort(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
|
||||
}
|
||||
|
||||
public void unionWith(BBox other) {
|
||||
// Short circuit union if either bounds is empty.
|
||||
if (other.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
setBounds(other);
|
||||
return;
|
||||
}
|
||||
|
||||
minX = Math.min(minX, other.getMinX());
|
||||
minY = Math.min(minY, other.getMinY());
|
||||
minZ = Math.min(minZ, other.getMinZ());
|
||||
maxX = Math.max(maxX, other.getMaxX());
|
||||
maxY = Math.max(maxY, other.getMaxY());
|
||||
maxZ = Math.max(maxZ, other.getMaxZ());
|
||||
}
|
||||
|
||||
|
||||
public void unionWith(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
// Short circuit union if either bounds is empty.
|
||||
if ((maxX < minX) || (maxY < minY) || (maxZ < minZ)) {
|
||||
return;
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
setBounds(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
return;
|
||||
}
|
||||
|
||||
this.minX = Math.min(this.minX, minX);
|
||||
this.minY = Math.min(this.minY, minY);
|
||||
this.minZ = Math.min(this.minZ, minZ);
|
||||
this.maxX = Math.max(this.maxX, maxX);
|
||||
this.maxY = Math.max(this.maxY, maxY);
|
||||
this.maxZ = Math.max(this.maxZ, maxZ);
|
||||
}
|
||||
|
||||
public void add(double x, double y, double z) {
|
||||
unionWith(x, y, z, x, y, z);
|
||||
}
|
||||
|
||||
public void add(Vector p) {
|
||||
add(p.x, p.y, p.z);
|
||||
}
|
||||
|
||||
public void intersectWith(BBox other) {
|
||||
// Short circuit intersect if either bounds is empty.
|
||||
if (this.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (other.isEmpty()) {
|
||||
makeEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
minX = Math.max(minX, other.getMinX());
|
||||
minY = Math.max(minY, other.getMinY());
|
||||
minZ = Math.max(minZ, other.getMinZ());
|
||||
maxX = Math.min(maxX, other.getMaxX());
|
||||
maxY = Math.min(maxY, other.getMaxY());
|
||||
maxZ = Math.min(maxZ, other.getMaxZ());
|
||||
}
|
||||
|
||||
public void intersectWith(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
// Short circuit intersect if either bounds is empty.
|
||||
if (this.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if ((maxX < minX) || (maxY < minY) || (maxZ < minZ)) {
|
||||
makeEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
this.minX = Math.max(this.minX, minX);
|
||||
this.minY = Math.max(this.minY, minY);
|
||||
this.minZ = Math.max(this.minZ, minZ);
|
||||
this.maxX = Math.min(this.maxX, maxX);
|
||||
this.maxY = Math.min(this.maxY, maxY);
|
||||
this.maxZ = Math.min(this.maxZ, maxZ);
|
||||
}
|
||||
|
||||
public boolean contains(Vector p) {
|
||||
if ((p == null) || isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return contains(p.x, p.y, p.z);
|
||||
}
|
||||
|
||||
public boolean contains(double x, double y, double z) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (x >= minX && x <= maxX && y >= minY && y <= maxY
|
||||
&& z >= minZ && z <= maxZ);
|
||||
}
|
||||
|
||||
public boolean contains(double x, double y, double z,
|
||||
double width, double height, double depth) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return contains(x, y, z) && contains(x + width, y + height, z + depth);
|
||||
}
|
||||
|
||||
public boolean intersects(double x, double y, double z,
|
||||
double width, double height, double depth) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (x + width >= minX &&
|
||||
y + height >= minY &&
|
||||
z + depth >= minZ &&
|
||||
x <= maxX &&
|
||||
y <= maxY &&
|
||||
z <= maxZ);
|
||||
}
|
||||
|
||||
public boolean intersects(BBox other) {
|
||||
if ((other == null) || other.isEmpty() || isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (other.getMaxX() >= minX &&
|
||||
other.getMaxY() >= minY &&
|
||||
other.getMaxZ() >= minZ &&
|
||||
other.getMinX() <= maxX &&
|
||||
other.getMinY() <= maxY &&
|
||||
other.getMinZ() <= maxZ);
|
||||
}
|
||||
|
||||
public boolean disjoint(double x, double y, double width, double height) {
|
||||
return disjoint(x, y, 0f, width, height, 0f);
|
||||
}
|
||||
|
||||
public boolean disjoint(double x, double y, double z,
|
||||
double width, double height, double depth) {
|
||||
if (isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return (x + width < minX ||
|
||||
y + height < minY ||
|
||||
z + depth < minZ ||
|
||||
x > maxX ||
|
||||
y > maxY ||
|
||||
z > maxZ);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return maxX < minX || maxY < minY || maxZ < minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the edges of this BoxBounds "outward" toward integral boundaries,
|
||||
* such that the rounded bounding box will always full enclose the original
|
||||
* bounding box.
|
||||
*/
|
||||
public void roundOut() {
|
||||
minX = Math.floor(minX);
|
||||
minY = Math.floor(minY);
|
||||
minZ = Math.floor(minZ);
|
||||
maxX = Math.ceil(maxX);
|
||||
maxY = Math.ceil(maxY);
|
||||
maxZ = Math.ceil(maxZ);
|
||||
}
|
||||
|
||||
public void grow(double h, double v, double d) {
|
||||
minX -= h;
|
||||
maxX += h;
|
||||
minY -= v;
|
||||
maxY += v;
|
||||
minZ -= d;
|
||||
maxZ += d;
|
||||
}
|
||||
|
||||
public BBox deriveWithPadding(double h, double v, double d) {
|
||||
grow(h, v, d);
|
||||
return this;
|
||||
}
|
||||
|
||||
// for convenience, this function returns a reference to itself, so we can
|
||||
// change from using "bounds.makeEmpty(); return bounds;" to just
|
||||
// "return bounds.makeEmpty()"
|
||||
public BBox makeEmpty() {
|
||||
minX = minY = minZ = 0.0f;
|
||||
maxX = maxY = maxZ = -1.0f;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void sortMinMax() {
|
||||
if (minX > maxX) {
|
||||
double tmp = maxX;
|
||||
maxX = minX;
|
||||
minX = tmp;
|
||||
}
|
||||
if (minY > maxY) {
|
||||
double tmp = maxY;
|
||||
maxY = minY;
|
||||
minY = tmp;
|
||||
}
|
||||
if (minZ > maxZ) {
|
||||
double tmp = maxZ;
|
||||
maxZ = minZ;
|
||||
minZ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
public void translate(double x, double y, double z) {
|
||||
setMinX(getMinX() + x);
|
||||
setMinY(getMinY() + y);
|
||||
setMaxX(getMaxX() + x);
|
||||
setMaxY(getMaxY() + y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final BBox other = (BBox) obj;
|
||||
if (minX != other.getMinX()) {
|
||||
return false;
|
||||
}
|
||||
if (minY != other.getMinY()) {
|
||||
return false;
|
||||
}
|
||||
if (minZ != other.getMinZ()) {
|
||||
return false;
|
||||
}
|
||||
if (maxX != other.getMaxX()) {
|
||||
return false;
|
||||
}
|
||||
if (maxY != other.getMaxY()) {
|
||||
return false;
|
||||
}
|
||||
if (maxZ != other.getMaxZ()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long hash = 7;
|
||||
hash = 79 * hash + Double.doubleToLongBits(minX);
|
||||
hash = 79 * hash + Double.doubleToLongBits(minY);
|
||||
hash = 79 * hash + Double.doubleToLongBits(minZ);
|
||||
hash = 79 * hash + Double.doubleToLongBits(maxX);
|
||||
hash = 79 * hash + Double.doubleToLongBits(maxY);
|
||||
hash = 79 * hash + Double.doubleToLongBits(maxZ);
|
||||
|
||||
return (int) hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BBox { minX:" + minX + ", minY:" + minY + ", minZ:" + minZ + ", maxX:" + maxX + ", maxY:" + maxY + ", maxZ:" + maxZ + "}";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.fx.Utils3D;
|
||||
import cad.gl.MeshNode;
|
||||
import cad.gl.Scene;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
|
||||
import javax.media.opengl.GLCapabilities;
|
||||
import javax.media.opengl.GLProfile;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Cad {
|
||||
|
||||
static {
|
||||
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
|
||||
|
||||
// Get the default OpenGL profile, reflecting the best for your running platform
|
||||
GLProfile glp = GLProfile.getDefault();
|
||||
GLCapabilities caps = new GLCapabilities(glp);
|
||||
GLWindow window = GLWindow.create(caps);
|
||||
|
||||
Scene scene = new Scene(window);
|
||||
scene.addNode(new MeshNode(Utils3D.createCube(1)));
|
||||
window.setSize(640, 480);
|
||||
window.setTitle("CAD");
|
||||
window.setVisible(true);
|
||||
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
Object monitor = new Object();
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (monitor) {
|
||||
monitor.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import com.jogamp.opengl.util.Animator;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.awt.AWTGLAutoDrawable;
|
||||
import javax.media.opengl.awt.GLCanvas;
|
||||
import javax.media.opengl.awt.GLJPanel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
/**
|
||||
* Gears.java <BR>
|
||||
* author: Brian Paul (converted to Java by Ron Cemer and Sven Goethel) <P>
|
||||
*
|
||||
* This version is equal to Brian Paul's version 1.2 1999/10/21
|
||||
*/
|
||||
|
||||
public class Cad2 implements GLEventListener, MouseListener, MouseMotionListener {
|
||||
public static void main(String[] args) {
|
||||
Frame frame = new Frame("Gear Demo");
|
||||
GLCanvas canvas = new GLCanvas();
|
||||
|
||||
final Cad2 gears = new Cad2();
|
||||
canvas.addGLEventListener(gears);
|
||||
|
||||
frame.add(canvas);
|
||||
frame.setSize(300, 300);
|
||||
final Animator animator = new Animator(canvas);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
// Run this on another thread than the AWT event queue to
|
||||
// make sure the call to Animator.stop() completes before
|
||||
// exiting
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
animator.stop();
|
||||
System.exit(0);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
frame.setVisible(true);
|
||||
// animator.start();
|
||||
}
|
||||
|
||||
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
|
||||
private int gear1, gear2, gear3;
|
||||
private float angle = 0.0f;
|
||||
|
||||
private int prevMouseX, prevMouseY;
|
||||
private boolean mouseRButtonDown = false;
|
||||
|
||||
public void init(GLAutoDrawable drawable) {
|
||||
// Use debug pipeline
|
||||
// drawable.setGL(new DebugGL(drawable.getGL()));
|
||||
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
System.err.println("INIT GL IS: " + gl.getClass().getName());
|
||||
|
||||
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
|
||||
|
||||
gl.setSwapInterval(1);
|
||||
|
||||
float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f };
|
||||
float red[] = { 0.8f, 0.1f, 0.0f, 1.0f };
|
||||
float green[] = { 0.0f, 0.8f, 0.2f, 1.0f };
|
||||
float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f };
|
||||
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos, 0);
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
|
||||
/* make the gears */
|
||||
gear1 = gl.glGenLists(1);
|
||||
gl.glNewList(gear1, GL2.GL_COMPILE);
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, red, 0);
|
||||
gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f);
|
||||
gl.glEndList();
|
||||
|
||||
gear2 = gl.glGenLists(1);
|
||||
gl.glNewList(gear2, GL2.GL_COMPILE);
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, green, 0);
|
||||
gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f);
|
||||
gl.glEndList();
|
||||
|
||||
gear3 = gl.glGenLists(1);
|
||||
gl.glNewList(gear3, GL2.GL_COMPILE);
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f);
|
||||
gl.glEndList();
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
if (drawable instanceof AWTGLAutoDrawable) {
|
||||
AWTGLAutoDrawable awtDrawable = (AWTGLAutoDrawable) drawable;
|
||||
awtDrawable.addMouseListener(this);
|
||||
awtDrawable.addMouseMotionListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
float h = (float)height / (float)width;
|
||||
|
||||
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||
|
||||
System.err.println("GL_VENDOR: " + gl.glGetString(GL2.GL_VENDOR));
|
||||
System.err.println("GL_RENDERER: " + gl.glGetString(GL2.GL_RENDERER));
|
||||
System.err.println("GL_VERSION: " + gl.glGetString(GL2.GL_VERSION));
|
||||
gl.glLoadIdentity();
|
||||
gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
|
||||
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||
gl.glLoadIdentity();
|
||||
gl.glTranslatef(0.0f, 0.0f, -40.0f);
|
||||
}
|
||||
|
||||
public void dispose(GLAutoDrawable drawable) {
|
||||
System.out.println("Gears.dispose: "+drawable);
|
||||
}
|
||||
|
||||
public void display(GLAutoDrawable drawable) {
|
||||
// Turn the gears' teeth
|
||||
angle += 2.0f;
|
||||
|
||||
// Get the GL corresponding to the drawable we are animating
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
// Special handling for the case where the GLJPanel is translucent
|
||||
// and wants to be composited with other Java 2D content
|
||||
if ((drawable instanceof GLJPanel) &&
|
||||
!((GLJPanel) drawable).isOpaque() &&
|
||||
((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
|
||||
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
|
||||
} else {
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// Rotate the entire assembly of gears based on how the user
|
||||
// dragged the mouse around
|
||||
gl.glPushMatrix();
|
||||
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
|
||||
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
|
||||
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Place the first gear and call its display list
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(-3.0f, -2.0f, 0.0f);
|
||||
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||
gl.glCallList(gear1);
|
||||
gl.glPopMatrix();
|
||||
|
||||
// Place the second gear and call its display list
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(3.1f, -2.0f, 0.0f);
|
||||
gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl.glCallList(gear2);
|
||||
gl.glPopMatrix();
|
||||
|
||||
// Place the third gear and call its display list
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(-3.1f, 4.2f, 0.0f);
|
||||
gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl.glCallList(gear3);
|
||||
gl.glPopMatrix();
|
||||
|
||||
// Remember that every push needs a pop; this one is paired with
|
||||
// rotating the entire gear assembly
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
|
||||
|
||||
public static void gear(GL2 gl,
|
||||
float inner_radius,
|
||||
float outer_radius,
|
||||
float width,
|
||||
int teeth,
|
||||
float tooth_depth)
|
||||
{
|
||||
int i;
|
||||
float r0, r1, r2;
|
||||
float angle, da;
|
||||
float u, v, len;
|
||||
|
||||
r0 = inner_radius;
|
||||
r1 = outer_radius - tooth_depth / 2.0f;
|
||||
r2 = outer_radius + tooth_depth / 2.0f;
|
||||
|
||||
da = 2.0f * (float) Math.PI / teeth / 4.0f;
|
||||
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
|
||||
gl.glNormal3f(0.0f, 0.0f, 1.0f);
|
||||
|
||||
/* draw front face */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||
if(i < teeth)
|
||||
{
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||
}
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw front sides of teeth */
|
||||
gl.glBegin(GL2.GL_QUADS);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2.0f * da), r2 * (float)Math.sin(angle + 2.0f * da), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw back face */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw back sides of teeth */
|
||||
gl.glBegin(GL2.GL_QUADS);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw outward faces of teeth */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||
u = r2 * (float)Math.cos(angle + da) - r1 * (float)Math.cos(angle);
|
||||
v = r2 * (float)Math.sin(angle + da) - r1 * (float)Math.sin(angle);
|
||||
len = (float)Math.sqrt(u * u + v * v);
|
||||
u /= len;
|
||||
v /= len;
|
||||
gl.glNormal3f(v, -u, 0.0f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
|
||||
gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
|
||||
u = r1 * (float)Math.cos(angle + 3 * da) - r2 * (float)Math.cos(angle + 2 * da);
|
||||
v = r1 * (float)Math.sin(angle + 3 * da) - r2 * (float)Math.sin(angle + 2 * da);
|
||||
gl.glNormal3f(v, -u, 0.0f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||
gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
|
||||
}
|
||||
gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), -width * 0.5f);
|
||||
gl.glEnd();
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
|
||||
/* draw inside radius cylinder */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glNormal3f(-(float)Math.cos(angle), -(float)Math.sin(angle), 0.0f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
}
|
||||
|
||||
// Methods required for the implementation of MouseListener
|
||||
public void mouseEntered(MouseEvent e) {}
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseClicked(MouseEvent e) {}
|
||||
|
||||
// Methods required for the implementation of MouseMotionListener
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
Dimension size = e.getComponent().getSize();
|
||||
|
||||
float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)size.width);
|
||||
float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)size.height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent e) {}
|
||||
}
|
||||
|
|
@ -1,349 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.fx.Polygon;
|
||||
import cad.fx.Utils3D;
|
||||
import cad.math.Vector;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLCapabilities;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.GLProfile;
|
||||
import javax.media.opengl.Threading;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Cad3 implements GLEventListener, com.jogamp.newt.event.MouseListener {
|
||||
|
||||
|
||||
static {
|
||||
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||
}
|
||||
|
||||
public static List<Polygon> initObjects = Utils3D.createCube(1);
|
||||
|
||||
static TIntObjectMap<Polygon> scene = new TIntObjectHashMap<>();
|
||||
|
||||
private static GLWindow window;
|
||||
|
||||
ExecutorService updater = Executors.newSingleThreadExecutor();
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException {
|
||||
|
||||
|
||||
// Get the default OpenGL profile, reflecting the best for your running platform
|
||||
GLProfile glp = GLProfile.getDefault();
|
||||
// Specifies a set of OpenGL capabilities, based on your profile.
|
||||
GLCapabilities caps = new GLCapabilities(glp);
|
||||
// Create the OpenGL rendering canvas
|
||||
window = GLWindow.create(caps);
|
||||
|
||||
// Create a animator that drives canvas' display() at the specified FPS.
|
||||
// final FPSAnimator animator = new FPSAnimator(window, 60, true);
|
||||
//// final Animator animator = new Animator(window);
|
||||
// window.addWindowListener(new com.jogamp.newt.event.WindowAdapter() {
|
||||
// @Override
|
||||
// public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) {
|
||||
// // Use a dedicate thread to run the stop() to ensure that the
|
||||
// // animator stops before program exits.
|
||||
// new Thread() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// if (animator.isStarted())
|
||||
// animator.stop(); // stop the animator loop
|
||||
// }
|
||||
// }.start();
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
window.addGLEventListener(new Cad3());
|
||||
|
||||
window.setSize(640, 480);
|
||||
window.setTitle("CAD");
|
||||
window.setVisible(true);
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
Object monitor = new Object();
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (monitor) {
|
||||
monitor.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// animator.start();
|
||||
}
|
||||
|
||||
float red[] = {0.8f, 0.1f, 0.0f, 1.0f};
|
||||
float green[] = {0.0f, 0.8f, 0.2f, 1.0f};
|
||||
float blue[] = {0.2f, 0.2f, 1.0f, 1.0f};
|
||||
float white[] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
|
||||
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
|
||||
|
||||
private int prevMouseX, prevMouseY;
|
||||
private boolean mouseRButtonDown = false;
|
||||
|
||||
public void init(GLAutoDrawable drawable) {
|
||||
// Use debug pipeline
|
||||
// drawable.setGL(new DebugGL(drawable.getGL()));
|
||||
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
System.err.println("INIT GL IS: " + gl.getClass().getName());
|
||||
|
||||
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
|
||||
|
||||
gl.setSwapInterval(0);
|
||||
|
||||
float pos0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos0, 0);
|
||||
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
|
||||
initNodes(gl);
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
if (drawable instanceof GLWindow) {
|
||||
GLWindow awtDrawable = (GLWindow) drawable;
|
||||
awtDrawable.addMouseListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void initNodes(GL2 gl) {
|
||||
for (Polygon poly : initObjects) {
|
||||
int id = gl.glGenLists(1);
|
||||
scene.put(id, poly);
|
||||
gl.glNewList(id, GL2.GL_COMPILE);
|
||||
|
||||
//http://devernay.free.fr/cours/opengl/materials.html
|
||||
// float[] amb = {0f, 0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, amb, 0);
|
||||
|
||||
float[] diff = {0.6901961f, 0.76862746f, 0.87058824f};
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, diff, 0);
|
||||
|
||||
// float[] spec = {0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, spec, 0);
|
||||
// float shine = 0.6f;
|
||||
// gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shine * 128.0f);
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
gl.glNormal3d(poly.normal.x, poly.normal.y, poly.normal.z); //very important!!
|
||||
for (Vector[] tr : poly.getTriangles()) {
|
||||
gl.glVertex3d(tr[0].x, tr[0].y, tr[0].z);
|
||||
gl.glVertex3d(tr[1].x, tr[1].y, tr[1].z);
|
||||
gl.glVertex3d(tr[2].x, tr[2].y, tr[2].z);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
gl.glEndList();
|
||||
}
|
||||
for (Polygon poly : initObjects) {
|
||||
int id = gl.glGenLists(1);
|
||||
scene.put(id, poly);
|
||||
gl.glNewList(id, GL2.GL_COMPILE);
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glNormal3d(poly.normal.x, poly.normal.y, poly.normal.z);
|
||||
for (int i = 0; i < poly.shell.size(); i++) {
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
Vector a = Polygon.get(poly.shell, i);
|
||||
Vector b = Polygon.get(poly.shell, i + 1);
|
||||
gl.glVertex3d(a.x, a.y, a.z);
|
||||
gl.glVertex3d(b.x, b.y, b.z);
|
||||
gl.glEnd();
|
||||
}
|
||||
gl.glEndList();
|
||||
}
|
||||
}
|
||||
|
||||
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
float h = (float) height / (float) width;
|
||||
|
||||
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||
gl.glLoadIdentity();
|
||||
gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
|
||||
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||
gl.glLoadIdentity();
|
||||
gl.glTranslatef(0.0f, 0.0f, -40.0f);
|
||||
}
|
||||
|
||||
public void dispose(GLAutoDrawable drawable) {
|
||||
System.out.println("Gears.dispose: " + drawable);
|
||||
}
|
||||
|
||||
public void display(GLAutoDrawable drawable) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
gl.glClearColor(0.5019608f, 0.5019608f, 0.5019608f, 0f);
|
||||
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.glPushMatrix();
|
||||
gl.glScalef(scale, scale, scale);
|
||||
|
||||
gl.glPushMatrix();
|
||||
|
||||
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
|
||||
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
|
||||
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
for (int id : scene.keys()) {
|
||||
gl.glCallList(id);
|
||||
}
|
||||
|
||||
//
|
||||
// gl.glPushMatrix();
|
||||
// gl.glScalef(3,3,3);
|
||||
// gl.glBegin(GL2.GL_QUADS);
|
||||
// gl.glNormal3f( 0.0F, 0.0F, 1.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f(-0.5F, 0.5F, 0.5F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F, 0.5F); gl.glVertex3f( 0.5F,-0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F, 0.0F,-1.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f(-0.5F, 0.5F,-0.5F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F,-0.5F); gl.glVertex3f( 0.5F,-0.5F,-0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F, 1.0F, 0.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f( 0.5F, 0.5F,-0.5F);
|
||||
// gl.glVertex3f(-0.5F, 0.5F,-0.5F); gl.glVertex3f(-0.5F, 0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 0.0F,-1.0F, 0.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f( 0.5F,-0.5F,-0.5F);
|
||||
// gl.glVertex3f( 0.5F,-0.5F, 0.5F); gl.glVertex3f(-0.5F,-0.5F, 0.5F);
|
||||
//
|
||||
// gl.glNormal3f( 1.0F, 0.0F, 0.0F);
|
||||
// gl.glVertex3f( 0.5F, 0.5F, 0.5F); gl.glVertex3f( 0.5F,-0.5F, 0.5F);
|
||||
// gl.glVertex3f( 0.5F,-0.5F,-0.5F); gl.glVertex3f( 0.5F, 0.5F,-0.5F);
|
||||
//
|
||||
// gl.glNormal3f(-1.0F, 0.0F, 0.0F);
|
||||
// gl.glVertex3f(-0.5F,-0.5F,-0.5F); gl.glVertex3f(-0.5F,-0.5F, 0.5F);
|
||||
// gl.glVertex3f(-0.5F, 0.5F, 0.5F); gl.glVertex3f(-0.5F, 0.5F,-0.5F);
|
||||
// gl.glEnd();
|
||||
// gl.glPopMatrix();
|
||||
|
||||
|
||||
gl.glPopMatrix();
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
int width = window.getWidth();
|
||||
int height = window.getHeight();
|
||||
|
||||
float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) width);
|
||||
float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
|
||||
|
||||
volatile boolean updating = false;
|
||||
|
||||
private void update(Runnable op) {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
Threading.invokeOnOpenGLThread(false, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
updating = true;
|
||||
|
||||
op.run();
|
||||
} finally {
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// updater.execute(() -> {
|
||||
// try {
|
||||
// updating = true;
|
||||
//
|
||||
// op.run();
|
||||
// } finally {
|
||||
// updating = false;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
float scale = 1;
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
|
||||
double scaleFactor = e.getRotation()[1] > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||
scale *= scaleFactor;
|
||||
update(window::display);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class Camera {
|
||||
|
||||
public float aspect = 1;
|
||||
public double near = 5.0f;
|
||||
public double far = 60.0f;
|
||||
|
||||
public int sceneW;
|
||||
public int sceneH;
|
||||
|
||||
public double near_width = 1;
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class CompiledNode {
|
||||
|
||||
public final int glId;
|
||||
public final Node node;
|
||||
|
||||
public CompiledNode(Node node, GL2 gl) {
|
||||
this.node = node;
|
||||
glId = gl.glGenLists(1);
|
||||
gl.glNewList(glId, GL2.GL_COMPILE);
|
||||
node.draw(gl);
|
||||
gl.glEndList();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import com.jogamp.opengl.util.Animator;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.awt.AWTGLAutoDrawable;
|
||||
import javax.media.opengl.awt.GLCanvas;
|
||||
import javax.media.opengl.awt.GLJPanel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
/**
|
||||
* Gears.java <BR>
|
||||
* author: Brian Paul (converted to Java by Ron Cemer and Sven Goethel) <P>
|
||||
*
|
||||
* This version is equal to Brian Paul's version 1.2 1999/10/21
|
||||
*/
|
||||
|
||||
public class Gears implements GLEventListener, MouseListener, MouseMotionListener {
|
||||
public static void main(String[] args) {
|
||||
Frame frame = new Frame("Gear Demo");
|
||||
GLCanvas canvas = new GLCanvas();
|
||||
|
||||
final Gears gears = new Gears();
|
||||
canvas.addGLEventListener(gears);
|
||||
|
||||
frame.add(canvas);
|
||||
frame.setSize(300, 300);
|
||||
final Animator animator = new Animator(canvas);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
// Run this on another thread than the AWT event queue to
|
||||
// make sure the call to Animator.stop() completes before
|
||||
// exiting
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
animator.stop();
|
||||
System.exit(0);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
frame.setVisible(true);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
|
||||
private int gear1, gear2, gear3;
|
||||
private float angle = 0.0f;
|
||||
|
||||
private int prevMouseX, prevMouseY;
|
||||
private boolean mouseRButtonDown = false;
|
||||
|
||||
public void init(GLAutoDrawable drawable) {
|
||||
// Use debug pipeline
|
||||
// drawable.setGL(new DebugGL(drawable.getGL()));
|
||||
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
System.err.println("INIT GL IS: " + gl.getClass().getName());
|
||||
|
||||
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
|
||||
|
||||
gl.setSwapInterval(1);
|
||||
|
||||
float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f };
|
||||
float red[] = { 0.8f, 0.1f, 0.0f, 1.0f };
|
||||
float green[] = { 0.0f, 0.8f, 0.2f, 1.0f };
|
||||
float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f };
|
||||
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos, 0);
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
|
||||
/* make the gears */
|
||||
gear1 = gl.glGenLists(1);
|
||||
gl.glNewList(gear1, GL2.GL_COMPILE);
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, red, 0);
|
||||
gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f);
|
||||
gl.glEndList();
|
||||
|
||||
gear2 = gl.glGenLists(1);
|
||||
gl.glNewList(gear2, GL2.GL_COMPILE);
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, green, 0);
|
||||
gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f);
|
||||
gl.glEndList();
|
||||
|
||||
gear3 = gl.glGenLists(1);
|
||||
gl.glNewList(gear3, GL2.GL_COMPILE);
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f);
|
||||
gl.glEndList();
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
if (drawable instanceof AWTGLAutoDrawable) {
|
||||
AWTGLAutoDrawable awtDrawable = (AWTGLAutoDrawable) drawable;
|
||||
awtDrawable.addMouseListener(this);
|
||||
awtDrawable.addMouseMotionListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
float h = (float)height / (float)width;
|
||||
|
||||
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||
|
||||
System.err.println("GL_VENDOR: " + gl.glGetString(GL2.GL_VENDOR));
|
||||
System.err.println("GL_RENDERER: " + gl.glGetString(GL2.GL_RENDERER));
|
||||
System.err.println("GL_VERSION: " + gl.glGetString(GL2.GL_VERSION));
|
||||
gl.glLoadIdentity();
|
||||
gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
|
||||
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||
gl.glLoadIdentity();
|
||||
gl.glTranslatef(0.0f, 0.0f, -40.0f);
|
||||
}
|
||||
|
||||
public void dispose(GLAutoDrawable drawable) {
|
||||
System.out.println("Gears.dispose: "+drawable);
|
||||
}
|
||||
|
||||
public void display(GLAutoDrawable drawable) {
|
||||
// Turn the gears' teeth
|
||||
angle += 2.0f;
|
||||
|
||||
// Get the GL corresponding to the drawable we are animating
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
// Special handling for the case where the GLJPanel is translucent
|
||||
// and wants to be composited with other Java 2D content
|
||||
if ((drawable instanceof GLJPanel) &&
|
||||
!((GLJPanel) drawable).isOpaque() &&
|
||||
((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
|
||||
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
|
||||
} else {
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// Rotate the entire assembly of gears based on how the user
|
||||
// dragged the mouse around
|
||||
gl.glPushMatrix();
|
||||
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
|
||||
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
|
||||
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Place the first gear and call its display list
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(-3.0f, -2.0f, 0.0f);
|
||||
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||
gl.glCallList(gear1);
|
||||
gl.glPopMatrix();
|
||||
|
||||
// Place the second gear and call its display list
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(3.1f, -2.0f, 0.0f);
|
||||
gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl.glCallList(gear2);
|
||||
gl.glPopMatrix();
|
||||
|
||||
// Place the third gear and call its display list
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(-3.1f, 4.2f, 0.0f);
|
||||
gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl.glCallList(gear3);
|
||||
gl.glPopMatrix();
|
||||
|
||||
// Remember that every push needs a pop; this one is paired with
|
||||
// rotating the entire gear assembly
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
|
||||
|
||||
public static void gear(GL2 gl,
|
||||
float inner_radius,
|
||||
float outer_radius,
|
||||
float width,
|
||||
int teeth,
|
||||
float tooth_depth)
|
||||
{
|
||||
int i;
|
||||
float r0, r1, r2;
|
||||
float angle, da;
|
||||
float u, v, len;
|
||||
|
||||
r0 = inner_radius;
|
||||
r1 = outer_radius - tooth_depth / 2.0f;
|
||||
r2 = outer_radius + tooth_depth / 2.0f;
|
||||
|
||||
da = 2.0f * (float) Math.PI / teeth / 4.0f;
|
||||
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
|
||||
gl.glNormal3f(0.0f, 0.0f, 1.0f);
|
||||
|
||||
/* draw front face */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||
if(i < teeth)
|
||||
{
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||
}
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw front sides of teeth */
|
||||
gl.glBegin(GL2.GL_QUADS);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2.0f * da), r2 * (float)Math.sin(angle + 2.0f * da), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw back face */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw back sides of teeth */
|
||||
gl.glBegin(GL2.GL_QUADS);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
/* draw outward faces of teeth */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i < teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
|
||||
u = r2 * (float)Math.cos(angle + da) - r1 * (float)Math.cos(angle);
|
||||
v = r2 * (float)Math.sin(angle + da) - r1 * (float)Math.sin(angle);
|
||||
len = (float)Math.sqrt(u * u + v * v);
|
||||
u /= len;
|
||||
v /= len;
|
||||
gl.glNormal3f(v, -u, 0.0f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
|
||||
gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), width * 0.5f);
|
||||
gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
|
||||
u = r1 * (float)Math.cos(angle + 3 * da) - r2 * (float)Math.cos(angle + 2 * da);
|
||||
v = r1 * (float)Math.sin(angle + 3 * da) - r2 * (float)Math.sin(angle + 2 * da);
|
||||
gl.glNormal3f(v, -u, 0.0f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
|
||||
gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
|
||||
}
|
||||
gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), width * 0.5f);
|
||||
gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), -width * 0.5f);
|
||||
gl.glEnd();
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
|
||||
/* draw inside radius cylinder */
|
||||
gl.glBegin(GL2.GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++)
|
||||
{
|
||||
angle = i * 2.0f * (float) Math.PI / teeth;
|
||||
gl.glNormal3f(-(float)Math.cos(angle), -(float)Math.sin(angle), 0.0f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
|
||||
gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
|
||||
}
|
||||
gl.glEnd();
|
||||
}
|
||||
|
||||
// Methods required for the implementation of MouseListener
|
||||
public void mouseEntered(MouseEvent e) {}
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseClicked(MouseEvent e) {}
|
||||
|
||||
// Methods required for the implementation of MouseMotionListener
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
Dimension size = e.getComponent().getSize();
|
||||
|
||||
float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)size.width);
|
||||
float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)size.height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent e) {}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import javax.media.opengl.GLCapabilities;
|
||||
import javax.media.opengl.GLProfile;
|
||||
import com.jogamp.newt.event.WindowAdapter;
|
||||
import com.jogamp.newt.event.WindowEvent;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
import com.jogamp.opengl.util.FPSAnimator;
|
||||
|
||||
/**
|
||||
* A program that draws with JOGL in a NEWT GLWindow.
|
||||
*
|
||||
*/
|
||||
public class JOGL2NewtDemo {
|
||||
private static String TITLE = "JOGL 2 with NEWT"; // window's title
|
||||
private static final int WINDOW_WIDTH = 640; // width of the drawable
|
||||
private static final int WINDOW_HEIGHT = 480; // height of the drawable
|
||||
private static final int FPS = 60; // animator's target frames per second
|
||||
|
||||
static {
|
||||
GLProfile.initSingleton(); // The method allows JOGL to prepare some Linux-specific locking optimizations
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry main() method.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// Get the default OpenGL profile, reflecting the best for your running platform
|
||||
GLProfile glp = GLProfile.getDefault();
|
||||
// Specifies a set of OpenGL capabilities, based on your profile.
|
||||
GLCapabilities caps = new GLCapabilities(glp);
|
||||
// Create the OpenGL rendering canvas
|
||||
GLWindow window = GLWindow.create(caps);
|
||||
|
||||
// Create a animator that drives canvas' display() at the specified FPS.
|
||||
final FPSAnimator animator = new FPSAnimator(window, FPS, true);
|
||||
|
||||
window.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowDestroyNotify(WindowEvent arg0) {
|
||||
// Use a dedicate thread to run the stop() to ensure that the
|
||||
// animator stops before program exits.
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (animator.isStarted())
|
||||
animator.stop(); // stop the animator loop
|
||||
System.exit(0);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
});
|
||||
|
||||
window.addGLEventListener(new JOGL2Renderer());
|
||||
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
window.setTitle(TITLE);
|
||||
window.setVisible(true);
|
||||
animator.start(); // start the animator loop
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import javax.media.opengl.GL;
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
|
||||
/**
|
||||
* Class handles the OpenGL events to render graphics.
|
||||
*
|
||||
*/
|
||||
public class JOGL2Renderer implements GLEventListener {
|
||||
private double theta = 0.0f; // rotational angle
|
||||
|
||||
@Override
|
||||
public void init(GLAutoDrawable drawable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(GLAutoDrawable drawable) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called back by the drawable to render OpenGL graphics
|
||||
*/
|
||||
@Override
|
||||
public void display(GLAutoDrawable drawable) {
|
||||
GL2 gl = drawable.getGL().getGL2(); // get the OpenGL graphics context
|
||||
|
||||
gl.glClear(GL.GL_COLOR_BUFFER_BIT); // clear background
|
||||
gl.glLoadIdentity(); // reset the model-view matrix
|
||||
|
||||
// Rendering code - draw a triangle
|
||||
float sine = (float)Math.sin(theta);
|
||||
float cosine = (float)Math.cos(theta);
|
||||
gl.glBegin(GL.GL_TRIANGLES);
|
||||
gl.glColor3f(1, 0, 0);
|
||||
gl.glVertex2d(-cosine, -cosine);
|
||||
gl.glColor3f(0, 1, 0);
|
||||
gl.glVertex2d(0, cosine);
|
||||
gl.glColor3f(0, 0, 1);
|
||||
gl.glVertex2d(sine, -sine);
|
||||
gl.glEnd();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the rotation angle after each frame refresh
|
||||
*/
|
||||
private void update() {
|
||||
theta += 0.01;
|
||||
}
|
||||
|
||||
/*... Other methods leave blank ...*/
|
||||
}
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.fx.Polygon;
|
||||
import cad.math.Vector;
|
||||
import com.sun.javafx.scene.input.PickResultChooser;
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.input.PickResult;
|
||||
import javafx.scene.shape.CullFace;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by verastov
|
||||
*/
|
||||
public class MeshNode extends Node {
|
||||
|
||||
public final List<Polygon> faces;
|
||||
|
||||
static boolean DRAW_LINES = false;
|
||||
private BBox cachedBounds;
|
||||
|
||||
public MeshNode(List<Polygon> faces) {
|
||||
this.faces = faces;
|
||||
}
|
||||
|
||||
@Override
|
||||
void draw(GL2 gl) {
|
||||
for (Polygon face : faces) {
|
||||
|
||||
//http://devernay.free.fr/cours/opengl/materials.html
|
||||
// float[] amb = {0f, 0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, amb, 0);
|
||||
|
||||
float[] diff = {0.6901961f, 0.76862746f, 0.87058824f};
|
||||
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, diff, 0);
|
||||
|
||||
// float[] spec = {0f, 0f, 0f};
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, spec, 0);
|
||||
// float shine = 0.6f;
|
||||
// gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, shine * 128.0f);
|
||||
// gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
|
||||
|
||||
gl.glShadeModel(GL2.GL_SMOOTH);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
|
||||
gl.glNormal3d(face.normal.x, face.normal.y, face.normal.z); //very important!!
|
||||
for (Vector[] tr : face.getTriangles()) {
|
||||
gl.glVertex3d(tr[0].x, tr[0].y, tr[0].z);
|
||||
gl.glVertex3d(tr[1].x, tr[1].y, tr[1].z);
|
||||
gl.glVertex3d(tr[2].x, tr[2].y, tr[2].z);
|
||||
}
|
||||
gl.glEnd();
|
||||
|
||||
if (DRAW_LINES) {
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glNormal3d(face.normal.x, face.normal.y, face.normal.z);
|
||||
for (int i = 0; i < face.shell.size(); i++) {
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
Vector a = Polygon.get(face.shell, i);
|
||||
Vector b = Polygon.get(face.shell, i + 1);
|
||||
gl.glVertex3d(a.x, a.y, a.z);
|
||||
gl.glVertex3d(b.x, b.y, b.z);
|
||||
gl.glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BBox computeBounds() {
|
||||
if (cachedBounds == null) {
|
||||
cachedBounds = new BBox();
|
||||
for (Polygon face : faces) {
|
||||
for (Vector vector : face.shell) {
|
||||
cachedBounds.add(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cachedBounds;
|
||||
}
|
||||
|
||||
protected boolean impl_computeIntersects(PickRay pickRay, PickResultChooser pickResult,
|
||||
javafx.scene.Node candidate, CullFace cullFace,
|
||||
boolean reportFace) {
|
||||
|
||||
boolean found = false;
|
||||
|
||||
final Vector o = pickRay.getOriginNoClone();
|
||||
final Vector d = pickRay.getDirectionNoClone();
|
||||
|
||||
for (Polygon face : faces) {
|
||||
for (Vector[] triangle : face.getTriangles()) {
|
||||
if (computeIntersectsFace(pickRay, o, d, triangle, cullFace, candidate,
|
||||
reportFace, pickResult)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private Point3D computeCentroid(
|
||||
double v0x, double v0y, double v0z,
|
||||
double v1x, double v1y, double v1z,
|
||||
double v2x, double v2y, double v2z) {
|
||||
|
||||
// Point3D center = v1.midpoint(v2);
|
||||
// Point3D vec = center.subtract(v0);
|
||||
// return v0.add(new Point3D(vec.getX() / 3.0, vec.getY() / 3.0, vec.getZ() / 3.0));
|
||||
|
||||
return new Point3D(
|
||||
v0x + (v2x + (v1x - v2x) / 2.0 - v0x) / 3.0,
|
||||
v0y + (v2y + (v1y - v2y) / 2.0 - v0y) / 3.0,
|
||||
v0z + (v2z + (v1z - v2z) / 2.0 - v0z) / 3.0);
|
||||
}
|
||||
|
||||
private boolean computeIntersectsFace(
|
||||
PickRay pickRay, Vector origin, Vector dir, Vector[] face,
|
||||
CullFace cullFace, javafx.scene.Node candidate, boolean reportFace,
|
||||
PickResultChooser result) {//, BoxBounds rayBounds) {
|
||||
|
||||
final float v0x = (float) face[0].x;
|
||||
final float v0y = (float) face[0].y;
|
||||
final float v0z = (float) face[0].z;
|
||||
final float v1x = (float) face[1].x;
|
||||
final float v1y = (float) face[1].y;
|
||||
final float v1z = (float) face[1].z;
|
||||
final float v2x = (float) face[2].x;
|
||||
final float v2y = (float) face[2].y;
|
||||
final float v2z = (float) face[2].z;
|
||||
|
||||
// e1 = v1.subtract(v0)
|
||||
final float e1x = v1x - v0x;
|
||||
final float e1y = v1y - v0y;
|
||||
final float e1z = v1z - v0z;
|
||||
// e2 = v2.subtract(v0)
|
||||
final float e2x = v2x - v0x;
|
||||
final float e2y = v2y - v0y;
|
||||
final float e2z = v2z - v0z;
|
||||
|
||||
// h = dir.crossProduct(e2)
|
||||
final double hx = dir.y * e2z - dir.z * e2y;
|
||||
final double hy = dir.z * e2x - dir.x * e2z;
|
||||
final double hz = dir.x * e2y - dir.y * e2x;
|
||||
|
||||
// a = e1.dotProduct(h)
|
||||
final double a = e1x * hx + e1y * hy + e1z * hz;
|
||||
if (a == 0.0) {
|
||||
return false;
|
||||
}
|
||||
final double f = 1.0 / a;
|
||||
|
||||
// s = origin.subtract(v0)
|
||||
final double sx = origin.x - v0x;
|
||||
final double sy = origin.y - v0y;
|
||||
final double sz = origin.z - v0z;
|
||||
|
||||
// u = f * (s.dotProduct(h))
|
||||
final double u = f * (sx * hx + sy * hy + sz * hz);
|
||||
|
||||
if (u < 0.0 || u > 1.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// q = s.crossProduct(e1)
|
||||
final double qx = sy * e1z - sz * e1y;
|
||||
final double qy = sz * e1x - sx * e1z;
|
||||
final double qz = sx * e1y - sy * e1x;
|
||||
|
||||
// v = f * dir.dotProduct(q)
|
||||
double v = f * (dir.x * qx + dir.y * qy + dir.z * qz);
|
||||
|
||||
if (v < 0.0 || u + v > 1.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// t = f * e2.dotProduct(q)
|
||||
final double t = f * (e2x * qx + e2y * qy + e2z * qz);
|
||||
|
||||
if (t >= pickRay.getNearClip() && t <= pickRay.getFarClip()) {
|
||||
// This branch is entered only for hit triangles (not so often),
|
||||
// so we can get smoothly back to the nice code using Point3Ds.
|
||||
|
||||
if (cullFace != CullFace.NONE) {
|
||||
// normal = e1.crossProduct(e2)
|
||||
final Point3D normal = new Point3D(
|
||||
e1y * e2z - e1z * e2y,
|
||||
e1z * e2x - e1x * e2z,
|
||||
e1x * e2y - e1y * e2x);
|
||||
|
||||
final double nangle = normal.angle(
|
||||
new Point3D(-dir.x, -dir.y, -dir.z));
|
||||
if ((nangle >= 90 || cullFace != CullFace.BACK) &&
|
||||
(nangle <= 90 || cullFace != CullFace.FRONT)) {
|
||||
// hit culled face
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Double.isInfinite(t) || Double.isNaN(t)) {
|
||||
// we've got a nonsense pick ray or triangle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result == null || !result.isCloser(t)) {
|
||||
// it intersects, but we are not interested in the result
|
||||
// or we already have a better (closer) result
|
||||
// so we can omit the point and texture computation
|
||||
return true;
|
||||
}
|
||||
|
||||
// Point3D point = PickResultChooser.computePoint(pickRay, t);
|
||||
|
||||
// result.offer(candidate, t,
|
||||
// reportFace ? faceIndex / vertexFormat.getFaceElementSize() : PickResult.FACE_UNDEFINED,
|
||||
// point, txCoords);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import com.sun.javafx.geom.PickRay;
|
||||
import com.sun.javafx.scene.input.PickResultChooser;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
|
||||
public abstract class Node {
|
||||
|
||||
abstract void draw(GL2 gl);
|
||||
|
||||
// protected final boolean impl_intersects(PickRay pickRay, PickResultChooser pickResult) {
|
||||
// double boundsDistance = impl_intersectsBounds(pickRay);
|
||||
// if (!Double.isNaN(boundsDistance)) {
|
||||
// if (isPickOnBounds()) {
|
||||
// if (pickResult != null) {
|
||||
// pickResult.offer(this, boundsDistance, PickResultChooser.computePoint(pickRay, boundsDistance));
|
||||
// }
|
||||
// return true;
|
||||
// } else {
|
||||
// return impl_computeIntersects(pickRay, pickResult);
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
|
||||
package cad.gl;
|
||||
|
||||
import cad.math.Vector;
|
||||
|
||||
/**
|
||||
* A ray used for picking.
|
||||
*/
|
||||
public class PickRay {
|
||||
private Vector origin = new Vector();
|
||||
private Vector direction = new Vector();
|
||||
private double nearClip = 0.0;
|
||||
private double farClip = Double.POSITIVE_INFINITY;
|
||||
|
||||
// static final double EPS = 1.0e-13;
|
||||
static final double EPS = 1.0e-5f;
|
||||
|
||||
public PickRay() {
|
||||
}
|
||||
|
||||
public PickRay(Vector origin, Vector direction, double nearClip, double farClip) {
|
||||
set(origin, direction, nearClip, farClip);
|
||||
}
|
||||
|
||||
public PickRay(double x, double y, double z, double nearClip, double farClip) {
|
||||
set(x, y, z, nearClip, farClip);
|
||||
}
|
||||
|
||||
|
||||
public final void set(Vector origin, Vector direction, double nearClip, double farClip) {
|
||||
setOrigin(origin);
|
||||
setDirection(direction);
|
||||
this.nearClip = nearClip;
|
||||
this.farClip = farClip;
|
||||
}
|
||||
|
||||
public final void set(double x, double y, double z, double nearClip, double farClip) {
|
||||
setOrigin(x, y, -z);
|
||||
setDirection(0, 0, z);
|
||||
this.nearClip = nearClip;
|
||||
this.farClip = farClip;
|
||||
}
|
||||
|
||||
|
||||
public void setPickRay(PickRay other) {
|
||||
setOrigin(other.origin);
|
||||
setDirection(other.direction);
|
||||
nearClip = other.nearClip;
|
||||
farClip = other.farClip;
|
||||
}
|
||||
|
||||
public PickRay copy() {
|
||||
return new PickRay(origin, direction, nearClip, farClip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the pick ray in world coordinates.
|
||||
*
|
||||
* @param origin the origin (in world coordinates).
|
||||
*/
|
||||
public void setOrigin(Vector origin) {
|
||||
this.origin.set(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the pick ray in world coordinates.
|
||||
*
|
||||
* @param x the origin X coordinate
|
||||
* @param y the origin Y coordinate
|
||||
* @param z the origin Z coordinate
|
||||
*/
|
||||
public void setOrigin(double x, double y, double z) {
|
||||
this.origin.set(x, y, z);
|
||||
}
|
||||
|
||||
public Vector getOrigin(Vector rv) {
|
||||
if (rv == null) {
|
||||
rv = new Vector();
|
||||
}
|
||||
rv.set(origin);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Vector getOriginNoClone() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction vector of the pick ray. This vector need not
|
||||
* be normalized.
|
||||
*
|
||||
* @param direction the direction vector
|
||||
*/
|
||||
public void setDirection(Vector direction) {
|
||||
this.direction.set(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction of the pick ray. The vector need not be normalized.
|
||||
*
|
||||
* @param x the direction X magnitude
|
||||
* @param y the direction Y magnitude
|
||||
* @param z the direction Z magnitude
|
||||
*/
|
||||
public void setDirection(double x, double y, double z) {
|
||||
this.direction.set(x, y, z);
|
||||
}
|
||||
|
||||
public Vector getDirection(Vector rv) {
|
||||
if (rv == null) {
|
||||
rv = new Vector();
|
||||
}
|
||||
rv.set(direction);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public Vector getDirectionNoClone() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public double getNearClip() {
|
||||
return nearClip;
|
||||
}
|
||||
|
||||
public double getFarClip() {
|
||||
return farClip;
|
||||
}
|
||||
|
||||
public double distance(Vector iPnt) {
|
||||
double x = iPnt.x - origin.x;
|
||||
double y = iPnt.y - origin.y;
|
||||
double z = iPnt.z - origin.z;
|
||||
return Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
|
||||
private static final double EPSILON_ABSOLUTE = 1.0e-5;
|
||||
|
||||
static boolean almostZero(double a) {
|
||||
return ((a < EPSILON_ABSOLUTE) && (a > -EPSILON_ABSOLUTE));
|
||||
}
|
||||
|
||||
private static boolean isNonZero(double v) {
|
||||
return ((v > EPS) || (v < -EPS));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "origin: " + origin + " direction: " + direction;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
package cad.gl;
|
||||
|
||||
import cad.math.Vector;
|
||||
import com.jogamp.newt.event.MouseEvent;
|
||||
import com.jogamp.newt.event.MouseListener;
|
||||
import com.jogamp.newt.opengl.GLWindow;
|
||||
import javafx.scene.input.PickResult;
|
||||
|
||||
import javax.media.opengl.GL2;
|
||||
import javax.media.opengl.GLAutoDrawable;
|
||||
import javax.media.opengl.GLEventListener;
|
||||
import javax.media.opengl.Threading;
|
||||
import javax.media.opengl.glu.GLU;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Scene implements GLEventListener, MouseListener {
|
||||
|
||||
private final List<Node> toCompile = new ArrayList<>();
|
||||
private final List<CompiledNode> scene = new ArrayList<>();
|
||||
private final GLWindow window;
|
||||
private final Camera camera = new Camera();
|
||||
private Vector[] pickRay = {new Vector(), new Vector()};
|
||||
private float winMouseY;
|
||||
private float winMouseX;
|
||||
private boolean pickRequest = false;
|
||||
|
||||
public Scene(GLWindow window) {
|
||||
this.window = window;
|
||||
window.addGLEventListener(this);
|
||||
}
|
||||
|
||||
float red[] = {0.8f, 0.1f, 0.0f, 1.0f};
|
||||
float green[] = {0.0f, 0.8f, 0.2f, 1.0f};
|
||||
float blue[] = {0.2f, 0.2f, 1.0f, 1.0f};
|
||||
float white[] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
private float view_rotx = 0.0f, view_roty = 0.0f, view_rotz = 0.0f;
|
||||
// private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
|
||||
|
||||
private int prevMouseX, prevMouseY;
|
||||
private boolean mouseRButtonDown = false;
|
||||
|
||||
public void init(GLAutoDrawable drawable) {
|
||||
// Use debug pipeline
|
||||
// drawable.setGL(new DebugGL(drawable.getGL()));
|
||||
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
System.err.println("INIT GL IS: " + gl.getClass().getName());
|
||||
|
||||
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
|
||||
|
||||
gl.setSwapInterval(0);
|
||||
|
||||
float pos0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos0, 0);
|
||||
|
||||
gl.glEnable(GL2.GL_CULL_FACE);
|
||||
gl.glEnable(GL2.GL_DEPTH_TEST);
|
||||
gl.glEnable(GL2.GL_LIGHTING);
|
||||
gl.glEnable(GL2.GL_LIGHT0);
|
||||
|
||||
compileNodes(gl);
|
||||
|
||||
gl.glEnable(GL2.GL_NORMALIZE);
|
||||
|
||||
window.addMouseListener(this);
|
||||
}
|
||||
|
||||
private void compileNodes(GL2 gl) {
|
||||
if (toCompile.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Node node : toCompile) {
|
||||
scene.add(new CompiledNode(node, gl));
|
||||
}
|
||||
}
|
||||
|
||||
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
camera.sceneW = width;
|
||||
camera.sceneH = height;
|
||||
camera.aspect = (float) height / (float) width;
|
||||
|
||||
gl.glMatrixMode(GL2.GL_PROJECTION);
|
||||
gl.glLoadIdentity();
|
||||
gl.glFrustum(-camera.near_width, camera.near_width,
|
||||
-camera.aspect * camera.near_width, camera.aspect * camera.near_width,
|
||||
camera.near, camera.far);
|
||||
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||
gl.glLoadIdentity();
|
||||
gl.glTranslatef(0.0f, 0.0f, -40.0f);
|
||||
}
|
||||
|
||||
public void dispose(GLAutoDrawable drawable) {
|
||||
System.out.println("dispose: " + drawable);
|
||||
}
|
||||
|
||||
public void display(GLAutoDrawable drawable) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
|
||||
gl.glClearColor(0.5019608f, 0.5019608f, 0.5019608f, 0f);
|
||||
|
||||
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.glPushMatrix();
|
||||
gl.glScalef(scale, scale, scale);
|
||||
|
||||
gl.glPushMatrix();
|
||||
|
||||
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
|
||||
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
|
||||
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
updatePickRay(gl);
|
||||
drawPickRay(gl);
|
||||
|
||||
for (CompiledNode cn : scene) {
|
||||
gl.glCallList(cn.glId);
|
||||
}
|
||||
|
||||
gl.glPopMatrix();
|
||||
gl.glPopMatrix();
|
||||
}
|
||||
|
||||
private void updatePickRay(GL2 gl) {
|
||||
if (!pickRequest) {
|
||||
return;
|
||||
}
|
||||
pickRequest = false;
|
||||
float[] model = new float[16];
|
||||
float[] proj = new float[16];
|
||||
int[] viewport = new int[16];
|
||||
|
||||
gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
|
||||
gl.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, model, 0);
|
||||
gl.glGetFloatv(GL2.GL_PROJECTION_MATRIX, proj, 0);
|
||||
|
||||
float[] out = new float[3];
|
||||
float y = viewport[3] - winMouseY;
|
||||
|
||||
glu.gluUnProject(winMouseX, y, 0, model, 0, proj, 0, viewport, 0, out, 0);
|
||||
pickRay[0].set3(out);
|
||||
|
||||
glu.gluUnProject(winMouseX, y, 1, model, 0, proj, 0, viewport, 0, out, 0);
|
||||
pickRay[1].set3(out);
|
||||
|
||||
|
||||
// Vector dir = pickRay[1].minus(pickRay[0]);
|
||||
|
||||
// pickRay[1] = pickRay[1].minus(pickRay[0]).scale(700);//.normalize().scale(55);
|
||||
pickRay[1] = pickRay[1].minus(pickRay[0]).normalize().multi(30);
|
||||
}
|
||||
|
||||
public static float[] fixW(float[] v) {
|
||||
float w = v[3];
|
||||
for (int i = 0; i < 4; i++)
|
||||
v[i] = v[i] / w;
|
||||
return v;
|
||||
}
|
||||
|
||||
private void drawPickRay(GL2 gl) {
|
||||
|
||||
if (pickRay != null) {
|
||||
|
||||
gl.glShadeModel(GL2.GL_FLAT);
|
||||
gl.glLineWidth(1.5f);
|
||||
gl.glColor3f(255.0f, 255.0f, 255.0f);
|
||||
gl.glDisable(GL2.GL_LIGHTING);
|
||||
|
||||
gl.glBegin(GL2.GL_LINES);
|
||||
// Vector a = pickRay;
|
||||
// Vector b = pickRay.plus(pickRay.normalize().scale(-60));
|
||||
vertex(gl, pickRay[0]);
|
||||
vertex(gl, pickRay[1]);
|
||||
System.out.println(Arrays.toString(pickRay));
|
||||
gl.glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void vertex(GL2 gl, Vector vector) {
|
||||
gl.glVertex3d(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
computePickRay(e.getX(), e.getY());
|
||||
update(window::display);
|
||||
pickRequest = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
prevMouseX = e.getX();
|
||||
prevMouseY = e.getY();
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
|
||||
mouseRButtonDown = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
|
||||
int width = window.getWidth();
|
||||
int height = window.getHeight();
|
||||
|
||||
float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) width);
|
||||
float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) height);
|
||||
|
||||
prevMouseX = x;
|
||||
prevMouseY = y;
|
||||
|
||||
view_rotx += thetaX;
|
||||
view_roty += thetaY;
|
||||
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
volatile boolean updating = false;
|
||||
|
||||
private void update(Runnable op) {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
Threading.invokeOnOpenGLThread(false, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
updating = true;
|
||||
op.run();
|
||||
} finally {
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final double SCALE_DELTA = 1.1;
|
||||
float scale = 1;
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseEvent e) {
|
||||
double scaleFactor = e.getRotation()[1] > 0 ? SCALE_DELTA : 1 / SCALE_DELTA;
|
||||
scale *= scaleFactor;
|
||||
update(window::display);
|
||||
}
|
||||
|
||||
public void addNode(Node node) {
|
||||
toCompile.add(node);
|
||||
}
|
||||
|
||||
|
||||
// private PickResult pick(final double x, final double y) {
|
||||
// final PickRay pickRay = computePickRay(x, y);
|
||||
// final double mag = pickRay.getDirectionNoClone().length();
|
||||
// pickRay.getDirectionNoClone().normalize();
|
||||
// final PickResult res = pickNode(pickRay);
|
||||
// return res;
|
||||
// }
|
||||
|
||||
GLU glu = new GLU();
|
||||
|
||||
private void computePickRay(float mx, float my) {
|
||||
|
||||
// winMouseX = mx - camera.sceneW / 2;
|
||||
// winMouseY = (camera.sceneH - my) - camera.sceneH / 2;
|
||||
|
||||
winMouseX = mx;
|
||||
winMouseY = my;
|
||||
//
|
||||
//
|
||||
// float winY = (camera.sceneH - my) - camera.sceneH/2;
|
||||
// double norm_y = winY/(camera.sceneH/2);
|
||||
//
|
||||
// float winX = mx - camera.sceneW/2;
|
||||
// double norm_x = winX/(camera.sceneW/2);
|
||||
|
||||
//
|
||||
// double y = camera.near_width * norm_y * camera.aspect;
|
||||
// double x = camera.near_width * norm_x;
|
||||
// System.out.println(x + ":" + y);
|
||||
// return new Vector(x, y, camera.near);
|
||||
}
|
||||
|
||||
private PickResult pickNode(PickRay ray) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
1037
src/cad/lm.in
1037
src/cad/lm.in
File diff suppressed because it is too large
Load diff
|
|
@ -1,258 +0,0 @@
|
|||
package cad.math;
|
||||
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.transform.Affine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
|
||||
public class HMath {
|
||||
|
||||
public static final int X = 0;
|
||||
public static final int Y = 1;
|
||||
public static final int Z = 2;
|
||||
public static final double[] EMPTY = new double[0];
|
||||
public static final Vector X_AXIS = new Vector(1, 0, 0);
|
||||
public static final Vector Y_AXIS = new Vector(0, 1, 0);
|
||||
public static final Vector Z_AXIS = new Vector(0, 0, 1);
|
||||
public static final Vector ZERO = new Vector(0, 0, 0);
|
||||
|
||||
public static final double TOLERANCE = 0.000001;
|
||||
|
||||
/**
|
||||
* x*p1 + x*p2 + p3 = 0
|
||||
* x*m1 + x*m2 + m3 = 0
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static double[] solveLinearSystem(double p1, double p2, double p3,
|
||||
double m1, double m2, double m3) {
|
||||
|
||||
double y = (m1 * m3 * p1 + m1 * p3) / (m1 * p2 - m1 * m2 * p1);
|
||||
double x = (-y * p2 - p3) / p1;
|
||||
return new double[]{x, y};
|
||||
}
|
||||
|
||||
/**
|
||||
* ax^2 + bx + c = 0
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static final double[] solveQuadraticEquation(double a, double b, double c) {
|
||||
final double D = b*b - 4 * a * c;
|
||||
double[] solutions;
|
||||
if (D > 0) {
|
||||
solutions = new double[2];
|
||||
solutions[0] = (-b + sqrt(D)) / (2 * a);
|
||||
solutions[1] = (-b - sqrt(D)) / (2 * a);
|
||||
|
||||
} else if (D == 0) {
|
||||
solutions = new double[2];
|
||||
solutions[0] = -b / (2 * a);
|
||||
} else {
|
||||
solutions = EMPTY;
|
||||
}
|
||||
return solutions;
|
||||
}
|
||||
|
||||
public static double length(double[] vector) {
|
||||
double sum = 0;
|
||||
for (double v : vector) {
|
||||
sum += v * v;
|
||||
}
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
public static double[] ortoXY(double[] vector) {
|
||||
return new double[]{-vector[Y], vector[X]};
|
||||
}
|
||||
|
||||
public static double[] plus(double[] vector1, double[] vector2) {
|
||||
double[] result = new double[max(vector1.length, vector2.length)];
|
||||
for (int i = 0; i < min(vector1.length, vector2.length); i++) {
|
||||
result[i] = vector1[i] + vector2[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double[] minus(double[] fromVector, double[] vector) {
|
||||
double[] result = new double[max(fromVector.length, vector.length)];
|
||||
for (int i = 0; i < min(fromVector.length, vector.length); i++) {
|
||||
result[i] = fromVector[i] - vector[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double[] scale(double[] vector, double factor) {
|
||||
double[] scaled = new double[vector.length];
|
||||
for (int i = 0; i < vector.length; i++) {
|
||||
scaled[i] = vector[i] * factor;
|
||||
}
|
||||
return scaled;
|
||||
}
|
||||
|
||||
public static double[] scale(double[] vector1, double[] vector2) {
|
||||
double[] result = new double[max(vector1.length, vector2.length)];
|
||||
for (int i = 0; i < min(vector1.length, vector2.length); i++) {
|
||||
result[i] = vector1[i] * vector2[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double[] norma(double[] vector) {
|
||||
double length = length(vector);
|
||||
double[] norma = new double[vector.length];
|
||||
for (int i = 0; i < vector.length; i++) {
|
||||
norma[i] = vector[i] / length;
|
||||
}
|
||||
return norma;
|
||||
}
|
||||
|
||||
public static double[] getOutOfCS2D(double[] point, double[] abscissa) {
|
||||
double[] ex = norma(abscissa);
|
||||
double[] ey = ortoXY(ex);
|
||||
|
||||
double[] xpart = scale(ex, point[X]);
|
||||
double[] ypart = scale(ey, point[Y]);
|
||||
|
||||
return plus(xpart, ypart);
|
||||
}
|
||||
|
||||
public static List<double[]> circleIntsc(double[] center1, double[] center2, double r1, double r2) {
|
||||
double[] abscissa = minus(center2, center1);
|
||||
double l = length(abscissa);
|
||||
double x = (l * l - r2 * r2 + r1 * r1) / (2 * l);
|
||||
double D = r1 * r1 - x * x;
|
||||
if (D > 0) {
|
||||
List<double[]> solutions = new ArrayList<>(2);
|
||||
solutions.add(plus(center1, getOutOfCS2D(vector(x, + Math.sqrt(D)), abscissa)));
|
||||
solutions.add(plus(center1, getOutOfCS2D(vector(x, - Math.sqrt(D)), abscissa)));
|
||||
return solutions;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Vector transform(Vector vector, Matrix transform) {
|
||||
return cross(transform, vector);
|
||||
}
|
||||
|
||||
public static Vector cross(Matrix transform, Vector vector) {
|
||||
double x = vector.x;
|
||||
double y = vector.y;
|
||||
double z = vector.z;
|
||||
return new Vector(
|
||||
transform.mxx * x + transform.mxy * y + transform.mxz * z + transform.tx,
|
||||
transform.myx * x + transform.myy * y + transform.myz * z + transform.ty,
|
||||
transform.mzx * x + transform.mzy * y + transform.mzz * z + transform.tz);
|
||||
}
|
||||
|
||||
|
||||
public static Matrix translateMatrix(Vector translation) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.tx = translation.x;
|
||||
matrix.ty = translation.y;
|
||||
matrix.tz = translation.z;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static Matrix rotateMatrix(double angle, Vector axis, Vector pivot) {
|
||||
final double sin = Math.sin(angle);
|
||||
final double cos = Math.cos(angle);
|
||||
double axisX, axisY, axisZ;
|
||||
Matrix m = new Matrix();
|
||||
|
||||
if (axis == X_AXIS || axis == Y_AXIS || axis == Z_AXIS) {
|
||||
axisX = axis.x;
|
||||
axisY = axis.y;
|
||||
axisZ = axis.z;
|
||||
} else {
|
||||
// normalize
|
||||
final double mag = axis.length();
|
||||
|
||||
if (mag == 0.0) {
|
||||
return m;
|
||||
} else {
|
||||
axisX = axis.x / mag;
|
||||
axisY = axis.y / mag;
|
||||
axisZ = axis.z / mag;
|
||||
}
|
||||
}
|
||||
|
||||
double px = pivot.x;
|
||||
double py = pivot.y;
|
||||
double pz = pivot.z;
|
||||
|
||||
m.mxx = cos + axisX * axisX * (1 - cos);
|
||||
m.mxy = axisX * axisY * (1 - cos) - axisZ * sin;
|
||||
m.mxz = axisX * axisZ * (1 - cos) + axisY * sin;
|
||||
|
||||
m.tx = px * (1 - m.mxx) - py * m.mxy - pz * m.mxz;
|
||||
|
||||
m.myx = axisY * axisX * (1 - cos) + axisZ * sin;
|
||||
m.myy = cos + axisY * axisY * (1 - cos);
|
||||
m.myz = axisY * axisZ * (1 - cos) - axisX * sin;
|
||||
m.ty = py * (1 - m.myy) - px * m.myx - pz * m.myz;
|
||||
|
||||
m.mzx = axisZ * axisX * (1 - cos) - axisY * sin;
|
||||
m.mzy = axisZ * axisY * (1 - cos) + axisX * sin;
|
||||
m.mzz = cos + axisZ * axisZ * (1 - cos);
|
||||
m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy;
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix scaleMatrix(Vector scale, Vector pivot) {
|
||||
double sx = scale.x;
|
||||
double sy = scale.y;
|
||||
double sz = scale.z;
|
||||
return new Matrix(
|
||||
sx, 0, 0, (1 - sx) * pivot.x,
|
||||
0, sy, 0, (1 - sy) * pivot.y,
|
||||
0, 0, sz, (1 - sz) * pivot.z);
|
||||
}
|
||||
|
||||
public static Matrix combine(Matrix... matrices) {
|
||||
if (matrices.length == 0) {
|
||||
return new Matrix();
|
||||
}
|
||||
if (matrices.length == 1) {
|
||||
return matrices[0];
|
||||
}
|
||||
Matrix m = matrices[0];
|
||||
|
||||
for (int i = 1; i < matrices.length; i++) {
|
||||
m = m.combine(matrices[i]);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public static double[] vector(double... data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Vector[] translate(Vector[] vectors, Vector delta) {
|
||||
vectors = copy(vectors);
|
||||
for (int i = 0; i < vectors.length; i++) {
|
||||
vectors[i].x += delta.x;
|
||||
vectors[i].y += delta.y;
|
||||
vectors[i].z += delta.z;
|
||||
}
|
||||
return vectors;
|
||||
}
|
||||
|
||||
public static Vector[] copy(Vector[] vectors) {
|
||||
Vector[] copy = new Vector[vectors.length];
|
||||
for (int i = 0; i < vectors.length; i++) {
|
||||
copy[i] = vectors[i].copy();
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static boolean areEqual(double v1, double v2, double tolerance) {
|
||||
return abs(v1 - v2) < tolerance;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
package cad.math;
|
||||
|
||||
/**
|
||||
* Created by verastov on 7/8/14.
|
||||
*/
|
||||
public class Matrix {
|
||||
|
||||
public double
|
||||
mxx, mxy, mxz, tx,
|
||||
myx, myy, myz, ty,
|
||||
mzx, mzy, mzz, tz;
|
||||
|
||||
public Matrix() {
|
||||
mxx = 1; mxy = 0; mxz = 0; tx = 0;
|
||||
myx = 0; myy = 1; myz = 0; ty = 0;
|
||||
mzx = 0; mzy = 0; mzz = 1; tz = 0;
|
||||
}
|
||||
|
||||
public Matrix(Vector[] basis) {
|
||||
Vector[] b = basis;
|
||||
mxx = b[0].x; mxy = b[1].x; mxz = b[2].x; tx = 0;
|
||||
myx = b[0].y; myy = b[1].y; myz = b[2].y; ty = 0;
|
||||
mzx = b[0].z; mzy = b[1].z; mzz = b[2].z; tz = 0;
|
||||
}
|
||||
|
||||
public Matrix(
|
||||
double mxx, double mxy, double mxz,
|
||||
double myx, double myy, double myz,
|
||||
double mzx, double mzy, double mzz
|
||||
) {
|
||||
this.mxx = mxx; this.mxy = mxy; this.mxz = mxz;
|
||||
this.myx = myx; this.myy = myy; this.myz = myz;
|
||||
this.mzx = mzx; this.mzy = mzy; this.mzz = mzz;
|
||||
}
|
||||
|
||||
public Matrix(
|
||||
double mxx, double mxy, double mxz, double tx,
|
||||
double myx, double myy, double myz, double ty,
|
||||
double mzx, double mzy, double mzz, double tz
|
||||
) {
|
||||
this.mxx = mxx; this.mxy = mxy; this.mxz = mxz; this.tx = tx;
|
||||
this.myx = myx; this.myy = myy; this.myz = myz; this.ty = ty;
|
||||
this.mzx = mzx; this.mzy = mzy; this.mzz = mzz; this.tz = tz;
|
||||
}
|
||||
|
||||
public void set(Matrix m) {
|
||||
this.mxx = m.mxx; this.mxy = m.mxy; this.mxz = m.mxz; this.tx = m.tx;
|
||||
this.myx = m.myx; this.myy = m.myy; this.myz = m.myz; this.ty = m.ty;
|
||||
this.mzx = m.mzx; this.mzy = m.mzy; this.mzz = m.mzz; this.tz = m.tz;
|
||||
}
|
||||
|
||||
public Matrix invert() {
|
||||
|
||||
final double det =
|
||||
mxx * (myy * mzz - mzy * myz) +
|
||||
mxy * (myz * mzx - mzz * myx) +
|
||||
mxz * (myx * mzy - mzx * myy);
|
||||
|
||||
if (det == 0.0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final double cxx = myy * mzz - myz * mzy;
|
||||
final double cyx = - myx * mzz + myz * mzx;
|
||||
final double czx = myx * mzy - myy * mzx;
|
||||
final double cxt = - mxy * (myz * tz - mzz * ty)
|
||||
- mxz * (ty * mzy - tz * myy)
|
||||
- tx * (myy * mzz - mzy * myz);
|
||||
final double cxy = - mxy * mzz + mxz * mzy;
|
||||
final double cyy = mxx * mzz - mxz * mzx;
|
||||
final double czy = - mxx * mzy + mxy * mzx;
|
||||
final double cyt = mxx * (myz * tz - mzz * ty)
|
||||
+ mxz * (ty * mzx - tz * myx)
|
||||
+ tx * (myx * mzz - mzx * myz);
|
||||
final double cxz = mxy * myz - mxz * myy;
|
||||
final double cyz = - mxx * myz + mxz * myx;
|
||||
final double czz = mxx * myy - mxy * myx;
|
||||
final double czt = - mxx * (myy * tz - mzy * ty)
|
||||
- mxy * (ty * mzx - tz * myx)
|
||||
- tx * (myx * mzy - mzx * myy);
|
||||
|
||||
Matrix result = new Matrix();
|
||||
result.mxx = cxx / det;
|
||||
result.mxy = cxy / det;
|
||||
result.mxz = cxz / det;
|
||||
result.tx = cxt / det;
|
||||
result.myx = cyx / det;
|
||||
result.myy = cyy / det;
|
||||
result.myz = cyz / det;
|
||||
result.ty = cyt / det;
|
||||
result.mzx = czx / det;
|
||||
result.mzy = czy / det;
|
||||
result.mzz = czz / det;
|
||||
result.tz = czt / det;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Matrix combine(Matrix transform) {
|
||||
final double txx = transform.mxx;
|
||||
final double txy = transform.mxy;
|
||||
final double txz = transform.mxz;
|
||||
final double ttx = transform.tx;
|
||||
final double tyx = transform.myx;
|
||||
final double tyy = transform.myy;
|
||||
final double tyz = transform.myz;
|
||||
final double tty = transform.ty;
|
||||
final double tzx = transform.mzx;
|
||||
final double tzy = transform.mzy;
|
||||
final double tzz = transform.mzz;
|
||||
final double ttz = transform.tz;
|
||||
|
||||
Matrix m = new Matrix();
|
||||
m.mxx = (this.mxx * txx + this.mxy * tyx + this.mxz * tzx);
|
||||
m.mxy = (this.mxx * txy + this.mxy * tyy + this.mxz * tzy);
|
||||
m.mxz = (this.mxx * txz + this.mxy * tyz + this.mxz * tzz);
|
||||
m.tx = (this.mxx * ttx + this.mxy * tty + this.mxz * ttz + this.tx);
|
||||
m.myx = (this.myx * txx + this.myy * tyx + this.myz * tzx);
|
||||
m.myy = (this.myx * txy + this.myy * tyy + this.myz * tzy);
|
||||
m.myz = (this.myx * txz + this.myy * tyz + this.myz * tzz);
|
||||
m.ty = (this.myx * ttx + this.myy * tty + this.myz * ttz + this.ty);
|
||||
m.mzx = (this.mzx * txx + this.mzy * tyx + this.mzz * tzx);
|
||||
m.mzy = (this.mzx * txy + this.mzy * tyy + this.mzz * tzy);
|
||||
m.mzz = (this.mzx * txz + this.mzy * tyz + this.mzz * tzz);
|
||||
m.tz = (this.mzx * ttx + this.mzy * tty + this.mzz * ttz + this.tz);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = "";
|
||||
str += String.format("%.4f, %.4f, %.4f, %.4f\n", mxx, mxy, mxz, tx);
|
||||
str += String.format("%.4f, %.4f, %.4f, %.4f\n", myx, myy, myz, ty);
|
||||
str += String.format("%.4f, %.4f, %.4f, %.4f" , mzx, mzy, mzz, tz);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
package cad.math;
|
||||
|
||||
public class Vector {
|
||||
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
|
||||
public static Vector fromArr3(float[] data) {
|
||||
return new Vector(data[0], data[1], data[2]);
|
||||
}
|
||||
|
||||
public static Vector fromArr3(double[] data) {
|
||||
return new Vector(data[0], data[1], data[2]);
|
||||
}
|
||||
|
||||
public Vector() {
|
||||
}
|
||||
|
||||
public Vector(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector(Vector vector) {
|
||||
this(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
public Vector(double x, double y) {
|
||||
this(x, y, 0);
|
||||
}
|
||||
|
||||
public void set(Vector vector) {
|
||||
set(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
public void set(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public void set3(float[] data) {
|
||||
this.x = data[0];
|
||||
this.y = data[1];
|
||||
this.z = data[2];
|
||||
}
|
||||
|
||||
public void set3(double[] data) {
|
||||
this.x = data[0];
|
||||
this.y = data[1];
|
||||
this.z = data[2];
|
||||
}
|
||||
|
||||
public Vector multi(double factor) {
|
||||
return multi(factor, factor, factor);
|
||||
}
|
||||
|
||||
public Vector multi(double dx, double dy, double dz) {
|
||||
return new Vector(x * dx, y * dy, z * dz);
|
||||
}
|
||||
|
||||
public double dot(Vector vector) {
|
||||
return x * vector.x + y * vector.y + z * vector.z;
|
||||
}
|
||||
|
||||
public Vector copy() {
|
||||
return new Vector(this);
|
||||
}
|
||||
|
||||
public double length() {
|
||||
return Math.sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%.4f, %.4f, %.4f]", x, y, z);
|
||||
}
|
||||
|
||||
public Vector minus(Vector vector) {
|
||||
return new Vector(x - vector.x, y - vector.y, z - vector.z);
|
||||
}
|
||||
|
||||
public Vector plus(Vector vector) {
|
||||
return new Vector(this)._plus(vector);
|
||||
}
|
||||
|
||||
public Vector _plus(Vector vector) {
|
||||
x += vector.x;
|
||||
y += vector.y;
|
||||
z += vector.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector plus(double dx, double dy, double dz) {
|
||||
return new Vector(x + dx, y + dy, z + dz);
|
||||
}
|
||||
|
||||
public Vector normalize() {
|
||||
final double mag = length();
|
||||
if (mag == 0.0) {
|
||||
return new Vector(0.0, 0.0, 0.0);
|
||||
}
|
||||
return new Vector(x / mag, y / mag, z / mag);
|
||||
}
|
||||
|
||||
public Vector cross(Vector a) {
|
||||
return new Vector(
|
||||
this.y * a.z - this.z * a.y,
|
||||
this.z * a.x - this.x * a.z,
|
||||
this.x * a.y - this.y * a.x
|
||||
);
|
||||
}
|
||||
|
||||
public boolean slightlyEqualTo(Vector vector) {
|
||||
return equalTo(vector, HMath.TOLERANCE);
|
||||
}
|
||||
|
||||
public boolean equalTo(Vector vector, double tolerance) {
|
||||
return
|
||||
HMath.areEqual(x, vector.x, tolerance) &&
|
||||
HMath.areEqual(y, vector.y, tolerance) &&
|
||||
HMath.areEqual(z, vector.z, tolerance);
|
||||
}
|
||||
|
||||
public Vector negate() {
|
||||
return multi(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri;
|
||||
|
||||
import org.poly2tri.geometry.polygon.Polygon;
|
||||
import org.poly2tri.geometry.polygon.PolygonSet;
|
||||
import org.poly2tri.triangulation.Triangulatable;
|
||||
import org.poly2tri.triangulation.TriangulationAlgorithm;
|
||||
import org.poly2tri.triangulation.TriangulationContext;
|
||||
import org.poly2tri.triangulation.TriangulationMode;
|
||||
import org.poly2tri.triangulation.TriangulationProcess;
|
||||
import org.poly2tri.triangulation.delaunay.sweep.DTSweep;
|
||||
import org.poly2tri.triangulation.delaunay.sweep.DTSweepContext;
|
||||
import org.poly2tri.triangulation.sets.ConstrainedPointSet;
|
||||
import org.poly2tri.triangulation.sets.PointSet;
|
||||
import org.poly2tri.triangulation.util.PolygonGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Poly2Tri
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger( Poly2Tri.class );
|
||||
|
||||
private static final TriangulationAlgorithm _defaultAlgorithm = TriangulationAlgorithm.DTSweep;
|
||||
|
||||
public static void triangulate( PolygonSet ps )
|
||||
{
|
||||
TriangulationContext<?> tcx = createContext( _defaultAlgorithm );
|
||||
for( Polygon p : ps.getPolygons() )
|
||||
{
|
||||
tcx.prepareTriangulation( p );
|
||||
triangulate( tcx );
|
||||
tcx.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void triangulate( Polygon p )
|
||||
{
|
||||
triangulate( _defaultAlgorithm, p );
|
||||
}
|
||||
|
||||
public static void triangulate( ConstrainedPointSet cps )
|
||||
{
|
||||
triangulate( _defaultAlgorithm, cps );
|
||||
}
|
||||
|
||||
public static void triangulate( PointSet ps )
|
||||
{
|
||||
triangulate( _defaultAlgorithm, ps );
|
||||
}
|
||||
|
||||
public static TriangulationContext<?> createContext( TriangulationAlgorithm algorithm )
|
||||
{
|
||||
switch( algorithm )
|
||||
{
|
||||
case DTSweep:
|
||||
default:
|
||||
return new DTSweepContext();
|
||||
}
|
||||
}
|
||||
|
||||
public static void triangulate( TriangulationAlgorithm algorithm,
|
||||
Triangulatable t )
|
||||
{
|
||||
TriangulationContext<?> tcx;
|
||||
|
||||
// long time = System.nanoTime();
|
||||
tcx = createContext( algorithm );
|
||||
tcx.prepareTriangulation( t );
|
||||
triangulate( tcx );
|
||||
// logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 );
|
||||
}
|
||||
|
||||
public static void triangulate( TriangulationContext<?> tcx )
|
||||
{
|
||||
switch( tcx.algorithm() )
|
||||
{
|
||||
case DTSweep:
|
||||
default:
|
||||
DTSweep.triangulate( (DTSweepContext)tcx );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will do a warmup run to let the JVM optimize the triangulation code
|
||||
*/
|
||||
public static void warmup()
|
||||
{
|
||||
/*
|
||||
* After a method is run 10000 times, the Hotspot compiler will compile
|
||||
* it into native code. Periodically, the Hotspot compiler may recompile
|
||||
* the method. After an unspecified amount of time, then the compilation
|
||||
* system should become quiet.
|
||||
*/
|
||||
Polygon poly = PolygonGenerator.RandomCircleSweep2( 50, 50000 );
|
||||
TriangulationProcess process = new TriangulationProcess();
|
||||
process.triangulate( poly );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,273 +0,0 @@
|
|||
package org.poly2tri.geometry.polygon;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.triangulation.Triangulatable;
|
||||
import org.poly2tri.triangulation.TriangulationContext;
|
||||
import org.poly2tri.triangulation.TriangulationMode;
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Polygon implements Triangulatable
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger( Polygon.class );
|
||||
|
||||
protected ArrayList<TriangulationPoint> _points = new ArrayList<TriangulationPoint>();
|
||||
protected ArrayList<TriangulationPoint> _steinerPoints;
|
||||
protected ArrayList<Polygon> _holes;
|
||||
|
||||
protected List<DelaunayTriangle> m_triangles;
|
||||
|
||||
protected PolygonPoint _last;
|
||||
|
||||
/**
|
||||
* To create a polygon we need atleast 3 separate points
|
||||
*
|
||||
* @param p1
|
||||
* @param p2
|
||||
* @param p3
|
||||
*/
|
||||
public Polygon( PolygonPoint p1, PolygonPoint p2, PolygonPoint p3 )
|
||||
{
|
||||
p1._next = p2;
|
||||
p2._next = p3;
|
||||
p3._next = p1;
|
||||
p1._previous = p3;
|
||||
p2._previous = p1;
|
||||
p3._previous = p2;
|
||||
_points.add( p1 );
|
||||
_points.add( p2 );
|
||||
_points.add( p3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires atleast 3 points
|
||||
* @param points - ordered list of points forming the polygon.
|
||||
* No duplicates are allowed
|
||||
*/
|
||||
public Polygon( List<PolygonPoint> points )
|
||||
{
|
||||
// Lets do one sanity check that first and last point hasn't got same position
|
||||
// Its something that often happen when importing polygon data from other formats
|
||||
if( points.get(0).equals( points.get(points.size()-1) ) )
|
||||
{
|
||||
logger.warn( "Removed duplicate point");
|
||||
points.remove( points.size()-1 );
|
||||
}
|
||||
_points.addAll( points );
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires atleast 3 points
|
||||
*
|
||||
* @param points
|
||||
*/
|
||||
public Polygon( PolygonPoint[] points )
|
||||
{
|
||||
this( Arrays.asList( points ) );
|
||||
}
|
||||
|
||||
public TriangulationMode getTriangulationMode()
|
||||
{
|
||||
return TriangulationMode.POLYGON;
|
||||
}
|
||||
|
||||
public int pointCount()
|
||||
{
|
||||
int count = _points.size();
|
||||
if( _steinerPoints != null )
|
||||
{
|
||||
count += _steinerPoints.size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void addSteinerPoint( TriangulationPoint point )
|
||||
{
|
||||
if( _steinerPoints == null )
|
||||
{
|
||||
_steinerPoints = new ArrayList<TriangulationPoint>();
|
||||
}
|
||||
_steinerPoints.add( point );
|
||||
}
|
||||
|
||||
public void addSteinerPoints( List<TriangulationPoint> points )
|
||||
{
|
||||
if( _steinerPoints == null )
|
||||
{
|
||||
_steinerPoints = new ArrayList<TriangulationPoint>();
|
||||
}
|
||||
_steinerPoints.addAll( points );
|
||||
}
|
||||
|
||||
public void clearSteinerPoints()
|
||||
{
|
||||
if( _steinerPoints != null )
|
||||
{
|
||||
_steinerPoints.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes: that given polygon is fully inside the current polygon
|
||||
* @param poly - a subtraction polygon
|
||||
*/
|
||||
public void addHole( Polygon poly )
|
||||
{
|
||||
if( _holes == null )
|
||||
{
|
||||
_holes = new ArrayList<Polygon>();
|
||||
}
|
||||
_holes.add( poly );
|
||||
// XXX: tests could be made here to be sure it is fully inside
|
||||
// addSubtraction( poly.getPoints() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Will insert a point in the polygon after given point
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
* @param p
|
||||
*/
|
||||
public void insertPointAfter( PolygonPoint a, PolygonPoint newPoint )
|
||||
{
|
||||
// Validate that
|
||||
int index = _points.indexOf( a );
|
||||
if( index != -1 )
|
||||
{
|
||||
newPoint.setNext( a.getNext() );
|
||||
newPoint.setPrevious( a );
|
||||
a.getNext().setPrevious( newPoint );
|
||||
a.setNext( newPoint );
|
||||
_points.add( index+1, newPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException( "Tried to insert a point into a Polygon after a point not belonging to the Polygon" );
|
||||
}
|
||||
}
|
||||
|
||||
public void addPoints( List<PolygonPoint> list )
|
||||
{
|
||||
PolygonPoint first;
|
||||
for( PolygonPoint p : list )
|
||||
{
|
||||
p.setPrevious( _last );
|
||||
if( _last != null )
|
||||
{
|
||||
p.setNext( _last.getNext() );
|
||||
_last.setNext( p );
|
||||
}
|
||||
_last = p;
|
||||
_points.add( p );
|
||||
}
|
||||
first = (PolygonPoint)_points.get(0);
|
||||
_last.setNext( first );
|
||||
first.setPrevious( _last );
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add a point after the last point added
|
||||
*
|
||||
* @param p
|
||||
*/
|
||||
public void addPoint(PolygonPoint p )
|
||||
{
|
||||
p.setPrevious( _last );
|
||||
p.setNext( _last.getNext() );
|
||||
_last.setNext( p );
|
||||
_points.add( p );
|
||||
}
|
||||
|
||||
public void removePoint( PolygonPoint p )
|
||||
{
|
||||
PolygonPoint next, prev;
|
||||
|
||||
next = p.getNext();
|
||||
prev = p.getPrevious();
|
||||
prev.setNext( next );
|
||||
next.setPrevious( prev );
|
||||
_points.remove( p );
|
||||
}
|
||||
|
||||
public PolygonPoint getPoint()
|
||||
{
|
||||
return _last;
|
||||
}
|
||||
|
||||
public List<TriangulationPoint> getPoints()
|
||||
{
|
||||
return _points;
|
||||
}
|
||||
|
||||
public List<DelaunayTriangle> getTriangles()
|
||||
{
|
||||
return m_triangles;
|
||||
}
|
||||
|
||||
public void addTriangle( DelaunayTriangle t )
|
||||
{
|
||||
m_triangles.add( t );
|
||||
}
|
||||
|
||||
public void addTriangles( List<DelaunayTriangle> list )
|
||||
{
|
||||
m_triangles.addAll( list );
|
||||
}
|
||||
|
||||
public void clearTriangulation()
|
||||
{
|
||||
if( m_triangles != null )
|
||||
{
|
||||
m_triangles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates constraints and populates the context with points
|
||||
*/
|
||||
public void prepareTriangulation( TriangulationContext<?> tcx )
|
||||
{
|
||||
if( m_triangles == null )
|
||||
{
|
||||
m_triangles = new ArrayList<DelaunayTriangle>( _points.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_triangles.clear();
|
||||
}
|
||||
|
||||
// Outer constraints
|
||||
for( int i = 0; i < _points.size()-1 ; i++ )
|
||||
{
|
||||
tcx.newConstraint( _points.get( i ), _points.get( i+1 ) );
|
||||
}
|
||||
tcx.newConstraint( _points.get( 0 ), _points.get( _points.size()-1 ) );
|
||||
tcx.addPoints( _points );
|
||||
|
||||
// Hole constraints
|
||||
if( _holes != null )
|
||||
{
|
||||
for( Polygon p : _holes )
|
||||
{
|
||||
for( int i = 0; i < p._points.size()-1 ; i++ )
|
||||
{
|
||||
tcx.newConstraint( p._points.get( i ), p._points.get( i+1 ) );
|
||||
}
|
||||
tcx.newConstraint( p._points.get( 0 ), p._points.get( p._points.size()-1 ) );
|
||||
tcx.addPoints( p._points );
|
||||
}
|
||||
}
|
||||
|
||||
if( _steinerPoints != null )
|
||||
{
|
||||
tcx.addPoints( _steinerPoints );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package org.poly2tri.geometry.polygon;
|
||||
|
||||
import org.poly2tri.triangulation.point.TPoint;
|
||||
|
||||
public class PolygonPoint extends TPoint
|
||||
{
|
||||
protected PolygonPoint _next;
|
||||
protected PolygonPoint _previous;
|
||||
|
||||
public PolygonPoint( double x, double y )
|
||||
{
|
||||
super( x, y );
|
||||
}
|
||||
|
||||
public PolygonPoint( double x, double y, double z )
|
||||
{
|
||||
super( x, y, z );
|
||||
}
|
||||
|
||||
public void setPrevious( PolygonPoint p )
|
||||
{
|
||||
_previous = p;
|
||||
}
|
||||
|
||||
public void setNext( PolygonPoint p )
|
||||
{
|
||||
_next = p;
|
||||
}
|
||||
|
||||
public PolygonPoint getNext()
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
public PolygonPoint getPrevious()
|
||||
{
|
||||
return _previous;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.geometry.polygon;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PolygonSet
|
||||
{
|
||||
protected ArrayList<Polygon> _polygons = new ArrayList<Polygon>();
|
||||
|
||||
public PolygonSet()
|
||||
{
|
||||
}
|
||||
|
||||
public PolygonSet( Polygon poly )
|
||||
{
|
||||
_polygons.add( poly );
|
||||
}
|
||||
|
||||
public void add( Polygon p )
|
||||
{
|
||||
_polygons.add( p );
|
||||
}
|
||||
|
||||
public List<Polygon> getPolygons()
|
||||
{
|
||||
return _polygons;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package org.poly2tri.geometry.polygon;
|
||||
|
||||
public class PolygonUtil
|
||||
{
|
||||
/**
|
||||
* TODO
|
||||
* @param polygon
|
||||
*/
|
||||
public static void validate( Polygon polygon )
|
||||
{
|
||||
// TODO: implement
|
||||
// 1. Check for duplicate points
|
||||
// 2. Check for intersecting sides
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package org.poly2tri.geometry.primitives;
|
||||
|
||||
public abstract class Edge<A extends Point>
|
||||
{
|
||||
protected A p;
|
||||
protected A q;
|
||||
|
||||
public A getP()
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
public A getQ()
|
||||
{
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.poly2tri.geometry.primitives;
|
||||
|
||||
public abstract class Point
|
||||
{
|
||||
public abstract double getX();
|
||||
public abstract double getY();
|
||||
public abstract double getZ();
|
||||
|
||||
public abstract float getXf();
|
||||
public abstract float getYf();
|
||||
public abstract float getZf();
|
||||
|
||||
public abstract void set( double x, double y, double z );
|
||||
|
||||
protected static int calculateHashCode( double x, double y, double z)
|
||||
{
|
||||
int result = 17;
|
||||
|
||||
final long a = Double.doubleToLongBits(x);
|
||||
result += 31 * result + (int) (a ^ (a >>> 32));
|
||||
|
||||
final long b = Double.doubleToLongBits(y);
|
||||
result += 31 * result + (int) (b ^ (b >>> 32));
|
||||
|
||||
final long c = Double.doubleToLongBits(z);
|
||||
result += 31 * result + (int) (c ^ (c >>> 32));
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
package org.poly2tri.transform.coordinate;
|
||||
|
||||
/**
|
||||
* A transform that aligns given source normal with the XY plane normal [0,0,1]
|
||||
*
|
||||
* @author thahlen@gmail.com
|
||||
*/
|
||||
|
||||
public class AnyToXYTransform extends Matrix3Transform
|
||||
{
|
||||
/**
|
||||
* Assumes source normal is normalized
|
||||
*/
|
||||
public AnyToXYTransform( double nx, double ny, double nz )
|
||||
{
|
||||
setSourceNormal( nx, ny, nz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes source normal is normalized
|
||||
*
|
||||
* @param nx
|
||||
* @param ny
|
||||
* @param nz
|
||||
*/
|
||||
public void setSourceNormal( double nx, double ny, double nz )
|
||||
{
|
||||
double h,f,c,vx,vy,hvx;
|
||||
|
||||
vx = -ny;
|
||||
vy = nx;
|
||||
c = nz;
|
||||
|
||||
h = (1-c)/(1-c*c);
|
||||
hvx = h*vx;
|
||||
f = (c < 0) ? -c : c;
|
||||
|
||||
if( f < 1.0 - 1.0E-4 )
|
||||
{
|
||||
m00=c + hvx*vx;
|
||||
m01=hvx*vy;
|
||||
m02=-vy;
|
||||
m10=hvx*vy;
|
||||
m11=c + h*vy*vy;
|
||||
m12=vx;
|
||||
m20=vy;
|
||||
m21=-vx;
|
||||
m22=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if "from" and "to" vectors are nearly parallel
|
||||
m00=1;
|
||||
m01=0;
|
||||
m02=0;
|
||||
m10=0;
|
||||
m11=1;
|
||||
m12=0;
|
||||
m20=0;
|
||||
m21=0;
|
||||
if( c > 0 )
|
||||
{
|
||||
m22=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m22=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.poly2tri.transform.coordinate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.geometry.primitives.Point;
|
||||
|
||||
public abstract interface CoordinateTransform
|
||||
{
|
||||
public abstract void transform(Point p, Point store);
|
||||
public abstract void transform(Point p);
|
||||
public abstract void transform(List<? extends Point> list);
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.poly2tri.transform.coordinate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.geometry.primitives.Point;
|
||||
|
||||
public abstract class Matrix3Transform implements CoordinateTransform
|
||||
{
|
||||
protected double m00,m01,m02,m10,m11,m12,m20,m21,m22;
|
||||
|
||||
public void transform( Point p, Point store )
|
||||
{
|
||||
final double px = p.getX();
|
||||
final double py = p.getY();
|
||||
final double pz = p.getZ();
|
||||
store.set(m00 * px + m01 * py + m02 * pz,
|
||||
m10 * px + m11 * py + m12 * pz,
|
||||
m20 * px + m21 * py + m22 * pz );
|
||||
}
|
||||
|
||||
public void transform( Point p )
|
||||
{
|
||||
final double px = p.getX();
|
||||
final double py = p.getY();
|
||||
final double pz = p.getZ();
|
||||
p.set(m00 * px + m01 * py + m02 * pz,
|
||||
m10 * px + m11 * py + m12 * pz,
|
||||
m20 * px + m21 * py + m22 * pz );
|
||||
}
|
||||
|
||||
public void transform( List<? extends Point> list )
|
||||
{
|
||||
for( Point p : list )
|
||||
{
|
||||
transform( p );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package org.poly2tri.transform.coordinate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.geometry.primitives.Point;
|
||||
|
||||
public class NoTransform implements CoordinateTransform
|
||||
{
|
||||
public void transform( Point p, Point store )
|
||||
{
|
||||
store.set( p.getX(), p.getY(), p.getZ() );
|
||||
}
|
||||
|
||||
public void transform( Point p )
|
||||
{
|
||||
}
|
||||
|
||||
public void transform( List<? extends Point> list )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package org.poly2tri.transform.coordinate;
|
||||
|
||||
/**
|
||||
* A transform that aligns the XY plane normal [0,0,1] with any given target normal
|
||||
*
|
||||
* http://www.cs.brown.edu/~jfh/papers/Moller-EBA-1999/paper.pdf
|
||||
*
|
||||
* @author thahlen@gmail.com
|
||||
*
|
||||
*/
|
||||
public class XYToAnyTransform extends Matrix3Transform
|
||||
{
|
||||
/**
|
||||
* Assumes target normal is normalized
|
||||
*/
|
||||
public XYToAnyTransform( double nx, double ny, double nz )
|
||||
{
|
||||
setTargetNormal( nx, ny, nz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes target normal is normalized
|
||||
*
|
||||
* @param nx
|
||||
* @param ny
|
||||
* @param nz
|
||||
*/
|
||||
public void setTargetNormal( double nx, double ny, double nz )
|
||||
{
|
||||
double h,f,c,vx,vy,hvx;
|
||||
|
||||
vx = ny;
|
||||
vy = -nx;
|
||||
c = nz;
|
||||
|
||||
h = (1-c)/(1-c*c);
|
||||
hvx = h*vx;
|
||||
f = (c < 0) ? -c : c;
|
||||
|
||||
if( f < 1.0 - 1.0E-4 )
|
||||
{
|
||||
m00=c + hvx*vx;
|
||||
m01=hvx*vy;
|
||||
m02=-vy;
|
||||
m10=hvx*vy;
|
||||
m11=c + h*vy*vy;
|
||||
m12=vx;
|
||||
m20=vy;
|
||||
m21=-vx;
|
||||
m22=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if "from" and "to" vectors are nearly parallel
|
||||
m00=1;
|
||||
m01=0;
|
||||
m02=0;
|
||||
m10=0;
|
||||
m11=1;
|
||||
m12=0;
|
||||
m20=0;
|
||||
m21=0;
|
||||
if( c > 0 )
|
||||
{
|
||||
m22=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m22=-1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.poly2tri.triangulation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
public interface Triangulatable
|
||||
{
|
||||
/**
|
||||
* Preparations needed before triangulation start should be handled here
|
||||
* @param tcx
|
||||
*/
|
||||
public void prepareTriangulation(TriangulationContext<?> tcx);
|
||||
|
||||
public List<DelaunayTriangle> getTriangles();
|
||||
public List<TriangulationPoint> getPoints();
|
||||
public void addTriangle(DelaunayTriangle t);
|
||||
public void addTriangles(List<DelaunayTriangle> list);
|
||||
public void clearTriangulation();
|
||||
|
||||
public TriangulationMode getTriangulationMode();
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
public enum TriangulationAlgorithm
|
||||
{
|
||||
DTSweep
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
/**
|
||||
* Forces a triangle edge between two points p and q
|
||||
* when triangulating. For example used to enforce
|
||||
* Polygon Edges during a polygon triangulation.
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*/
|
||||
public class TriangulationConstraint
|
||||
{
|
||||
protected TriangulationPoint p;
|
||||
protected TriangulationPoint q;
|
||||
|
||||
public TriangulationPoint getP()
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
public TriangulationPoint getQ()
|
||||
{
|
||||
return q;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
public abstract class TriangulationContext<A extends TriangulationDebugContext>
|
||||
{
|
||||
protected A _debug;
|
||||
protected boolean _debugEnabled = false;
|
||||
|
||||
protected ArrayList<DelaunayTriangle> _triList = new ArrayList<DelaunayTriangle>();
|
||||
|
||||
protected ArrayList<TriangulationPoint> _points = new ArrayList<TriangulationPoint>(200);
|
||||
protected TriangulationMode _triangulationMode;
|
||||
protected Triangulatable _triUnit;
|
||||
|
||||
private boolean _terminated = false;
|
||||
private boolean _waitUntilNotified;
|
||||
|
||||
private int _stepTime = -1;
|
||||
private int _stepCount = 0;
|
||||
public int getStepCount() { return _stepCount; }
|
||||
|
||||
public void done()
|
||||
{
|
||||
_stepCount++;
|
||||
}
|
||||
|
||||
public abstract TriangulationAlgorithm algorithm();
|
||||
|
||||
public void prepareTriangulation( Triangulatable t )
|
||||
{
|
||||
_triUnit = t;
|
||||
_triangulationMode = t.getTriangulationMode();
|
||||
t.prepareTriangulation( this );
|
||||
}
|
||||
|
||||
public abstract TriangulationConstraint newConstraint( TriangulationPoint a, TriangulationPoint b );
|
||||
|
||||
public void addToList( DelaunayTriangle triangle )
|
||||
{
|
||||
_triList.add( triangle );
|
||||
}
|
||||
|
||||
public List<DelaunayTriangle> getTriangles()
|
||||
{
|
||||
return _triList;
|
||||
}
|
||||
|
||||
public Triangulatable getTriangulatable()
|
||||
{
|
||||
return _triUnit;
|
||||
}
|
||||
|
||||
public List<TriangulationPoint> getPoints()
|
||||
{
|
||||
return _points;
|
||||
}
|
||||
|
||||
public synchronized void update(String message)
|
||||
{
|
||||
if( _debugEnabled )
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
_stepCount++;
|
||||
if( _stepTime > 0 )
|
||||
{
|
||||
wait( (int)_stepTime );
|
||||
/** Can we resume execution or are we expected to wait? */
|
||||
if( _waitUntilNotified )
|
||||
{
|
||||
wait();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wait();
|
||||
}
|
||||
// We have been notified
|
||||
_waitUntilNotified = false;
|
||||
}
|
||||
}
|
||||
catch( InterruptedException e )
|
||||
{
|
||||
update("Triangulation was interrupted");
|
||||
}
|
||||
}
|
||||
if( _terminated )
|
||||
{
|
||||
throw new RuntimeException( "Triangulation process terminated before completion");
|
||||
}
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
_points.clear();
|
||||
_terminated = false;
|
||||
if( _debug != null )
|
||||
{
|
||||
_debug.clear();
|
||||
}
|
||||
_stepCount=0;
|
||||
}
|
||||
|
||||
public TriangulationMode getTriangulationMode()
|
||||
{
|
||||
return _triangulationMode;
|
||||
}
|
||||
|
||||
public synchronized void waitUntilNotified(boolean b)
|
||||
{
|
||||
_waitUntilNotified = b;
|
||||
}
|
||||
|
||||
public void terminateTriangulation()
|
||||
{
|
||||
_terminated=true;
|
||||
}
|
||||
|
||||
public boolean isDebugEnabled()
|
||||
{
|
||||
return _debugEnabled;
|
||||
}
|
||||
|
||||
public abstract void isDebugEnabled( boolean b );
|
||||
|
||||
public A getDebugContext()
|
||||
{
|
||||
return _debug;
|
||||
}
|
||||
|
||||
public void addPoints( List<TriangulationPoint> points )
|
||||
{
|
||||
_points.addAll( points );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package org.poly2tri.triangulation;
|
||||
|
||||
public abstract class TriangulationDebugContext
|
||||
{
|
||||
protected TriangulationContext<?> _tcx;
|
||||
|
||||
public TriangulationDebugContext( TriangulationContext<?> tcx )
|
||||
{
|
||||
_tcx = tcx;
|
||||
}
|
||||
|
||||
public abstract void clear();
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
package org.poly2tri.triangulation;
|
||||
|
||||
public enum TriangulationMode
|
||||
{
|
||||
UNCONSTRAINED,CONSTRAINED,POLYGON;
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.poly2tri.geometry.primitives.Point;
|
||||
import org.poly2tri.triangulation.delaunay.sweep.DTSweepConstraint;
|
||||
|
||||
|
||||
public abstract class TriangulationPoint extends Point
|
||||
{
|
||||
// List of edges this point constitutes an upper ending point (CDT)
|
||||
private ArrayList<DTSweepConstraint> edges;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "[" + getX() + "," + getY() + "]";
|
||||
}
|
||||
|
||||
public abstract double getX();
|
||||
public abstract double getY();
|
||||
public abstract double getZ();
|
||||
|
||||
public abstract float getXf();
|
||||
public abstract float getYf();
|
||||
public abstract float getZf();
|
||||
|
||||
public abstract void set( double x, double y, double z );
|
||||
|
||||
public ArrayList<DTSweepConstraint> getEdges()
|
||||
{
|
||||
return edges;
|
||||
}
|
||||
|
||||
public void addEdge( DTSweepConstraint e )
|
||||
{
|
||||
if( edges == null )
|
||||
{
|
||||
edges = new ArrayList<DTSweepConstraint>();
|
||||
}
|
||||
edges.add( e );
|
||||
}
|
||||
|
||||
public boolean hasEdges()
|
||||
{
|
||||
return edges != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p - edge destination point
|
||||
* @return the edge from this point to given point
|
||||
*/
|
||||
public DTSweepConstraint getEdge( TriangulationPoint p )
|
||||
{
|
||||
for( DTSweepConstraint c : edges )
|
||||
{
|
||||
if( c.p == p )
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if( obj instanceof TriangulationPoint )
|
||||
{
|
||||
TriangulationPoint p = (TriangulationPoint)obj;
|
||||
return getX() == p.getX() && getY() == p.getY();
|
||||
}
|
||||
return super.equals( obj );
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
long bits = Double.doubleToLongBits(getX());
|
||||
bits ^= Double.doubleToLongBits(getY()) * 31;
|
||||
return (((int) bits) ^ ((int) (bits >> 32)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,347 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
import java.lang.Thread.State;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.poly2tri.Poly2Tri;
|
||||
import org.poly2tri.geometry.polygon.Polygon;
|
||||
import org.poly2tri.geometry.polygon.PolygonSet;
|
||||
import org.poly2tri.triangulation.sets.ConstrainedPointSet;
|
||||
import org.poly2tri.triangulation.sets.PointSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*
|
||||
*/
|
||||
public class TriangulationProcess implements Runnable
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger( TriangulationProcess.class );
|
||||
|
||||
private final TriangulationAlgorithm _algorithm;
|
||||
|
||||
private TriangulationContext<?> _tcx;
|
||||
private Thread _thread;
|
||||
private boolean _isTerminated = false;
|
||||
private int _pointCount = 0;
|
||||
private long _timestamp = 0;
|
||||
private double _triangulationTime = 0;
|
||||
|
||||
private boolean _awaitingTermination;
|
||||
private boolean _restart = false;
|
||||
|
||||
private ArrayList<Triangulatable> _triangulations = new ArrayList<Triangulatable>();
|
||||
|
||||
private ArrayList<TriangulationProcessListener> _listeners = new ArrayList<TriangulationProcessListener>();
|
||||
|
||||
public void addListener( TriangulationProcessListener listener )
|
||||
{
|
||||
_listeners.add( listener );
|
||||
}
|
||||
|
||||
public void removeListener( TriangulationProcessListener listener )
|
||||
{
|
||||
_listeners.remove( listener );
|
||||
}
|
||||
|
||||
public void clearListeners()
|
||||
{
|
||||
_listeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all listeners of this new event
|
||||
* @param event
|
||||
*/
|
||||
private void sendEvent( TriangulationProcessEvent event )
|
||||
{
|
||||
for( TriangulationProcessListener l : _listeners )
|
||||
{
|
||||
l.triangulationEvent( event, _tcx.getTriangulatable() );
|
||||
}
|
||||
}
|
||||
|
||||
public int getStepCount()
|
||||
{
|
||||
return _tcx.getStepCount();
|
||||
}
|
||||
|
||||
public long getTimestamp()
|
||||
{
|
||||
return _timestamp;
|
||||
}
|
||||
|
||||
public double getTriangulationTime()
|
||||
{
|
||||
return _triangulationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses SweepLine algorithm by default
|
||||
* @param algorithm
|
||||
*/
|
||||
public TriangulationProcess()
|
||||
{
|
||||
this( TriangulationAlgorithm.DTSweep );
|
||||
}
|
||||
|
||||
public TriangulationProcess( TriangulationAlgorithm algorithm )
|
||||
{
|
||||
_algorithm = algorithm;
|
||||
_tcx = Poly2Tri.createContext( algorithm );
|
||||
}
|
||||
|
||||
/**
|
||||
* This retriangulates same set as previous triangulation
|
||||
* useful if you want to do consecutive triangulations with
|
||||
* same data. Like when you when you want to do performance
|
||||
* tests.
|
||||
*/
|
||||
// public void triangulate()
|
||||
// {
|
||||
// start();
|
||||
// }
|
||||
|
||||
/**
|
||||
* Triangulate a PointSet with eventual constraints
|
||||
*
|
||||
* @param cps
|
||||
*/
|
||||
public void triangulate( PointSet ps )
|
||||
{
|
||||
_triangulations.clear();
|
||||
_triangulations.add( ps );
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triangulate a PointSet with eventual constraints
|
||||
*
|
||||
* @param cps
|
||||
*/
|
||||
public void triangulate( ConstrainedPointSet cps )
|
||||
{
|
||||
_triangulations.clear();
|
||||
_triangulations.add( cps );
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triangulate a PolygonSet
|
||||
*
|
||||
* @param ps
|
||||
*/
|
||||
public void triangulate( PolygonSet ps )
|
||||
{
|
||||
_triangulations.clear();
|
||||
_triangulations.addAll( ps.getPolygons() );
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triangulate a Polygon
|
||||
*
|
||||
* @param ps
|
||||
*/
|
||||
public void triangulate( Polygon polygon )
|
||||
{
|
||||
_triangulations.clear();
|
||||
_triangulations.add( polygon );
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triangulate a List of Triangulatables
|
||||
*
|
||||
* @param ps
|
||||
*/
|
||||
public void triangulate( List<Triangulatable> list )
|
||||
{
|
||||
_triangulations.clear();
|
||||
_triangulations.addAll( list );
|
||||
start();
|
||||
}
|
||||
|
||||
private void start()
|
||||
{
|
||||
if( _thread == null || _thread.getState() == State.TERMINATED )
|
||||
{
|
||||
_isTerminated = false;
|
||||
_thread = new Thread( this, _algorithm.name() + "." + _tcx.getTriangulationMode() );
|
||||
_thread.start();
|
||||
sendEvent( TriangulationProcessEvent.Started );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Triangulation already running. Terminate it so we can start a new
|
||||
shutdown();
|
||||
_restart = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWaiting()
|
||||
{
|
||||
if( _thread != null && _thread.getState() == State.WAITING )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
_pointCount=0;
|
||||
try
|
||||
{
|
||||
long time = System.nanoTime();
|
||||
for( Triangulatable t : _triangulations )
|
||||
{
|
||||
_tcx.clear();
|
||||
_tcx.prepareTriangulation( t );
|
||||
_pointCount += _tcx._points.size();
|
||||
Poly2Tri.triangulate( _tcx );
|
||||
}
|
||||
_triangulationTime = ( System.nanoTime() - time ) / 1e6;
|
||||
logger.info( "Triangulation of {} points [{}ms]", _pointCount, _triangulationTime );
|
||||
sendEvent( TriangulationProcessEvent.Done );
|
||||
}
|
||||
catch( RuntimeException e )
|
||||
{
|
||||
if( _awaitingTermination )
|
||||
{
|
||||
_awaitingTermination = false;
|
||||
logger.info( "Thread[{}] : {}", _thread.getName(), e.getMessage() );
|
||||
sendEvent( TriangulationProcessEvent.Aborted );
|
||||
}
|
||||
else
|
||||
{
|
||||
e.printStackTrace();
|
||||
sendEvent( TriangulationProcessEvent.Failed );
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
logger.info( "Triangulation exception {}", e.getMessage() );
|
||||
sendEvent( TriangulationProcessEvent.Failed );
|
||||
}
|
||||
finally
|
||||
{
|
||||
_timestamp = System.currentTimeMillis();
|
||||
_isTerminated = true;
|
||||
_thread = null;
|
||||
}
|
||||
|
||||
// Autostart a new triangulation?
|
||||
if( _restart )
|
||||
{
|
||||
_restart = false;
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
public void resume()
|
||||
{
|
||||
if( _thread != null )
|
||||
{
|
||||
// Only force a resume when process is waiting for a notification
|
||||
if( _thread.getState() == State.WAITING )
|
||||
{
|
||||
synchronized( _tcx )
|
||||
{
|
||||
_tcx.notify();
|
||||
}
|
||||
}
|
||||
else if( _thread.getState() == State.TIMED_WAITING )
|
||||
{
|
||||
_tcx.waitUntilNotified( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
_awaitingTermination = true;
|
||||
_tcx.terminateTriangulation();
|
||||
resume();
|
||||
}
|
||||
|
||||
public TriangulationContext<?> getContext()
|
||||
{
|
||||
return _tcx;
|
||||
}
|
||||
|
||||
public boolean isDone()
|
||||
{
|
||||
return _isTerminated;
|
||||
}
|
||||
|
||||
public void requestRead()
|
||||
{
|
||||
_tcx.waitUntilNotified( true );
|
||||
}
|
||||
|
||||
public boolean isReadable()
|
||||
{
|
||||
if( _thread == null )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
synchronized( _thread )
|
||||
{
|
||||
if( _thread.getState() == State.WAITING )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if( _thread.getState() == State.TIMED_WAITING )
|
||||
{
|
||||
// Make sure that it stays readable
|
||||
_tcx.waitUntilNotified( true );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getPointCount()
|
||||
{
|
||||
return _pointCount;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
public enum TriangulationProcessEvent
|
||||
{
|
||||
Started,Waiting,Failed,Aborted,Done
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation;
|
||||
|
||||
public interface TriangulationProcessListener
|
||||
{
|
||||
public void triangulationEvent(TriangulationProcessEvent e, Triangulatable unit);
|
||||
}
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/package org.poly2tri.triangulation;
|
||||
|
||||
|
||||
/**
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*/
|
||||
public class TriangulationUtil
|
||||
{
|
||||
public final static double EPSILON = 1e-12;
|
||||
|
||||
// Returns triangle circumcircle point and radius
|
||||
// public static Tuple2<TPoint, Double> circumCircle( TPoint a, TPoint b, TPoint c )
|
||||
// {
|
||||
// double A = det( a, b, c );
|
||||
// double C = detC( a, b, c );
|
||||
//
|
||||
// double sa = a.getX() * a.getX() + a.getY() * a.getY();
|
||||
// double sb = b.getX() * b.getX() + b.getY() * b.getY();
|
||||
// double sc = c.getX() * c.getX() + c.getY() * c.getY();
|
||||
//
|
||||
// TPoint bx1 = new TPoint( sa, a.getY() );
|
||||
// TPoint bx2 = new TPoint( sb, b.getY() );
|
||||
// TPoint bx3 = new TPoint( sc, c.getY() );
|
||||
// double bx = det( bx1, bx2, bx3 );
|
||||
//
|
||||
// TPoint by1 = new TPoint( sa, a.getX() );
|
||||
// TPoint by2 = new TPoint( sb, b.getX() );
|
||||
// TPoint by3 = new TPoint( sc, c.getX() );
|
||||
// double by = det( by1, by2, by3 );
|
||||
//
|
||||
// double x = bx / ( 2 * A );
|
||||
// double y = by / ( 2 * A );
|
||||
//
|
||||
// TPoint center = new TPoint( x, y );
|
||||
// double radius = Math.sqrt( bx * bx + by * by - 4 * A * C ) / ( 2 * Math.abs( A ) );
|
||||
//
|
||||
// return new Tuple2<TPoint, Double>( center, radius );
|
||||
// }
|
||||
|
||||
/**
|
||||
* <b>Requirement</b>:<br>
|
||||
* 1. a,b and c form a triangle.<br>
|
||||
* 2. a and d is know to be on opposite side of bc<br>
|
||||
* <pre>
|
||||
* a
|
||||
* +
|
||||
* / \
|
||||
* / \
|
||||
* b/ \c
|
||||
* +-------+
|
||||
* / B \
|
||||
* / \
|
||||
* </pre>
|
||||
* <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by
|
||||
* a,b and c<br>
|
||||
* d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW<br>
|
||||
* This preknowledge gives us a way to optimize the incircle test
|
||||
* @param a - triangle point, opposite d
|
||||
* @param b - triangle point
|
||||
* @param c - triangle point
|
||||
* @param d - point opposite a
|
||||
* @return true if d is inside circle, false if on circle edge
|
||||
*/
|
||||
public static boolean smartIncircle( final TriangulationPoint pa,
|
||||
final TriangulationPoint pb,
|
||||
final TriangulationPoint pc,
|
||||
final TriangulationPoint pd )
|
||||
{
|
||||
final double pdx = pd.getX();
|
||||
final double pdy = pd.getY();
|
||||
final double adx = pa.getX() - pdx;
|
||||
final double ady = pa.getY() - pdy;
|
||||
final double bdx = pb.getX() - pdx;
|
||||
final double bdy = pb.getY() - pdy;
|
||||
|
||||
final double adxbdy = adx * bdy;
|
||||
final double bdxady = bdx * ady;
|
||||
final double oabd = adxbdy - bdxady;
|
||||
// oabd = orient2d(pa,pb,pd);
|
||||
if( oabd <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final double cdx = pc.getX() - pdx;
|
||||
final double cdy = pc.getY() - pdy;
|
||||
|
||||
final double cdxady = cdx * ady;
|
||||
final double adxcdy = adx * cdy;
|
||||
final double ocad = cdxady - adxcdy;
|
||||
// ocad = orient2d(pc,pa,pd);
|
||||
if( ocad <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final double bdxcdy = bdx * cdy;
|
||||
final double cdxbdy = cdx * bdy;
|
||||
|
||||
final double alift = adx * adx + ady * ady;
|
||||
final double blift = bdx * bdx + bdy * bdy;
|
||||
final double clift = cdx * cdx + cdy * cdy;
|
||||
|
||||
final double det = alift * ( bdxcdy - cdxbdy ) + blift * ocad + clift * oabd;
|
||||
|
||||
return det > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see smartIncircle
|
||||
* @param pa
|
||||
* @param pb
|
||||
* @param pc
|
||||
* @param pd
|
||||
* @return
|
||||
*/
|
||||
public static boolean inScanArea( final TriangulationPoint pa,
|
||||
final TriangulationPoint pb,
|
||||
final TriangulationPoint pc,
|
||||
final TriangulationPoint pd )
|
||||
{
|
||||
final double pdx = pd.getX();
|
||||
final double pdy = pd.getY();
|
||||
final double adx = pa.getX() - pdx;
|
||||
final double ady = pa.getY() - pdy;
|
||||
final double bdx = pb.getX() - pdx;
|
||||
final double bdy = pb.getY() - pdy;
|
||||
|
||||
final double adxbdy = adx * bdy;
|
||||
final double bdxady = bdx * ady;
|
||||
final double oabd = adxbdy - bdxady;
|
||||
// oabd = orient2d(pa,pb,pd);
|
||||
if( oabd <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final double cdx = pc.getX() - pdx;
|
||||
final double cdy = pc.getY() - pdy;
|
||||
|
||||
final double cdxady = cdx * ady;
|
||||
final double adxcdy = adx * cdy;
|
||||
final double ocad = cdxady - adxcdy;
|
||||
// ocad = orient2d(pc,pa,pd);
|
||||
if( ocad <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forumla to calculate signed area<br>
|
||||
* Positive if CCW<br>
|
||||
* Negative if CW<br>
|
||||
* 0 if collinear<br>
|
||||
* <pre>
|
||||
* A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
|
||||
* = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
|
||||
* </pre>
|
||||
*/
|
||||
public static Orientation orient2d( TriangulationPoint pa,
|
||||
TriangulationPoint pb,
|
||||
TriangulationPoint pc )
|
||||
{
|
||||
double detleft = ( pa.getX() - pc.getX() ) * ( pb.getY() - pc.getY() );
|
||||
double detright = ( pa.getY() - pc.getY() ) * ( pb.getX() - pc.getX() );
|
||||
double val = detleft - detright;
|
||||
if( val > -EPSILON && val < EPSILON )
|
||||
{
|
||||
return Orientation.Collinear;
|
||||
}
|
||||
else if( val > 0 )
|
||||
{
|
||||
return Orientation.CCW;
|
||||
}
|
||||
return Orientation.CW;
|
||||
}
|
||||
|
||||
public enum Orientation
|
||||
{
|
||||
CW,CCW,Collinear;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,693 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation.delaunay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.sweep.DTSweepConstraint;
|
||||
import org.poly2tri.triangulation.point.TPoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class DelaunayTriangle
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger( DelaunayTriangle.class );
|
||||
|
||||
/** Neighbor pointers */
|
||||
public final DelaunayTriangle[] neighbors = new DelaunayTriangle[3];
|
||||
/** Flags to determine if an edge is a Constrained edge */
|
||||
public final boolean[] cEdge = new boolean[] { false, false, false };
|
||||
/** Flags to determine if an edge is a Delauney edge */
|
||||
public final boolean[] dEdge = new boolean[] { false, false, false };
|
||||
/** Has this triangle been marked as an interior triangle? */
|
||||
protected boolean interior = false;
|
||||
|
||||
public final TriangulationPoint[] points = new TriangulationPoint[3];
|
||||
|
||||
public DelaunayTriangle( TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3 )
|
||||
{
|
||||
points[0] = p1;
|
||||
points[1] = p2;
|
||||
points[2] = p3;
|
||||
}
|
||||
|
||||
public int index( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if( p == points[2] )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
throw new RuntimeException("Calling index with a point that doesn't exist in triangle");
|
||||
}
|
||||
|
||||
public int indexCW( TriangulationPoint p )
|
||||
{
|
||||
int index = index(p);
|
||||
switch( index )
|
||||
{
|
||||
case 0: return 2;
|
||||
case 1: return 0;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int indexCCW( TriangulationPoint p )
|
||||
{
|
||||
int index = index(p);
|
||||
switch( index )
|
||||
{
|
||||
case 0: return 1;
|
||||
case 1: return 2;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains( TriangulationPoint p )
|
||||
{
|
||||
return ( p == points[0] || p == points[1] || p == points[2] );
|
||||
}
|
||||
|
||||
public boolean contains( DTSweepConstraint e )
|
||||
{
|
||||
return ( contains( e.p ) && contains( e.q ) );
|
||||
}
|
||||
|
||||
public boolean contains( TriangulationPoint p, TriangulationPoint q )
|
||||
{
|
||||
return ( contains( p ) && contains( q ) );
|
||||
}
|
||||
|
||||
// Update neighbor pointers
|
||||
private void markNeighbor( TriangulationPoint p1,
|
||||
TriangulationPoint p2,
|
||||
DelaunayTriangle t )
|
||||
{
|
||||
if( ( p1 == points[2] && p2 == points[1] ) || ( p1 == points[1] && p2 == points[2] ) )
|
||||
{
|
||||
neighbors[0] = t;
|
||||
}
|
||||
else if( ( p1 == points[0] && p2 == points[2] ) || ( p1 == points[2] && p2 == points[0] ) )
|
||||
{
|
||||
neighbors[1] = t;
|
||||
}
|
||||
else if( ( p1 == points[0] && p2 == points[1] ) || ( p1 == points[1] && p2 == points[0] ) )
|
||||
{
|
||||
neighbors[2] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error( "Neighbor error, please report!" );
|
||||
// throw new Exception("Neighbor error, please report!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Exhaustive search to update neighbor pointers */
|
||||
public void markNeighbor( DelaunayTriangle t )
|
||||
{
|
||||
if( t.contains( points[1], points[2] ) )
|
||||
{
|
||||
neighbors[0] = t;
|
||||
t.markNeighbor( points[1], points[2], this );
|
||||
}
|
||||
else if( t.contains( points[0], points[2] ) )
|
||||
{
|
||||
neighbors[1] = t;
|
||||
t.markNeighbor( points[0], points[2], this );
|
||||
}
|
||||
else if( t.contains( points[0], points[1] ) )
|
||||
{
|
||||
neighbors[2] = t;
|
||||
t.markNeighbor( points[0], points[1], this );
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error( "markNeighbor failed" );
|
||||
}
|
||||
}
|
||||
|
||||
public void clearNeighbors()
|
||||
{
|
||||
neighbors[0] = neighbors[1] = neighbors[2] = null;
|
||||
}
|
||||
|
||||
public void clearNeighbor( DelaunayTriangle triangle )
|
||||
{
|
||||
if( neighbors[0] == triangle )
|
||||
{
|
||||
neighbors[0] = null;
|
||||
}
|
||||
else if( neighbors[1] == triangle )
|
||||
{
|
||||
neighbors[1] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
neighbors[2] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all references to all other triangles and points
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
DelaunayTriangle t;
|
||||
for( int i=0; i<3; i++ )
|
||||
{
|
||||
t = neighbors[i];
|
||||
if( t != null )
|
||||
{
|
||||
t.clearNeighbor( this );
|
||||
}
|
||||
}
|
||||
clearNeighbors();
|
||||
points[0]=points[1]=points[2]=null;
|
||||
}
|
||||
/**
|
||||
* @param t - opposite triangle
|
||||
* @param p - the point in t that isn't shared between the triangles
|
||||
* @return
|
||||
*/
|
||||
public TriangulationPoint oppositePoint( DelaunayTriangle t, TriangulationPoint p )
|
||||
{
|
||||
assert t != this : "self-pointer error";
|
||||
return pointCW( t.pointCW(p) );
|
||||
}
|
||||
|
||||
// The neighbor clockwise to given point
|
||||
public DelaunayTriangle neighborCW( TriangulationPoint point )
|
||||
{
|
||||
if( point == points[0] )
|
||||
{
|
||||
return neighbors[1];
|
||||
}
|
||||
else if( point == points[1] )
|
||||
{
|
||||
return neighbors[2];
|
||||
}
|
||||
return neighbors[0];
|
||||
}
|
||||
|
||||
// The neighbor counter-clockwise to given point
|
||||
public DelaunayTriangle neighborCCW( TriangulationPoint point )
|
||||
{
|
||||
if( point == points[0] )
|
||||
{
|
||||
return neighbors[2];
|
||||
}
|
||||
else if( point == points[1] )
|
||||
{
|
||||
return neighbors[0];
|
||||
}
|
||||
return neighbors[1];
|
||||
}
|
||||
|
||||
// The neighbor across to given point
|
||||
public DelaunayTriangle neighborAcross( TriangulationPoint opoint )
|
||||
{
|
||||
if( opoint == points[0] )
|
||||
{
|
||||
return neighbors[0];
|
||||
}
|
||||
else if( opoint == points[1] )
|
||||
{
|
||||
return neighbors[1];
|
||||
}
|
||||
return neighbors[2];
|
||||
}
|
||||
|
||||
// The point counter-clockwise to given point
|
||||
public TriangulationPoint pointCCW( TriangulationPoint point )
|
||||
{
|
||||
if( point == points[0] )
|
||||
{
|
||||
return points[1];
|
||||
}
|
||||
else if( point == points[1] )
|
||||
{
|
||||
return points[2];
|
||||
}
|
||||
else if( point == points[2] )
|
||||
{
|
||||
return points[0];
|
||||
}
|
||||
logger.error( "point location error" );
|
||||
throw new RuntimeException("[FIXME] point location error");
|
||||
}
|
||||
|
||||
// The point counter-clockwise to given point
|
||||
public TriangulationPoint pointCW( TriangulationPoint point )
|
||||
{
|
||||
if( point == points[0] )
|
||||
{
|
||||
return points[2];
|
||||
}
|
||||
else if( point == points[1] )
|
||||
{
|
||||
return points[0];
|
||||
}
|
||||
else if( point == points[2] )
|
||||
{
|
||||
return points[1];
|
||||
}
|
||||
logger.error( "point location error" );
|
||||
throw new RuntimeException("[FIXME] point location error");
|
||||
}
|
||||
|
||||
// Legalize triangle by rotating clockwise around oPoint
|
||||
public void legalize( TriangulationPoint oPoint, TriangulationPoint nPoint )
|
||||
{
|
||||
if( oPoint == points[0] )
|
||||
{
|
||||
points[1] = points[0];
|
||||
points[0] = points[2];
|
||||
points[2] = nPoint;
|
||||
}
|
||||
else if( oPoint == points[1] )
|
||||
{
|
||||
points[2] = points[1];
|
||||
points[1] = points[0];
|
||||
points[0] = nPoint;
|
||||
}
|
||||
else if( oPoint == points[2] )
|
||||
{
|
||||
points[0] = points[2];
|
||||
points[2] = points[1];
|
||||
points[1] = nPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error( "legalization error" );
|
||||
throw new RuntimeException("legalization bug");
|
||||
}
|
||||
}
|
||||
|
||||
public void printDebug()
|
||||
{
|
||||
System.out.println( points[0] + "," + points[1] + "," + points[2] );
|
||||
}
|
||||
|
||||
// Finalize edge marking
|
||||
public void markNeighborEdges()
|
||||
{
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if( cEdge[i] )
|
||||
{
|
||||
switch( i )
|
||||
{
|
||||
case 0:
|
||||
if( neighbors[0] != null )
|
||||
neighbors[0].markConstrainedEdge( points[1], points[2] );
|
||||
break;
|
||||
case 1:
|
||||
if( neighbors[1] != null )
|
||||
neighbors[1].markConstrainedEdge( points[0], points[2] );
|
||||
break;
|
||||
case 2:
|
||||
if( neighbors[2] != null )
|
||||
neighbors[2].markConstrainedEdge( points[0], points[1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void markEdge( DelaunayTriangle triangle )
|
||||
{
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if( cEdge[i] )
|
||||
{
|
||||
switch( i )
|
||||
{
|
||||
case 0:
|
||||
triangle.markConstrainedEdge( points[1], points[2] );
|
||||
break;
|
||||
case 1:
|
||||
triangle.markConstrainedEdge( points[0], points[2] );
|
||||
break;
|
||||
case 2:
|
||||
triangle.markConstrainedEdge( points[0], points[1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void markEdge( ArrayList<DelaunayTriangle> tList )
|
||||
{
|
||||
|
||||
for( DelaunayTriangle t : tList )
|
||||
{
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if( t.cEdge[i] )
|
||||
{
|
||||
switch( i )
|
||||
{
|
||||
case 0:
|
||||
markConstrainedEdge( t.points[1], t.points[2] );
|
||||
break;
|
||||
case 1:
|
||||
markConstrainedEdge( t.points[0], t.points[2] );
|
||||
break;
|
||||
case 2:
|
||||
markConstrainedEdge( t.points[0], t.points[1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void markConstrainedEdge( int index )
|
||||
{
|
||||
cEdge[index] = true;
|
||||
}
|
||||
|
||||
public void markConstrainedEdge( DTSweepConstraint edge )
|
||||
{
|
||||
markConstrainedEdge( edge.p, edge.q );
|
||||
if( ( edge.q == points[0] && edge.p == points[1] )
|
||||
|| ( edge.q == points[1] && edge.p == points[0] ) )
|
||||
{
|
||||
cEdge[2] = true;
|
||||
}
|
||||
else if( ( edge.q == points[0] && edge.p == points[2] )
|
||||
|| ( edge.q == points[2] && edge.p == points[0] ) )
|
||||
{
|
||||
cEdge[1] = true;
|
||||
}
|
||||
else if( ( edge.q == points[1] && edge.p == points[2] )
|
||||
|| ( edge.q == points[2] && edge.p == points[1] ) )
|
||||
{
|
||||
cEdge[0] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark edge as constrained
|
||||
public void markConstrainedEdge( TriangulationPoint p, TriangulationPoint q )
|
||||
{
|
||||
if( ( q == points[0] && p == points[1] ) || ( q == points[1] && p == points[0] ) )
|
||||
{
|
||||
cEdge[2] = true;
|
||||
}
|
||||
else if( ( q == points[0] && p == points[2] ) || ( q == points[2] && p == points[0] ) )
|
||||
{
|
||||
cEdge[1] = true;
|
||||
}
|
||||
else if( ( q == points[1] && p == points[2] ) || ( q == points[2] && p == points[1] ) )
|
||||
{
|
||||
cEdge[0] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public double area()
|
||||
{
|
||||
double a = (points[0].getX() - points[2].getX())*(points[1].getY() - points[0].getY());
|
||||
double b = (points[0].getX() - points[1].getX())*(points[2].getY() - points[0].getY());
|
||||
|
||||
return 0.5*Math.abs( a - b );
|
||||
}
|
||||
|
||||
public TPoint centroid()
|
||||
{
|
||||
double cx = ( points[0].getX() + points[1].getX() + points[2].getX() ) / 3d;
|
||||
double cy = ( points[0].getY() + points[1].getY() + points[2].getY() ) / 3d;
|
||||
return new TPoint( cx, cy );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the neighbor that share this edge
|
||||
*
|
||||
* @param constrainedEdge
|
||||
* @return index of the shared edge or -1 if edge isn't shared
|
||||
*/
|
||||
public int edgeIndex( TriangulationPoint p1, TriangulationPoint p2 )
|
||||
{
|
||||
if( points[0] == p1 )
|
||||
{
|
||||
if( points[1] == p2 )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if( points[2] == p2 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if( points[1] == p1 )
|
||||
{
|
||||
if( points[2] == p2 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if( points[0] == p2 )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if( points[2] == p1 )
|
||||
{
|
||||
if( points[0] == p2 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if( points[1] == p2 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean getConstrainedEdgeCCW( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return cEdge[2];
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return cEdge[0];
|
||||
}
|
||||
return cEdge[1];
|
||||
}
|
||||
|
||||
public boolean getConstrainedEdgeCW( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return cEdge[1];
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return cEdge[2];
|
||||
}
|
||||
return cEdge[0];
|
||||
}
|
||||
|
||||
public boolean getConstrainedEdgeAcross( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return cEdge[0];
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return cEdge[1];
|
||||
}
|
||||
return cEdge[2];
|
||||
}
|
||||
|
||||
public void setConstrainedEdgeCCW( TriangulationPoint p, boolean ce )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
cEdge[2] = ce;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
cEdge[0] = ce;
|
||||
}
|
||||
else
|
||||
{
|
||||
cEdge[1] = ce;
|
||||
}
|
||||
}
|
||||
|
||||
public void setConstrainedEdgeCW( TriangulationPoint p, boolean ce )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
cEdge[1] = ce;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
cEdge[2] = ce;
|
||||
}
|
||||
else
|
||||
{
|
||||
cEdge[0] = ce;
|
||||
}
|
||||
}
|
||||
|
||||
public void setConstrainedEdgeAcross( TriangulationPoint p, boolean ce )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
cEdge[0] = ce;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
cEdge[1] = ce;
|
||||
}
|
||||
else
|
||||
{
|
||||
cEdge[2] = ce;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getDelunayEdgeCCW( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return dEdge[2];
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return dEdge[0];
|
||||
}
|
||||
return dEdge[1];
|
||||
}
|
||||
|
||||
public boolean getDelunayEdgeCW( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return dEdge[1];
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return dEdge[2];
|
||||
}
|
||||
return dEdge[0];
|
||||
}
|
||||
|
||||
public boolean getDelunayEdgeAcross( TriangulationPoint p )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
return dEdge[0];
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
return dEdge[1];
|
||||
}
|
||||
return dEdge[2];
|
||||
}
|
||||
|
||||
public void setDelunayEdgeCCW( TriangulationPoint p, boolean e )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
dEdge[2] = e;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
dEdge[0] = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
dEdge[1] = e;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDelunayEdgeCW( TriangulationPoint p, boolean e )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
dEdge[1] = e;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
dEdge[2] = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
dEdge[0] = e;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDelunayEdgeAcross( TriangulationPoint p, boolean e )
|
||||
{
|
||||
if( p == points[0] )
|
||||
{
|
||||
dEdge[0] = e;
|
||||
}
|
||||
else if( p == points[1] )
|
||||
{
|
||||
dEdge[1] = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
dEdge[2] = e;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearDelunayEdges()
|
||||
{
|
||||
dEdge[0] = false;
|
||||
dEdge[1] = false;
|
||||
dEdge[2] = false;
|
||||
}
|
||||
|
||||
public boolean isInterior()
|
||||
{
|
||||
return interior;
|
||||
}
|
||||
|
||||
public void isInterior( boolean b )
|
||||
{
|
||||
interior = b;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
|
||||
|
||||
/**
|
||||
* @author Thomas Åhlen (thahlen@gmail.com)
|
||||
*/
|
||||
public class AdvancingFront
|
||||
{
|
||||
public AdvancingFrontNode head;
|
||||
public AdvancingFrontNode tail;
|
||||
protected AdvancingFrontNode search;
|
||||
|
||||
public AdvancingFront( AdvancingFrontNode head, AdvancingFrontNode tail )
|
||||
{
|
||||
this.head = head;
|
||||
this.tail = tail;
|
||||
this.search = head;
|
||||
addNode( head );
|
||||
addNode( tail );
|
||||
}
|
||||
|
||||
public void addNode( AdvancingFrontNode node )
|
||||
{
|
||||
// _searchTree.put( node.key, node );
|
||||
}
|
||||
|
||||
public void removeNode( AdvancingFrontNode node )
|
||||
{
|
||||
// _searchTree.delete( node.key );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
AdvancingFrontNode node = head;
|
||||
while( node != tail )
|
||||
{
|
||||
sb.append( node.point.getX() ).append( "->" );
|
||||
node = node.next;
|
||||
}
|
||||
sb.append( tail.point.getX() );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private final AdvancingFrontNode findSearchNode( double x )
|
||||
{
|
||||
// TODO: implement BST index
|
||||
return search;
|
||||
}
|
||||
|
||||
/**
|
||||
* We use a balancing tree to locate a node smaller or equal to
|
||||
* given key value
|
||||
*
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public AdvancingFrontNode locateNode( TriangulationPoint point )
|
||||
{
|
||||
return locateNode( point.getX() );
|
||||
}
|
||||
|
||||
private AdvancingFrontNode locateNode( double x )
|
||||
{
|
||||
AdvancingFrontNode node = findSearchNode(x);
|
||||
if( x < node.value )
|
||||
{
|
||||
while( (node = node.prev) != null )
|
||||
{
|
||||
if( x >= node.value )
|
||||
{
|
||||
search = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( (node = node.next) != null )
|
||||
{
|
||||
if( x < node.value )
|
||||
{
|
||||
search = node.prev;
|
||||
return node.prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation will use simple node traversal algorithm to find
|
||||
* a point on the front
|
||||
*
|
||||
* @param point
|
||||
* @return
|
||||
*/
|
||||
public AdvancingFrontNode locatePoint( final TriangulationPoint point )
|
||||
{
|
||||
final double px = point.getX();
|
||||
AdvancingFrontNode node = findSearchNode(px);
|
||||
final double nx = node.point.getX();
|
||||
|
||||
if( px == nx )
|
||||
{
|
||||
if( point != node.point )
|
||||
{
|
||||
// We might have two nodes with same x value for a short time
|
||||
if( point == node.prev.point )
|
||||
{
|
||||
node = node.prev;
|
||||
}
|
||||
else if( point == node.next.point )
|
||||
{
|
||||
node = node.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException( "Failed to find Node for given afront point");
|
||||
// node = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( px < nx )
|
||||
{
|
||||
while( (node = node.prev) != null )
|
||||
{
|
||||
if( point == node.point )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( (node = node.next) != null )
|
||||
{
|
||||
if( point == node.point )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
search = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
public class AdvancingFrontIndex<A>
|
||||
{
|
||||
double _min,_max;
|
||||
IndexNode<A> _root;
|
||||
|
||||
public AdvancingFrontIndex( double min, double max, int depth )
|
||||
{
|
||||
if( depth > 5 ) depth = 5;
|
||||
_root = createIndex( depth );
|
||||
}
|
||||
|
||||
private IndexNode<A> createIndex( int n )
|
||||
{
|
||||
IndexNode<A> node = null;
|
||||
if( n > 0 )
|
||||
{
|
||||
node = new IndexNode<A>();
|
||||
node.bigger = createIndex( n-1 );
|
||||
node.smaller = createIndex( n-1 );
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public A fetchAndRemoveIndex( A key )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public A fetchAndInsertIndex( A key )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
class IndexNode<A>
|
||||
{
|
||||
A value;
|
||||
IndexNode<A> smaller;
|
||||
IndexNode<A> bigger;
|
||||
double range;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
|
||||
|
||||
public class AdvancingFrontNode
|
||||
{
|
||||
protected AdvancingFrontNode next = null;
|
||||
protected AdvancingFrontNode prev = null;
|
||||
|
||||
protected final Double key; // XXX: BST
|
||||
protected final double value;
|
||||
protected final TriangulationPoint point;
|
||||
protected DelaunayTriangle triangle;
|
||||
|
||||
public AdvancingFrontNode( TriangulationPoint point )
|
||||
{
|
||||
this.point = point;
|
||||
value = point.getX();
|
||||
key = Double.valueOf( value ); // XXX: BST
|
||||
}
|
||||
|
||||
public AdvancingFrontNode getNext()
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
public AdvancingFrontNode getPrevious()
|
||||
{
|
||||
return prev;
|
||||
}
|
||||
|
||||
public TriangulationPoint getPoint()
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
public DelaunayTriangle getTriangle()
|
||||
{
|
||||
return triangle;
|
||||
}
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
return next != null;
|
||||
}
|
||||
|
||||
public boolean hasPrevious()
|
||||
{
|
||||
return prev != null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,106 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationConstraint;
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*
|
||||
*/
|
||||
public class DTSweepConstraint extends TriangulationConstraint
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger( DTSweepConstraint.class );
|
||||
|
||||
public TriangulationPoint p;
|
||||
public TriangulationPoint q;
|
||||
|
||||
/**
|
||||
* Give two points in any order. Will always be ordered so
|
||||
* that q.y > p.y and q.x > p.x if same y value
|
||||
*
|
||||
* @param p1
|
||||
* @param p2
|
||||
*/
|
||||
public DTSweepConstraint( TriangulationPoint p1, TriangulationPoint p2 )
|
||||
// throws DuplicatePointException
|
||||
{
|
||||
p = p1;
|
||||
q = p2;
|
||||
if( p1.getY() > p2.getY() )
|
||||
{
|
||||
q = p1;
|
||||
p = p2;
|
||||
}
|
||||
else if( p1.getY() == p2.getY() )
|
||||
{
|
||||
if( p1.getX() > p2.getX() )
|
||||
{
|
||||
q = p1;
|
||||
p = p2;
|
||||
}
|
||||
else if( p1.getX() == p2.getX() )
|
||||
{
|
||||
logger.info( "Failed to create constraint {}={}", p1, p2 );
|
||||
// throw new DuplicatePointException( p1 + "=" + p2 );
|
||||
// return;
|
||||
}
|
||||
}
|
||||
q.addEdge(this);
|
||||
}
|
||||
|
||||
// public TPoint intersect( TPoint a, TPoint b )
|
||||
// {
|
||||
// double pqx,pqy,bax,bay,t;
|
||||
//
|
||||
// pqx = p.getX()-q.getX();
|
||||
// pqy = p.getY()-q.getY();
|
||||
// t = pqy*(a.getX()-q.getX()) - pqx*(a.getY()-q.getY() );
|
||||
// t /= pqx*(b.getY()-a.getY()) - pqy*(b.getX()-a.getX());
|
||||
// bax = t*(b.getX()-a.getX()) + a.getX();
|
||||
// bay = t*(b.getY()-a.getY()) + a.getY();
|
||||
// return new TPoint( bax, bay );
|
||||
// }
|
||||
|
||||
public TriangulationPoint getP()
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
public TriangulationPoint getQ()
|
||||
{
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.poly2tri.triangulation.Triangulatable;
|
||||
import org.poly2tri.triangulation.TriangulationAlgorithm;
|
||||
import org.poly2tri.triangulation.TriangulationConstraint;
|
||||
import org.poly2tri.triangulation.TriangulationContext;
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
import org.poly2tri.triangulation.point.TPoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Thomas Åhlén, thahlen@gmail.com
|
||||
*
|
||||
*/
|
||||
public class DTSweepContext extends TriangulationContext<DTSweepDebugContext>
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger( DTSweepContext.class );
|
||||
|
||||
// Inital triangle factor, seed triangle will extend 30% of
|
||||
// PointSet width to both left and right.
|
||||
private final float ALPHA = 0.3f;
|
||||
|
||||
/** Advancing front **/
|
||||
protected AdvancingFront aFront;
|
||||
/** head point used with advancing front */
|
||||
private TriangulationPoint _head;
|
||||
/** tail point used with advancing front */
|
||||
private TriangulationPoint _tail;
|
||||
protected Basin basin = new Basin();
|
||||
protected EdgeEvent edgeEvent = new EdgeEvent();
|
||||
|
||||
private DTSweepPointComparator _comparator = new DTSweepPointComparator();
|
||||
|
||||
public DTSweepContext()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
public void isDebugEnabled( boolean b )
|
||||
{
|
||||
if( b )
|
||||
{
|
||||
if( _debug == null )
|
||||
{
|
||||
_debug = new DTSweepDebugContext(this);
|
||||
}
|
||||
}
|
||||
_debugEnabled = b;
|
||||
}
|
||||
|
||||
public void removeFromList( DelaunayTriangle triangle )
|
||||
{
|
||||
_triList.remove( triangle );
|
||||
// TODO: remove all neighbor pointers to this triangle
|
||||
// for( int i=0; i<3; i++ )
|
||||
// {
|
||||
// if( triangle.neighbors[i] != null )
|
||||
// {
|
||||
// triangle.neighbors[i].clearNeighbor( triangle );
|
||||
// }
|
||||
// }
|
||||
// triangle.clearNeighbors();
|
||||
}
|
||||
|
||||
protected void meshClean(DelaunayTriangle triangle)
|
||||
{
|
||||
DelaunayTriangle t1,t2;
|
||||
if( triangle != null )
|
||||
{
|
||||
ArrayDeque<DelaunayTriangle> deque = new ArrayDeque<DelaunayTriangle>();
|
||||
deque.addFirst(triangle);
|
||||
triangle.isInterior(true);
|
||||
|
||||
while( !deque.isEmpty() )
|
||||
{
|
||||
t1 = deque.removeFirst();
|
||||
_triUnit.addTriangle( t1 );
|
||||
for( int i=0; i<3; ++i )
|
||||
{
|
||||
if( !t1.cEdge[i] )
|
||||
{
|
||||
t2 = t1.neighbors[i];
|
||||
if( t2 != null && !t2.isInterior() )
|
||||
{
|
||||
t2.isInterior(true);
|
||||
deque.addLast(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
super.clear();
|
||||
_triList.clear();
|
||||
}
|
||||
|
||||
public AdvancingFront getAdvancingFront()
|
||||
{
|
||||
return aFront;
|
||||
}
|
||||
|
||||
public void setHead( TriangulationPoint p1 ) { _head = p1; }
|
||||
public TriangulationPoint getHead() { return _head; }
|
||||
|
||||
public void setTail( TriangulationPoint p1 ) { _tail = p1; }
|
||||
public TriangulationPoint getTail() { return _tail; }
|
||||
|
||||
public void addNode( AdvancingFrontNode node )
|
||||
{
|
||||
// System.out.println( "add:" + node.key + ":" + System.identityHashCode(node.key));
|
||||
// m_nodeTree.put( node.getKey(), node );
|
||||
aFront.addNode( node );
|
||||
}
|
||||
|
||||
public void removeNode( AdvancingFrontNode node )
|
||||
{
|
||||
// System.out.println( "remove:" + node.key + ":" + System.identityHashCode(node.key));
|
||||
// m_nodeTree.delete( node.getKey() );
|
||||
aFront.removeNode( node );
|
||||
}
|
||||
|
||||
public AdvancingFrontNode locateNode( TriangulationPoint point )
|
||||
{
|
||||
return aFront.locateNode( point );
|
||||
}
|
||||
|
||||
public void createAdvancingFront()
|
||||
{
|
||||
AdvancingFrontNode head,tail,middle;
|
||||
// Initial triangle
|
||||
DelaunayTriangle iTriangle = new DelaunayTriangle( _points.get(0),
|
||||
getTail(),
|
||||
getHead() );
|
||||
addToList( iTriangle );
|
||||
|
||||
head = new AdvancingFrontNode( iTriangle.points[1] );
|
||||
head.triangle = iTriangle;
|
||||
middle = new AdvancingFrontNode( iTriangle.points[0] );
|
||||
middle.triangle = iTriangle;
|
||||
tail = new AdvancingFrontNode( iTriangle.points[2] );
|
||||
|
||||
aFront = new AdvancingFront( head, tail );
|
||||
aFront.addNode( middle );
|
||||
|
||||
// TODO: I think it would be more intuitive if head is middles next and not previous
|
||||
// so swap head and tail
|
||||
aFront.head.next = middle;
|
||||
middle.next = aFront.tail;
|
||||
middle.prev = aFront.head;
|
||||
aFront.tail.prev = middle;
|
||||
}
|
||||
|
||||
class Basin
|
||||
{
|
||||
AdvancingFrontNode leftNode;
|
||||
AdvancingFrontNode bottomNode;
|
||||
AdvancingFrontNode rightNode;
|
||||
public double width;
|
||||
public boolean leftHighest;
|
||||
}
|
||||
|
||||
class EdgeEvent
|
||||
{
|
||||
DTSweepConstraint constrainedEdge;
|
||||
public boolean right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to map a node to all sides of this triangle that don't have
|
||||
* a neighbor.
|
||||
*
|
||||
* @param t
|
||||
*/
|
||||
public void mapTriangleToNodes( DelaunayTriangle t )
|
||||
{
|
||||
AdvancingFrontNode n;
|
||||
for( int i=0; i<3; i++ )
|
||||
{
|
||||
if( t.neighbors[i] == null )
|
||||
{
|
||||
n = aFront.locatePoint( t.pointCW( t.points[i] ) );
|
||||
if( n != null )
|
||||
{
|
||||
n.triangle = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareTriangulation( Triangulatable t )
|
||||
{
|
||||
super.prepareTriangulation( t );
|
||||
|
||||
double xmax, xmin;
|
||||
double ymax, ymin;
|
||||
|
||||
xmax = xmin = _points.get(0).getX();
|
||||
ymax = ymin = _points.get(0).getY();
|
||||
// Calculate bounds. Should be combined with the sorting
|
||||
for( TriangulationPoint p : _points )
|
||||
{
|
||||
if( p.getX() > xmax )
|
||||
xmax = p.getX();
|
||||
if( p.getX() < xmin )
|
||||
xmin = p.getX();
|
||||
if( p.getY() > ymax )
|
||||
ymax = p.getY();
|
||||
if( p.getY() < ymin )
|
||||
ymin = p.getY();
|
||||
}
|
||||
|
||||
double deltaX = ALPHA * ( xmax - xmin );
|
||||
double deltaY = ALPHA * ( ymax - ymin );
|
||||
TPoint p1 = new TPoint( xmax + deltaX, ymin - deltaY );
|
||||
TPoint p2 = new TPoint( xmin - deltaX, ymin - deltaY );
|
||||
|
||||
setHead( p1 );
|
||||
setTail( p2 );
|
||||
|
||||
// long time = System.nanoTime();
|
||||
// Sort the points along y-axis
|
||||
Collections.sort( _points, _comparator );
|
||||
// logger.info( "Triangulation setup [{}ms]", ( System.nanoTime() - time ) / 1e6 );
|
||||
}
|
||||
|
||||
|
||||
public void finalizeTriangulation()
|
||||
{
|
||||
_triUnit.addTriangles( _triList );
|
||||
_triList.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriangulationConstraint newConstraint( TriangulationPoint a, TriangulationPoint b )
|
||||
{
|
||||
return new DTSweepConstraint( a, b );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriangulationAlgorithm algorithm()
|
||||
{
|
||||
return TriangulationAlgorithm.DTSweep;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationContext;
|
||||
import org.poly2tri.triangulation.TriangulationDebugContext;
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
|
||||
|
||||
public class DTSweepDebugContext extends TriangulationDebugContext
|
||||
{
|
||||
/*
|
||||
* Fields used for visual representation of current triangulation
|
||||
*/
|
||||
protected DelaunayTriangle _primaryTriangle;
|
||||
protected DelaunayTriangle _secondaryTriangle;
|
||||
protected TriangulationPoint _activePoint;
|
||||
protected AdvancingFrontNode _activeNode;
|
||||
protected DTSweepConstraint _activeConstraint;
|
||||
|
||||
public DTSweepDebugContext( DTSweepContext tcx )
|
||||
{
|
||||
super( tcx );
|
||||
}
|
||||
|
||||
public boolean isDebugContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// private Tuple2<TPoint,Double> m_circumCircle = new Tuple2<TPoint,Double>( new TPoint(), new Double(0) );
|
||||
// public Tuple2<TPoint,Double> getCircumCircle() { return m_circumCircle; }
|
||||
public DelaunayTriangle getPrimaryTriangle()
|
||||
{
|
||||
return _primaryTriangle;
|
||||
}
|
||||
|
||||
public DelaunayTriangle getSecondaryTriangle()
|
||||
{
|
||||
return _secondaryTriangle;
|
||||
}
|
||||
|
||||
public AdvancingFrontNode getActiveNode()
|
||||
{
|
||||
return _activeNode;
|
||||
}
|
||||
|
||||
public DTSweepConstraint getActiveConstraint()
|
||||
{
|
||||
return _activeConstraint;
|
||||
}
|
||||
|
||||
public TriangulationPoint getActivePoint()
|
||||
{
|
||||
return _activePoint;
|
||||
}
|
||||
|
||||
public void setPrimaryTriangle( DelaunayTriangle triangle )
|
||||
{
|
||||
_primaryTriangle = triangle;
|
||||
_tcx.update("setPrimaryTriangle");
|
||||
}
|
||||
|
||||
public void setSecondaryTriangle( DelaunayTriangle triangle )
|
||||
{
|
||||
_secondaryTriangle = triangle;
|
||||
_tcx.update("setSecondaryTriangle");
|
||||
}
|
||||
|
||||
public void setActivePoint( TriangulationPoint point )
|
||||
{
|
||||
_activePoint = point;
|
||||
}
|
||||
|
||||
public void setActiveConstraint( DTSweepConstraint e )
|
||||
{
|
||||
_activeConstraint = e;
|
||||
_tcx.update("setWorkingSegment");
|
||||
}
|
||||
|
||||
public void setActiveNode( AdvancingFrontNode node )
|
||||
{
|
||||
_activeNode = node;
|
||||
_tcx.update("setWorkingNode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
_primaryTriangle = null;
|
||||
_secondaryTriangle = null;
|
||||
_activePoint = null;
|
||||
_activeNode = null;
|
||||
_activeConstraint = null;
|
||||
}
|
||||
|
||||
// public void setWorkingCircumCircle( TPoint point, TPoint point2, TPoint point3 )
|
||||
// {
|
||||
// double dx,dy;
|
||||
//
|
||||
// CircleXY.circumCenter( point, point2, point3, m_circumCircle.a );
|
||||
// dx = m_circumCircle.a.getX()-point.getX();
|
||||
// dy = m_circumCircle.a.getY()-point.getY();
|
||||
// m_circumCircle.b = Double.valueOf( Math.sqrt( dx*dx + dy*dy ) );
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
|
||||
public class DTSweepPointComparator implements Comparator<TriangulationPoint>
|
||||
{
|
||||
public int compare( TriangulationPoint p1, TriangulationPoint p2 )
|
||||
{
|
||||
if(p1.getY() < p2.getY() )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if( p1.getY() > p2.getY())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(p1.getX() < p2.getX())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if( p1.getX() > p2.getX() )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package org.poly2tri.triangulation.delaunay.sweep;
|
||||
|
||||
public class PointOnEdgeException extends RuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PointOnEdgeException( String msg )
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/* Poly2Tri
|
||||
* Copyright (c) 2009-2010, Poly2Tri Contributors
|
||||
* http://code.google.com/p/poly2tri/
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Poly2Tri nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.poly2tri.triangulation.point;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import org.poly2tri.triangulation.TriangulationPoint;
|
||||
|
||||
|
||||
public class FloatBufferPoint extends TriangulationPoint
|
||||
{
|
||||
private final FloatBuffer _fb;
|
||||
private final int _ix,_iy,_iz;
|
||||
|
||||
public FloatBufferPoint( FloatBuffer fb, int index )
|
||||
{
|
||||
_fb = fb;
|
||||
_ix = index;
|
||||
_iy = index+1;
|
||||
_iz = index+2;
|
||||
}
|
||||
|
||||
public final double getX()
|
||||
{
|
||||
return _fb.get( _ix );
|
||||
}
|
||||
public final double getY()
|
||||
{
|
||||
return _fb.get( _iy );
|
||||
}
|
||||
public final double getZ()
|
||||
{
|
||||
return _fb.get( _iz );
|
||||
}
|
||||
|
||||
public final float getXf()
|
||||
{
|
||||
return _fb.get( _ix );
|
||||
}
|
||||
public final float getYf()
|
||||
{
|
||||
return _fb.get( _iy );
|
||||
}
|
||||
public final float getZf()
|
||||
{
|
||||
return _fb.get( _iz );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set( double x, double y, double z )
|
||||
{
|
||||
_fb.put( _ix, (float)x );
|
||||
_fb.put( _iy, (float)y );
|
||||
_fb.put( _iz, (float)z );
|
||||
}
|
||||
|
||||
public static TriangulationPoint[] toPoints( FloatBuffer fb )
|
||||
{
|
||||
FloatBufferPoint[] points = new FloatBufferPoint[fb.limit()/3];
|
||||
for( int i=0,j=0; i<points.length; i++, j+=3 )
|
||||
{
|
||||
points[i] = new FloatBufferPoint(fb, j);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue