/**
* ORIPA - Origami Pattern Editor
* Copyright (C) 2005-2009 Jun Mitani http://mitani.cs.tsukuba.ac.jp/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package oripa.fold;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.vecmath.Vector2d;
import oripa.Config;
import oripa.ORIPA;
import oripa.doc.Doc;
import oripa.doc.exporter.Exporter;
import oripa.doc.exporter.ExporterEPS;
import oripa.geom.GeomUtil;
import oripa.geom.Line;
import oripa.paint.core.PaintConfig;
import oripa.paint.creasepattern.CreasePattern;
import oripa.value.OriLine;
public class Folder {
private ArrayList<Condition4> condition4s = new ArrayList<>();
private int workORmat[][];
private ArrayList<SubFace> subFaces;
// helper object
private OrigamiModelFactory modelFactory = new OrigamiModelFactory();
private FolderTool folderTool = new FolderTool();
public Folder() {
}
// TODO: this method should return FoldedModelInfo.
public int fold(OrigamiModel origamiModel, FoldedModelInfo foldedModelInfo) {
// OrigamiModel origamiModel = m_doc.getOrigamiModel();
// FoldedModelInfo foldedModelInfo = m_doc.getFoldedModelInfo();
List<OriFace> sortedFaces = origamiModel.getSortedFaces();
List<OriFace> faces = origamiModel.getFaces();
List<OriVertex> vertices = origamiModel.getVertices();
List<OriEdge> edges = origamiModel.getEdges();
List<int[][]> foldableOverlapRelations = foldedModelInfo.getFoldableOverlapRelations();
foldableOverlapRelations.clear();
simpleFoldWithoutZorder(faces, edges);
foldedModelInfo.setBoundBox(
folderTool.calcFoldedBoundingBox(faces));
sortedFaces.addAll(faces);
folderTool.setFacesOutline(vertices, faces, false);
if (!PaintConfig.bDoFullEstimation) {
origamiModel.setFolded(true);
return 0;
}
// After folding construct the sbfaces
double paperSize = origamiModel.getPaperSize();
subFaces = makeSubFaces(faces, paperSize);
System.out.println("subFaces.size() = " + subFaces.size());
foldedModelInfo.setOverlapRelation(
createOverlapRelation(faces));
int[][] overlapRelation = foldedModelInfo.getOverlapRelation();
// Set overlap relations based on valley/mountain folds information
step1(faces, overlapRelation);
holdCondition3s(faces, paperSize, overlapRelation);
holdCondition4s(edges, overlapRelation);
estimation(faces, overlapRelation);
int size = faces.size();
workORmat = new int[size][size];
for (int i = 0; i < size; i++) {
System.arraycopy(overlapRelation[i], 0, workORmat[i], 0, size);
}
ORIPA.tmpInt = 0;
for (SubFace sub : subFaces) {
sub.sortFaceOverlapOrder(faces, workORmat);
}
findAnswer(foldedModelInfo, 0, overlapRelation);
foldedModelInfo.setCurrentORmatIndex(0);
if (foldableOverlapRelations.isEmpty()) {
ORIPA.outMessage("No answer was found");
return 0;
} else {
matrixCopy(foldableOverlapRelations.get(0), overlapRelation);
}
folderTool.setFacesOutline(vertices, faces, false);
// Color the faces
Random rand = new Random();
for (OriFace face : faces) {
int r = (int) (rand.nextDouble() * 255);
int g = (int) (rand.nextDouble() * 255);
int b = (int) (rand.nextDouble() * 255);
if (r < 0) {
r = 0;
} else if (r > 255) {
r = 255;
}
if (g < 0) {
g = 0;
} else if (g > 255) {
g = 255;
}
if (b < 0) {
b = 0;
} else if (b > 255) {
b = 255;
}
face.intColor = (r << 16) | (g << 8) | b | 0xff000000;
}
origamiModel.setFolded(true);
return foldableOverlapRelations.size();
}
private void findAnswer(
FoldedModelInfo foldedModelInfo, int subFaceIndex, int[][] orMat) {
//FoldedModelInfo foldedModelInfo = m_doc.getFoldedModelInfo();
SubFace sub = subFaces.get(subFaceIndex);
List<int[][]> foldableOverlapRelations = foldedModelInfo.getFoldableOverlapRelations();
if (sub.allFaceOrderDecided) {
int s = orMat.length;
int[][] passMat = new int[s][s];
for (int i = 0; i < s; i++) {
System.arraycopy(orMat[i], 0, passMat[i], 0, s);
}
if (subFaceIndex == subFaces.size() - 1) {
s = orMat.length;
int[][] ansMat = new int[s][s];
for (int i = 0; i < s; i++) {
System.arraycopy(passMat[i], 0, ansMat[i], 0, s);
}
foldableOverlapRelations.add(ansMat);
} else {
findAnswer(foldedModelInfo, subFaceIndex + 1, passMat);
}
} else {
for (ArrayList<OriFace> vec : sub.answerStacks) {
int size = vec.size();
boolean bOK = true;
for (int i = 0; i < size; i++) {
int index0 = vec.get(i).tmpInt;
for (int j = i + 1; j < size; j++) {
int index1 = vec.get(j).tmpInt;
if (orMat[index0][index1] == Doc.LOWER) {
bOK = false;
break;
}
}
if (!bOK) {
break;
}
}
if (!bOK) {
continue;
}
int s = orMat.length;
int[][] passMat = new int[s][s];
for (int i = 0; i < s; i++) {
System.arraycopy(orMat[i], 0, passMat[i], 0, s);
}
for (int i = 0; i < size; i++) {
int index0 = vec.get(i).tmpInt;
for (int j = i + 1; j < size; j++) {
int index1 = vec.get(j).tmpInt;
passMat[index0][index1] = Doc.UPPER;
passMat[index1][index0] = Doc.LOWER;
}
}
if (subFaceIndex == subFaces.size() - 1) {
s = orMat.length;
int[][] ansMat = new int[s][s];
for (int i = 0; i < s; i++) {
System.arraycopy(passMat[i], 0, ansMat[i], 0, s);
}
foldableOverlapRelations.add(ansMat);
} else {
findAnswer(foldedModelInfo, subFaceIndex + 1, passMat);
}
}
}
}
private void estimation(
List<OriFace> faces, int[][] orMat) {
boolean bChanged;
do {
bChanged = false;
if (estimate_by3faces(faces, orMat)) {
bChanged = true;
}
if (estimate_by3faces2(orMat)) {
bChanged = true;
}
if (estimate_by4faces(orMat)) {
bChanged = true;
}
} while (bChanged);
}
// If face[i] and face[j] touching edge is covered by face[k]
// then OR[i][k] = OR[j][k]
private void holdCondition3s(
List<OriFace> faces, double paperSize, int[][] overlapRelation) {
// OrigamiModel origamiModel = m_doc.getOrigamiModel();
// FoldedModelInfo foldedModelInfo = m_doc.getFoldedModelInfo();
;
for (OriFace f_i : faces) {
for (OriHalfedge he : f_i.halfedges) {
if (he.pair == null) {
continue;
}
OriFace f_j = he.pair.face;
if (overlapRelation[f_i.tmpInt][f_j.tmpInt] != Doc.LOWER) {
continue;
}
for (OriFace f_k : faces) {
if (f_k == f_i || f_k == f_j) {
continue;
}
if (folderTool.isLineCrossFace4(f_k, he, paperSize)) {
Condition3 cond = new Condition3();
cond.upper = f_i.tmpInt;
cond.lower = f_j.tmpInt;
cond.other = f_k.tmpInt;
Condition3 cond3_f = new Condition3();
cond3_f.lower = cond.lower;
cond3_f.upper = cond.upper;
cond3_f.other = cond.other;
f_k.condition3s.add(cond3_f);
// Add condition to all subfaces of the 3 faces
for (SubFace sub : subFaces) {
if (sub.faces.contains(f_i) && sub.faces.contains(f_j) && sub.faces.contains(f_k)) {
sub.condition3s.add(cond);
}
}
}
}
}
}
}
private void holdCondition4s(
List<OriEdge> edges, int[][] overlapRelation) {
// OrigamiModel origamiModel = m_doc.getOrigamiModel();
// FoldedModelInfo foldedModelInfo = m_doc.getFoldedModelInfo();
int edgeNum = edges.size();
System.out.println("edgeNum = " + edgeNum);
for (int i = 0; i < edgeNum; i++) {
OriEdge e0 = edges.get(i);
if (e0.left == null || e0.right == null) {
continue;
}
for (int j = i + 1; j < edgeNum; j++) {
OriEdge e1 = edges.get(j);
if (e1.left == null || e1.right == null) {
continue;
}
//TODO extract as function
if (GeomUtil.isLineSegmentsOverlap(e0.left.positionAfterFolded, e0.left.next.positionAfterFolded,
e1.left.positionAfterFolded, e1.left.next.positionAfterFolded)) {
Condition4 cond_f;
if (overlapRelation[e0.left.face.tmpInt][e0.right.face.tmpInt] == Doc.UPPER) {
if (overlapRelation[e1.left.face.tmpInt][e1.right.face.tmpInt] == Doc.UPPER) {
cond_f = new Condition4();
cond_f.upper1 = e0.right.face.tmpInt;
cond_f.lower1 = e0.left.face.tmpInt;
cond_f.upper2 = e1.right.face.tmpInt;
cond_f.lower2 = e1.left.face.tmpInt;
e0.right.face.condition4s.add(cond_f);
cond_f = new Condition4();
cond_f.upper2 = e0.right.face.tmpInt;
cond_f.lower2 = e0.left.face.tmpInt;
cond_f.upper1 = e1.right.face.tmpInt;
cond_f.lower1 = e1.left.face.tmpInt;
e1.right.face.condition4s.add(cond_f);
} else {
cond_f = new Condition4();
cond_f.upper1 = e0.right.face.tmpInt;
cond_f.lower1 = e0.left.face.tmpInt;
cond_f.upper2 = e1.left.face.tmpInt;
cond_f.lower2 = e1.right.face.tmpInt;
e0.right.face.condition4s.add(cond_f);
cond_f = new Condition4();
cond_f.upper2 = e0.right.face.tmpInt;
cond_f.lower2 = e0.left.face.tmpInt;
cond_f.upper1 = e1.left.face.tmpInt;
cond_f.lower1 = e1.right.face.tmpInt;
e1.left.face.condition4s.add(cond_f);
}
} else {
if (overlapRelation[e1.left.face.tmpInt][e1.right.face.tmpInt] == Doc.UPPER) {
cond_f = new Condition4();
cond_f.upper1 = e0.left.face.tmpInt;
cond_f.lower1 = e0.right.face.tmpInt;
cond_f.upper2 = e1.right.face.tmpInt;
cond_f.lower2 = e1.left.face.tmpInt;
e0.left.face.condition4s.add(cond_f);
cond_f.upper2 = e0.left.face.tmpInt;
cond_f.lower2 = e0.right.face.tmpInt;
cond_f.upper1 = e1.right.face.tmpInt;
cond_f.lower1 = e1.left.face.tmpInt;
e1.right.face.condition4s.add(cond_f);
} else {
cond_f = new Condition4();
cond_f.upper1 = e0.left.face.tmpInt;
cond_f.lower1 = e0.right.face.tmpInt;
cond_f.upper2 = e1.left.face.tmpInt;
cond_f.lower2 = e1.right.face.tmpInt;
e0.left.face.condition4s.add(cond_f);
cond_f.upper2 = e0.left.face.tmpInt;
cond_f.lower2 = e0.right.face.tmpInt;
cond_f.upper1 = e1.left.face.tmpInt;
cond_f.lower1 = e1.right.face.tmpInt;
e1.left.face.condition4s.add(cond_f);
}
}
Condition4 cond = new Condition4();
// Add condition to all subfaces of the 4 faces
boolean bOverlap = false;
for (SubFace sub : subFaces) {
if (sub.faces.contains(e0.left.face) && sub.faces.contains(e0.right.face)
&& sub.faces.contains(e1.left.face) && sub.faces.contains(e1.right.face)) {
sub.condition4s.add(cond);
bOverlap = true;
}
}
if (overlapRelation[e0.left.face.tmpInt][e0.right.face.tmpInt] == Doc.UPPER) {
cond.upper1 = e0.right.face.tmpInt;
cond.lower1 = e0.left.face.tmpInt;
} else {
cond.upper1 = e0.left.face.tmpInt;
cond.lower1 = e0.right.face.tmpInt;
}
if (overlapRelation[e1.left.face.tmpInt][e1.right.face.tmpInt] == Doc.UPPER) {
cond.upper2 = e1.right.face.tmpInt;
cond.lower2 = e1.left.face.tmpInt;
} else {
cond.upper2 = e1.left.face.tmpInt;
cond.lower2 = e1.right.face.tmpInt;
}
if (bOverlap) {
condition4s.add(cond);
}
}
}
}
}
public static void matrixCopy(int[][] from, int[][] to) {
int size = from.length;
for (int i = 0; i < size; i++) {
System.arraycopy(from[i], 0, to[i], 0, size);
}
}
private void setOR(int[][] orMat, int i, int j, int value, boolean bSetPairAtSameTime) {
orMat[i][j] = value;
if (bSetPairAtSameTime) {
if (value == Doc.LOWER) {
orMat[j][i] = Doc.UPPER;
} else {
orMat[j][i] = Doc.LOWER;
}
}
}
private void setLowerValueIfUndefined(int[][] orMat, int i, int j, boolean[] changed) {
if (orMat[i][j] == Doc.UNDEFINED) {
orMat[i][j] = Doc.LOWER;
orMat[j][i] = Doc.UPPER;
changed[0] = true;
}
}
private boolean estimate_by4faces(int[][] orMat) {
boolean[] changed = new boolean[1];
changed[0] = false;
for (Condition4 cond : condition4s) {
// if: lower1 > upper2, then: upper1 > upper2, upper1 > lower2, lower1 > lower2
if (orMat[cond.lower1][cond.upper2] == Doc.LOWER) {
setLowerValueIfUndefined(orMat, cond.upper1, cond.upper2, changed);
setLowerValueIfUndefined(orMat, cond.upper1, cond.lower2, changed);
setLowerValueIfUndefined(orMat, cond.lower1, cond.lower2, changed);
}
// if: lower2 > upper1, then: upper2 > upper1, upper2 > lower1, lower2 > lower1
if (orMat[cond.lower2][cond.upper1] == Doc.LOWER) {
setLowerValueIfUndefined(orMat, cond.upper2, cond.upper1, changed);
setLowerValueIfUndefined(orMat, cond.upper2, cond.lower1, changed);
setLowerValueIfUndefined(orMat, cond.lower2, cond.lower1, changed);
}
// if: upper1 > upper2 > lower1, then: upper1 > lower2, lower2 > lower1
if (orMat[cond.upper1][cond.upper2] == Doc.LOWER
&& orMat[cond.upper2][cond.lower1] == Doc.LOWER) {
setLowerValueIfUndefined(orMat, cond.upper1, cond.lower2, changed);
setLowerValueIfUndefined(orMat, cond.lower2, cond.lower1, changed);
}
// if: upper1 > lower2 > lower1, then: upper1 > upper2, upper2 > lower1
if (orMat[cond.upper1][cond.lower2] == Doc.LOWER
&& orMat[cond.lower2][cond.lower1] == Doc.LOWER) {
setLowerValueIfUndefined(orMat, cond.upper1, cond.upper2, changed);
setLowerValueIfUndefined(orMat, cond.upper2, cond.lower1, changed);
}
// if: upper2 > upper1 > lower2, then: upper2 > lower1, lower1 > lower2
if (orMat[cond.upper2][cond.upper1] == Doc.LOWER
&& orMat[cond.upper1][cond.lower2] == Doc.LOWER) {
setLowerValueIfUndefined(orMat, cond.upper2, cond.lower1, changed);
setLowerValueIfUndefined(orMat, cond.lower1, cond.lower2, changed);
}
// if: upper2 > lower1 > lower2, then: upper2 > upper1, upper1 > lower2
if (orMat[cond.upper2][cond.lower1] == Doc.LOWER
&& orMat[cond.lower1][cond.lower2] == Doc.LOWER) {
setLowerValueIfUndefined(orMat, cond.upper2, cond.upper1, changed);
setLowerValueIfUndefined(orMat, cond.upper1, cond.lower2, changed);
}
}
return changed[0];
}
// If the subface a>b and b>c then a>c
private boolean estimate_by3faces2(int[][] orMat) {
boolean bChanged = false;
for (SubFace sub : subFaces) {
boolean changed;
while (true) {
changed = false;
boolean bFound = false;
for (int i = 0; i < sub.faces.size(); i++) {
for (int j = i + 1; j < sub.faces.size(); j++) {
// seach for undertermined relations
int index_i = sub.faces.get(i).tmpInt;
int index_j = sub.faces.get(j).tmpInt;
if (orMat[index_i][index_j] == Doc.NO_OVERLAP) {
continue;
}
if (orMat[index_i][index_j] != Doc.UNDEFINED) {
continue;
}
// Find the intermediary face
for (int k = 0; k < sub.faces.size(); k++) {
if (k == i) {
continue;
}
if (k == j) {
continue;
}
int index_k = sub.faces.get(k).tmpInt;
if (orMat[index_i][index_k] == Doc.UPPER && orMat[index_k][index_j] == Doc.UPPER) {
orMat[index_i][index_j] = Doc.UPPER;
orMat[index_j][index_i] = Doc.LOWER;
bFound = true;
changed = true;
bChanged = true;
break;
}
if (orMat[index_i][index_k] == Doc.LOWER && orMat[index_k][index_j] == Doc.LOWER) {
orMat[index_i][index_j] = Doc.LOWER;
orMat[index_j][index_i] = Doc.UPPER;
bFound = true;
changed = true;
bChanged = true;
break;
}
if (bFound) {
break;
}
}
if (bFound) {
break;
}
}
if (bFound) {
break;
}
}
if (!changed) {
break;
}
}
}
return bChanged;
}
// If face[i] and face[j] touching edge is covered by face[k]
// then OR[i][k] = OR[j][k]
private boolean estimate_by3faces(
List<OriFace> faces,
int[][] orMat) {
boolean bChanged = false;
for (OriFace f_i : faces) {
for (OriHalfedge he : f_i.halfedges) {
if (he.pair == null) {
continue;
}
OriFace f_j = he.pair.face;
for (OriFace f_k : faces) {
if (f_k == f_i || f_k == f_j) {
continue;
}
if (GeomUtil.isLineCrossFace(f_k, he, 0.0001)) {
if (orMat[f_i.tmpInt][f_k.tmpInt] != Doc.UNDEFINED
&& orMat[f_j.tmpInt][f_k.tmpInt] == Doc.UNDEFINED) {
setOR(orMat, f_j.tmpInt, f_k.tmpInt, orMat[f_i.tmpInt][f_k.tmpInt], true);
bChanged = true;
} else if (orMat[f_j.tmpInt][f_k.tmpInt] != Doc.UNDEFINED
&& orMat[f_i.tmpInt][f_k.tmpInt] == Doc.UNDEFINED) {
setOR(orMat, f_i.tmpInt, f_k.tmpInt, orMat[f_j.tmpInt][f_k.tmpInt], true);
bChanged = true;
}
}
}
}
}
return bChanged;
}
private ArrayList<SubFace> makeSubFaces(
List<OriFace> faces, double paperSize) {
//OrigamiModel origamiModel = m_doc.getOrigamiModel();
Doc temp_doc = new Doc(paperSize);
CreasePattern temp_creasePattern = temp_doc.getCreasePattern();
OrigamiModel temp_origamiModel = temp_doc.getOrigamiModel();
temp_creasePattern.clear();
for (OriFace face : faces) {
for (OriHalfedge he : face.halfedges) {
temp_doc.addLine(new OriLine(he.positionAfterFolded, he.next.positionAfterFolded, OriLine.TYPE_RIDGE));
}
}
folderTool.cleanDuplicatedLines(temp_creasePattern);
if (Config.FOR_STUDY) {
try {
Exporter exporter = new ExporterEPS();
exporter.export(temp_doc, "c:\\_jun\\tmp\\te.eps");
} catch (Exception e) {
}
}
System.out.println("debugging");
Vector2d sp1 = new Vector2d(0.0, 0.0);
Vector2d ep1 = new Vector2d(0.0, 10.0);
Vector2d sp2 = new Vector2d(0.0, 0.0);
Vector2d ep2 = new Vector2d(0.0, 5.0);
Vector2d dummy1 = new Vector2d();
Vector2d dummy2 = new Vector2d();
int crossNum = GeomUtil.getCrossPoint(dummy1, dummy2, sp1, ep1, sp2, ep2);
System.out.println("getCrossPoint results " + crossNum + "::::" + dummy1 + ", " + dummy2);
//temp_doc.buildOrigami(origamiModel, false);
temp_origamiModel = modelFactory.buildOrigami(temp_creasePattern, temp_doc.getPaperSize(), false);
temp_doc.setOrigamiModel(temp_origamiModel);
ArrayList<SubFace> localSubFaces = new ArrayList<>();
List<OriFace> subFaceSources = temp_origamiModel.getFaces();
for (OriFace face : subFaceSources) {
localSubFaces.add(new SubFace(face));
}
int cnt = 0;
for (SubFace sub : localSubFaces) {
cnt++;
Vector2d innerPoint = sub.getInnerPoint();
for (OriFace face : faces) {
if (GeomUtil.isContainsPointFoldedFace(face, innerPoint, paperSize / 1000)) {
sub.faces.add(face);
}
}
}
System.out.println("=---------------------=");
// Check if the SubFace exactly equal to the Face
ArrayList<SubFace> tmpFaces = new ArrayList<>();
for (SubFace sub : localSubFaces) {
boolean sameCase = false;
for (SubFace s : tmpFaces) {
boolean sameCk = true;
if (sub.faces.size() != s.faces.size()) {
sameCk = false;
} else {
for (OriFace face : sub.faces) {
if (!s.faces.contains(face)) {
sameCk = false;
break;
}
}
}
if (sameCk) {
sameCase = true;
break;
}
}
if (!sameCase) {
tmpFaces.add(sub);
} else {
}
}
localSubFaces.clear();
localSubFaces.addAll(tmpFaces);
return localSubFaces;
}
private void simpleFoldWithoutZorder(
List<OriFace> faces, List<OriEdge> edges) {
//OrigamiModel origamiModel = m_doc.getOrigamiModel();
// List<OriFace> faces = origamiModel.getFaces();
// List<OriEdge> edges = origamiModel.getEdges();
int id = 0;
for (OriFace face : faces) {
face.faceFront = true;
face.tmpFlg = false;
face.z_order = 0;
face.tmpInt = id;
id++;
for (OriHalfedge he : face.halfedges) {
he.tmpVec.set(he.vertex.p);
}
}
walkFace(faces.get(0));
for (OriEdge e : edges) {
e.sv.p.set(e.left.tmpVec);
if (e.right != null) {
e.ev.p.set(e.right.tmpVec);
}
e.sv.tmpFlg = false;
e.ev.tmpFlg = false;
}
for (OriFace face : faces) {
face.tmpFlg = false;
for (OriHalfedge he : face.halfedges) {
he.positionAfterFolded.set(he.tmpVec);
}
}
}
// Recursive method that flips the faces, making the folds
private void walkFace(OriFace face) {
face.tmpFlg = true;
for (OriHalfedge he : face.halfedges) {
if (he.pair == null) {
continue;
}
if (he.pair.face.tmpFlg) {
continue;
}
flipFace(he.pair.face, he);
he.pair.face.tmpFlg = true;
walkFace(he.pair.face);
}
}
private void flipFace(OriFace face, OriHalfedge baseHe) {
Vector2d preOrigin = new Vector2d(baseHe.pair.next.tmpVec);
Vector2d afterOrigin = new Vector2d(baseHe.tmpVec);
// Creates the base unit vector for before the rotation
Vector2d baseDir = new Vector2d();
baseDir.sub(baseHe.pair.tmpVec, baseHe.pair.next.tmpVec);
// Creates the base unit vector for after the rotation
Vector2d afterDir = new Vector2d();
afterDir.sub(baseHe.next.tmpVec, baseHe.tmpVec);
afterDir.normalize();
Line preLine = new Line(preOrigin, baseDir);
for (OriHalfedge he : face.halfedges) {
double param[] = new double[1];
double d0 = GeomUtil.Distance(he.tmpVec, preLine, param);
double d1 = param[0];
Vector2d footV = new Vector2d(afterOrigin);
footV.x += d1 * afterDir.x;
footV.y += d1 * afterDir.y;
Vector2d afterDirFromFoot = new Vector2d();
afterDirFromFoot.x = afterDir.y;
afterDirFromFoot.y = -afterDir.x;
he.tmpVec.x = footV.x + d0 * afterDirFromFoot.x;
he.tmpVec.y = footV.y + d0 * afterDirFromFoot.y;
}
// Ivertion
if (face.faceFront == baseHe.face.faceFront) {
Vector2d ep = baseHe.next.tmpVec;
Vector2d sp = baseHe.tmpVec;
Vector2d b = new Vector2d();
b.sub(ep, sp);
for (OriHalfedge he : face.halfedges) {
if (GeomUtil.Distance(he.tmpVec, new Line(sp, b)) < GeomUtil.EPS) {
continue;
}
if (Math.abs(b.y) < GeomUtil.EPS) {
Vector2d a = new Vector2d();
a.sub(he.tmpVec, sp);
a.y = -a.y;
he.tmpVec.y = a.y + sp.y;
} else {
Vector2d a = new Vector2d();
a.sub(he.tmpVec, sp);
he.tmpVec.y = ((b.y * b.y - b.x * b.x) * a.y + 2 * b.x * b.y * a.x) / b.lengthSquared();
he.tmpVec.x = b.x / b.y * a.y - a.x + b.x / b.y * he.tmpVec.y;
he.tmpVec.x += sp.x;
he.tmpVec.y += sp.y;
}
}
face.faceFront = !face.faceFront;
}
}
//creates the matrix overlapRelation and fills it with "no overlap" or "undifined"
private int[][] createOverlapRelation(List<OriFace> faces) {
int overlapCount = 0;
int size = faces.size();
int[][] overlapRelation = new int[size][size];
for (int i = 0; i < size; i++) {
overlapRelation[i][i] = Doc.NO_OVERLAP;
for (int j = i + 1; j < size; j++) {
if (GeomUtil.isFaceOverlap(faces.get(i), faces.get(j), size * 0.00001)) {
overlapRelation[i][j] = Doc.UNDEFINED;
overlapRelation[j][i] = Doc.UNDEFINED;
overlapCount++;
} else {
overlapRelation[i][j] = Doc.NO_OVERLAP;
overlapRelation[j][i] = Doc.NO_OVERLAP;
}
}
}
return overlapRelation;
}
// Determines the overlap relations
private void step1(
List<OriFace> faces, int[][] overlapRelation) {
for (OriFace face : faces) {
for (OriHalfedge he : face.halfedges) {
if (he.pair == null) {
continue;
}
OriFace pairFace = he.pair.face;
// If the relation is already decided, skip
if (overlapRelation[face.tmpInt][pairFace.tmpInt] == Doc.UPPER
|| overlapRelation[face.tmpInt][pairFace.tmpInt] == Doc.LOWER) {
continue;
}
if ((face.faceFront && he.edge.type == OriLine.TYPE_RIDGE)
|| (!face.faceFront && he.edge.type == OriLine.TYPE_VALLEY)) {
overlapRelation[face.tmpInt][pairFace.tmpInt] = Doc.UPPER;
overlapRelation[pairFace.tmpInt][face.tmpInt] = Doc.LOWER;
} else {
overlapRelation[face.tmpInt][pairFace.tmpInt] = Doc.LOWER;
overlapRelation[pairFace.tmpInt][face.tmpInt] = Doc.UPPER;
}
}
}
}
public BoundBox foldWithoutLineType(
OrigamiModel model) {
List<OriVertex> vertices = model.getVertices();
List<OriEdge> edges = model.getEdges();
List<OriFace> faces = model.getFaces();
for (OriFace face : faces) {
face.faceFront = true;
}
faces.get(0).z_order = 0;
walkFace(faces, faces.get(0), 0);
Collections.sort(faces, new FaceOrderComparator());
model.getSortedFaces().clear();
model.getSortedFaces().addAll(faces);
for (OriEdge e : edges) {
e.sv.p.set(e.left.tmpVec);
e.sv.tmpFlg = false;
}
folderTool.setFacesOutline(vertices, faces, false);
return folderTool.calcFoldedBoundingBox(faces);
}
// Make the folds by flipping the faces
private void walkFace(List<OriFace> faces, OriFace face, int walkFaceCount) {
face.tmpFlg = true;
if (walkFaceCount > 1000) {
System.out.println("walkFace too deap");
return;
}
for (OriHalfedge he : face.halfedges) {
if (he.pair == null) {
continue;
}
if (he.pair.face.tmpFlg) {
continue;
}
flipFace2(faces, he.pair.face, he);
he.pair.face.tmpFlg = true;
walkFace(faces, he.pair.face, walkFaceCount + 1);
}
}
// Method that doesnt use sin con
private void flipFace2(List<OriFace> faces, OriFace face, OriHalfedge baseHe) {
Vector2d preOrigin = new Vector2d(baseHe.pair.next.tmpVec);
Vector2d afterOrigin = new Vector2d(baseHe.tmpVec);
// Creates the base unit vector for before the rotation
Vector2d baseDir = new Vector2d();
baseDir.sub(baseHe.pair.tmpVec, baseHe.pair.next.tmpVec);
// Creates the base unit vector for after the rotation
Vector2d afterDir = new Vector2d();
afterDir.sub(baseHe.next.tmpVec, baseHe.tmpVec);
afterDir.normalize();
Line preLine = new Line(preOrigin, baseDir);
for (OriHalfedge he : face.halfedges) {
double param[] = new double[1];
double d0 = GeomUtil.Distance(he.tmpVec, preLine, param);
double d1 = param[0];
Vector2d footV = new Vector2d(afterOrigin);
footV.x += d1 * afterDir.x;
footV.y += d1 * afterDir.y;
Vector2d afterDirFromFoot = new Vector2d();
afterDirFromFoot.x = afterDir.y;
afterDirFromFoot.y = -afterDir.x;
he.tmpVec.x = footV.x + d0 * afterDirFromFoot.x;
he.tmpVec.y = footV.y + d0 * afterDirFromFoot.y;
}
// Ivertion
if (face.faceFront == baseHe.face.faceFront) {
Vector2d ep = baseHe.next.tmpVec;
Vector2d sp = baseHe.tmpVec;
Vector2d b = new Vector2d();
b.sub(ep, sp);
for (OriHalfedge he : face.halfedges) {
if (GeomUtil.Distance(he.tmpVec, new Line(sp, b)) < GeomUtil.EPS) {
continue;
}
if (Math.abs(b.y) < GeomUtil.EPS) {
Vector2d a = new Vector2d();
a.sub(he.tmpVec, sp);
a.y = -a.y;
he.tmpVec.y = a.y + sp.y;
} else {
Vector2d a = new Vector2d();
a.sub(he.tmpVec, sp);
he.tmpVec.y = ((b.y * b.y - b.x * b.x) * a.y + 2 * b.x * b.y * a.x) / b.lengthSquared();
he.tmpVec.x = b.x / b.y * a.y - a.x + b.x / b.y * he.tmpVec.y;
he.tmpVec.x += sp.x;
he.tmpVec.y += sp.y;
}
}
face.faceFront = !face.faceFront;
}
faces.remove(face);
faces.add(face);
}
}