diff --git a/.gitignore b/.gitignore index dd158e4..b3e3458 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,6 @@ target/ #IntelliJ Files *.idea + +#Subdivision Log Generator log file +logs/* diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli_application.py b/cli_application.py new file mode 100755 index 0000000..237f1d4 --- /dev/null +++ b/cli_application.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +""" +@author Peter Zaffetti 2017 +""" +import argparse +import cmd +import os +import sys + +from user_interface.curve_parser import parse_curve_file +from logger import get_logger + + +class CliApplication(cmd.Cmd): + + def __init__(self, application_path=None, application_name="generator", args=None): + self.logger = get_logger(__name__) + self.curve_paths = os.path.join(application_path, "curves") + self.arguments = args + self.parse_cmd_args(self.arguments) + sys.exit(1) + + def parse_cmd_args(self, args): + if args is not None: + if args.generate_m_value: + if os.path.exists(args.generate_m_value): + self.generate_m_value(args.generate_m_value) + else: + curve_path = os.path.join(self.curve_paths, args.generate_m_value) + if os.path.exists(curve_path): + self.generate_m_value(curve_path) + else: + self.logger.info("The curve file doesn't exist. Please choose an appropriate file.") + else: + raise Exception("There were no arguments when running the application") + + def generate_m_value(self, curve_file="test.curve"): + knot_curve = parse_curve_file(curve_file) + + pass + + +def main(): + """The main function that runs the Subdivision Generator application""" + + application_path = os.path.dirname(os.path.abspath(__file__)) + application_name = os.path.splitext(os.path.basename(__file__))[0] + + argument_parser = argparse.ArgumentParser( + description='Generates the required number of subdivisions for a Bezier curve to match the stick knot it was created from') + argument_parser.add_argument("-g", "--generate_m_value", help="generates the minimum number of iterations needed for the supplied \ + stick knot's Bezier cure to match the stick knot", default=None, action="store") + arguments = argument_parser.parse_args() + + get_logger().debug("Subdivision-Generator Starting Up") + application = CliApplication(application_path, application_name, arguments) + + +if __name__ == "__main__": + main() diff --git a/curve_data_objects/__init__.py b/curve_data_objects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/curve_data_objects/straight_curve.py b/curve_data_objects/straight_curve.py new file mode 100644 index 0000000..c3d2892 --- /dev/null +++ b/curve_data_objects/straight_curve.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +""" +@author Peter Zaffetti 2017 +""" + +class StraightCurve: + + def __init__(self, curve_points): + pass + diff --git a/curves/TJP-4_1_stick-unknot-halved-1.curve b/curves/TJP-4_1_stick-unknot-halved-1.curve new file mode 100644 index 0000000..16f6d44 --- /dev/null +++ b/curves/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/curves/TJP-4_1_stick-unknot-halved-2.curve b/curves/TJP-4_1_stick-unknot-halved-2.curve new file mode 100644 index 0000000..083c2bd --- /dev/null +++ b/curves/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/curves/TJP-4_1_stick-unknot-halved-3.curve b/curves/TJP-4_1_stick-unknot-halved-3.curve new file mode 100644 index 0000000..92bb3e9 --- /dev/null +++ b/curves/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/curves/TJP-4_1_stick-unknot.curve b/curves/TJP-4_1_stick-unknot.curve new file mode 100644 index 0000000..e1d9f92 --- /dev/null +++ b/curves/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/curves/TJP-4_1_stick-unknot_TEST.curve b/curves/TJP-4_1_stick-unknot_TEST.curve new file mode 100644 index 0000000..c7f3fb2 --- /dev/null +++ b/curves/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/curves/TJP-4th-C1-high-precision.curve b/curves/TJP-4th-C1-high-precision.curve new file mode 100644 index 0000000..1ac6bbb --- /dev/null +++ b/curves/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/curves/test.curve b/curves/test.curve new file mode 100644 index 0000000..27f824e --- /dev/null +++ b/curves/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/data_objects/point.py b/data_objects/point.py index cb1f020..214292b 100644 --- a/data_objects/point.py +++ b/data_objects/point.py @@ -4,6 +4,14 @@ """ +def distance_between_points(start_point, end_point): + x = end_point.get_x() - start_point.get_x() + y = end_point.get_y() - start_point.get_y() + z = end_point.get_z() - start_point.get_z() + + return float((x * x + y * y + z * z) ** (1 / 2)) + + class Point: def __init__(self, x_val, y_val, z_val): @@ -17,3 +25,12 @@ def __eq__(self, other): return self.x_val == other.x_val and self.y_val == other.y_val and self.z_val == other.z_val return False + def get_x(self): + return self.x_val + + def get_y(self): + return self.y_val + + def get_z(self): + return self.z_val + diff --git a/data_objects/stick_knot.py b/data_objects/stick_knot.py index e735457..fac6ae0 100644 --- a/data_objects/stick_knot.py +++ b/data_objects/stick_knot.py @@ -5,7 +5,6 @@ from point import Point - class StickKnot: def __init__(self, knot_points_arr=None): @@ -13,4 +12,4 @@ def __init__(self, knot_points_arr=None): pass def get_points(self): - return self.knot_points \ No newline at end of file + return self.knot_points diff --git a/generator/__init__.py b/generator/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/generator/old_parser.py b/generator/old_parser.py new file mode 100644 index 0000000..0a63575 --- /dev/null +++ b/generator/old_parser.py @@ -0,0 +1,33 @@ +# #!/usr/bin/env python +# """ +# @author Peter Zaffetti 2017 +# """ +# class Parser: +# +# def __init__(self): +# pass +# +# def parse_curve(curve_filename=None): +# +# if curve_filename is None: +# return None +# +# curve_file = open(curve_filename, "r") +# +# +# for line in curve_file: +# comment_parts = "" +# curve_points = list() +# +# if line.startswith("%"): +# continue +# elif "%" in line: +# comment_parts = line.split("%") +# +# if comment_parts is not None: +# curve_string = comment_parts[0] +# curve_points = curve_string.split(",") +# else: +# curve_points = line.split(",") +# +# if len(curve_points) == 3: \ No newline at end of file diff --git a/logger.py b/logger.py new file mode 100644 index 0000000..3d3bfaf --- /dev/null +++ b/logger.py @@ -0,0 +1,30 @@ +""" +A simplistic Logger class which wraps the Python logging class + +@author Peter Zaffetti +@date 10/10/2017 +""" +import logging +import os + + +def get_logger(classname=None): + log_dir = "logs" + if not os.path.exists(log_dir): + os.makedirs(log_dir) + + root = logging.getLogger() + if root.handlers: + for handler in root.handlers: + root.removeHandler(handler) + + logging.basicConfig(format='%(asctime)s: %(filename)s: %(funcName)s: %(levelname)s:\t %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', filename="logs/generator_log.txt") + + if classname is None: + classname = "Subdivision Generator" + + logger = logging.getLogger(classname) + logger.setLevel(logging.INFO) + logger.addHandler(logging.StreamHandler()) + + return logging.getLogger(classname) diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..48fffd9 --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" +"$SCRIPT_DIR/cli_application.py" $* diff --git a/subdivision_generator_orig_pyth_3_6.py b/subdivision_generator_orig_pyth_3_6.py new file mode 100644 index 0000000..25ee45d --- /dev/null +++ b/subdivision_generator_orig_pyth_3_6.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/unit_tests/parser_test.py b/unit_tests/parser_test.py index 7ae371d..774df6e 100644 --- a/unit_tests/parser_test.py +++ b/unit_tests/parser_test.py @@ -3,7 +3,7 @@ @author Peter Zaffetti 2017 """ import unittest -from user_interface.parser import parse_curve_file +from user_interface.curve_parser import parse_curve_file from data_objects.point import Point diff --git a/unit_tests/point_test.py b/unit_tests/point_test.py new file mode 100644 index 0000000..7745e0c --- /dev/null +++ b/unit_tests/point_test.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +""" +@author Peter Zaffetti 2017 +""" +import unittest +from data_objects.point import Point, distance_between_points + + +class PointTest(unittest.TestCase): + origin_test_point = Point(0, 0, 0) + test_point = Point(12, 8, 4) + + def test_getters(self): + self.assertTrue(self.test_point.get_x() == 12) + self.assertTrue(self.test_point.get_y() == 8) + self.assertTrue(self.test_point.get_z() == 4) + + def test_distance_between_points(self): + """Test the distance from the origin to 12, 8 , 4 -> it should be about 14.96662954""" + distance = distance_between_points(self.origin_test_point, self.test_point) + self.assertTrue( distance == 14.96662954) + + +if __name__ == "__main__": + unittest.main() diff --git a/user_interface/cli.py b/user_interface/cli.py deleted file mode 100644 index 3104f00..0000000 --- a/user_interface/cli.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -""" -@author Peter Zaffetti 2017 -""" -import logging -import argparse - - -class Cli: - - def __init__(self): - self.parser = argparse.ArgumentParser(description='Generates the required number of subdivisions for a Bezier curve to match the stick knot it was created from') - self.parser.add_argument() - pass - - def generate_m_value(self, curve_file=None): - pass - -class GenerateMValue(app.CommandLineApp): - - def setup(self): - self.add_param("-g", "--generateM", help="generates the minimum number of iterations needed for the supplied \ - stick knot's Bezier cure to match the stick knot", default=None, action="store") - - -def main(): - logging.info("Pretend to do something here...") - return True - - -if __name__ == "__main__": - GenerateMValue.run() \ No newline at end of file diff --git a/user_interface/parser.py b/user_interface/curve_parser.py similarity index 77% rename from user_interface/parser.py rename to user_interface/curve_parser.py index dd573d0..4c0be08 100644 --- a/user_interface/parser.py +++ b/user_interface/curve_parser.py @@ -4,18 +4,24 @@ """ from data_objects.point import Point from data_objects.stick_knot import StickKnot +from logger import get_logger def parse_curve_file(filename="test.curve"): + logger = get_logger(parse_curve_file.__name__) + curve_file = open(filename, "r") stick_knot_points = list() for line in curve_file: - if line.startswith("%"): + line = ''.join(line.split()) # PDZ- Remove all whitespace in the row + + if line.startswith("%") or line == "": continue comment_split_line = line.split("%") point_values = comment_split_line[0] comma_split_point_values = point_values.split(",") + logger.debug(comma_split_point_values) if len(comma_split_point_values) != 3: raise Exception("The curve file is not formatted properly") diff --git a/user_interface/gui.py b/user_interface/gui.py index ae3331f..3aac5fb 100644 --- a/user_interface/gui.py +++ b/user_interface/gui.py @@ -2,4 +2,3 @@ TODO: This is stubbed out for now. Eventually, the GUI will sit on top of the CLI functionality in the cli.py file @author Peter Zaffetti 2017 """ -from cli import GenerateMValue