diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..cd29d98 --- /dev/null +++ b/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index 32858aa..0ed9f38 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,10 @@ .mtj.tmp/ # Package Files # -*.jar *.war *.ear # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +/build/ +*.settings diff --git a/.project b/.project new file mode 100644 index 0000000..89a000d --- /dev/null +++ b/.project @@ -0,0 +1,31 @@ + + + Knot-Renderer-Servlet + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.jdt.core.javanature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope new file mode 100644 index 0000000..92e666d --- /dev/null +++ b/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..0c68a61 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..ee26233 --- /dev/null +++ b/.settings/org.eclipse.wst.common.component @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..bf8f8be --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.name b/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/Testing_Files/3d_line_intersection_test.py b/Testing_Files/3d_line_intersection_test.py new file mode 100644 index 0000000..25ee45d --- /dev/null +++ b/Testing_Files/3d_line_intersection_test.py @@ -0,0 +1,462 @@ +import numpy as np +import math + +def closestDistanceBetweenLines(a0,a1,b0,b1,clampAll=False,clampA0=False,clampA1=False,clampB0=False,clampB1=False): + ''' Given two lines defined by numpy.array pairs (a0,a1,b0,b1) + Return distance, the two closest points, and their average + ''' + + # If clampAll=True, set all clamps to True + if clampAll: + clampA0=True + clampA1=True + clampB0=True + clampB1=True + + # Calculate denomitator + A = a1 - a0 + B = b1 - b0 + + normA = np.linalg.norm(B) + if normA == 0: + print ("HERE", b0, b1) + _A = A / np.linalg.norm(A) + _B = B / np.linalg.norm(B) + cross = np.cross(_A, _B); + + denom = np.linalg.norm(cross)**2 + + # If denominator is 0, lines are parallel: Calculate distance with a projection + # and evaluate clamp edge cases + if (denom == 0): + d0 = np.dot(_A,(b0-a0)) + d = np.linalg.norm(((d0*_A)+a0)-b0) + + # If clamping: the only time we'll get closest points will be when lines don't overlap at all. + # Find if segments overlap using dot products. + if clampA0 or clampA1 or clampB0 or clampB1: + d1 = np.dot(_A,(b1-a0)) + + # Is segment B before A? + if d0 <= 0 >= d1: + if clampA0 == True and clampB1 == True: + if np.absolute(d0) < np.absolute(d1): + return b0,a0,np.linalg.norm(b0-a0) + return b1,a0,np.linalg.norm(b1-a0) + + # Is segment B after A? + elif d0 >= np.linalg.norm(A) <= d1: + if clampA1 == True and clampB0 == True: + if np.absolute(d0) < np.absolute(d1): + return b0,a1,np.linalg.norm(b0-a1) + return b1,a1,np.linalg.norm(b1,a1) + + # If clamping is off, or segments overlapped, we have infinite results, just return position. + return None,None,d + + + + # Lines criss-cross: Calculate the dereminent and return points + t = (b0 - a0); + det0 = np.linalg.det([t, _B, cross]) + det1 = np.linalg.det([t, _A, cross]) + + t0 = det0/denom; + t1 = det1/denom; + + pA = a0 + (_A * t0); + pB = b0 + (_B * t1); + + # Clamp results to line segments if needed + if clampA0 or clampA1 or clampB0 or clampB1: + + if t0 < 0 and clampA0: + pA = a0 + elif t0 > np.linalg.norm(A) and clampA1: + pA = a1 + + if t1 < 0 and clampB0: + pB = b0 + elif t1 > np.linalg.norm(B) and clampB1: + pB = b1 + + d = np.linalg.norm(pA-pB) + + return pA,pB,d + +''' +Calculate the distance of the line segment between the start and end points +''' +def distanceBetweenTwoPoints(startPoint, endPoint): + x = endPoint[0] - startPoint[0] + y = endPoint[1] - startPoint[1] + z = endPoint[2] - startPoint[2] + return math.sqrt( x*x + y*y + z*z) +''' +A function used to reduce a line segment between the startPoint and the endPoint +by the recduce amount. So if you have a line that is 1 distance long and you want to +move both of its end points in by .25 this function will return the two new end points +and the length of the new line will be .5. +''' +def reduceLineSegment(startPoint, endPoint, reduceAmount): + vector = [] + ''' + Parametrize the line segment so that you can subtract the distace. Since the line + is parametrized its distance will be from 0 to 1. To reduce it by the desired amount + we need to figure out the proportion of the line compared to the parameter and then + subtract that amount. + ''' + vector.append(startPoint[0] - endPoint[0]) #Calculate Vector X + vector.append(startPoint[1] - endPoint[1]) #Calculate Vector Y + vector.append(startPoint[2] - endPoint[2]) #Calculate Vector Z + dist = distanceBetweenTwoPoints(startPoint, endPoint) + proportion = reduceAmount / dist + newX = endPoint[0] + proportion * vector[0] + newY = endPoint[1] + proportion * vector[1] + newZ = endPoint[2] + proportion * vector[2] + newEndPoint = np.array([newX, newY, newZ]) + + output = [] + newX = endPoint[0] + (1 - proportion) * vector[0] + newY = endPoint[1] + (1 - proportion) * vector[1] + newZ = endPoint[2] + (1 - proportion) * vector[2] + newStartPoint = np.array([newX, newY, newZ]) + output.append(newStartPoint) + output.append(newEndPoint) + return output +''' +Generates the set of second iterated forward difference operator. This comes from Professor Peters' and +Ji Li's paper. In the paper it is define. It shows up as a triangle with a subscript 2 and and set P next to it +''' +def secondIteratedForwardDifferenceOperator(listOfControlPoints, index): + deltaSub2Set = [] + numCtrlPts = len(listOfControlPoints) + #Need to wrap around and connect back to the first point + for i in range(0, numCtrlPts): #Add -1 to numCtrlPts to make it an open curve again + deltaSub2Ofi = listOfControlPoints[(i+2) % numCtrlPts][index] - (2 * listOfControlPoints[(i + 1) % numCtrlPts][index]) + listOfControlPoints[i][index] + deltaSub2Set.append(deltaSub2Ofi) + return deltaSub2Set +''' +This is the l1 - Norm for a set. The l1 norm is just the summation of the absolute value of all the +elements in the set. +''' +def l1Norm(setForNorming): + norm = 0 + i = 0 + for element in setForNorming: + norm += abs(element) + i+= 1 + print ('Terms in L1 Norm: ', i) + return norm +''' +This generates the Omega one value from Professor Peters' and Ji Li's paper. Omega one is used in combination with the delta from the Denne-Sullivan paper to figure out m1 +''' +def omegaOne(listOfControlPoints): + deltaSetX = secondIteratedForwardDifferenceOperator(listOfControlPoints, 0) + deltaSetY = secondIteratedForwardDifferenceOperator(listOfControlPoints, 1) + deltaSetZ = secondIteratedForwardDifferenceOperator(listOfControlPoints, 2) + + l1NormX = l1Norm(deltaSetX) + l1NormY = l1Norm(deltaSetY) + l1NormZ = l1Norm(deltaSetZ) + + return max(l1NormX, l1NormY, l1NormZ) +''' +This function generates the m1 value from Professor Peters' and Ji Li's paper. M1 is compared against +m2 and m3 to determine the number of iterations, j, that need to be done in order for the stick knot +to properly associate with its correct bezier curve +''' +def generateM1(omegaOne, delta): + omegaOneSquared = omegaOne * omegaOne + deltaSquared = delta * delta + intermediate = ((float(7)/float(16) * omegaOneSquared * (1 / deltaSquared)) - (float(1)/ float(7)) ) + logResult = math.log(intermediate, 2) + return math.ceil(logResult) + +''' +Generates the hodograph delta sub 2 set from Professor Peters' and Ji Li's paper. It is defined in the paper +''' +def generateHodographDeltaTwoSet(listOfControlPoints, index): + hodographDelta2Set = [] + numControlPoints = len(listOfControlPoints) + #Need to wrap around and connect back to the first point + for i in range(1, numControlPoints): #Add -1 to numControlPoints to make it an open curve again + hodographDeltaSub2Ofi = numControlPoints * (listOfControlPoints[(i + 2) % numControlPoints][index] - (3 * listOfControlPoints[(i+1)% numControlPoints][index]) + (3 * listOfControlPoints[i][index]) - listOfControlPoints[i - 1][index]) + hodographDelta2Set.append(hodographDeltaSub2Ofi) + return hodographDelta2Set + +''' +Found the same way as Omega One but uses the hodograph sets instead +''' +def omegaTwo(listOfControlPoints): + hodographX = generateHodographDeltaTwoSet(listOfControlPoints, 0) + hodographY = generateHodographDeltaTwoSet(listOfControlPoints, 1) + hodographZ = generateHodographDeltaTwoSet(listOfControlPoints, 2) + + l1NormX = l1Norm(hodographX) + l1NormY = l1Norm(hodographY) + l1NormZ = l1Norm(hodographZ) + + return max(l1NormX, l1NormY, l1NormZ) + +''' +The M2 value from Professor Peters' and Ji Li's paper. It is found using the hodograph set +''' +def generateM2(omegaTwo, lambdaVal, numCtrlPts): + j = 0 + #This gets the next int higher to what would be an unreducible logarithm + while( (numCtrlPts * math.pow(2, 3 * j) + math.pow(2, 2 * j)) < math.pow( omegaTwo/lambdaVal , 2)): + j += 1 + return j + +''' +The M3 value from Professor Peters' and Ji Li's paper. It is very similar to M2 except for the additional sin(pi/ 8) value +''' +def generateM3(omegaTwo, lambdaVal, numCtrlPts): + j = 0 + #This gets the next int higher to what would be an unreducible logarithm + while( ( numCtrlPts * math.pow(2, 3 * j) + math.pow(2, 2 * j)) < math.pow( (omegaTwo / (math.sin(math.pi / 8) * lambdaVal)), 2 ) ): + j+=1 + return j + +if __name__ == '__main__': + [testa, testb, testdist] = closestDistanceBetweenLines(np.array([0.0, 0.0, 0.0]), np.array([5.0, 0.0, 0.0]), np.array([6.0, 0.0, 1.0]), np.array([10.0, 0.0, 1.0]), clampAll=True) + print ("Done: ",testdist) + ''' + Add the line segments of the control polygon to a list + ''' + + segmentArray = [] + segmentArray.append(np.array([1.3076, -3.3320, -2.5072])) + segmentArray.append(np.array([-1.3841, 4.6826, 0.9135])) + segmentArray.append(np.array([-3.2983, -4.0567, 2.6862])) + segmentArray.append(np.array([-0.1233, 2.7683, -2.4636])) + segmentArray.append(np.array([3.9080, -4.5334, 1.2264])) + segmentArray.append(np.array([-3.9360, -0.4383, -0.9834])) + segmentArray.append(np.array([3.2182, 4.2961, 2.1125])) + [a, b, dist] = closestDistanceBetweenLines(segmentArray[0], segmentArray[1], segmentArray[2], segmentArray[3], clampAll = True) + print ('TEST: a is: ', a, ' b is: ', b, ' dist is: ', dist) + ''' + segmentArray = [] + segmentArray.append(np.array([1.28318923, -2.84316645, -2.25593748])) + segmentArray.append(np.array([1.139367593750000, -2.831090593750000, -2.293403687500000])) + segmentArray.append(np.array([0.971135187500000, -2.330181187500000, -2.079607375000000])) + segmentArray.append(np.array([0.802902781250000, -1.829271781250000, -1.865811062500000])) + segmentArray.append(np.array([0.634670375000000, -1.328362375000000, -1.652014750000000])) + segmentArray.append(np.array([0.466437968750000, -0.827452968750000, -1.438218437500000])) + segmentArray.append(np.array([0.298205562500000, -0.326543562500000, -1.224422125000000])) + segmentArray.append(np.array([0.129973156250000, 0.174365843750000, -1.010625812500000])) + segmentArray.append(np.array([-0.038259250000000, 0.675275250000000, -0.796829500000000])) + segmentArray.append(np.array([-0.206491656250000, 1.176184656250000, -0.583033187500000])) + segmentArray.append(np.array([-0.374724062500000, 1.677094062500000, -0.369236875000000])) + segmentArray.append(np.array([-0.542956468750000, 2.178003468750000, -0.155440562500000])) + segmentArray.append(np.array([-0.711188875000000, 2.678912875000000, 0.058355750000000])) + segmentArray.append(np.array([-0.879421281250000, 3.179822281250000, 0.272152062500000])) + segmentArray.append(np.array([-1.047653687500000, 3.680731687500000, 0.485948375000000])) + segmentArray.append(np.array([-1.215886093750000, 4.181641093750000, 0.699744687500000])) + segmentArray.append(np.array([-1.384118500000000, 4.682550500000000, 0.913541000000000])) + segmentArray.append(np.array([-1.50375, 4.13635, 1.02434])) + segmentArray.append(np.array([-1.62339, 3.59015, 1.13513])) + segmentArray.append(np.array([-1.74303, 3.04394, 1.24592])) + segmentArray.append(np.array([-1.86266, 2.49774, 1.35671])) + segmentArray.append(np.array([-1.9823, 1.95154, 1.4675])) + segmentArray.append(np.array([-2.10194, 1.40534, 1.57829])) + segmentArray.append(np.array([-2.22157, 0.859137, 1.68908])) + segmentArray.append(np.array([-2.34121, 0.312934, 1.79987])) + segmentArray.append(np.array([-2.46084, -0.233267, 1.91066])) + segmentArray.append(np.array([-2.58048, -0.779468, 2.02145])) + segmentArray.append(np.array([-2.70012, -1.32567, 2.13224])) + segmentArray.append(np.array([-2.81976, -1.87187, 2.24303])) + segmentArray.append(np.array([-2.9394, -2.41807, 2.35382])) + segmentArray.append(np.array([-3.05903, -2.96428, 2.46461])) + segmentArray.append(np.array([-3.17867, -3.51048, 2.5754])) + segmentArray.append(np.array([-3.2983075,-4.0566825,2.686189])) + segmentArray.append(np.array([-3.09987, -3.63013, 2.36433])) + segmentArray.append(np.array([-2.90143, -3.20357, 2.04247])) + segmentArray.append(np.array([-2.70299, -2.77701, 1.72061])) + segmentArray.append(np.array([-2.50455, -2.35045, 1.39875])) + segmentArray.append(np.array([-2.30611, -1.92389, 1.07689])) + segmentArray.append(np.array([-2.10767, -1.49733, 0.755026])) + segmentArray.append(np.array([-1.90924, -1.07077, 0.433165])) + segmentArray.append(np.array([-1.7108, -0.644214, 0.111303])) + segmentArray.append(np.array([-1.51236, -0.217655, -0.210558])) + segmentArray.append(np.array([-1.31393, 0.208903, -0.532419])) + segmentArray.append(np.array([-1.11549, 0.635462, -0.854279])) + segmentArray.append(np.array([-0.91705, 1.06202, -1.17614])) + segmentArray.append(np.array([-0.718613, 1.48858, -1.498])) + segmentArray.append(np.array([-0.520175, 1.91514, -1.81986])) + segmentArray.append(np.array([-0.321737, 2.3417, -2.14172])) + segmentArray.append(np.array([-0.1232995,2.768254,-2.463584])) + segmentArray.append(np.array([0.128657, 2.3119, -2.23296])) + segmentArray.append(np.array([0.380613, 1.85555, -2.00234])) + segmentArray.append(np.array([0.632569, 1.3992, -1.77172])) + segmentArray.append(np.array([0.884525, 0.942852, -1.5411])) + segmentArray.append(np.array([1.13648, 0.486501, -1.31047])) + segmentArray.append(np.array([1.38844, 0.0301505, -1.07985])) + segmentArray.append(np.array([1.64039, -0.4262, -0.849228])) + segmentArray.append(np.array([1.89235, -0.882551, -0.618607])) + segmentArray.append(np.array([2.14431, -1.3389, -0.387985])) + segmentArray.append(np.array([2.39626, -1.79525, -0.157363])) + segmentArray.append(np.array([2.64821, -2.2516, 0.0732595])) + segmentArray.append(np.array([2.90017, -2.70795, 0.303882])) + segmentArray.append(np.array([3.15212, -3.1643, 0.534504])) + segmentArray.append(np.array([3.40408, -3.62065, 0.765126])) + segmentArray.append(np.array([3.65604, -4.077, 0.995748])) + segmentArray.append(np.array([3.9079915,-4.533357,1.2263705])) + segmentArray.append(np.array([3.41775, -4.27741, 1.08826])) + segmentArray.append(np.array([2.9275, -4.02147, 0.950154])) + segmentArray.append(np.array([2.43725, -3.76553, 0.812045])) + segmentArray.append(np.array([1.947, -3.50958, 0.673937])) + segmentArray.append(np.array([1.45675, -3.25364, 0.535829])) + segmentArray.append(np.array([0.966502, -2.9977, 0.39772])) + segmentArray.append(np.array([0.476253, -2.74175, 0.259611])) + segmentArray.append(np.array([-0.0139957, -2.48581, 0.121503])) + segmentArray.append(np.array([-0.504244, -2.22986, -0.0166055])) + segmentArray.append(np.array([-0.994493, -1.97392, -0.154714])) + segmentArray.append(np.array([-1.48474, -1.71798, -0.292822])) + segmentArray.append(np.array([-1.97499, -1.46204, -0.430931])) + segmentArray.append(np.array([-2.46524, -1.2061, -0.56904])) + segmentArray.append(np.array([-2.95549, -0.950156, -0.707148])) + segmentArray.append(np.array([-3.44574, -0.694214, -0.845257])) + segmentArray.append(np.array([-3.935983,-0.438272,-0.983365])) + segmentArray.append(np.array([-3.48885, -0.142371, -0.789876])) + segmentArray.append(np.array([-3.04171, 0.153529, -0.596387])) + segmentArray.append(np.array([-2.59457, 0.449429, -0.402898])) + segmentArray.append(np.array([-2.14744, 0.745329, -0.209409])) + segmentArray.append(np.array([-1.7003, 1.04123, -0.01592])) + segmentArray.append(np.array([-1.25317, 1.33713, 0.177569])) + segmentArray.append(np.array([-0.806037, 1.63303, 0.371058])) + segmentArray.append(np.array([-0.358904, 1.92893, 0.564547])) + segmentArray.append(np.array([0.0882295, 2.22483, 0.758035])) + segmentArray.append(np.array([0.535363, 2.52073, 0.951523])) + segmentArray.append(np.array([0.982496, 2.81663, 1.14501])) + segmentArray.append(np.array([1.42963, 3.11253, 1.3385])) + segmentArray.append(np.array([1.87677, 3.40843, 1.53199])) + segmentArray.append(np.array([2.3239, 3.70433, 1.72548])) + segmentArray.append(np.array([2.77104, 4.00023, 1.91897])) + segmentArray.append(np.array([3.218174000000000, 4.296123000000000, 2.112459500000000])) + segmentArray.append(np.array([3.098763125000000, 3.819365312500000, 1.823730781250000])) + segmentArray.append(np.array([2.979352250000000, 3.342607625000000, 1.535002062500000])) + segmentArray.append(np.array([2.859941375000000, 2.865849937500000, 1.246273343750000])) + segmentArray.append(np.array([2.740530500000000, 2.389092250000000, 0.957544625000000])) + segmentArray.append(np.array([2.621119625000000, 1.912334562500000, 0.668815906250000])) + segmentArray.append(np.array([2.501708750000000, 1.435576875000000, 0.380087187500000])) + segmentArray.append(np.array([2.382297875000000, 0.958819187500000, 0.091358468750000])) + segmentArray.append(np.array([2.262887000000000, 0.482061500000000, -0.197370250000000])) + segmentArray.append(np.array([2.143476125000000, 0.005303812500000, -0.486098968750000])) + segmentArray.append(np.array([2.024065250000000, -0.471453875000000, -0.774827687500000])) + segmentArray.append(np.array([1.904654375000000, -0.948211562500000, -1.063556406250000])) + segmentArray.append(np.array([1.785243500000000, -1.424969250000000, -1.352285125000000])) + segmentArray.append(np.array([1.665832625000000, -1.901726937500000, -1.641013843750000])) + segmentArray.append(np.array([1.546421750000000, -2.378484625000000, -1.929742562500000])) + segmentArray.append(np.array([1.427010875000000, -2.855242312500000, -2.218471281250000])) + ''' + + minimums = [] + ''' + For each line segment, compare it to all non-incident (non-adjacent) line segments. Add the distances + to the minimums list. + ''' + numCtrlPointSegments = len(segmentArray) + for i in range(0, numCtrlPointSegments): + #print'i is: ' ,i + j = i + 2 + while j < numCtrlPointSegments: + if(i == 0 and (j+1)% numCtrlPointSegments == 0): + j+=1 + continue + #print 'j is: ', j, ' and j + 1 mod 7 is', (j+1)% numCtrlPointSegments + [a, b, dist] = closestDistanceBetweenLines(segmentArray[i],segmentArray[i+1],segmentArray[j],segmentArray[(j+1) % numCtrlPointSegments],clampAll=True) + print ('a is: ', a, ' b is: ', b, ' dist is: ', dist) + #print(dist) + minimums.append(dist) + j+= 1 + + ''' + Of all the distances, take the minimum. This is the r1 value from the Denne-Sullivan paper + ''' + r1 = min(minimums) + print ('r1 is: ', r1) + ''' + Epsilon is a constant that we have pre selected and can change + ''' + epsilon = 1.0 + ''' + r2 is also from the Denne-Sullivan paper + ''' + r2 = min(r1/2, epsilon/2) + print ('r2 is: ', r2) + + ''' + For each line segment of the control polygon, remove r2 from each end. + ''' + adjustedSegments = [] + for i in range(0, numCtrlPointSegments): + #print 'i is: ', i, 'and the Line Segment is ', segmentArray[i], segmentArray[(i+1)%numCtrlPointSegments] + [segment1, segment2] = reduceLineSegment(segmentArray[i], segmentArray[(i+1)%numCtrlPointSegments], r2) + adjustedSegments.append(segment1) + adjustedSegments.append(segment2) + #print 'The new segment is: ', segment1, segment2 + i+=1 + #At this point the segments have been reduced along the vertex. This means that the number of points is 2 times the number of control points. This is because the segments no longer share any common points between themselves + + numAdjustedPoints = len(adjustedSegments) + newMinimums = [] + + ''' + Then, for each reduced segment find the distance from that segment to all other reduced segments + ''' + i = 0 + while i + 3 < numAdjustedPoints: + j = i + 2 + while j+1 < numAdjustedPoints: + #print 'Comparing: ', adjustedSegments[i], adjustedSegments[i+1], 'to: ', adjustedSegments[j],adjustedSegments[j+1] + [a, b, dist] = closestDistanceBetweenLines(adjustedSegments[i],adjustedSegments[i+1],adjustedSegments[j],adjustedSegments[j+1],clampAll=True) + newMinimums.append(dist) + #print dist + j+=2 + i+=2 + + ''' + Take r3 (also from Denne-Sullivan) to be the minimum distance of all distances between line segments + ''' + r3 = min(newMinimums) + print ('r3 is: ', r3) + + ''' + r4 is also from Denne-Sullivan paper + ''' + r4 = r3 / 6 + print ('r4 is: ', r4) + + ''' + Finally, calculate delta (from Denne-Sullivan) + ''' + delta = r4 / 3 + print ('delta is: ', delta) + + omega1 = omegaOne(segmentArray) + print ('Omega One is: ', omega1) + m1 = generateM1(omega1, delta) + print ('M1 is: ', m1) + + segmentLengths = [] + for i in range(0, numCtrlPointSegments): + segmentLengths.append(distanceBetweenTwoPoints(segmentArray[i], segmentArray[(i +1) % numCtrlPointSegments])) + + lambdaVal = min(segmentLengths) + print ('Lambda is: ', lambdaVal) + omega2 = omegaTwo(segmentArray) + print ('Omega Two is: ', omega2) + m2 = generateM2(omega2, lambdaVal, numCtrlPointSegments) + print ('M2 is: ', m2) + + m3 = generateM3(omega2, lambdaVal, numCtrlPointSegments) + print ('M3 is: ', m3) + + + + + + + diff --git a/Testing_Files/TJP-4_1_stick-unknot-halved-1.curve b/Testing_Files/TJP-4_1_stick-unknot-halved-1.curve new file mode 100644 index 0000000..16f6d44 --- /dev/null +++ b/Testing_Files/TJP-4_1_stick-unknot-halved-1.curve @@ -0,0 +1,33 @@ + 1.307600000000000, -3.332000000000000, -2.507200000000000 + +-0.0765185, 0.67527525, -0.7968295 + + -1.384118500000000, 4.682550500000000, 0.913541000000000 +-1.44393425, 4.40945025, 0.9689405 + + +-1.50375, 4.13635, 1.02434 +-2.40102875, 0.03983375, 1.8552645 + + +-3.2983075,-4.0566825,2.686189 +-1.7108035, -0.64421425, 0.1113025 + + +-0.1232995,2.768254,-2.463584 +1.892346, -0.8825515, -0.61860675 + + +3.9079915,-4.533357,1.2263705 +-0.01399575, -2.4858145, 0.12150275 + + +-3.935983,-0.438272,-0.983365 +-0.3589045, 1.9289255, 0.56454725 + + +3.218174000000000, 4.296123000000000, 2.112459500000000 +2.262887, 0.4820615, -0.19737025 + + +1.307600000000000, -3.332000000000000, -2.507200000000000 diff --git a/Testing_Files/TJP-4_1_stick-unknot-halved-2.curve b/Testing_Files/TJP-4_1_stick-unknot-halved-2.curve new file mode 100644 index 0000000..083c2bd --- /dev/null +++ b/Testing_Files/TJP-4_1_stick-unknot-halved-2.curve @@ -0,0 +1,65 @@ + 1.307600000000000, -3.332000000000000, -2.507200000000000 + +0.634670375,-1.328362375,-1.65201475 + +-0.03825925,0.67527525,-0.7968295 +-0.711188875,2.678912875,0.05835575 + + + -1.384118500000000, 4.682550500000000, 0.913541000000000 +-1.414026375,4.546000375,0.94124075 + + +-1.44393425,4.40945025,0.9689405 +-1.473842125,4.272900125,0.99664025 + + +-1.50375,4.13635,1.02434 +-1.952389375,2.088091875,1.43980225 + + +-2.40102875,0.03983375,1.8552645 +-2.849668125,-2.008424375,2.27072675 + + +-3.2983075,-4.0566825,2.686189 +-2.5045555,-2.350448375,1.39874575 + + +-1.7108035,-0.64421425,0.1113025 +-0.9170515,1.062019875,-1.17614075 + + +-0.1232995,2.768254,-2.463584 +0.88452325,0.94285125,-1.541095375 + + +1.892346,-0.8825515,-0.61860675 +2.90016875,-2.70795425,0.303881875 + + +3.9079915,-4.533357,1.2263705 +1.946997875,-3.50958575,0.673936625 + + +-0.01399575,-2.4858145,0.12150275 +-1.974989375,-1.46204325,-0.430931125 + + +-3.935983,-0.438272,-0.983365 +-2.14744375,0.74532675,-0.209408875 + + +-0.3589045,1.9289255,0.56454725 +1.42963475,3.11252425,1.338503375 + + +3.218174000000000, 4.296123000000000, 2.112459500000000 +2.7405305,2.38909225,0.957544625 + + +2.262887,0.4820615,-0.19737025 +1.7852435,-1.42496925,-1.352285125 + + +1.307600000000000, -3.332000000000000, -2.507200000000000 diff --git a/Testing_Files/TJP-4_1_stick-unknot-halved-3.curve b/Testing_Files/TJP-4_1_stick-unknot-halved-3.curve new file mode 100644 index 0000000..92bb3e9 --- /dev/null +++ b/Testing_Files/TJP-4_1_stick-unknot-halved-3.curve @@ -0,0 +1,130 @@ + 1.307600000000000, -3.332000000000000, -2.507200000000000 + +0.9711351875,-2.3301811875,-2.079607375 + +0.634670375,-1.328362375,-1.65201475 +0.2982055625,-0.3265435625,-1.224422125 + + +-0.03825925,0.67527525,-0.7968295 +-0.3747240625,1.6770940625,-0.369236875 + + +-0.711188875,2.678912875,0.05835575 +-1.0476536875,3.6807316875,0.485948375 + + + -1.384118500000000, 4.682550500000000, 0.913541000000000 +-1.3990724375,4.6142754375,0.927390875 + + +-1.414026375,4.546000375,0.94124075 +-1.4289803125,4.4777253125,0.955090625 + + +-1.44393425,4.40945025,0.9689405 +-1.4588881875,4.3411751875,0.982790375 + + +-1.473842125,4.272900125,0.99664025 +-1.4887960625,4.2046250625,1.010490125 + + +-1.50375,4.13635,1.02434 +-1.7280696875,3.1122209375,1.232071125 + + +-1.952389375,2.088091875,1.43980225 +-2.1767090625,1.0639628125,1.647533375 + + +-2.40102875,0.03983375,1.8552645 +-2.6253484375,-0.9842953125,2.062995625 + + +-2.849668125,-2.008424375,2.27072675 +-3.0739878125,-3.0325534375,2.478457875 + + +-3.2983075,-4.0566825,2.686189 +-2.9014315,-3.2035654375,2.042467375 + + +-2.5045555,-2.350448375,1.39874575 +-2.1076795,-1.4973313125,0.755024125 + + +-1.7108035,-0.64421425,0.1113025 +-1.3139275,0.2089028125,-0.532419125 + + +-0.9170515,1.062019875,-1.17614075 +-0.5201755,1.9151369375,-1.819862375 + + +-0.1232995,2.768254,-2.463584 +0.380611875,1.855552625,-2.0023396875 + + +0.88452325,0.94285125,-1.541095375 +1.388434625,0.030149875,-1.0798510625 + + +1.892346,-0.8825515,-0.61860675 +2.396257375,-1.795252875,-0.1573624375 + + +2.90016875,-2.70795425,0.303881875 +3.404080125,-3.620655625,0.7651261875 + + +3.9079915,-4.533357,1.2263705 +2.9274946875,-4.021471375,0.9501535625 + + +1.946997875,-3.50958575,0.673936625 +0.9665010625,-2.997700125,0.3977196875 + + +-0.01399575,-2.4858145,0.12150275 +-0.9944925625,-1.973928875,-0.1547141875 + + +-1.974989375,-1.46204325,-0.430931125 +-2.9554861875,-0.950157625,-0.7071480625 + + +-3.935983,-0.438272,-0.983365 +-3.041713375,0.153527375,-0.5963869375 + + +-2.14744375,0.74532675,-0.209408875 +-1.253174125,1.337126125,0.1775691875 + + +-0.3589045,1.9289255,0.56454725 +0.535365125,2.520724875,0.9515253125 + + +1.42963475,3.11252425,1.338503375 +2.323904375,3.704323625,1.7254814375 + + +3.218174000000000, 4.296123000000000, 2.112459500000000 +2.97935225,3.342607625,1.5350020625 + + +2.7405305,2.38909225,0.957544625 +2.50170875,1.435576875,0.3800871875 + + +2.262887,0.4820615,-0.19737025 +2.02406525,-0.471453875,-0.7748276875 + + +1.7852435,-1.42496925,-1.352285125 +1.54642175,-2.378484625,-1.9297425625 + + +1.307600000000000, -3.332000000000000, -2.507200000000000 + diff --git a/Testing_Files/TJP-4_1_stick-unknot.curve b/Testing_Files/TJP-4_1_stick-unknot.curve new file mode 100644 index 0000000..e1d9f92 --- /dev/null +++ b/Testing_Files/TJP-4_1_stick-unknot.curve @@ -0,0 +1,16 @@ + %ignore me + 1.307600000000000, -3.332000000000000, -2.507200000000000 + -1.384118500000000, 4.682550500000000, 0.913541000000000 + + + +-3.2983075,-4.0566825,2.686189 + +-0.1232995,2.768254,-2.463584 + +3.9079915,-4.533357,1.2263705 + +-3.935983,-0.438272,-0.983365 + +3.218174000000000, 4.296123000000000, 2.112459500000000 + diff --git a/Testing_Files/TJP-4_1_stick-unknot_TEST.curve b/Testing_Files/TJP-4_1_stick-unknot_TEST.curve new file mode 100644 index 0000000..c7f3fb2 --- /dev/null +++ b/Testing_Files/TJP-4_1_stick-unknot_TEST.curve @@ -0,0 +1,28 @@ +1.3076, -3.332, -2.5072 + +-0.038259268, 0.6752752, -0.79682946 + +-1.3841186, 4.6825504, 0.913541 + +-2.341213, 0.31293392, 1.799865 + +-3.2983074, -4.0566826, 2.686189 + +-1.7108035, -0.6442143, 0.111302495 + +-0.1232995, 2.768254, -2.463584 + +1.8923459, -0.88255155, -0.61860675 + +3.9079914, -4.533357, 1.2263705 + +-0.013995767, -2.4858146, 0.12150273 + +-3.935983, -0.438272, -0.983365 + +-0.35890448, 1.9289255, 0.5645472 + +3.218174, 4.296123, 2.1124594 + +2.262887, 0.4820615, -0.19737029 + diff --git a/Testing_Files/TJP-4th-C1-high-precision.curve b/Testing_Files/TJP-4th-C1-high-precision.curve new file mode 100644 index 0000000..1ac6bbb --- /dev/null +++ b/Testing_Files/TJP-4th-C1-high-precision.curve @@ -0,0 +1,194 @@ + 1.28318923, -2.84316645, -2.25593748 + 1.139367593750000, -2.831090593750000, -2.293403687500000 + 0.971135187500000, -2.330181187500000, -2.079607375000000 + 0.802902781250000, -1.829271781250000, -1.865811062500000 + 0.634670375000000, -1.328362375000000, -1.652014750000000 + 0.466437968750000, -0.827452968750000, -1.438218437500000 + 0.298205562500000, -0.326543562500000, -1.224422125000000 + 0.129973156250000, 0.174365843750000, -1.010625812500000 + -0.038259250000000, 0.675275250000000, -0.796829500000000 + -0.206491656250000, 1.176184656250000, -0.583033187500000 + -0.374724062500000, 1.677094062500000, -0.369236875000000 + -0.542956468750000, 2.178003468750000, -0.155440562500000 + -0.711188875000000, 2.678912875000000, 0.058355750000000 + -0.879421281250000, 3.179822281250000, 0.272152062500000 + -1.047653687500000, 3.680731687500000, 0.485948375000000 + -1.215886093750000, 4.181641093750000, 0.699744687500000 + -1.384118500000000, 4.682550500000000, 0.913541000000000 + +-1.50375, 4.13635, 1.02434 + +-1.62339, 3.59015, 1.13513 + +-1.74303, 3.04394, 1.24592 + +-1.86266, 2.49774, 1.35671 + +-1.9823, 1.95154, 1.4675 + +-2.10194, 1.40534, 1.57829 + +-2.22157, 0.859137, 1.68908 + +-2.34121, 0.312934, 1.79987 + +-2.46084, -0.233267, 1.91066 + +-2.58048, -0.779468, 2.02145 + +-2.70012, -1.32567, 2.13224 + +-2.81976, -1.87187, 2.24303 + +-2.9394, -2.41807, 2.35382 + +-3.05903, -2.96428, 2.46461 + +-3.17867, -3.51048, 2.5754 + +-3.2983075,-4.0566825,2.686189 + +-3.09987, -3.63013, 2.36433 + +-2.90143, -3.20357, 2.04247 + +-2.70299, -2.77701, 1.72061 + +-2.50455, -2.35045, 1.39875 + +-2.30611, -1.92389, 1.07689 + +-2.10767, -1.49733, 0.755026 + +-1.90924, -1.07077, 0.433165 + +-1.7108, -0.644214, 0.111303 + +-1.51236, -0.217655, -0.210558 + +-1.31393, 0.208903, -0.532419 + +-1.11549, 0.635462, -0.854279 + +-0.91705, 1.06202, -1.17614 + +-0.718613, 1.48858, -1.498 + +-0.520175, 1.91514, -1.81986 + +-0.321737, 2.3417, -2.14172 + +-0.1232995,2.768254,-2.463584 + +0.128657, 2.3119, -2.23296 + +0.380613, 1.85555, -2.00234 + +0.632569, 1.3992, -1.77172 + +0.884525, 0.942852, -1.5411 + +1.13648, 0.486501, -1.31047 + +1.38844, 0.0301505, -1.07985 + +1.64039, -0.4262, -0.849228 + +1.89235, -0.882551, -0.618607 + +2.14431, -1.3389, -0.387985 + +2.39626, -1.79525, -0.157363 + +2.64821, -2.2516, 0.0732595 + +2.90017, -2.70795, 0.303882 + +3.15212, -3.1643, 0.534504 + +3.40408, -3.62065, 0.765126 + +3.65604, -4.077, 0.995748 + +3.9079915,-4.533357,1.2263705 + +3.41775, -4.27741, 1.08826 + +2.9275, -4.02147, 0.950154 + +2.43725, -3.76553, 0.812045 + +1.947, -3.50958, 0.673937 + +1.45675, -3.25364, 0.535829 + +0.966502, -2.9977, 0.39772 + +0.476253, -2.74175, 0.259611 + +-0.0139957, -2.48581, 0.121503 + +-0.504244, -2.22986, -0.0166055 + +-0.994493, -1.97392, -0.154714 + +-1.48474, -1.71798, -0.292822 + +-1.97499, -1.46204, -0.430931 + +-2.46524, -1.2061, -0.56904 + +-2.95549, -0.950156, -0.707148 + +-3.44574, -0.694214, -0.845257 + +-3.935983,-0.438272,-0.983365 + +-3.48885, -0.142371, -0.789876 + +-3.04171, 0.153529, -0.596387 + +-2.59457, 0.449429, -0.402898 + +-2.14744, 0.745329, -0.209409 + +-1.7003, 1.04123, -0.01592 + +-1.25317, 1.33713, 0.177569 + +-0.806037, 1.63303, 0.371058 + +-0.358904, 1.92893, 0.564547 + +0.0882295, 2.22483, 0.758035 + +0.535363, 2.52073, 0.951523 + +0.982496, 2.81663, 1.14501 + +1.42963, 3.11253, 1.3385 + +1.87677, 3.40843, 1.53199 + +2.3239, 3.70433, 1.72548 + +2.77104, 4.00023, 1.91897 + + + 3.218174000000000, 4.296123000000000, 2.112459500000000 + 3.098763125000000, 3.819365312500000, 1.823730781250000 + 2.979352250000000, 3.342607625000000, 1.535002062500000 + 2.859941375000000, 2.865849937500000, 1.246273343750000 + 2.740530500000000, 2.389092250000000, 0.957544625000000 + 2.621119625000000, 1.912334562500000, 0.668815906250000 + 2.501708750000000, 1.435576875000000, 0.380087187500000 + 2.382297875000000, 0.958819187500000, 0.091358468750000 + 2.262887000000000, 0.482061500000000, -0.197370250000000 + 2.143476125000000, 0.005303812500000, -0.486098968750000 + 2.024065250000000, -0.471453875000000, -0.774827687500000 + 1.904654375000000, -0.948211562500000, -1.063556406250000 + 1.785243500000000, -1.424969250000000, -1.352285125000000 + 1.665832625000000, -1.901726937500000, -1.641013843750000 + 1.546421750000000, -2.378484625000000, -1.929742562500000 + 1.427010875000000, -2.855242312500000, -2.218471281250000 + 1.28318923, -2.84316645, -2.25593748 diff --git a/Testing_Files/test.curve b/Testing_Files/test.curve new file mode 100644 index 0000000..27f824e --- /dev/null +++ b/Testing_Files/test.curve @@ -0,0 +1,17 @@ + %ignore me + 1.307600000000000, -3.332000000000000, -2.507200000000000 + -1.384118500000000, 4.682550500000000, 0.913541000000000 + + + +-3.2983075,-4.0566825,2.686189 + +-0.1232995,2.768254,-2.463584 + +3.9079915,-4.533357,1.2263705 + +-3.935983,-0.438272,-0.983365 + +3.218174000000000, 4.296123000000000, 2.112459500000000 + 1.307600000000000, -3.332000000000000, -2.507200000000000 + diff --git a/WebContent/META-INF/MANIFEST.MF b/WebContent/META-INF/MANIFEST.MF new file mode 100644 index 0000000..254272e --- /dev/null +++ b/WebContent/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/junit_tests/com/knotrenderer/modeltest/BezierCurveTest.java b/junit_tests/com/knotrenderer/modeltest/BezierCurveTest.java new file mode 100644 index 0000000..5b0cb00 --- /dev/null +++ b/junit_tests/com/knotrenderer/modeltest/BezierCurveTest.java @@ -0,0 +1,80 @@ +package com.knotrenderer.modeltest; + +import static org.junit.Assert.*; + +import java.util.ArrayList; + +import org.junit.Test; + +import com.knotrenderer.model.BezierCurve; +import com.knotrenderer.model.Curve; +import com.knotrenderer.util.CurveLoader; +import com.knotrenderer.utiltest.TestUtils; + +import processing.core.PVector; + +public class BezierCurveTest +{ +// private static final String CURVE_PATH = "/Users/peterzaffetti/UC/Knot-Renderer-Processing/Testing_Files/test.curve"; +// private static final String CURVE_PATH = "D:/Peter/College_Grad_School/Independent_Study_Spring_2016_Cont/Knot-Renderer-Processing/Testing_Files/test.curve"; + private static final String CURVE_PATH = "D:/Peter/College_Grad_School/Independent_Study_Spring_2016_Cont/Knot-Renderer-Processing/Testing_Files/TJP-4th-C1-high-precision.curve"; + + private static final Curve CURVE = CurveLoader.loadCurveFromFile(CURVE_PATH); + private static final BezierCurve BEZIER_CURVE = new BezierCurve(CURVE.getKnotPoints()); + + private static final PVector CONTROL_POINT_0 = CURVE.getKnotPoints().get(0); + private static final PVector CONTROL_POINT_1 = CURVE.getKnotPoints().get(1); + private static final PVector CONTROL_POINT_2 = CURVE.getKnotPoints().get(2); + private static final PVector CONTROL_POINT_3 = CURVE.getKnotPoints().get(3); + private static final PVector CONTROL_POINT_4 = CURVE.getKnotPoints().get(4); + private static final PVector CONTROL_POINT_5 = CURVE.getKnotPoints().get(5); + private static final PVector CONTROL_POINT_6 = CURVE.getKnotPoints().get(6); + private static final PVector CONTROL_POINT_7 = CURVE.getKnotPoints().get(7); + + + @Test + public void calculateBezierCurveValueTestRecursive_StartAndEndEqual() + { + final PVector startPoint = BEZIER_CURVE.getCurveValueRecursively(0); + final PVector endPoint = BEZIER_CURVE.getCurveValueRecursively(1); + assertTrue("Start and End point were not the same. Start point was " + startPoint + " and End point was: " + endPoint, + startPoint.equals(endPoint)); + } + + @Test + public void calculateBezierCurveValueTestSummation_StartAndEndEqual() + { + final PVector startPoint = BEZIER_CURVE.getCurveValueFromSummationExpansion(0); + final PVector endPoint = BEZIER_CURVE.getCurveValueFromSummationExpansion(1); + assertTrue("Start and End point were not the same. Start point was " + startPoint + " and End point was: " + endPoint, + startPoint.equals(endPoint)); + } + + /** + * A test to make sure that both recursive generation and summation generation of the values is the same. + */ + @Test + public void calculateBezierCurveValue_EqualityOfBothMethods() + { + final double epsilon = 0.1; + final ArrayList recursivePoints = new ArrayList(); + final ArrayList summationPoints = new ArrayList(); + + for(double i = 0; i <= 1; i+=0.001) + { + recursivePoints.add(BEZIER_CURVE.getCurveValueRecursively(i)); + summationPoints.add(BEZIER_CURVE.getCurveValueFromSummationExpansion(i)); + } + + System.out.println(recursivePoints.size()); + for(int i = 0; i < recursivePoints.size(); i++) + { + PVector recursivePoint = recursivePoints.get(i); + PVector summationPoint = summationPoints.get(i); + System.out.println("i: " + i + " Recursive: " + recursivePoint + " Summation: " + summationPoint); + assertTrue("Points were not equal. Recursive Point was: " + recursivePoint + " and Summation Point was: " + summationPoint, + TestUtils.areVectorsEqualWithEpsilon(recursivePoint, summationPoint, epsilon)); + } + } + +} diff --git a/junit_tests/com/knotrenderer/modeltest/LineSegmentTest.java b/junit_tests/com/knotrenderer/modeltest/LineSegmentTest.java new file mode 100644 index 0000000..1036813 --- /dev/null +++ b/junit_tests/com/knotrenderer/modeltest/LineSegmentTest.java @@ -0,0 +1,117 @@ +package com.knotrenderer.modeltest; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.knotrenderer.model.LineSegment; + +import processing.core.PVector; + + +public class LineSegmentTest { + private final double epsilon = 0.0001; + + /** + * Begin: + * LineSegment Closest distance tests- these test will determine the closest distance (line segment) given two line segments. + * It currently only tests with clamping turned on. Clamping is where you only want a value on either line + * segment (you resulting line segment must have its end points on either line segment). + * + */ + @Test + public void closestDistanceTest() { + final double expectedLength = 0.924675529894; + + PVector vector1 = new PVector(1.3076f, -3.3320f, -2.5072f); + PVector vector2 = new PVector(-1.3842f, 4.6826f, 0.9135f); + PVector vector3 = new PVector(-3.2982f,-4.0567f, 2.6862f); + PVector vector4 = new PVector(-0.1233f, 2.7683f, -2.4636f); + + LineSegment testSegment1 = new LineSegment(vector1, vector2); + LineSegment testSegment2 = new LineSegment(vector3, vector4); + LineSegment resultSegment = testSegment1.closestDistanceToLineSegment(testSegment2); + assertTrue(resultSegment.getLength() - epsilon < expectedLength && resultSegment.getLength() + epsilon > expectedLength); + } + + @Test + public void closestDistanceTest_Parallel() + { + final double expectedLength = 2.0; + + PVector vector1 = new PVector(0.f, 0.f, 0.f); + PVector vector2 = new PVector(1.f, 0.f, 0.f); + PVector vector3 = new PVector(0.f, 2.f, 0.f); + PVector vector4 = new PVector(1.f, 2.f, 0.f); + + LineSegment testSegment1 = new LineSegment(vector1, vector2); + LineSegment testSegment2 = new LineSegment(vector3, vector4); + LineSegment resultSegment = testSegment1.closestDistanceToLineSegment(testSegment2); + assertTrue(resultSegment.getLength() - epsilon < expectedLength && resultSegment.getLength() + epsilon > expectedLength); + } + + @Test + public void closestDistanceTest_SharedEndPoint() + { + final double expectedLength = 0.0; + + PVector vector1 = new PVector(0.f, 0.f, 0.f); + PVector vector2 = new PVector(1.f, 0.f, 0.f); + PVector vector3 = new PVector(0.f, 0.f, 0.f); + PVector vector4 = new PVector(0.f, 2.f, 0.f); + + LineSegment testSegment1 = new LineSegment(vector1, vector2); + LineSegment testSegment2 = new LineSegment(vector3, vector4); + LineSegment resultSegment = testSegment1.closestDistanceToLineSegment(testSegment2); + assertTrue(resultSegment.getLength() - epsilon < expectedLength && resultSegment.getLength() + epsilon > expectedLength); + } + + @Test + public void closestDistanceTest_OrthogonalStraightZ() + { + final double expectedLength = 2.0; + + PVector vector1 = new PVector(0.f, 0.f, 0.f); + PVector vector2 = new PVector(1.f, 0.f, 0.f); + PVector vector3 = new PVector(0.5f, 2.f, -2.f); + PVector vector4 = new PVector(0.5f, 2.f, 2.f); + + LineSegment testSegment1 = new LineSegment(vector1, vector2); + LineSegment testSegment2 = new LineSegment(vector3, vector4); + LineSegment resultSegment = testSegment1.closestDistanceToLineSegment(testSegment2); + assertTrue(resultSegment.getLength() - epsilon < expectedLength && resultSegment.getLength() + epsilon > expectedLength); + } + + + @Test + public void closestDistanceTest_OrthogonalSlantingZ() + { + final double expectedLength = 5.0990195135; + + PVector vector1 = new PVector(0.f, 0.f, 0.f); + PVector vector2 = new PVector(1.f, 0.f, 0.f); + PVector vector3 = new PVector(2.f, 5.f, -2.f); + PVector vector4 = new PVector(2.f, 5.f, 2.f); + + LineSegment testSegment1 = new LineSegment(vector1, vector2); + LineSegment testSegment2 = new LineSegment(vector3, vector4); + LineSegment resultSegment = testSegment1.closestDistanceToLineSegment(testSegment2); + assertTrue(resultSegment.getLength() - epsilon < expectedLength && resultSegment.getLength() + epsilon > expectedLength); + } + + @Test + public void closestDistanceTest_SameLine() + { + final double expectedLength = 0; + + PVector vector1 = new PVector(0.f, 0.f, 0.f); + PVector vector2 = new PVector(1.f, 0.f, 0.f); + + LineSegment testSegment1 = new LineSegment(vector1, vector2); + LineSegment testSegment2 = new LineSegment(vector1, vector2); + LineSegment resultSegment = testSegment1.closestDistanceToLineSegment(testSegment2); + assertTrue(resultSegment.getLength() - epsilon < expectedLength && resultSegment.getLength() + epsilon > expectedLength); + } + + +} diff --git a/junit_tests/com/knotrenderer/utiltest/CurveLoaderTest.java b/junit_tests/com/knotrenderer/utiltest/CurveLoaderTest.java new file mode 100644 index 0000000..a5d7641 --- /dev/null +++ b/junit_tests/com/knotrenderer/utiltest/CurveLoaderTest.java @@ -0,0 +1,16 @@ +package com.knotrenderer.utiltest; + +import static org.junit.Assert.*; + +import org.junit.Assert; +import org.junit.Test; + +public class CurveLoaderTest { + + @Test + public void test() { +// fail("Not yet implemented"); + Assert.assertTrue(true); + } + +} diff --git a/junit_tests/com/knotrenderer/utiltest/MathUtilTest.java b/junit_tests/com/knotrenderer/utiltest/MathUtilTest.java new file mode 100644 index 0000000..45126c2 --- /dev/null +++ b/junit_tests/com/knotrenderer/utiltest/MathUtilTest.java @@ -0,0 +1,81 @@ +package com.knotrenderer.utiltest; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.knotrenderer.model.BezierCurve; +import com.knotrenderer.model.Curve; +import com.knotrenderer.util.CurveLoader; +import com.knotrenderer.util.MathUtil; + +import processing.core.PMatrix3D; +import processing.core.PVector; + +public class MathUtilTest +{ + private static final String CURVE_PATH = "/Users/peterzaffetti/UC/Knot-Renderer-Processing/Testing_Files/test.curve"; +// private static final String CURVE_PATH = "D:/Peter/College_Grad_School/Independent_Study_Spring_2016_Cont/Knot-Renderer-Processing/Testing_Files/test.curve"; + private static final Curve CURVE = CurveLoader.loadCurveFromFile(CURVE_PATH); + private static final BezierCurve BEZIER_CURVE = new BezierCurve(CURVE.getKnotPoints()); + + private static final PVector CONTROL_POINT_0 = CURVE.getKnotPoints().get(0); + private static final PVector CONTROL_POINT_1 = CURVE.getKnotPoints().get(1); + private static final PVector CONTROL_POINT_2 = CURVE.getKnotPoints().get(2); + private static final PVector CONTROL_POINT_3 = CURVE.getKnotPoints().get(3); + private static final PVector CONTROL_POINT_4 = CURVE.getKnotPoints().get(4); + private static final PVector CONTROL_POINT_5 = CURVE.getKnotPoints().get(5); + private static final PVector CONTROL_POINT_6 = CURVE.getKnotPoints().get(6); + private static final PVector CONTROL_POINT_7 = CURVE.getKnotPoints().get(7); + + private static final double epsilon = 1.0; + + @Test + public void l1NormTest() + { + double expectedNorm = 452.3; + double[] values = {100.0, -50.0, 15.4, 17.3, -257.3, 12.4}; + double norm = MathUtil.calculateL1Norm(values); + assertTrue(TestUtils.isEqualWithEpsilon(norm, expectedNorm, epsilon)); + } + + @Test + public void l2NormTest() + { + double expectedNorm = 264.57513110645; + double[] values = {100.0, 100.0, 100.0, 100.0, 100.0, 100.d /*pretty cool - you can specify double by putting the d*/, 100.0}; + double norm = MathUtil.calculateL2Norm(values); + assertTrue(TestUtils.isEqualWithEpsilon(norm, expectedNorm, epsilon)); + } + + @Test + public void determinant3x3Test() + { + PMatrix3D testMatrix = new PMatrix3D(6, 1, 1, 0, 4, -2, 5, 0, 2, 8, 7, 0, 0, 0, 0, 0); + double determinant = MathUtil.calculate3x3Determinant(testMatrix); + assertTrue(determinant == -306); + } + + @Test + public void binomialCoefficientAsDoubleTest() + { + double expectedResult = 535983370403809682970d; + double actualResult = MathUtil.binomialCoefficientAsDouble(100, 20); + assertTrue(TestUtils.isEqualWithEpsilon(expectedResult, actualResult, 100000)); //PDZ- this has to be 100000 since it loses precision in scientific notation for some reason + + expectedResult = 1; + actualResult = MathUtil.binomialCoefficientAsDouble(100, 0); + assertTrue(actualResult == expectedResult); + + actualResult = MathUtil.binomialCoefficientAsDouble(100, 100); + assertTrue(actualResult == expectedResult); + } + + @Test + public void binomialCoefficientAsDoubleTest_ControlPoints() + { + + } + + +} diff --git a/junit_tests/com/knotrenderer/utiltest/OptimumIterationGeneratorTest.java b/junit_tests/com/knotrenderer/utiltest/OptimumIterationGeneratorTest.java new file mode 100644 index 0000000..d315a7d --- /dev/null +++ b/junit_tests/com/knotrenderer/utiltest/OptimumIterationGeneratorTest.java @@ -0,0 +1,258 @@ +package com.knotrenderer.utiltest; + +import java.util.ArrayList; + +import org.junit.Assert; +import org.junit.Test; + +import com.knotrenderer.model.LineSegment; +import com.knotrenderer.util.OptimumIterationGenerator; + +import processing.core.PVector; + +public class OptimumIterationGeneratorTest +{ + private static final double epsilon = 0.001; + private static final double userEpsilon = 1.00; + private static PVector vector1 = new PVector(1.307600000000000f, -3.332000000000000f, -2.507200000000000f); + private static PVector vector2 = new PVector(-1.384118500000000f, 4.682550500000000f, 0.913541000000000f); + private static PVector vector3 = new PVector(-3.2983075f, -4.0566825f, 2.686189f); + private static PVector vector4 = new PVector(-0.1232995f, 2.768254f, -2.463584f); + private static PVector vector5 = new PVector(3.9079915f, -4.533357f, 1.2263705f); + private static PVector vector6 = new PVector(-3.935983f, -0.438272f, -0.983365f); + private static PVector vector7 = new PVector(3.218174000000000f, 4.296123000000000f, 2.112459500000000f); + private static PVector vector8 = new PVector(1.307600000000000f, -3.332000000000000f, -2.507200000000000f); + + + private static ArrayList knotPoints = new ArrayList(); + static{ + knotPoints.add(vector1); + knotPoints.add(vector2); + knotPoints.add(vector3); + knotPoints.add(vector4); + knotPoints.add(vector5); + knotPoints.add(vector6); + knotPoints.add(vector7); + knotPoints.add(vector8); + } + + private static ArrayList uniqueControlPoints = new ArrayList(); + static{ + uniqueControlPoints.add(vector1); + uniqueControlPoints.add(vector2); + uniqueControlPoints.add(vector3); + uniqueControlPoints.add(vector4); + uniqueControlPoints.add(vector5); + uniqueControlPoints.add(vector6); + uniqueControlPoints.add(vector7); + } + + private static ArrayList lineSegments = new ArrayList(); + static{ + lineSegments.add(new LineSegment(vector1, vector2)); + lineSegments.add(new LineSegment(vector2, vector3)); + lineSegments.add(new LineSegment(vector3, vector4)); + lineSegments.add(new LineSegment(vector4, vector5)); + lineSegments.add(new LineSegment(vector5, vector6)); + lineSegments.add(new LineSegment(vector6, vector7)); +// lineSegments.add(new LineSegment(vector7, vector1)); + lineSegments.add(new LineSegment(vector7, vector8)); + }; + + @Test + public void shortenLineSegmentTest_xOnly() throws Exception + { + PVector testSegmentStart = new PVector(0, 0, 0); + PVector testSegmentEnd = new PVector(6, 0, 0); + LineSegment testSegment = new LineSegment(testSegmentStart, testSegmentEnd); + LineSegment shortenedSegment = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 2.); + Assert.assertTrue("The shortened line segment end points aren't correct", + shortenedSegment.getStartPoint().equals(new PVector(2.f, 0.f, 0.f)) + && shortenedSegment.getEndPoint().equals(new PVector(4.f, 0.f, 0.f))); + + Assert.assertTrue("The shortened line segment isn't the correct length", shortenedSegment.getLength() == 2.0); + + LineSegment shortenedSegment2 = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 1.); + Assert.assertTrue("The shortened line segment end points aren't correct", + shortenedSegment2.getStartPoint().equals(new PVector(1.f, 0.f, 0.f)) + && shortenedSegment2.getEndPoint().equals(new PVector(5.f, 0.f, 0.f))); + + Assert.assertTrue("The shortened line segment isn't the correct length", shortenedSegment2.getLength() == 4.0); + } + + + @Test + public void shortenLineSegmentTest_yOnly() throws Exception + { + PVector testSegmentStart = new PVector(0, 0, 0); + PVector testSegmentEnd = new PVector(0, 10, 0); + LineSegment testSegment = new LineSegment(testSegmentStart, testSegmentEnd); + LineSegment shortenedSegment = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 3.5); + Assert.assertTrue("The shortened line segment end points aren't correct", + shortenedSegment.getStartPoint().equals(new PVector(0.f, 3.5f, 0.f)) + && shortenedSegment.getEndPoint().equals(new PVector(0.f, 6.5f, 0.f))); + + Assert.assertTrue("The shortened line segment isn't the correct length", shortenedSegment.getLength() == 3.0); + + LineSegment shortenedSegment2 = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 0.); + Assert.assertTrue("The shortened line segment end points aren't correct", + shortenedSegment2.getStartPoint().equals(new PVector(0.f, 0.f, 0.f)) + && shortenedSegment2.getEndPoint().equals(new PVector(0.f, 10.f, 0.f))); + + Assert.assertTrue("The shortened line segment isn't the correct length", shortenedSegment2.getLength() == 10.0); + } + + @Test + public void shortenLineSegmentTest_zOnly() throws Exception + { + PVector testSegmentStart = new PVector(0, 0, -100); + PVector testSegmentEnd = new PVector(0, 0, 0); + LineSegment testSegment = new LineSegment(testSegmentStart, testSegmentEnd); + LineSegment shortenedSegment = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 15.0); + Assert.assertTrue("The shortened line segment end points aren't correct", + shortenedSegment.getStartPoint().equals(new PVector(0.f, 0.f, -85.f)) + && shortenedSegment.getEndPoint().equals(new PVector(0.f, 0.f, -15.f))); + + Assert.assertTrue("The shortened line segment isn't the correct length", shortenedSegment.getLength() == 70.0); + + LineSegment shortenedSegment2 = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 50.0); + Assert.assertTrue("The shortened line segment end points aren't correct", + shortenedSegment2.getStartPoint().equals(new PVector(0.f, 0.f, -50.f)) + && shortenedSegment2.getEndPoint().equals(new PVector(0.f, 0.f, -50.f))); + + Assert.assertTrue("The shortened line segment isn't the correct length", shortenedSegment2.getLength() == 0.0); + } + + @Test + public void shortenLineSegmentTest_xyz() throws Exception + { + PVector expectedStartVector = new PVector(.758f, 1.516f, -1.0612f); + PVector expectedEndVector = new PVector(4.242f, 8.484f, -5.9388f); + double expectedLength = 9.1909; + + PVector testSegmentStart = new PVector(0, 0, 0); + PVector testSegmentEnd = new PVector(5, 10, -7); + LineSegment testSegment = new LineSegment(testSegmentStart, testSegmentEnd); + LineSegment shortenedSegment = OptimumIterationGenerator.shortenLineSegmentEnds(testSegment, 2.0); + Assert.assertTrue("The shortened line segment end points aren't correct", + TestUtils.areVectorsEqualWithEpsilon(shortenedSegment.getStartPoint(), expectedStartVector, epsilon) + && TestUtils.areVectorsEqualWithEpsilon(shortenedSegment.getEndPoint(), expectedEndVector, epsilon)); + + Assert.assertTrue("The shortened line segment isn't the correct length", + shortenedSegment.getLength() + epsilon > expectedLength && + shortenedSegment.getLength() - epsilon < expectedLength); + } + + @Test + public void r1Test() + { + final double expectedR1 = 0.257633722007; + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + Assert.assertTrue("R1 wasn't correctly calculated", TestUtils.isEqualWithEpsilon(r1, expectedR1, epsilon)); + } + + @Test + public void r2Test() + { + final double expectedR2 = 0.128816861003; + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + double r2 = Math.min(r1 / 2, userEpsilon / 2); //PDZ- 1.00 is the user selected epsilon from the paper + Assert.assertTrue("R2 wasn't correctly calculated. R2 was: " + r2, TestUtils.isEqualWithEpsilon(r2, expectedR2, epsilon)); + } + + @Test + public void r3Test() throws Exception + { + final double expectedR3 = 0.0576477635811; + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + double r2 = Math.min(r1 / 2, userEpsilon / 2); + ArrayList shortenedCurveSegments = OptimumIterationGenerator.shortenSegments(lineSegments, r2); + double r3 = OptimumIterationGenerator.calculateMinimumDistanceBetweenAllSegments(shortenedCurveSegments); + Assert.assertTrue("R3 wasn't correctly calculated", TestUtils.isEqualWithEpsilon(r3, expectedR3, epsilon)); + } + + @Test + public void r4Test() throws Exception + { + final double expectedR4 = 0.00960796059685; + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + double r2 = Math.min(r1 / 2, userEpsilon/ 2); + ArrayList shortenedCurveSegments = OptimumIterationGenerator.shortenSegments(lineSegments, r2); + double r3 = OptimumIterationGenerator.calculateMinimumDistanceBetweenAllSegments(shortenedCurveSegments); + double r4 = r3 / 6; + Assert.assertTrue("R4 wasn't correctly calculated", TestUtils.isEqualWithEpsilon(r4, expectedR4, epsilon)); + } + + @Test + public void deltaTest() throws Exception + { + final double expectedDelta = 0.00320265353228; + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + double r2 = Math.min(r1 / 2, userEpsilon/ 2); + ArrayList shortenedCurveSegments = OptimumIterationGenerator.shortenSegments(lineSegments, r2); + double r3 = OptimumIterationGenerator.calculateMinimumDistanceBetweenAllSegments(shortenedCurveSegments); + double r4 = r3 / 6; + double delta = r4 / 3; + Assert.assertTrue("Delta wasn't correctly calculated", TestUtils.isEqualWithEpsilon(delta, expectedDelta, epsilon)); + } + + @Test + public void omegaOneTest() throws Exception + { + final double expectedOmegaOne = 86.4862; + double omegaOne = OptimumIterationGenerator.calculateOmegaOne(uniqueControlPoints, true); + Assert.assertTrue("Omega one wasn't correctly calculated", TestUtils.isEqualWithEpsilon(omegaOne, expectedOmegaOne, epsilon)); + } + + @Test + public void m1Test() throws Exception + { + final double expectedM1 = 29; + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + double r2 = Math.min(r1 / 2, userEpsilon/ 2); + ArrayList shortenedCurveSegments = OptimumIterationGenerator.shortenSegments(lineSegments, r2); + double r3 = OptimumIterationGenerator.calculateMinimumDistanceBetweenAllSegments(shortenedCurveSegments); + double r4 = r3 / 6; + double delta = r4 / 3; + double omegaOne = OptimumIterationGenerator.calculateOmegaOne(uniqueControlPoints, true); + int m1 = OptimumIterationGenerator.calculateM1(omegaOne, delta); + Assert.assertTrue("M1 wasn't correctly calculated", m1 == expectedM1); + } + + @Test + public void omegaTwoTest() + { + final double expectedOmegaTwo = 975.0804; + final double epsilon = 0.01; + double omegaTwo = OptimumIterationGenerator.calculateOmegaTwo(uniqueControlPoints); + Assert.assertTrue("Omega two wasn't correctly calculated", TestUtils.isEqualWithEpsilon(omegaTwo, expectedOmegaTwo, epsilon)); + } + + @Test + public void lambdaTest() + { + final double expectedLambda = 9.12030317807473; + double lambda = OptimumIterationGenerator.calculateLambda(lineSegments); + Assert.assertTrue("Lambda wasn't correctly calculated", TestUtils.isEqualWithEpsilon(lambda, expectedLambda, epsilon)); + } + + @Test + public void m2Test() + { + int expectedM2 = 4; + double omegaTwo = OptimumIterationGenerator.calculateOmegaTwo(knotPoints); + double lambda = OptimumIterationGenerator.calculateLambda(lineSegments); + int m2 = OptimumIterationGenerator.calculateM2(lineSegments, omegaTwo, lambda); + Assert.assertTrue("M2 wasn't correctly calculated", m2 == expectedM2); + } + + @Test + public void m3Test() + { + int expectedM3 = 5; + double omegaTwo = OptimumIterationGenerator.calculateOmegaTwo(knotPoints); + double lambda = OptimumIterationGenerator.calculateLambda(lineSegments); + int m3 = OptimumIterationGenerator.calculateM3(lineSegments, omegaTwo, lambda); + Assert.assertTrue("M3 wasn't correctly calculated", m3 == expectedM3); + } +} \ No newline at end of file diff --git a/junit_tests/com/knotrenderer/utiltest/TestUtils.java b/junit_tests/com/knotrenderer/utiltest/TestUtils.java new file mode 100644 index 0000000..d92c56b --- /dev/null +++ b/junit_tests/com/knotrenderer/utiltest/TestUtils.java @@ -0,0 +1,30 @@ +package com.knotrenderer.utiltest; + +import processing.core.PVector; + +/** + * A utility class for tests. This contains methods which allows for easier testing and less + * duplicate/redundant code. + * @author Peter + * + */ +public class TestUtils +{ + public static boolean areVectorsExactlyEqual(PVector vector1, PVector vector2) + { + return areVectorsEqualWithEpsilon(vector1, vector2, 0.0); + } + + public static boolean areVectorsEqualWithEpsilon(PVector vector1, PVector vector2, double epsilon) + { + return isEqualWithEpsilon(vector1.x, vector2.x, epsilon) + && isEqualWithEpsilon(vector1.y, vector2.y, epsilon) + && isEqualWithEpsilon(vector1.z, vector2.z, epsilon); + } + + public static boolean isEqualWithEpsilon(double value1, double value2, double epsilon) + { + return value1 + epsilon > value2 && value1 - epsilon < value2; + } + +} diff --git a/junit_tests/com/knotrenderer/utiltest/UnboxUtilsTest.java b/junit_tests/com/knotrenderer/utiltest/UnboxUtilsTest.java new file mode 100644 index 0000000..49d3f4a --- /dev/null +++ b/junit_tests/com/knotrenderer/utiltest/UnboxUtilsTest.java @@ -0,0 +1,14 @@ +package com.knotrenderer.utiltest; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class UnboxUtilsTest +{ + @Test + public static void unboxDoublesFromArrayList() + { + + } +} diff --git a/libs/controlP5.jar b/libs/controlP5.jar new file mode 100644 index 0000000..eb84880 Binary files /dev/null and b/libs/controlP5.jar differ diff --git a/libs/core.jar b/libs/core.jar new file mode 100644 index 0000000..99f0ba3 Binary files /dev/null and b/libs/core.jar differ diff --git a/libs/export.txt b/libs/export.txt new file mode 100644 index 0000000..88d0bc2 --- /dev/null +++ b/libs/export.txt @@ -0,0 +1,11 @@ +# If you want to support more platforms, visit jogamp.org to get the +# natives libraries for the platform in question (i.e. Solaris). + +name = OpenGL + +application.macosx=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-macosx-universal.jar,gluegen-rt-natives-macosx-universal.jar +application.windows32=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-windows-i586.jar,gluegen-rt-natives-windows-i586.jar +application.windows64=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-windows-amd64.jar,gluegen-rt-natives-windows-amd64.jar +application.linux32=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-i586.jar,gluegen-rt-natives-linux-i586.jar +application.linux64=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-amd64.jar,gluegen-rt-natives-linux-amd64.jar +application.linux-armv6hf=core.jar,jogl-all.jar,gluegen-rt.jar,jogl-all-natives-linux-armv6hf.jar,gluegen-rt-natives-linux-armv6hf.jar \ No newline at end of file diff --git a/libs/gluegen-rt-natives-linux-amd64.jar b/libs/gluegen-rt-natives-linux-amd64.jar new file mode 100644 index 0000000..a2466f4 Binary files /dev/null and b/libs/gluegen-rt-natives-linux-amd64.jar differ diff --git a/libs/gluegen-rt-natives-linux-armv6hf.jar b/libs/gluegen-rt-natives-linux-armv6hf.jar new file mode 100644 index 0000000..5ef0673 Binary files /dev/null and b/libs/gluegen-rt-natives-linux-armv6hf.jar differ diff --git a/libs/gluegen-rt-natives-linux-i586.jar b/libs/gluegen-rt-natives-linux-i586.jar new file mode 100644 index 0000000..914a259 Binary files /dev/null and b/libs/gluegen-rt-natives-linux-i586.jar differ diff --git a/libs/gluegen-rt-natives-macosx-universal.jar b/libs/gluegen-rt-natives-macosx-universal.jar new file mode 100644 index 0000000..15df5e8 Binary files /dev/null and b/libs/gluegen-rt-natives-macosx-universal.jar differ diff --git a/libs/gluegen-rt-natives-windows-amd64.jar b/libs/gluegen-rt-natives-windows-amd64.jar new file mode 100644 index 0000000..517fb84 Binary files /dev/null and b/libs/gluegen-rt-natives-windows-amd64.jar differ diff --git a/libs/gluegen-rt-natives-windows-i586.jar b/libs/gluegen-rt-natives-windows-i586.jar new file mode 100644 index 0000000..1c393b7 Binary files /dev/null and b/libs/gluegen-rt-natives-windows-i586.jar differ diff --git a/libs/gluegen-rt.jar b/libs/gluegen-rt.jar new file mode 100644 index 0000000..742fdb2 Binary files /dev/null and b/libs/gluegen-rt.jar differ diff --git a/libs/jogl-all-natives-linux-amd64.jar b/libs/jogl-all-natives-linux-amd64.jar new file mode 100644 index 0000000..e57b8c7 Binary files /dev/null and b/libs/jogl-all-natives-linux-amd64.jar differ diff --git a/libs/jogl-all-natives-linux-armv6hf.jar b/libs/jogl-all-natives-linux-armv6hf.jar new file mode 100644 index 0000000..5aea1b2 Binary files /dev/null and b/libs/jogl-all-natives-linux-armv6hf.jar differ diff --git a/libs/jogl-all-natives-linux-i586.jar b/libs/jogl-all-natives-linux-i586.jar new file mode 100644 index 0000000..88a27ce Binary files /dev/null and b/libs/jogl-all-natives-linux-i586.jar differ diff --git a/libs/jogl-all-natives-macosx-universal.jar b/libs/jogl-all-natives-macosx-universal.jar new file mode 100644 index 0000000..c65ea99 Binary files /dev/null and b/libs/jogl-all-natives-macosx-universal.jar differ diff --git a/libs/jogl-all-natives-windows-amd64.jar b/libs/jogl-all-natives-windows-amd64.jar new file mode 100644 index 0000000..9577bf1 Binary files /dev/null and b/libs/jogl-all-natives-windows-amd64.jar differ diff --git a/libs/jogl-all-natives-windows-i586.jar b/libs/jogl-all-natives-windows-i586.jar new file mode 100644 index 0000000..4439f1d Binary files /dev/null and b/libs/jogl-all-natives-windows-i586.jar differ diff --git a/libs/jogl-all.jar b/libs/jogl-all.jar new file mode 100644 index 0000000..e2c7b44 Binary files /dev/null and b/libs/jogl-all.jar differ diff --git a/libs/junit.jar b/libs/junit.jar new file mode 100644 index 0000000..3a7fc26 Binary files /dev/null and b/libs/junit.jar differ diff --git a/libs/org.hamcrest.core_1.3.0.v201303031735.jar b/libs/org.hamcrest.core_1.3.0.v201303031735.jar new file mode 100644 index 0000000..0adbff1 Binary files /dev/null and b/libs/org.hamcrest.core_1.3.0.v201303031735.jar differ diff --git a/src/com/knotrenderer/model/BezierCurve.java b/src/com/knotrenderer/model/BezierCurve.java new file mode 100644 index 0000000..5fbbc67 --- /dev/null +++ b/src/com/knotrenderer/model/BezierCurve.java @@ -0,0 +1,104 @@ +package com.knotrenderer.model; + +import java.math.BigInteger; +import java.util.ArrayList; + +import com.knotrenderer.util.MathUtil; + +import processing.core.PVector; + +public class BezierCurve +{ + private final PVector[] controlPoints; + private final PVector[] coefficients; + + public BezierCurve(ArrayList controlPoints) + { + this(controlPoints.toArray(new PVector[controlPoints.size()])); + } + + public BezierCurve(PVector[] controlPoints) + { + this.controlPoints = controlPoints; + coefficients = new PVector[controlPoints.length]; + generateBezierCoefficients(); + } + + private void generateBezierCoefficients() + { + for(int k = 0; k < controlPoints.length; k++) + { + PVector vector = controlPoints[k].copy(); + coefficients[k] = vector.mult((float) MathUtil.binomialCoefficientAsDouble(controlPoints.length-1, k)); + System.out.println(coefficients[k]); + } + } + + public PVector getCurveValueFromSummationExpansion(double t) + { + double n = coefficients.length; + double initialOneMinusTFactor = Math.pow((1 - t), n); + PVector value = coefficients[0].copy().mult((float) initialOneMinusTFactor); + + /* + * PDZ- We only want to go to the second to last point (hence coefficient.length - 1) because the last term will be zero if the + * (1-t)^n-i is left in. It is undefined and will ruin the value if we leave it. + */ + + for(int i = 1; i < coefficients.length-1; i++) + { + double parametricFactor = Math.pow((1 - t), n-i) * Math.pow(t, i); + PVector partialSum = coefficients[i].copy().mult((float)parametricFactor); + value.add(partialSum); + } + + //PDZ- finally, add the product from the last (or end) term (t^n * PN) + double finalOneMinusTFactor = Math.pow(t, n); + PVector endControlPointProduct = coefficients[coefficients.length-1].copy().mult((float)finalOneMinusTFactor); + value.add(endControlPointProduct); + return value; + } + + /** + * Given a parametrized point (between 0 and 1) return the value of the Bezier curve at that point. + *
Since the Bezier curve is represented in a parametric form spanning from 0 to 1 you must + * provide a point in the range. + * @param parametrizedPoint + * @return {@link PVector} - point on the Bezier curve at the parametrized value + */ + public PVector getCurveValueRecursively(double parametrizedPoint) + { + return getCurveValueRecursively(parametrizedPoint, 0, controlPoints.length - 1); + } + + /** + * Given a parametrized point (between 0 and 1) return the value of the Bezier curve at that point. + *
Since the Bezier curve is represented in a parametric form spanning from 0 to 1 you must + * provide a point in the range. + * @param parametrizedPoint + * @param numberOfControlPoints + * @return {@link PVector} - point on the Bezier curve at the parametrized value + */ + public PVector getCurveValueRecursively(double parametrizedPoint, int leftControlPointIndex, int rightControlPointIndex) + { + /** + * TODO: PDZ- A very nice to have would be to load Bezier curves from a file. Since + * expanding the entire curve out in it's explicit form is going to get expensive, + * especially if it is calculated every single time, it would be good to have a file + * which stores the expanded form. Given the number of points on the Bezier curve it + * should check to see if a generated file (or line in a file) is already in existence. + * Otherwise, it should generate/add the calculated value. + */ + if(parametrizedPoint < 0 || parametrizedPoint > 1) + { + return null; + } + if(leftControlPointIndex == rightControlPointIndex) + { + return controlPoints[leftControlPointIndex].copy(); + } + PVector leftRecurseBranch = getCurveValueRecursively(parametrizedPoint, leftControlPointIndex, rightControlPointIndex - 1).mult((float)(1 - parametrizedPoint)); + PVector rightRecurseBranch = getCurveValueRecursively(parametrizedPoint, leftControlPointIndex + 1, rightControlPointIndex).mult((float)parametrizedPoint); + return leftRecurseBranch.add(rightRecurseBranch); + } +} diff --git a/src/com/knotrenderer/model/Curve.java b/src/com/knotrenderer/model/Curve.java new file mode 100644 index 0000000..abf9d67 --- /dev/null +++ b/src/com/knotrenderer/model/Curve.java @@ -0,0 +1,241 @@ +package com.knotrenderer.model; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; + +import com.knotrenderer.util.OptimumIterationGenerator; + +import processing.core.PVector; + +public class Curve +{ + private final String curvePath; + + /** + * PDZ- knotPoints is the set of points from the curve file- this file has the start and end point the same since + * for a closed Bezier curve the start and point are the same. + */ + private final ArrayList knotPoints; + /** + * PDZ- uniqueControlPoints is the set of UNIQUE control points for the Bezier curve. This remove the end point + * of the knotPoints set since that will mess up some calculations (like the closest distance to segment when generating + * the OptimumIterations) + */ + private final ArrayList uniqueControlPoints; + + private final ArrayList lineSegments; + private final double epsilon = 1.0; + private final int[] optimumIterations; + + public Curve(ArrayList knotPoints, String curvePath) + { + this.curvePath = curvePath; + this.knotPoints = knotPoints; + uniqueControlPoints = new ArrayList(knotPoints.size()); + + /** + * PDZ- Copy the knot points to the uniqueControlPoints and remove the duplicate control point. + * Since the Bezier curve's start and end point in the file are the same (this is because the curve is closed) + * we need to remove the last point since it is a duplicate. The duplicity causes issues when calculating closest + * distances and Omega Two. + */ + for(PVector vector : knotPoints) + { + uniqueControlPoints.add(vector.copy()); + } + /** + * PDZ- Check to see if the curve is closed. If it isn't, report it to the user + */ + if(uniqueControlPoints.get(0).equals(uniqueControlPoints.get(uniqueControlPoints.size()-1))) + { + uniqueControlPoints.remove(uniqueControlPoints.size()-1); + } + else + { + System.out.println("Curve isn't closed"); + } + + this.lineSegments = new ArrayList(); + generateLineSegments(); + optimumIterations = calculateOptimumIterations(); + } + + /** + * Returns the knot points of the curve. This returns a new instance of an {@link ArrayList} which + * contains new instances of every {@link PVector} in {@link #knotPoints} since {@link PVector}s + * modify the original object whenever vector arithmetic is applied to the {@link PVector} + * @return + */ + public ArrayList getKnotPoints() + { + ArrayList points = new ArrayList(); + for(PVector vector : knotPoints) + { + points.add(vector.copy()); + } + return points; + } + + /** + * @return int[3] - the three M values from Professor Peter's and Ji Li's paper. + */ + public int[] getOptimumIterations() + { + return optimumIterations; + } + + /** + * + * @return int - M1 which was generated from the algorithm in Professor Peters' and Ji Li's paper. + */ + public int getM1() + { + return optimumIterations[0]; + } + + /** + * + * @return int - M1 which was generated from the algorithm in Professor Peters' and Ji Li's paper. + */ + public int getM2() + { + return optimumIterations[1]; + } + + /** + * + * @return int - M1 which was generated from the algorithm in Professor Peters' and Ji Li's paper. + */ + public int getM3() + { + return optimumIterations[2]; + } + + /** + * Generates the line segments from the points in the curve. The line segments consist of consecutive points. For + * example, (p1, p2), (p2, p3), ... are line segments where p1, p2, etc. are points. + */ + private void generateLineSegments() + { + int numPoints = knotPoints.size(); + for(int i = 0; i < numPoints - 1; i++) + { + // if(i == (numPoints - 1)) + // { + // lineSegments.add(new LineSegment(knotPoints.get(i), knotPoints.get(0))); //Close off the curve + // } + // else + // { + // lineSegments.add(new LineSegment(knotPoints.get(i), knotPoints.get(i + 1))); + // } + lineSegments.add(new LineSegment(knotPoints.get(i), knotPoints.get(i + 1))); + } + } + + private int[] calculateOptimumIterations() + { + /** + * r1, r2, r3, r4, delta, are from the Denne-Sullivan paper; + * omega1, omega2, lambda, m1, m2, m3 are all from the Peters' paper + */ + double r1 = OptimumIterationGenerator.calculateMinimumDistanceBetweenNonAdjacentSegments(lineSegments); + System.out.println("r1 is: " + r1); + + double r2 = Math.min(r1 / 2, epsilon / 2); + System.out.println("r2 is: " + r2); + + double r3 = -1; //This shouldn't ever remain -1 unless there is an exception below + try + { + ArrayList shortenedCurveSegments = OptimumIterationGenerator.shortenSegments(lineSegments, r2); + r3 = OptimumIterationGenerator.calculateMinimumDistanceBetweenAllSegments(shortenedCurveSegments); + } + catch(Exception e) + { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + System.out.println("r3 is: " + r3); + + double r4 = r3 / 6; + System.out.println("r4 is: " + r4); + + double delta = r4 / 3; + System.out.println("delta is: " + delta); + + double omegaOne = OptimumIterationGenerator.calculateOmegaOne(this.uniqueControlPoints, true); + System.out.println("omega one is: " + omegaOne); + + int m1 = OptimumIterationGenerator.calculateM1(omegaOne, delta); + System.out.println("m1 is: " + m1); + + double omegaTwo = OptimumIterationGenerator.calculateOmegaTwo(this.uniqueControlPoints); + System.out.println("omega two is: " + omegaTwo); + + double lambda = OptimumIterationGenerator.calculateLambda(lineSegments); + System.out.println("lambda is: " + lambda); + + int m2 = OptimumIterationGenerator.calculateM2(lineSegments, omegaTwo, lambda); + System.out.println("m2 is: " + m2); + + int m3 = OptimumIterationGenerator.calculateM3(lineSegments, omegaTwo, lambda); + System.out.println("m3 is: " + m3); + + return new int[]{m1, m2, m3}; + } + + /** + * Generates the next iteration of the curve. This is done by taking each line segment + * and finding the midpoint of the segment. The new curve consists of all the curve points + * from the original curve plus the midpoints that were generated. + * @return + */ + public Curve generateNextSubdivision() + { + final ArrayList pointsToWrite = new ArrayList(); + final ArrayList subdivisionPoints = new ArrayList(); + + String[] curveSplit = curvePath.split(".curve"); + String newPath = curveSplit[0] + "_TEST.curve"; + Path filePath = Paths.get(newPath); + + /** + * PDZ- Iterate through all the points and find the midpoint. + * Don't add the end point since on the next iteration of the loop + * it becomes the start point and we add it then. This works since if we didn't + * do this we would have one point twice which would mess up shortening the segments later. + */ + for(int i = 0; i < knotPoints.size(); i++) + { + final PVector startPoint = knotPoints.get(i); + final PVector endPoint = knotPoints.get((i + 1) % knotPoints.size()); + float midPointX = (startPoint.x + endPoint.x) / 2; + float midPointY = (startPoint.y + endPoint.y) / 2; + float midPointZ = (startPoint.z + endPoint.z) / 2; + PVector midPoint = new PVector(midPointX, midPointY, midPointZ); + + subdivisionPoints.add(startPoint); + subdivisionPoints.add(midPoint); + + String startPointString = startPoint.x + ", " + startPoint.y + ", " + startPoint.z + "\n"; + String midPointString = midPoint.x + ", " + midPoint.y + ", " + midPoint.z + "\n"; + pointsToWrite.add(startPointString); + pointsToWrite.add(midPointString); + } + + try { + Files.write(filePath, pointsToWrite, Charset.forName("UTF-8")); + } catch (IOException e) { + e.printStackTrace(); + } + + return new Curve(subdivisionPoints, newPath); + } + + +} diff --git a/src/com/knotrenderer/model/LineSegment.java b/src/com/knotrenderer/model/LineSegment.java new file mode 100644 index 0000000..4dcdaf3 --- /dev/null +++ b/src/com/knotrenderer/model/LineSegment.java @@ -0,0 +1,200 @@ +package com.knotrenderer.model; + +import com.knotrenderer.util.MathUtil; +import processing.core.PMatrix3D; +import processing.core.PVector; + +public class LineSegment +{ + private final PVector startPoint; + private final PVector endPoint; + private final double length; + + public LineSegment(PVector startPoint, PVector endPoint) + { + this.startPoint = startPoint; + this.endPoint = endPoint; + this.length = calculateLength(); + } + + /** + * A special private constructor which returns a nulled out line segment with a length. This + * is used when two lines are being compared for the closest distance between the two and the + * segments are found to be parallel. In such a case there are infinite lines that can be + * taken between the lines but all having the same distance. + * @param distance + */ + private LineSegment(double distance) + { + startPoint = null; + endPoint = null; + this.length = distance; + } + + /** + * @return a copy of the start point segment. Since all operations on PVectors will modify the original + * we want to make sure we send a copy so that this instance isn't modified + */ + public PVector getStartPoint() + { + return this.startPoint.copy(); + } + + /** + * @return a copy of the end point segment. Since all operations on PVectors will modify the original + * we want to make sure we send a copy so that this instance isn't modified + */ + public PVector getEndPoint() + { + return this.endPoint.copy(); + } + + public double getLength() + { + return this.length; + } + + public LineSegment closestDistanceToLineSegment(LineSegment segment) + { + return this.closestDistanceToLineSegment(segment, true); + } + + public LineSegment closestDistanceToLineSegment(LineSegment segment, boolean clampAll) + { + return this.closestDistanceToLineSegment(segment, true, true, true, true); + } + + public LineSegment closestDistanceToLineSegment(LineSegment segment, boolean clampThisSegmentStart, boolean clampThisSegmentEnd, boolean clampComparingSegmentStart, boolean clampComparingSegmentEnd) + { + /* + * PDZ - This comes from the Python version in 3d_line_intersection_test.py (not the best name since it does more than that) but + * + */ + //Renamed for convenience + LineSegment segmentA = this; //A0 and A1 + LineSegment segmentB = segment; //B0 and B1 + + PVector segAStartPoint = segmentA.getStartPoint(); //A0 + PVector segAEndPoint = segmentA.getEndPoint(); //A1 + PVector segBStartPoint = segmentB.getStartPoint(); //B0 + PVector segBEndPoint = segmentB.getEndPoint(); //B1 + + boolean clampThisSegStart = clampThisSegmentStart; //clampA0 + boolean clampThisSegEnd = clampThisSegmentEnd; //clampA1 + boolean clampComparingSegStart = clampComparingSegmentStart; //clampB0 + boolean clampComparingSegEnd = clampComparingSegmentEnd; //clampB1 + + //Calculate the denominator + PVector segADenom = segAEndPoint.copy().sub(segAStartPoint); //A + PVector segBDenom = segBEndPoint.copy().sub(segBStartPoint); //B + + float normA = (float) MathUtil.calculateL2Norm(segADenom); + float normB = (float) MathUtil.calculateL2Norm(segBDenom); + PVector segANormalized = segADenom.copy().normalize(); //_A + PVector segBNormalized = segBDenom.copy().normalize(); //_B + + PVector crossProduct = segANormalized.cross(segBNormalized); + + double denom = Math.pow(MathUtil.calculateL2Norm(crossProduct), 2); + + //lines are parallel so we need to calculate the distance with a projection and evaluate clamp edge cases + if(denom < 0.0000001) //Since it is a double you can't check == 0 + { + float d0 = segANormalized.dot(segBStartPoint.sub(segAStartPoint)); + PVector d = (segANormalized.copy().mult(d0).add(segAStartPoint)).sub(segBStartPoint); + double dNormalized = MathUtil.calculateL2Norm(d); + + //If clamping: the only time the points will have a distance is if they aren't the same line - check to see if they overlap (on the line) using dot product + if(clampThisSegStart || clampThisSegEnd || clampComparingSegStart || clampComparingSegEnd) + { + PVector bEndDiffAStartVector = segBEndPoint.copy().sub(segAStartPoint); + double dist1 = segANormalized.dot(bEndDiffAStartVector); + + //Check to see if segment B is before segment A + if(d0 <= 0.0000001 && 0.0000001 >= dist1) + { + if(clampThisSegStart && clampComparingSegEnd) + { + if(Math.abs(d0) < Math.abs(dist1)) + { + return new LineSegment(segBStartPoint, segAStartPoint); + } + return new LineSegment(segBEndPoint, segAStartPoint); + } + } + //Check to see if segment B is after A + else if(d0 >= normA && normA <= dist1) + { + if(clampThisSegEnd && clampComparingSegStart) + { + if(Math.abs(d0) < Math.abs(dist1)) + { + return new LineSegment(segBStartPoint, segAEndPoint); + } + return new LineSegment(segBEndPoint, segAEndPoint); + } + } + } + //Otherwise, the segments are overlapping (or clamping is off) so just return the distance 0 since there are an infinite amount of points that could be closest + //This happens when they are parallel or the same line + return new LineSegment(dNormalized); + } + + //Else - lines are crossing: calculate the determinant and return the segment + + PVector t = segBStartPoint.copy().sub(segAStartPoint); + final float IGNORED_VALUE = 0; + PMatrix3D normalizedBMatrix = new PMatrix3D(t.x, segBNormalized.x, crossProduct.x, IGNORED_VALUE, + t.y, segBNormalized.y, crossProduct.y, IGNORED_VALUE, + t.z, segBNormalized.z, crossProduct.z, IGNORED_VALUE, + IGNORED_VALUE, IGNORED_VALUE, IGNORED_VALUE, IGNORED_VALUE); + + PMatrix3D normalizedAMatrix = new PMatrix3D(t.x, segANormalized.x, crossProduct.x, IGNORED_VALUE, + t.y, segANormalized.y, crossProduct.y, IGNORED_VALUE, + t.z, segANormalized.z, crossProduct.z, IGNORED_VALUE, + IGNORED_VALUE, IGNORED_VALUE, IGNORED_VALUE, IGNORED_VALUE); + + float det0 = (float) MathUtil.calculate3x3Determinant(normalizedBMatrix); + float det1 = (float) MathUtil.calculate3x3Determinant(normalizedAMatrix); + + float t0 = (float) (det0 / denom); + float t1 = (float) (det1 / denom); + + PVector pointA = segAStartPoint.copy().add(segANormalized.mult(t0)); + PVector pointB = segBStartPoint.copy().add(segBNormalized.mult(t1)); + + //Clamp if needed: + if(clampThisSegStart || clampThisSegEnd | clampComparingSegEnd || clampComparingSegEnd) + { + if(t0 < 0 && clampThisSegStart) + { + pointA = segAStartPoint; + } + else if(t0 > normA && clampThisSegEnd) + { + pointA = segAEndPoint; + } + + if(t1 < 0 && clampComparingSegStart) + { + pointB = segBStartPoint; + } + else if(t1 > normB && clampComparingSegEnd) + { + pointB = segBEndPoint; + } + } + +// PVector diffpApB = pointA.copy().sub(pointB); +// double distance = MathUtil.calculateL2Norm(diffpApB); +// System.out.println("The closest distance is: " + distance); + + return new LineSegment(pointA, pointB); + } + + private double calculateLength() + { + PVector diff = startPoint.copy().sub(endPoint); + return MathUtil.calculateL2Norm(diff); + } +} diff --git a/src/com/knotrenderer/util/CurveLoader.java b/src/com/knotrenderer/util/CurveLoader.java new file mode 100644 index 0000000..b7cdca7 --- /dev/null +++ b/src/com/knotrenderer/util/CurveLoader.java @@ -0,0 +1,59 @@ +package com.knotrenderer.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; + +import com.knotrenderer.model.Curve; + +import processing.core.PVector; + +public class CurveLoader +{ + public static Curve loadCurveFromFile(String path) + { + File file = new File(path); + ArrayList knotPoints = new ArrayList(); + + try{ + BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); + String line; + while ((line = bufferedReader.readLine()) != null) + { + if(line.equals("") || line.replaceAll("\\s+", "").startsWith("%")) + continue; + else + { + //TODO: handle the case where you have a comment at the end of the line + line = line.replaceAll("\\s+", ""); + String[] splitString = line.split(","); + + //TODO: handle when a line has more or less than 3 coordinates on it (meaning display to the user when it isn't correct) + if(splitString.length != 3) + { + throw new Exception("File line wasn't the correct lenght. It should have exactly 3 numbers on it."); + } + else + { + //TODO: Figure out why there is some precision loss here and how to fix it (compare file to values read in) + float x = Float.parseFloat(splitString[0]); + float y = Float.parseFloat(splitString[1]); + float z = Float.parseFloat(splitString[2]); + + System.out.println("X is: " + x + " Y is: " + y + " Z is: " + z); + knotPoints.add(new PVector(x, y, z)); + } + + } + } + bufferedReader.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } + + return new Curve(knotPoints, path); + } +} diff --git a/src/com/knotrenderer/util/MathUtil.java b/src/com/knotrenderer/util/MathUtil.java new file mode 100644 index 0000000..bb5553a --- /dev/null +++ b/src/com/knotrenderer/util/MathUtil.java @@ -0,0 +1,115 @@ +package com.knotrenderer.util; + +import java.math.BigInteger; +import java.util.Arrays; + +import processing.core.PMatrix3D; +import processing.core.PVector; + +public class MathUtil +{ + /** + * Calculates the l1 norm of the given values. The l1 norm is + * the sum of the absolute values of the given values + * @param values + * @return double - the l1 norm value + */ + public static double calculateL1Norm(double...values) + { + double l1Norm = 0; + for(double value : values) + { + l1Norm += Math.abs(value); + } + return l1Norm; + } + + /** + * Calculates the l2 norm of the given vector. The l2 norm is the + * square root of the sum of the squares of the x, y, and z coordinates. + * @param vector + * @return double - the l2 norm value + */ + public static double calculateL2Norm(PVector vector) + { + return MathUtil.calculateL2Norm(vector.x, vector.y, vector.z); + } + + + /** + * Calculates the l2 norm. l2 norm is the square root of the sum + * of all values squared. + * @param values + * @return the l2 norm from the values + */ + public static double calculateL2Norm(double...values) + { + double squaredSum = 0; + + for(double value : values) + { + squaredSum += value * value; + } + return Math.sqrt(squaredSum); + } + + /** + * Matrix looks like this:
+ * | a b c ? |
+ * | d e f ? |
+ * | g h i ? |
+ * | ? ? ? ? |
+ * since {@link PMatrix3D} is a 4 x 4. We are expecting a 3 x 3 in the format above where + * everything with a (?) will not be used. This function will return the determinant of the + * inner 3x3 matrix. + * @param matrix + * @return double determinant of the matrix + */ + public static double calculate3x3Determinant(PMatrix3D matrix) + { + double a = matrix.m00; + double b = matrix.m01; + double c = matrix.m02; + double d = matrix.m10; + double e = matrix.m11; + double f = matrix.m12; + double g = matrix.m20; + double h = matrix.m21; + double i = matrix.m22; + + double firstSubDeterminant = a * ((e * i) - (f * h)); + double secondSubDeterminant = b * ((d * i) - (f * g)); + double thirdSubDeterminant = c * ((d * h) - (e * g)); + + return firstSubDeterminant - secondSubDeterminant + thirdSubDeterminant; + } + + /** + * Returns N Choose K or the binomial coefficient as a double + * @param N + * @param K + * @return double - the binomial coefficient of N choose K + */ + public static double binomialCoefficientAsDouble(final int N, final int K) + { + if(K == 0 || K == N) + { + return 1; + } + + double nChooseK = 1; + for (int k = 0; k < K; k++) { + nChooseK = nChooseK * (N-k) / (k+1); + } + return nChooseK; + } + +// static BigInteger binomial(final int N, final int K) { +// BigInteger ret = BigInteger.ONE; +// for (int k = 0; k < K; k++) { +// ret = ret.multiply(BigInteger.valueOf(N-k)) +// .divide(BigInteger.valueOf(k+1)); +// } +// return ret; +// } +} diff --git a/src/com/knotrenderer/util/OptimumIterationGenerator.java b/src/com/knotrenderer/util/OptimumIterationGenerator.java new file mode 100644 index 0000000..14dba31 --- /dev/null +++ b/src/com/knotrenderer/util/OptimumIterationGenerator.java @@ -0,0 +1,330 @@ +package com.knotrenderer.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; + +import com.knotrenderer.model.LineSegment; + +import processing.core.PVector; + +/** + * PDZ - This class is used to calculate the optimum number of subdivisions (iterations) of the stick + * knot (control polygon for the Bezier curve). It comes directly from Peters' paper. + * + */ +public class OptimumIterationGenerator +{ + + /** + * Calculates the minimum distance between all non-adjacent line segments. It will compare every line + * segment to all other non-adjacent line segments and return the minimum of all the comparisons + * @param lineSegments + * @return {@link Double} the minimum of all the comparisons + */ + public static Double calculateMinimumDistanceBetweenNonAdjacentSegments(ArrayList lineSegments) + { + Double[] distances = calculateDistancesBetweenNonAdjacentSegments(lineSegments); + Arrays.sort(distances); //Sorts in increasing order + return distances[0]; + } + + /** + * Given a list of line segments, return the array of distances between every segment compared to all other + * NON-ADJACENT segments in the list. Adjacent segments are the previous and next segments in the array list + * input. + * @param lineSegments + * @return array of Doubles of the calculated distances + */ + public static Double[] calculateDistancesBetweenNonAdjacentSegments(ArrayList lineSegments) + { + //Each segment between two points (aka control points of the Bezier curve) on the curve determines the drawn knot (Bezier polygon) + int numControlPointSegments = lineSegments.size(); + ArrayList distances = new ArrayList(); + + for(int i = 0; i < numControlPointSegments; i++) //For all the line segments + { + //Compare them to all NON_ADJACENT (hence j = i + 2) segments + int j = i + 2; + while(j < numControlPointSegments) + { + //The first line segment and the last are adjacent so don't check those + if( i == 0 && ((j + 1) % numControlPointSegments == 0)) + { + j += 1; + continue; + } + + LineSegment distanceSegment = lineSegments.get(i).closestDistanceToLineSegment(lineSegments.get(j)); + distances.add(distanceSegment.getLength()); + j += 1; + } + } + + return distances.toArray(new Double[distances.size()]); + } + + /** + * Compares all line segments to all other line segments and returns the minimums of all distances + * @param lineSegments + * @return {@link Double} the minimum distance of all comparisons + */ + public static Double calculateMinimumDistanceBetweenAllSegments(ArrayList lineSegments) + { + Double[] distances = calculateDistancesBetweenAllSegments(lineSegments); + Arrays.sort(distances); //Sorts the array in increasing order + return distances[0]; + } + + /** + * Calculates the distances between all line segments and all other line segments + * @param lineSegments + * @return {@link Double[]} array of all the distances from comparing the segments. + */ + public static Double[] calculateDistancesBetweenAllSegments(ArrayList lineSegments) + { + ArrayList distances = new ArrayList(); + for(int i = 0; i < lineSegments.size(); i++) + { + LineSegment segment = lineSegments.get(i); + for(int j = i ; j < lineSegments.size(); j++) + { + LineSegment comparingSegment = lineSegments.get(j); + distances.add(segment.closestDistanceToLineSegment(comparingSegment).getLength()); + } + } + return distances.toArray(new Double[distances.size()]); + } + + /** + * Removes the shorteningDistance from each line segment and returns the resulting ArrayList + * @param segmentsToBeShortened + * @param shorteningDistance + * @return + */ + public static ArrayList shortenSegments(ArrayList segmentsToBeShortened, double shorteningDistance) throws Exception + { + ArrayList shortenedSegments = new ArrayList(); + + for(LineSegment segment : segmentsToBeShortened) + { + LineSegment shortenedSegment = shortenLineSegmentEnds(segment, shorteningDistance); + shortenedSegments.add(shortenedSegment); + } + + return shortenedSegments; + } + + /** + * Shortens the given segment by the shorteningDistance. It will remove shorteningDistanceFromEachEnd from + * each side of the segment so that the total length reduction is 2 *shorteningDistance. + * @param segment + * @param shorteningDistanceFromEachEnd + * @return the new LineSegment of the shortened length + */ + public static LineSegment shortenLineSegmentEnds(LineSegment segment, double shorteningDistanceFromEachEnd) throws Exception + { + /** + * Parametrize the line segment so that you can subtract the distance. Since the line is + * parametrized its distance will be from 0 to 1. To reduce it by the desired amount we need + * to figure out the proportion of the line compared to the parameter and then subtract that + * amount. + */ + double length = segment.getLength(); + if(2 * shorteningDistanceFromEachEnd > length) + throw new Exception("Line Segment isn't long enough to be shortened by that amount. It would result in a length less than 0."); + + PVector lineVector = segment.getStartPoint().sub(segment.getEndPoint()); + double vectorReduction = shorteningDistanceFromEachEnd / length; //Proportion + + float newEndX = (float) (segment.getEndPoint().x + vectorReduction * lineVector.x); + float newEndY = (float) (segment.getEndPoint().y + vectorReduction * lineVector.y); + float newEndZ = (float) (segment.getEndPoint().z + vectorReduction * lineVector.z); + + PVector newEndPoint = new PVector(newEndX, newEndY, newEndZ); + + float newStartX = (float) (segment.getEndPoint().x + (1 - vectorReduction) * lineVector.x); + float newStartY = (float) (segment.getEndPoint().y + (1 - vectorReduction) * lineVector.y); + float newStartZ = (float) (segment.getEndPoint().z + (1 - vectorReduction) * lineVector.z); + + PVector newStartPoint = new PVector(newStartX, newStartY, newStartZ); + + return new LineSegment(newStartPoint, newEndPoint); + } + + /** + * This generates the omega one value from Professor Peters' and Ji Li's paper. Omega one is used in combination with the delta + * from the Denne-Sullivan paper to figure out m1. + * @return double - the omega one value + */ + public static double calculateOmegaOne(ArrayList knotPoints, boolean isCurveClosed) + { + double[] coordinateNorms = {0.0, 0.0, 0.0}; + + /** + * Generates the set of second iterated forward difference operator. This comes from Professor Peters' and + * Ji Li's paper. It is defined in the paper. It shows up as a triangle with a subscript 2 and set P next to it + */ + //TODO: PDZ- might need to adjust this to make the curve either open or closed - it needs to wrap the points (modulo) + for(int i = 0; i < knotPoints.size(); i++) + { + double valueX, valueY, valueZ; + if(i == knotPoints.size() - 1) + { + valueX = knotPoints.get(1).x - (2 * knotPoints.get(0).x) + knotPoints.get(i).x; + valueY = knotPoints.get(1).y - (2 * knotPoints.get(0).y) + knotPoints.get(i).y; + valueZ = knotPoints.get(1).z - (2 * knotPoints.get(0).z) + knotPoints.get(i).z; + } + else if((i + 1) == knotPoints.size() - 1) + { + valueX = knotPoints.get(0).x - (2 * knotPoints.get(i+1).x) + knotPoints.get(i).x; + valueY = knotPoints.get(0).y - (2 * knotPoints.get(i+1).y) + knotPoints.get(i).y; + valueZ = knotPoints.get(0).z - (2 * knotPoints.get(i+1).z) + knotPoints.get(i).z; + } + else + { + valueX = knotPoints.get(i + 2).x - (2 * knotPoints.get(i+1).x) + knotPoints.get(i).x; + valueY = knotPoints.get(i + 2).y - (2 * knotPoints.get(i+1).y) + knotPoints.get(i).y; + valueZ = knotPoints.get(i + 2).z - (2 * knotPoints.get(i+1).z) + knotPoints.get(i).z; + } + + /* + * Generate the l1- norm for the given coordinate by adding the absolute values of all the deltaSub2 + */ + coordinateNorms[0] += Math.abs(valueX); + coordinateNorms[1] += Math.abs(valueY); + coordinateNorms[2] += Math.abs(valueZ); + } + + /** + * Get omega one - which is the largest of all the l1 - norms for x, y, and z + */ + return Math.max(coordinateNorms[0], Math.max(coordinateNorms[1], coordinateNorms[2])); + } + + /** + * Calculates the M1 value from Professor Peters' and Ji Li's paper + * @param omegaOne + * @param delta + * @return int - the value of M1 + */ + public static int calculateM1(double omegaOne, double delta) + { + double omegaOneSquared = Math.pow(omegaOne, 2); + double deltaSquared = Math.pow(delta, 2); + double intermediate = ((7.0 / 16.0) * omegaOneSquared * (1 / deltaSquared)) - (1.0 / 7.0); + double logResult = Math.log(intermediate) / Math.log(2); + return (int) Math.ceil(logResult); + } + + /** + * Generates the hodograph delta sub 2 set from Professor Peters' and Ji Li's paper. It is defined in + * the paper. + * @param controlPoints + * @return- ArrayList[] - an array of array lists of doubles. Each coordinate (x, y, z) has its set + * generated and all 3 sets are returned. + */ + public static ArrayList[] generateHodographDeltaTwoSet(ArrayList controlPoints) + { + //An array of array lists. There are 3 array lists in the array - one for each component (x, y, and z) + @SuppressWarnings("unchecked") + ArrayList[] hodographDelta2Sets = (ArrayList[]) new ArrayList[3]; + hodographDelta2Sets[0] = new ArrayList(); + hodographDelta2Sets[1] = new ArrayList(); + hodographDelta2Sets[2] = new ArrayList(); + + + //PDZ- need to wrap around and connect back to the first point + for(int i = 1; i < controlPoints.size(); i++) //Add -1 to controlPoints.size() to make it an open curve again + { + int numControlPoints = controlPoints.size(); + + //TODO: fix this - need to move numControlPoints to multiply by everything else + double hodographDeltaSub2Ofi_xcoord = numControlPoints * (controlPoints.get((i + 2) % numControlPoints).x + - (3 * controlPoints.get((i + 1) % numControlPoints).x) + + (3 * controlPoints.get(i).x) + - controlPoints.get(i - 1).x); + double hodographDeltaSub2Ofi_ycoord = numControlPoints * (controlPoints.get((i + 2) % numControlPoints).y + - (3 * controlPoints.get((i + 1) % numControlPoints).y) + + (3 * controlPoints.get(i).y) + - controlPoints.get(i - 1).y); + double hodographDeltaSub2Ofi_zcoord = numControlPoints * (controlPoints.get((i + 2) % numControlPoints).z + - (3 * controlPoints.get((i + 1) % numControlPoints).z) + + (3 * controlPoints.get(i).z) + - controlPoints.get(i - 1).z); + + hodographDelta2Sets[0].add(hodographDeltaSub2Ofi_xcoord); + hodographDelta2Sets[1].add(hodographDeltaSub2Ofi_ycoord); + hodographDelta2Sets[2].add(hodographDeltaSub2Ofi_zcoord); + } + return hodographDelta2Sets; + } + + /** + * Calculates the omega two value from Professor Peters' and Ji Li's paper. Omega two is + * calculated by generating the hodograph delta two sets for each coordinate (x, y, and z) + * and then taking the max of the l1-norms of those. + * @param controlPoints + * @return double - the omega two value + */ + public static double calculateOmegaTwo(ArrayList controlPoints) + { + ArrayList[] hodographSets = generateHodographDeltaTwoSet(controlPoints); + double l1NormX = MathUtil.calculateL1Norm(UnboxUtils.unboxDoubles(hodographSets[0])); + double l1NormY = MathUtil.calculateL1Norm(UnboxUtils.unboxDoubles(hodographSets[1])); + double l1NormZ = MathUtil.calculateL1Norm(UnboxUtils.unboxDoubles(hodographSets[2])); + return Math.max(l1NormX, Math.max(l1NormY, l1NormZ)); + } + + /** + * Calculates the lambda of the given segments. The lambda (as defined in Professor Peters' paper) is + * the minimum length of all the segments passed in. + * @param segments + * @return + */ + public static double calculateLambda(ArrayList segments) + { + double lambda = segments.get(0).getLength(); + for(LineSegment segment : segments) + { + lambda = segment.getLength() < lambda ? segment.getLength() : lambda; + } + return lambda; + } + + /** + * Calculates m2 from Professor Peters' and Ji Li's paper. + * @param segments + * @param omegaTwo + * @param lambda + * @return int - the value of m2 + */ + public static int calculateM2(ArrayList segments, double omegaTwo, double lambda) + { + int m2 = 0; + int numControlPoints = segments.size(); + while((numControlPoints * Math.pow(2, 3 * m2) + Math.pow(2, 2 * m2)) < Math.pow(omegaTwo / lambda, 2)) + { + m2++; + } + return m2; + } + + /** + * Calculates m3 from Professor Peters' and Ji Li's paper + * @param segments + * @param omegaTwo + * @param lambda + * @return int - the value of m3 + */ + public static int calculateM3(ArrayList segments, double omegaTwo , double lambda) + { + int m3 = 0; + int numControlPoints = segments.size(); + while((numControlPoints * Math.pow(2, 3 * m3) + Math.pow(2, 2 * m3)) < Math.pow((omegaTwo / (Math.sin(Math.PI / 8) * lambda)), 2)) + { + m3++; + } + return m3; + } +} diff --git a/src/com/knotrenderer/util/UnboxUtils.java b/src/com/knotrenderer/util/UnboxUtils.java new file mode 100644 index 0000000..24720dc --- /dev/null +++ b/src/com/knotrenderer/util/UnboxUtils.java @@ -0,0 +1,28 @@ +package com.knotrenderer.util; + +import java.util.ArrayList; +import java.util.Arrays; + +public class UnboxUtils +{ + /** + * Creates an array of doubles (primitive) equal to the values in the array list + * @param valuesToUnbox + * @return double[] - the unboxed doubles + */ + public static double[] unboxDoubles(ArrayList valuesToUnbox) + { + return unboxDoubles(valuesToUnbox.toArray(new Double[valuesToUnbox.size()])); + } + + /** + * Creates an array of doubles (primitive) equal to the values in the array of Doubles + * @param valuesToUnbox + * @return double[] - the unboxed doubles + */ + public static double[] unboxDoubles(Double[] valuesToUnbox) + { + return Arrays.stream(valuesToUnbox).mapToDouble(i -> i).toArray(); + } + +} diff --git a/src/com/knotrenderer/view/ControlP5Controller.java b/src/com/knotrenderer/view/ControlP5Controller.java new file mode 100644 index 0000000..75a632a --- /dev/null +++ b/src/com/knotrenderer/view/ControlP5Controller.java @@ -0,0 +1,15 @@ +package com.knotrenderer.view; + +import controlP5.ControlP5; +import processing.core.PApplet; + +public class ControlP5Controller +{ + private final ControlP5 controlP5; + + public ControlP5Controller(PApplet applet) + { + controlP5 = new ControlP5(applet); + new ControlP5CurveLoaderTab(controlP5); + } +} diff --git a/src/com/knotrenderer/view/ControlP5CurveLoaderTab.java b/src/com/knotrenderer/view/ControlP5CurveLoaderTab.java new file mode 100644 index 0000000..ed4a83b --- /dev/null +++ b/src/com/knotrenderer/view/ControlP5CurveLoaderTab.java @@ -0,0 +1,33 @@ +package com.knotrenderer.view; + +import controlP5.ControlP5; + +public class ControlP5CurveLoaderTab +{ + private static final int TAB_BACKGROUND = 0xFFFDE7F1; + private final ControlP5 controlP5; + + public ControlP5CurveLoaderTab(ControlP5 controlP5Instance) + { + controlP5 = controlP5Instance; + initTab(); + } + + private void initTab() + { + controlP5.addTab("extra") + .setColorBackground(TAB_BACKGROUND) + .setColorLabel(0x135eda) + .setColorActive(TAB_BACKGROUND) + .setLabel("TEST") + .setPosition(100, 200); + + controlP5.addButton("button") + .setBroadcast(false) + .setPosition(100,100) + .setSize(80,40) + .setValue(1) + .setBroadcast(true) + .getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER); + } +} diff --git a/src/com/knotrenderer/view/KnotRenderer.java b/src/com/knotrenderer/view/KnotRenderer.java new file mode 100644 index 0000000..0dacb01 --- /dev/null +++ b/src/com/knotrenderer/view/KnotRenderer.java @@ -0,0 +1,196 @@ +package com.knotrenderer.view; + +import com.knotrenderer.model.Curve; +import com.knotrenderer.util.CurveLoader; + +import processing.core.PApplet; +import processing.event.KeyEvent; +import processing.event.MouseEvent; + +public class KnotRenderer extends PApplet +{ +// private static final float CAMERA_START_Z = 40f; +// private static final float ZOOM_MULTIPLIER = 20.f; + private static final float CAMERA_START_Z = 40f; + private static final float ZOOM_MULTIPLIER = 5.f; + + private static int WIDTH = 640; + private static int HEIGHT = 480; + + private RenderCurve renderCurve; + private float cameraX = WIDTH / 2; + private float cameraY = HEIGHT / 2; + private float cameraZ = CAMERA_START_Z; + + private float startMouseX; + private float startMouseY; + private float rotationX = 0; + private float rotationY = 0; + + public static void main(String[] args) + { + PApplet.main(new String[] {KnotRenderer.class.getName()}); + } + + public void test() + { +// getSurface().get + } + @Override + public void settings() + { + size(WIDTH, HEIGHT, "processing.opengl.PGraphics3D"); + } + + @Override + public void setup() + { + new ControlP5Controller(this); + + surface.setResizable(true); + + +// Curve curve = CurveLoader.loadCurveFromFile("D:/Peter/College_Grad_School/Independent_Study_Spring_2016_Cont/Knot-Renderer-Processing/Testing_Files/TJP-4th-C1-high-precision.curve"); +// Curve curve = CurveLoader.loadCurveFromFile("D:/Peter/College_Grad_School/Independent_Study_Spring_2016_Cont/Knot-Renderer-Processing/Testing_Files/TJP-4_1_stick-unknot-halved-3.curve"); + Curve curve = CurveLoader.loadCurveFromFile("D:/Peter/College_Grad_School/Independent_Study_Spring_2016_Cont/Knot-Renderer-Processing/Testing_Files/test.curve"); + +// Curve curve = CurveLoader.loadCurveFromFile("/Users/peterzaffetti/UC/Knot-Renderer-Processing/Testing_Files/TJP-4_1_stick-unknot.curve"); +// Curve curve = CurveLoader.loadCurveFromFile("/Users/peterzaffetti/UC/Knot-Renderer-Processing/Testing_Files/test.curve"); +// Curve curve = CurveLoader.loadCurveFromFile("/Users/peterzaffetti/UC/Knot-Renderer-Processing/Testing_Files/TJP-4_1_stick-unknot-halved-3.curve"); + renderCurve = new RenderCurve(this, curve); + } + + @Override + public void mouseWheel(MouseEvent event) + { + cameraZ -= ZOOM_MULTIPLIER * event.getCount(); + } + + @Override + public void frameResized(int w, int h) { + super.frameResized(w, h); + WIDTH = w; + System.out.println(WIDTH); + HEIGHT = h; + } + + @Override + public void keyPressed(KeyEvent event) { + super.keyPressed(event); + if(event.getKey() == CODED) + { + int keyCode = event.getKeyCode(); + switch (keyCode) + { + case UP: + rotationX += Math.PI / 6; + break; + case DOWN: + rotationX -= Math.PI / 6; + break; + case LEFT: + rotationY -= Math.PI / 6; + break; + case RIGHT: + rotationY += Math.PI / 6; + break; + } + } + else + { + switch(event.getKey()) + { + case ' ': + //PDZ- when the user presses space make sure that the WIDTH and HEIGHT are updated to the latest + WIDTH = width; + HEIGHT = height; + + //TODO: PDZ- Doing it this way will apply the same transformation to every curve. Might want to make it so that you + //can control/rotate/translate each curve individually **SEE BELOW** + cameraX = WIDTH/2; + cameraY = HEIGHT/2; + + //PDZ- Uncomment these if you want the space bar to also undo any rotations and scaling of the knot/curve +// cameraZ = CAMERA_START_Z; +// rotationX = 0; +// rotationY = 0; + break; + case 'w': + cameraY -= 20; + break; + case 's': + cameraY += 20; + break; + case 'a': + cameraX -=20; + break; + case 'd': + cameraX +=20; + break; + } + + } + } + + @Override + public void mouseDragged(MouseEvent event) + { + //TODO: PDZ- Fix the issue where panning will slightly rotate the object (might be an issue with the camera) + if(mousePressed && (mouseButton == LEFT)) + { + if(startMouseX < 1) + { + startMouseX = mouseX; + } + float deltaX = mouseX - startMouseX; + cameraX += deltaX; + startMouseX = mouseX; + + if(startMouseY < 1) + { + startMouseY = mouseY; + } + float deltaY = mouseY - startMouseY; + cameraY += deltaY; + startMouseY = mouseY; + } + else if(mousePressed && (mouseButton == RIGHT)) + { + + } + } + + @Override + public void mouseClicked(MouseEvent event) + { + startMouseX = mouseX; + startMouseY = mouseY; + } + + @Override + public void draw() + { + background(0); + + //PDZ- camera needs to be first since the translation messes up the coordinate + pushMatrix(); + camera(WIDTH / 2, HEIGHT / 2, 40f, WIDTH/2.0f, HEIGHT/2.0f, 0f, 0f, 1f, 0f); + popMatrix(); + + pushMatrix(); + //TODO: PDZ- see comment above about separating the camera from the curves **SEE ABOVE** + // You would just need to apply the translation/rotation in the curve draw methods + translate(cameraX, cameraY, cameraZ); + stroke(255); + strokeWeight(0.2f); + rotateX(rotationX); + rotateY(rotationY); + scale(20); //PDZ- this needs to come after the translation + noFill(); + + renderCurve.drawBezierCurve(); + renderCurve.drawStickKnot(); + popMatrix(); + } + +} diff --git a/src/com/knotrenderer/view/KnotRendererApplet.java b/src/com/knotrenderer/view/KnotRendererApplet.java new file mode 100644 index 0000000..413bc85 --- /dev/null +++ b/src/com/knotrenderer/view/KnotRendererApplet.java @@ -0,0 +1,27 @@ +package com.knotrenderer.view; + +import java.applet.Applet; +import java.awt.Graphics; + +public class KnotRendererApplet extends Applet +{ + @Override + public void init() { + super.init(); + + KnotRenderer renderer = new KnotRenderer(); +// renderer. + + + } + + @Override + public void start() { + super.start(); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + } +} diff --git a/src/com/knotrenderer/view/RenderCurve.java b/src/com/knotrenderer/view/RenderCurve.java new file mode 100644 index 0000000..10e6f60 --- /dev/null +++ b/src/com/knotrenderer/view/RenderCurve.java @@ -0,0 +1,176 @@ +package com.knotrenderer.view; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.Semaphore; + +import com.knotrenderer.model.BezierCurve; +import com.knotrenderer.model.Curve; + +import processing.core.PApplet; +import processing.core.PVector; + +/** + * PDZ- This class is backed by a {@link Curve} as its model. However, this curve, since it is being + * drawn and needs to be drawn smoothly, has additional draw points which we calculate here and don't + * want to mix in with the model points. The additional points are for the smoothness of the Bezier + * curve. This class also holds the draw methods for both the stick knot and Bezier curve of the + * model knot. + * + */ +public class RenderCurve +{ + Thread testThread; + private PApplet applet; + private Curve knotCurve; + private BezierCurve bezierCurve; + private ArrayList knotPoints; + private ArrayList bezierDrawPoints; + private ArrayList testPoints; + private float scale = 1.f; + private static final Semaphore semaphore = new Semaphore(1); + + //PDZ- For testing: + private PVector recursive; + private PVector summation; + + public RenderCurve(PApplet applet, Curve knotCurve) + { + this.applet = applet; + this.knotCurve = knotCurve; + this.knotPoints = knotCurve.getKnotPoints(); + this.bezierDrawPoints = new ArrayList(); + this.testPoints = new ArrayList(); + this.bezierCurve = new BezierCurve(knotPoints); + //TODO: PDZ- figure out a better way to handle the mess of recursion when calculating the values + testThread = new Thread(new Runnable() { + + @Override + public void run() { + + try { + semaphore.acquire(1); + try + { + calculateBezierDrawPoints(); + calculateBezierDrawPoints_recurive(); + } + finally + { + semaphore.release(1); + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + + testThread.start(); +// calculateBezierDrawPoints_recurive(); +// calculateBezierDrawPoints(); +// PVector bezierPoint = bezierCurve.getCurveValueFromExpansion(.1); +// this.bezierDrawPoints.add(bezierPoint); + } + + private void calculateBezierDrawPoints_recurive() + { + for(double i = 0; i <= 1; i+= 0.0001) + { + PVector bezierPoint = bezierCurve.getCurveValueRecursively(i); + if(i == 0.25) + { + recursive = bezierPoint.copy(); + } + this.bezierDrawPoints.add(bezierPoint); + } + } + + private void calculateBezierDrawPoints() + { + for(double t = 0; t <= 1; t += 0.0001) //PDZ- Had to crank 0.001 to 0.0001 since there were gaps for the super high precision curve + { + PVector bezierPoint = bezierCurve.getCurveValueFromSummationExpansion(t); + if(t == 0.25) + { + summation = bezierPoint.copy(); + } + this.testPoints.add(bezierPoint); + } + } + + public void setScale(float scale) + { + this.scale = scale; + } + + public void drawStickKnot() + { + applet.stroke(255, 255, 255); + applet.scale(scale); + ArrayList points = knotCurve.getKnotPoints(); + + applet.beginShape(); + Iterator it = points.iterator(); + while(it.hasNext()) + { + PVector vec = it.next(); + applet.vertex(vec.x, vec.y, vec.z); + } + applet.endShape(PApplet.CLOSE); + } + + public void drawBezierCurve() + { + boolean didAcquire = semaphore.tryAcquire(1); + if(!didAcquire || bezierDrawPoints.size() < 1) + { +// System.out.println("HOPE"); + return; + } + + recursive = bezierCurve.getCurveValueRecursively(0.25); + summation = bezierCurve.getCurveValueFromSummationExpansion(0.25); + + System.out.println("Recurisve = " + recursive); + System.out.println("Summation = " + summation); + + applet.stroke(255, 0, 0); + applet.scale(scale); + applet.beginShape(); + applet.vertex(bezierDrawPoints.get(0).x, bezierDrawPoints.get(0).y, bezierDrawPoints.get(0).z); + Iterator it = bezierDrawPoints.iterator(); + int j = 0; + while(it.hasNext()) + { +// j++; +// if(j == 150) +// break; + PVector bezierPoint = it.next(); + applet.vertex(bezierPoint.x, bezierPoint.y, bezierPoint.z); + } + applet.endShape(); + + if(!didAcquire) + { + return; + } + + applet.stroke(0, 255, 0); + applet.scale(scale); + applet.beginShape(); + applet.vertex(testPoints.get(0).x, testPoints.get(0).y, testPoints.get(0).z); + Iterator iterator = testPoints.iterator(); + int i = 0; + while(iterator.hasNext()) + { +// i++; +// if(i == 150) +// break; + PVector bezierPoint = iterator.next(); + applet.vertex(bezierPoint.x, bezierPoint.y, bezierPoint.z); + } + applet.endShape(); + semaphore.release(1); + } +} diff --git a/src/com/knotrenderer/web/PointGeneratorServlet.java b/src/com/knotrenderer/web/PointGeneratorServlet.java new file mode 100644 index 0000000..4546df6 --- /dev/null +++ b/src/com/knotrenderer/web/PointGeneratorServlet.java @@ -0,0 +1,41 @@ +package com.knotrenderer.web; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Servlet implementation class PointGeneratorServlet + */ +@WebServlet("/PointGeneratorServlet") +public class PointGeneratorServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + /** + * @see HttpServlet#HttpServlet() + */ + public PointGeneratorServlet() { + super(); + // TODO Auto-generated constructor stub + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) + */ + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // TODO Auto-generated method stub + response.getWriter().append("Served at: ").append(request.getContextPath()); + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // TODO Auto-generated method stub + doGet(request, response); + } + +}