package Connectivity; import java.util.ArrayList; import java.util.HashMap; import Command.LDrawPart; import Common.Matrix4; import Common.Vector3f; import ConnectivityEditor.Connectivity.AxleT; import LDraw.Support.MatrixMath; import LDraw.Support.type.LDrawGridTypeT; public class Axle extends Connectivity { int startCapped; int endCapped; float length; int grabbing; int requireGrabbing; public Axle() { } public int getstartCapped() { return startCapped; } public void setstartCapped(String startCapped) { this.startCapped = Integer.parseInt(startCapped); } public int getendCapped() { return endCapped; } public void setendCapped(String endCapped) { this.endCapped = Integer.parseInt(endCapped); } public int getgrabbing() { return grabbing; } public void setgrabbing(String grabbing) { this.grabbing = Integer.parseInt(grabbing); } public int getrequireGrabbing() { return requireGrabbing; } public void setrequireGrabbing(String requireGrabbing) { this.requireGrabbing = Integer.parseInt(requireGrabbing); } public float getlength() { return length; } public void setlength(String length) { this.length = Float.parseFloat(length) * 25; } @Override public String toString() { return super.toString(String.format("%d %d %f %d %d", startCapped, endCapped, length / 25.0f, grabbing, requireGrabbing)); } @Override public int parseString(String[] line) { int size = super.parseString(line); setstartCapped(line[size + 1]); setendCapped(line[size + 2]); setlength(line[size + 3]); setgrabbing(line[size + 4]); setrequireGrabbing(line[size + 5]); return 0; } @Override public String getName() { return "Axle"; } @Override public Matrix4 getTransformMatrixForSnapConnecting( Connectivity existingConn, Matrix4 initialTransformOfPart) { if (existingConn == null || (existingConn instanceof Axle == false)) return null; Matrix4 newTransform = getRotationMatrixForConnection(existingConn, initialTransformOfPart); if (newTransform != null) { Vector3f posDiff = getCurrentPos(initialTransformOfPart).sub( getCurrentPos(newTransform)); newTransform.translate(posDiff.x, posDiff.y, posDiff.z); Axle existingAxle = (Axle) existingConn; Vector3f realMatchingPosOfExistingConn = existingConn .getCurrentPos(); Vector3f realPosOfTestingConn = getCurrentPos(newTransform); Vector3f posDifferent = realPosOfTestingConn .sub(realMatchingPosOfExistingConn); Vector3f axleDirection = getDirectionVector(newTransform); float endPointOfExsiting = existingAxle.getDirectionVector() .scale(existingAxle.getlength()).dot(axleDirection); float minSlidingLength = 0; float maxSlidingLength = getlength(); boolean isSameDirection = false; if (endPointOfExsiting > 0) { isSameDirection = true; minSlidingLength = -(getlength() + existingAxle.getlength()); if (existingAxle.getstartCapped() != 0 || getendCapped() != 0) minSlidingLength = 0; maxSlidingLength = Math.max(existingAxle.getlength(), getlength()); if (getstartCapped() != 0 || existingAxle.getendCapped() != 0) { maxSlidingLength = Math.min(existingAxle.getlength(), getlength()); } } else { minSlidingLength = -(getlength() + existingAxle.getlength()); if (existingAxle.getendCapped() != 0) minSlidingLength = Math.max(minSlidingLength, -existingAxle.getlength()); if (getendCapped() != 0) minSlidingLength = Math.max(minSlidingLength, -getlength()); maxSlidingLength = 0; if (existingAxle.getstartCapped() != 0) { maxSlidingLength = Math.min(maxSlidingLength, -getlength()); } if (getstartCapped() != 0) maxSlidingLength = Math.min(maxSlidingLength, getlength()); } // if start or end capped, restrict the axle sliding. if (maxSlidingLength < minSlidingLength) return null; float projectedDistance = posDifferent.dot(axleDirection); // System.out.println("isSameDirection: " + isSameDirection); // System.out.println("Connectible Range: " + minSlidingLength + // ", " // + maxSlidingLength); // System.out.println("ProjectedDistance: " + projectedDistance); float distance = posDifferent.dot(posDifferent) - projectedDistance * projectedDistance; distance = (float) Math.sqrt(distance); if (MatrixMath.compareFloat(distance, LDrawGridTypeT.Coarse.getXZValue() * 2) > 0) return null; if (MatrixMath.compareFloat(projectedDistance, maxSlidingLength + LDrawGridTypeT.Coarse.getXZValue()) >= 0) return null; else if (MatrixMath.compareFloat(projectedDistance, maxSlidingLength) >= 0) projectedDistance = maxSlidingLength; else if (MatrixMath.compareFloat(projectedDistance, minSlidingLength - LDrawGridTypeT.Coarse.getXZValue()) < 0) return null; else if (MatrixMath.compareFloat(projectedDistance, minSlidingLength) < 0) projectedDistance = minSlidingLength; Vector3f posAdjust = realMatchingPosOfExistingConn .sub(realPosOfTestingConn); posAdjust = posAdjust.add(axleDirection.scale(projectedDistance)); newTransform.translate(posAdjust.x, posAdjust.y, posAdjust.z); } return newTransform; } @Override public ConnectivityTestResultT isConnectable(IConnectivity connector) { if (connector == null || (connector instanceof Axle == false)) return ConnectivityTestResultT.None; if (this.getClass().isInstance(connector) == true) { if (this.gettype() % 2 == 1) if (this.gettype() - 1 == ((Connectivity) connector).gettype()) return ConnectivityTestResultT.True; if (((Connectivity) connector).gettype() % 2 == 1) if (((Connectivity) connector).gettype() - 1 == this.gettype()) return ConnectivityTestResultT.True; } Axle other = (Axle) connector; AxleT thisType = AxleT.byValue(gettype()); AxleT otherType = AxleT.byValue(other.gettype()); if (thisType.toString().contains("Socket_O_") && otherType.toString().contains("Axle_")) return ConnectivityTestResultT.True; if (thisType.toString().contains("Socket_Cross_") && otherType.toString().contains("Axle_")) { return ConnectivityTestResultT.True; } if (thisType.toString().contains("Axle_O_") && (otherType.toString().contains("Socket_O_") || otherType .toString().contains("Socket_Cross_"))) return ConnectivityTestResultT.True; if (thisType.toString().contains("Axle_Cross_") && (otherType.toString().contains("Socket_O_") || otherType .toString().contains("Socket_Cross_"))) return ConnectivityTestResultT.True; return ConnectivityTestResultT.None; } @Override public ConnectivityTestResultT isConnectable(IConnectivity connector, Matrix4 partTransformMatrix) { ConnectivityTestResultT result = isConnectable(connector); if (result != ConnectivityTestResultT.True) return result; Matrix4 newTransformMatrix = getTransformMatrixForSnapConnecting( connector.getConnectivity(), partTransformMatrix); if (newTransformMatrix == null) { return ConnectivityTestResultT.False; } if (getCurrentPos(partTransformMatrix).sub( getCurrentPos(newTransformMatrix)).length() > 3f) { // System.out.println(getCurrentPos(partTransformMatrix).sub( // getCurrentPos(newTransformMatrix)).length()); return ConnectivityTestResultT.False; } return result; } @Override public Matrix4 getRotationMatrixForConnection(Connectivity existingConn, Matrix4 initialTransformMatrixOfPart) { Matrix4 newMatrix = new Matrix4(initialTransformMatrixOfPart); newMatrix.element[3][0] = newMatrix.element[3][1] = newMatrix.element[3][2] = 0; LDrawPart existingPart = existingConn.getParent(); Matrix4 existingConnTransformMatrix = Matrix4.multiply( existingConn.getTransformMatrix(), existingPart.transformationMatrix()); Matrix4 candidate = Matrix4.multiply(Matrix4.inverse(transformMatrix), existingConnTransformMatrix); for (int i = 0; i < 3; i++) candidate.element[3][i] = 0; Vector3f rotationVector = getRotationVector(candidate); Matrix4 inverseOfCandidate = new Matrix4(candidate); inverseOfCandidate.rotate((float) Math.toRadians(180), rotationVector); Matrix4 initMatrix = new Matrix4(initialTransformMatrixOfPart); for (int i = 0; i < 3; i++) initMatrix.element[3][i] = 0; Vector3f directionVector_init = getDirectionVector(initMatrix); Vector3f directionVector_candidate = getDirectionVector(candidate); Vector3f directionVector_icandidate = getDirectionVector(inverseOfCandidate); float dirDiff = (float) Math.acos(directionVector_init .dot(directionVector_candidate) / directionVector_candidate.length() / directionVector_init.length()); float dirDiff2 = (float) Math.acos(directionVector_init .dot(directionVector_icandidate) / directionVector_icandidate.length() / directionVector_init.length()); // System.out.println(getDirectionVector(initMatrix)); // System.out.println(getDirectionVector(candidate)); // System.out.println(getDirectionVector(inverseOfCandidate)); // System.out.println("DirectionVectorDiff: " + dirDiff + ", " + // dirDiff2); // System.out.println("#####################"); if (directionVector_init.equals(directionVector_candidate)) ; else if (directionVector_init.equals(directionVector_icandidate)) { candidate = inverseOfCandidate; } else if (dirDiff > dirDiff2) { candidate = inverseOfCandidate; } ArrayList<Matrix4> candidateForRotation = new ArrayList<Matrix4>(); candidateForRotation.add(candidate); for (int i = 0; i < 3; i++) { candidate = new Matrix4(candidate); candidate.rotate((float) Math.toRadians(90), existingConn.getDirectionVector()); candidateForRotation.add(candidate); } dirDiff = -1; // System.out.println("#########################"); for (Matrix4 matrix : candidateForRotation) { dirDiff2 = matrix .getDifferentValueForRotation(initialTransformMatrixOfPart); if (dirDiff < 0) { dirDiff = dirDiff2; newMatrix = matrix; } else if (dirDiff > dirDiff2 + 0.1f) { dirDiff = dirDiff2; newMatrix = matrix; } } return newMatrix; } private Vector3f getRotationVector(Matrix4 candidate) { Vector3f directionVector = getDirectionVector(candidate); // System.out.println("DirectionVector: "+directionVector); Vector3f rotationVector = null; switch (Direction6T.getDirectionOfTransformMatrix(Matrix4.multiply( transformMatrix, candidate))) { case X_Minus: case X_Plus: rotationVector = directionVector.cross(new Vector3f(0, 1, 0)); if (rotationVector.equals(new Vector3f())) rotationVector = new Vector3f(0, 1, 0); break; case Y_Minus: case Y_Plus: rotationVector = directionVector.cross(new Vector3f(0, 0, 1)); if (rotationVector.equals(new Vector3f())) rotationVector = new Vector3f(0, 0, 1); break; case Z_Minus: case Z_Plus: rotationVector = directionVector.cross(new Vector3f(1, 0, 0)); if (rotationVector.equals(new Vector3f())) rotationVector = new Vector3f(1, 0, 0); break; } // System.out.println("Rotation Vector: "+rotationVector); return rotationVector; } @Override public Vector3f getDirectionVector() { Vector3f directionVector = new Vector3f(0, 1, 0); Matrix4 tempMatrix = Matrix4.multiply(getTransformMatrix(), parent.transformationMatrix()); directionVector = MatrixMath.V3RotateByTransformMatrix(directionVector, tempMatrix); return directionVector.scale(-1); } @Override public Vector3f getDirectionVector(Matrix4 newTransformMatrix) { Vector3f directionVector = new Vector3f(0, 1, 0); Matrix4 tempMatrix = Matrix4.multiply(getTransformMatrix(), newTransformMatrix); directionVector = MatrixMath.V3RotateByTransformMatrix(directionVector, tempMatrix); return directionVector.scale(-1); } public boolean isRotatible() { if (getConnectedConnectivity() == null) return false; if (getConnectedConnectivity().size() == 0) return false; Axle cAxle = (Axle) getConnectedConnectivity().get(0); if (AxleT.byValue(gettype()).toString().startsWith("Socket_O")) return true; if (AxleT.byValue(gettype()).toString().startsWith("Axle_O")) return true; if (AxleT.byValue(cAxle.gettype()).toString().startsWith("Socket_O")) return true; if (AxleT.byValue(cAxle.gettype()).toString().startsWith("Axle_O")) return true; return false; } }